1160814Ssimon/* rsa_pss.c */
2296341Sdelphij/*
3296341Sdelphij * Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL project
4296341Sdelphij * 2005.
5160814Ssimon */
6160814Ssimon/* ====================================================================
7160814Ssimon * Copyright (c) 2005 The OpenSSL Project.  All rights reserved.
8160814Ssimon *
9160814Ssimon * Redistribution and use in source and binary forms, with or without
10160814Ssimon * modification, are permitted provided that the following conditions
11160814Ssimon * are met:
12160814Ssimon *
13160814Ssimon * 1. Redistributions of source code must retain the above copyright
14296341Sdelphij *    notice, this list of conditions and the following disclaimer.
15160814Ssimon *
16160814Ssimon * 2. Redistributions in binary form must reproduce the above copyright
17160814Ssimon *    notice, this list of conditions and the following disclaimer in
18160814Ssimon *    the documentation and/or other materials provided with the
19160814Ssimon *    distribution.
20160814Ssimon *
21160814Ssimon * 3. All advertising materials mentioning features or use of this
22160814Ssimon *    software must display the following acknowledgment:
23160814Ssimon *    "This product includes software developed by the OpenSSL Project
24160814Ssimon *    for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
25160814Ssimon *
26160814Ssimon * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
27160814Ssimon *    endorse or promote products derived from this software without
28160814Ssimon *    prior written permission. For written permission, please contact
29160814Ssimon *    licensing@OpenSSL.org.
30160814Ssimon *
31160814Ssimon * 5. Products derived from this software may not be called "OpenSSL"
32160814Ssimon *    nor may "OpenSSL" appear in their names without prior written
33160814Ssimon *    permission of the OpenSSL Project.
34160814Ssimon *
35160814Ssimon * 6. Redistributions of any form whatsoever must retain the following
36160814Ssimon *    acknowledgment:
37160814Ssimon *    "This product includes software developed by the OpenSSL Project
38160814Ssimon *    for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
39160814Ssimon *
40160814Ssimon * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
41160814Ssimon * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
42160814Ssimon * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
43160814Ssimon * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
44160814Ssimon * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
45160814Ssimon * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
46160814Ssimon * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
47160814Ssimon * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
48160814Ssimon * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
49160814Ssimon * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
50160814Ssimon * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
51160814Ssimon * OF THE POSSIBILITY OF SUCH DAMAGE.
52160814Ssimon * ====================================================================
53160814Ssimon *
54160814Ssimon * This product includes cryptographic software written by Eric Young
55160814Ssimon * (eay@cryptsoft.com).  This product includes software written by Tim
56160814Ssimon * Hudson (tjh@cryptsoft.com).
57160814Ssimon *
58160814Ssimon */
59160814Ssimon
60160814Ssimon#include <stdio.h>
61160814Ssimon#include "cryptlib.h"
62160814Ssimon#include <openssl/bn.h>
63160814Ssimon#include <openssl/rsa.h>
64160814Ssimon#include <openssl/evp.h>
65160814Ssimon#include <openssl/rand.h>
66160814Ssimon#include <openssl/sha.h>
67160814Ssimon
68296341Sdelphijstatic const unsigned char zeroes[] = { 0, 0, 0, 0, 0, 0, 0, 0 };
69160814Ssimon
70160814Ssimon#if defined(_MSC_VER) && defined(_ARM_)
71296341Sdelphij# pragma optimize("g", off)
72160814Ssimon#endif
73160814Ssimon
74160814Ssimonint RSA_verify_PKCS1_PSS(RSA *rsa, const unsigned char *mHash,
75296341Sdelphij                         const EVP_MD *Hash, const unsigned char *EM,
76296341Sdelphij                         int sLen)
77296341Sdelphij{
78296341Sdelphij    return RSA_verify_PKCS1_PSS_mgf1(rsa, mHash, Hash, NULL, EM, sLen);
79296341Sdelphij}
80238405Sjkim
81238405Sjkimint RSA_verify_PKCS1_PSS_mgf1(RSA *rsa, const unsigned char *mHash,
82296341Sdelphij                              const EVP_MD *Hash, const EVP_MD *mgf1Hash,
83296341Sdelphij                              const unsigned char *EM, int sLen)
84296341Sdelphij{
85296341Sdelphij    int i;
86296341Sdelphij    int ret = 0;
87296341Sdelphij    int hLen, maskedDBLen, MSBits, emLen;
88296341Sdelphij    const unsigned char *H;
89296341Sdelphij    unsigned char *DB = NULL;
90296341Sdelphij    EVP_MD_CTX ctx;
91296341Sdelphij    unsigned char H_[EVP_MAX_MD_SIZE];
92296341Sdelphij    EVP_MD_CTX_init(&ctx);
93160814Ssimon
94296341Sdelphij    if (mgf1Hash == NULL)
95296341Sdelphij        mgf1Hash = Hash;
96238405Sjkim
97296341Sdelphij    hLen = EVP_MD_size(Hash);
98296341Sdelphij    if (hLen < 0)
99296341Sdelphij        goto err;
100296341Sdelphij    /*-
101296341Sdelphij     * Negative sLen has special meanings:
102296341Sdelphij     *      -1      sLen == hLen
103296341Sdelphij     *      -2      salt length is autorecovered from signature
104296341Sdelphij     *      -N      reserved
105296341Sdelphij     */
106296341Sdelphij    if (sLen == -1)
107296341Sdelphij        sLen = hLen;
108296341Sdelphij    else if (sLen == -2)
109296341Sdelphij        sLen = -2;
110296341Sdelphij    else if (sLen < -2) {
111296341Sdelphij        RSAerr(RSA_F_RSA_VERIFY_PKCS1_PSS_MGF1, RSA_R_SLEN_CHECK_FAILED);
112296341Sdelphij        goto err;
113296341Sdelphij    }
114160814Ssimon
115296341Sdelphij    MSBits = (BN_num_bits(rsa->n) - 1) & 0x7;
116296341Sdelphij    emLen = RSA_size(rsa);
117296341Sdelphij    if (EM[0] & (0xFF << MSBits)) {
118296341Sdelphij        RSAerr(RSA_F_RSA_VERIFY_PKCS1_PSS_MGF1, RSA_R_FIRST_OCTET_INVALID);
119296341Sdelphij        goto err;
120296341Sdelphij    }
121296341Sdelphij    if (MSBits == 0) {
122296341Sdelphij        EM++;
123296341Sdelphij        emLen--;
124296341Sdelphij    }
125296341Sdelphij    if (emLen < (hLen + sLen + 2)) { /* sLen can be small negative */
126296341Sdelphij        RSAerr(RSA_F_RSA_VERIFY_PKCS1_PSS_MGF1, RSA_R_DATA_TOO_LARGE);
127296341Sdelphij        goto err;
128296341Sdelphij    }
129296341Sdelphij    if (EM[emLen - 1] != 0xbc) {
130296341Sdelphij        RSAerr(RSA_F_RSA_VERIFY_PKCS1_PSS_MGF1, RSA_R_LAST_OCTET_INVALID);
131296341Sdelphij        goto err;
132296341Sdelphij    }
133296341Sdelphij    maskedDBLen = emLen - hLen - 1;
134296341Sdelphij    H = EM + maskedDBLen;
135296341Sdelphij    DB = OPENSSL_malloc(maskedDBLen);
136296341Sdelphij    if (!DB) {
137296341Sdelphij        RSAerr(RSA_F_RSA_VERIFY_PKCS1_PSS_MGF1, ERR_R_MALLOC_FAILURE);
138296341Sdelphij        goto err;
139296341Sdelphij    }
140296341Sdelphij    if (PKCS1_MGF1(DB, maskedDBLen, H, hLen, mgf1Hash) < 0)
141296341Sdelphij        goto err;
142296341Sdelphij    for (i = 0; i < maskedDBLen; i++)
143296341Sdelphij        DB[i] ^= EM[i];
144296341Sdelphij    if (MSBits)
145296341Sdelphij        DB[0] &= 0xFF >> (8 - MSBits);
146296341Sdelphij    for (i = 0; DB[i] == 0 && i < (maskedDBLen - 1); i++) ;
147296341Sdelphij    if (DB[i++] != 0x1) {
148296341Sdelphij        RSAerr(RSA_F_RSA_VERIFY_PKCS1_PSS_MGF1, RSA_R_SLEN_RECOVERY_FAILED);
149296341Sdelphij        goto err;
150296341Sdelphij    }
151296341Sdelphij    if (sLen >= 0 && (maskedDBLen - i) != sLen) {
152296341Sdelphij        RSAerr(RSA_F_RSA_VERIFY_PKCS1_PSS_MGF1, RSA_R_SLEN_CHECK_FAILED);
153296341Sdelphij        goto err;
154296341Sdelphij    }
155296341Sdelphij    if (!EVP_DigestInit_ex(&ctx, Hash, NULL)
156296341Sdelphij        || !EVP_DigestUpdate(&ctx, zeroes, sizeof zeroes)
157296341Sdelphij        || !EVP_DigestUpdate(&ctx, mHash, hLen))
158296341Sdelphij        goto err;
159296341Sdelphij    if (maskedDBLen - i) {
160296341Sdelphij        if (!EVP_DigestUpdate(&ctx, DB + i, maskedDBLen - i))
161296341Sdelphij            goto err;
162296341Sdelphij    }
163296341Sdelphij    if (!EVP_DigestFinal_ex(&ctx, H_, NULL))
164296341Sdelphij        goto err;
165296341Sdelphij    if (memcmp(H_, H, hLen)) {
166296341Sdelphij        RSAerr(RSA_F_RSA_VERIFY_PKCS1_PSS_MGF1, RSA_R_BAD_SIGNATURE);
167296341Sdelphij        ret = 0;
168296341Sdelphij    } else
169296341Sdelphij        ret = 1;
170160814Ssimon
171296341Sdelphij err:
172296341Sdelphij    if (DB)
173296341Sdelphij        OPENSSL_free(DB);
174296341Sdelphij    EVP_MD_CTX_cleanup(&ctx);
175160814Ssimon
176296341Sdelphij    return ret;
177160814Ssimon
178296341Sdelphij}
179160814Ssimon
180160814Ssimonint RSA_padding_add_PKCS1_PSS(RSA *rsa, unsigned char *EM,
181296341Sdelphij                              const unsigned char *mHash,
182296341Sdelphij                              const EVP_MD *Hash, int sLen)
183296341Sdelphij{
184296341Sdelphij    return RSA_padding_add_PKCS1_PSS_mgf1(rsa, EM, mHash, Hash, NULL, sLen);
185296341Sdelphij}
186238405Sjkim
187238405Sjkimint RSA_padding_add_PKCS1_PSS_mgf1(RSA *rsa, unsigned char *EM,
188296341Sdelphij                                   const unsigned char *mHash,
189296341Sdelphij                                   const EVP_MD *Hash, const EVP_MD *mgf1Hash,
190296341Sdelphij                                   int sLen)
191296341Sdelphij{
192296341Sdelphij    int i;
193296341Sdelphij    int ret = 0;
194296341Sdelphij    int hLen, maskedDBLen, MSBits, emLen;
195296341Sdelphij    unsigned char *H, *salt = NULL, *p;
196296341Sdelphij    EVP_MD_CTX ctx;
197160814Ssimon
198296341Sdelphij    if (mgf1Hash == NULL)
199296341Sdelphij        mgf1Hash = Hash;
200238405Sjkim
201296341Sdelphij    hLen = EVP_MD_size(Hash);
202296341Sdelphij    if (hLen < 0)
203296341Sdelphij        goto err;
204296341Sdelphij    /*-
205296341Sdelphij     * Negative sLen has special meanings:
206296341Sdelphij     *      -1      sLen == hLen
207296341Sdelphij     *      -2      salt length is maximized
208296341Sdelphij     *      -N      reserved
209296341Sdelphij     */
210296341Sdelphij    if (sLen == -1)
211296341Sdelphij        sLen = hLen;
212296341Sdelphij    else if (sLen == -2)
213296341Sdelphij        sLen = -2;
214296341Sdelphij    else if (sLen < -2) {
215296341Sdelphij        RSAerr(RSA_F_RSA_PADDING_ADD_PKCS1_PSS_MGF1, RSA_R_SLEN_CHECK_FAILED);
216296341Sdelphij        goto err;
217296341Sdelphij    }
218160814Ssimon
219296341Sdelphij    MSBits = (BN_num_bits(rsa->n) - 1) & 0x7;
220296341Sdelphij    emLen = RSA_size(rsa);
221296341Sdelphij    if (MSBits == 0) {
222296341Sdelphij        *EM++ = 0;
223296341Sdelphij        emLen--;
224296341Sdelphij    }
225296341Sdelphij    if (sLen == -2) {
226296341Sdelphij        sLen = emLen - hLen - 2;
227296341Sdelphij    } else if (emLen < (hLen + sLen + 2)) {
228296341Sdelphij        RSAerr(RSA_F_RSA_PADDING_ADD_PKCS1_PSS_MGF1,
229296341Sdelphij               RSA_R_DATA_TOO_LARGE_FOR_KEY_SIZE);
230296341Sdelphij        goto err;
231296341Sdelphij    }
232296341Sdelphij    if (sLen > 0) {
233296341Sdelphij        salt = OPENSSL_malloc(sLen);
234296341Sdelphij        if (!salt) {
235296341Sdelphij            RSAerr(RSA_F_RSA_PADDING_ADD_PKCS1_PSS_MGF1,
236296341Sdelphij                   ERR_R_MALLOC_FAILURE);
237296341Sdelphij            goto err;
238296341Sdelphij        }
239296341Sdelphij        if (RAND_bytes(salt, sLen) <= 0)
240296341Sdelphij            goto err;
241296341Sdelphij    }
242296341Sdelphij    maskedDBLen = emLen - hLen - 1;
243296341Sdelphij    H = EM + maskedDBLen;
244296341Sdelphij    EVP_MD_CTX_init(&ctx);
245296341Sdelphij    if (!EVP_DigestInit_ex(&ctx, Hash, NULL)
246296341Sdelphij        || !EVP_DigestUpdate(&ctx, zeroes, sizeof zeroes)
247296341Sdelphij        || !EVP_DigestUpdate(&ctx, mHash, hLen))
248296341Sdelphij        goto err;
249296341Sdelphij    if (sLen && !EVP_DigestUpdate(&ctx, salt, sLen))
250296341Sdelphij        goto err;
251296341Sdelphij    if (!EVP_DigestFinal_ex(&ctx, H, NULL))
252296341Sdelphij        goto err;
253296341Sdelphij    EVP_MD_CTX_cleanup(&ctx);
254160814Ssimon
255296341Sdelphij    /* Generate dbMask in place then perform XOR on it */
256296341Sdelphij    if (PKCS1_MGF1(EM, maskedDBLen, H, hLen, mgf1Hash))
257296341Sdelphij        goto err;
258160814Ssimon
259296341Sdelphij    p = EM;
260160814Ssimon
261296341Sdelphij    /*
262296341Sdelphij     * Initial PS XORs with all zeroes which is a NOP so just update pointer.
263296341Sdelphij     * Note from a test above this value is guaranteed to be non-negative.
264296341Sdelphij     */
265296341Sdelphij    p += emLen - sLen - hLen - 2;
266296341Sdelphij    *p++ ^= 0x1;
267296341Sdelphij    if (sLen > 0) {
268296341Sdelphij        for (i = 0; i < sLen; i++)
269296341Sdelphij            *p++ ^= salt[i];
270296341Sdelphij    }
271296341Sdelphij    if (MSBits)
272296341Sdelphij        EM[0] &= 0xFF >> (8 - MSBits);
273160814Ssimon
274296341Sdelphij    /* H is already in place so just set final 0xbc */
275160814Ssimon
276296341Sdelphij    EM[emLen - 1] = 0xbc;
277160814Ssimon
278296341Sdelphij    ret = 1;
279160814Ssimon
280296341Sdelphij err:
281296341Sdelphij    if (salt)
282296341Sdelphij        OPENSSL_free(salt);
283160814Ssimon
284296341Sdelphij    return ret;
285160814Ssimon
286296341Sdelphij}
287160814Ssimon
288160814Ssimon#if defined(_MSC_VER)
289296341Sdelphij# pragma optimize("",on)
290160814Ssimon#endif
291