1*c4bb5f42Sjoshua /* $OpenBSD: rsa_pss.c,v 1.19 2024/03/26 05:26:27 joshua Exp $ */
282a8dcafSdjm /* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL
30dd13104Sdjm * project 2005.
40dd13104Sdjm */
50dd13104Sdjm /* ====================================================================
60dd13104Sdjm * Copyright (c) 2005 The OpenSSL Project. All rights reserved.
70dd13104Sdjm *
80dd13104Sdjm * Redistribution and use in source and binary forms, with or without
90dd13104Sdjm * modification, are permitted provided that the following conditions
100dd13104Sdjm * are met:
110dd13104Sdjm *
120dd13104Sdjm * 1. Redistributions of source code must retain the above copyright
130dd13104Sdjm * notice, this list of conditions and the following disclaimer.
140dd13104Sdjm *
150dd13104Sdjm * 2. Redistributions in binary form must reproduce the above copyright
160dd13104Sdjm * notice, this list of conditions and the following disclaimer in
170dd13104Sdjm * the documentation and/or other materials provided with the
180dd13104Sdjm * distribution.
190dd13104Sdjm *
200dd13104Sdjm * 3. All advertising materials mentioning features or use of this
210dd13104Sdjm * software must display the following acknowledgment:
220dd13104Sdjm * "This product includes software developed by the OpenSSL Project
230dd13104Sdjm * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
240dd13104Sdjm *
250dd13104Sdjm * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
260dd13104Sdjm * endorse or promote products derived from this software without
270dd13104Sdjm * prior written permission. For written permission, please contact
280dd13104Sdjm * licensing@OpenSSL.org.
290dd13104Sdjm *
300dd13104Sdjm * 5. Products derived from this software may not be called "OpenSSL"
310dd13104Sdjm * nor may "OpenSSL" appear in their names without prior written
320dd13104Sdjm * permission of the OpenSSL Project.
330dd13104Sdjm *
340dd13104Sdjm * 6. Redistributions of any form whatsoever must retain the following
350dd13104Sdjm * acknowledgment:
360dd13104Sdjm * "This product includes software developed by the OpenSSL Project
370dd13104Sdjm * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
380dd13104Sdjm *
390dd13104Sdjm * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
400dd13104Sdjm * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
410dd13104Sdjm * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
420dd13104Sdjm * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
430dd13104Sdjm * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
440dd13104Sdjm * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
450dd13104Sdjm * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
460dd13104Sdjm * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
470dd13104Sdjm * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
480dd13104Sdjm * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
490dd13104Sdjm * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
500dd13104Sdjm * OF THE POSSIBILITY OF SUCH DAMAGE.
510dd13104Sdjm * ====================================================================
520dd13104Sdjm *
530dd13104Sdjm * This product includes cryptographic software written by Eric Young
540dd13104Sdjm * (eay@cryptsoft.com). This product includes software written by Tim
550dd13104Sdjm * Hudson (tjh@cryptsoft.com).
560dd13104Sdjm *
570dd13104Sdjm */
580dd13104Sdjm
590dd13104Sdjm #include <stdio.h>
60ef624301Sjsing #include <stdlib.h>
61a8913c44Sjsing #include <string.h>
62a8913c44Sjsing
630dd13104Sdjm #include <openssl/bn.h>
64b6ab114eSjsing #include <openssl/err.h>
650dd13104Sdjm #include <openssl/evp.h>
66b6ab114eSjsing #include <openssl/rsa.h>
670dd13104Sdjm #include <openssl/sha.h>
680dd13104Sdjm
69c9675a23Stb #include "evp_local.h"
70c9675a23Stb #include "rsa_local.h"
71bc366ef8Stb
725650a0e1Sdjm static const unsigned char zeroes[] = { 0, 0, 0, 0, 0, 0, 0, 0 };
735650a0e1Sdjm
7487203b09Smiod int
RSA_verify_PKCS1_PSS(RSA * rsa,const unsigned char * mHash,const EVP_MD * Hash,const unsigned char * EM,int sLen)7587203b09Smiod RSA_verify_PKCS1_PSS(RSA *rsa, const unsigned char *mHash, const EVP_MD *Hash,
7687203b09Smiod const unsigned char *EM, int sLen)
770dd13104Sdjm {
78ec07fdf1Sdjm return RSA_verify_PKCS1_PSS_mgf1(rsa, mHash, Hash, NULL, EM, sLen);
79ec07fdf1Sdjm }
801da36015Sbeck LCRYPTO_ALIAS(RSA_verify_PKCS1_PSS);
81ec07fdf1Sdjm
8287203b09Smiod int
RSA_verify_PKCS1_PSS_mgf1(RSA * rsa,const unsigned char * mHash,const EVP_MD * Hash,const EVP_MD * mgf1Hash,const unsigned char * EM,int sLen)8387203b09Smiod RSA_verify_PKCS1_PSS_mgf1(RSA *rsa, const unsigned char *mHash,
8487203b09Smiod const EVP_MD *Hash, const EVP_MD *mgf1Hash, const unsigned char *EM,
8587203b09Smiod int sLen)
86ec07fdf1Sdjm {
870dd13104Sdjm int i;
880dd13104Sdjm int ret = 0;
890dd13104Sdjm int hLen, maskedDBLen, MSBits, emLen;
900dd13104Sdjm const unsigned char *H;
910dd13104Sdjm unsigned char *DB = NULL;
92*c4bb5f42Sjoshua EVP_MD_CTX *md_ctx;
930dd13104Sdjm unsigned char H_[EVP_MAX_MD_SIZE];
9487203b09Smiod
95*c4bb5f42Sjoshua if ((md_ctx = EVP_MD_CTX_new()) == NULL)
96*c4bb5f42Sjoshua goto err;
97ec07fdf1Sdjm
98ec07fdf1Sdjm if (mgf1Hash == NULL)
99ec07fdf1Sdjm mgf1Hash = Hash;
1000dd13104Sdjm
101f1535dc8Sdjm hLen = EVP_MD_size(Hash);
102f1535dc8Sdjm if (hLen < 0)
103f1535dc8Sdjm goto err;
1040dd13104Sdjm /*
1050dd13104Sdjm * Negative sLen has special meanings:
1060dd13104Sdjm * -1 sLen == hLen
1070dd13104Sdjm * -2 salt length is autorecovered from signature
1080dd13104Sdjm * -N reserved
1090dd13104Sdjm */
11087203b09Smiod if (sLen == -1)
11187203b09Smiod sLen = hLen;
11287203b09Smiod else if (sLen == -2)
11387203b09Smiod sLen = -2;
11487203b09Smiod else if (sLen < -2) {
1155067ae9fSbeck RSAerror(RSA_R_SLEN_CHECK_FAILED);
1160dd13104Sdjm goto err;
1170dd13104Sdjm }
1180dd13104Sdjm
1190dd13104Sdjm MSBits = (BN_num_bits(rsa->n) - 1) & 0x7;
1200dd13104Sdjm emLen = RSA_size(rsa);
12187203b09Smiod if (EM[0] & (0xFF << MSBits)) {
1225067ae9fSbeck RSAerror(RSA_R_FIRST_OCTET_INVALID);
1230dd13104Sdjm goto err;
1240dd13104Sdjm }
12587203b09Smiod if (MSBits == 0) {
1260dd13104Sdjm EM++;
1270dd13104Sdjm emLen--;
1280dd13104Sdjm }
12914a995a9Sjsing if (emLen < (hLen + sLen + 2)) {
13014a995a9Sjsing /* sLen can be small negative */
1315067ae9fSbeck RSAerror(RSA_R_DATA_TOO_LARGE);
1320dd13104Sdjm goto err;
1330dd13104Sdjm }
13487203b09Smiod if (EM[emLen - 1] != 0xbc) {
1355067ae9fSbeck RSAerror(RSA_R_LAST_OCTET_INVALID);
1360dd13104Sdjm goto err;
1370dd13104Sdjm }
1380dd13104Sdjm maskedDBLen = emLen - hLen - 1;
1390dd13104Sdjm H = EM + maskedDBLen;
1406f3a6cb1Sbeck DB = malloc(maskedDBLen);
14187203b09Smiod if (!DB) {
1425067ae9fSbeck RSAerror(ERR_R_MALLOC_FAILURE);
1430dd13104Sdjm goto err;
1440dd13104Sdjm }
145ec07fdf1Sdjm if (PKCS1_MGF1(DB, maskedDBLen, H, hLen, mgf1Hash) < 0)
146f1535dc8Sdjm goto err;
1470dd13104Sdjm for (i = 0; i < maskedDBLen; i++)
1480dd13104Sdjm DB[i] ^= EM[i];
1490dd13104Sdjm if (MSBits)
1500dd13104Sdjm DB[0] &= 0xFF >> (8 - MSBits);
15187203b09Smiod for (i = 0; DB[i] == 0 && i < (maskedDBLen - 1); i++)
15287203b09Smiod ;
15387203b09Smiod if (DB[i++] != 0x1) {
1545067ae9fSbeck RSAerror(RSA_R_SLEN_RECOVERY_FAILED);
1550dd13104Sdjm goto err;
1560dd13104Sdjm }
15787203b09Smiod if (sLen >= 0 && (maskedDBLen - i) != sLen) {
1585067ae9fSbeck RSAerror(RSA_R_SLEN_CHECK_FAILED);
1590dd13104Sdjm goto err;
1600dd13104Sdjm }
161*c4bb5f42Sjoshua if (!EVP_DigestInit_ex(md_ctx, Hash, NULL) ||
162*c4bb5f42Sjoshua !EVP_DigestUpdate(md_ctx, zeroes, sizeof zeroes) ||
163*c4bb5f42Sjoshua !EVP_DigestUpdate(md_ctx, mHash, hLen))
164ec07fdf1Sdjm goto err;
16587203b09Smiod if (maskedDBLen - i) {
166*c4bb5f42Sjoshua if (!EVP_DigestUpdate(md_ctx, DB + i, maskedDBLen - i))
167ec07fdf1Sdjm goto err;
168ec07fdf1Sdjm }
169*c4bb5f42Sjoshua if (!EVP_DigestFinal_ex(md_ctx, H_, NULL))
170ec07fdf1Sdjm goto err;
1712f115aa8Sdjm if (timingsafe_bcmp(H_, H, hLen)) {
1725067ae9fSbeck RSAerror(RSA_R_BAD_SIGNATURE);
1730dd13104Sdjm ret = 0;
174*c4bb5f42Sjoshua } else {
1750dd13104Sdjm ret = 1;
176*c4bb5f42Sjoshua }
1770dd13104Sdjm
1780dd13104Sdjm err:
1796f3a6cb1Sbeck free(DB);
180*c4bb5f42Sjoshua EVP_MD_CTX_free(md_ctx);
1810dd13104Sdjm
1820dd13104Sdjm return ret;
1830dd13104Sdjm }
1841da36015Sbeck LCRYPTO_ALIAS(RSA_verify_PKCS1_PSS_mgf1);
1850dd13104Sdjm
18687203b09Smiod int
RSA_padding_add_PKCS1_PSS(RSA * rsa,unsigned char * EM,const unsigned char * mHash,const EVP_MD * Hash,int sLen)18787203b09Smiod RSA_padding_add_PKCS1_PSS(RSA *rsa, unsigned char *EM,
18887203b09Smiod const unsigned char *mHash, const EVP_MD *Hash, int sLen)
1890dd13104Sdjm {
190ec07fdf1Sdjm return RSA_padding_add_PKCS1_PSS_mgf1(rsa, EM, mHash, Hash, NULL, sLen);
191ec07fdf1Sdjm }
1921da36015Sbeck LCRYPTO_ALIAS(RSA_padding_add_PKCS1_PSS);
193ec07fdf1Sdjm
19487203b09Smiod int
RSA_padding_add_PKCS1_PSS_mgf1(RSA * rsa,unsigned char * EM,const unsigned char * mHash,const EVP_MD * Hash,const EVP_MD * mgf1Hash,int sLen)19587203b09Smiod RSA_padding_add_PKCS1_PSS_mgf1(RSA *rsa, unsigned char *EM,
19687203b09Smiod const unsigned char *mHash, const EVP_MD *Hash, const EVP_MD *mgf1Hash,
19787203b09Smiod int sLen)
198ec07fdf1Sdjm {
1990dd13104Sdjm int i;
2000dd13104Sdjm int ret = 0;
2010dd13104Sdjm int hLen, maskedDBLen, MSBits, emLen;
2020dd13104Sdjm unsigned char *H, *salt = NULL, *p;
203*c4bb5f42Sjoshua EVP_MD_CTX *md_ctx;
2040dd13104Sdjm
205*c4bb5f42Sjoshua if ((md_ctx = EVP_MD_CTX_new()) == NULL)
206*c4bb5f42Sjoshua goto err;
20740dd9be9Smiod
208ec07fdf1Sdjm if (mgf1Hash == NULL)
209ec07fdf1Sdjm mgf1Hash = Hash;
210ec07fdf1Sdjm
211f1535dc8Sdjm hLen = EVP_MD_size(Hash);
212f1535dc8Sdjm if (hLen < 0)
213f1535dc8Sdjm goto err;
2140dd13104Sdjm /*
2150dd13104Sdjm * Negative sLen has special meanings:
2160dd13104Sdjm * -1 sLen == hLen
2170dd13104Sdjm * -2 salt length is maximized
2180dd13104Sdjm * -N reserved
2190dd13104Sdjm */
22087203b09Smiod if (sLen == -1)
22187203b09Smiod sLen = hLen;
22287203b09Smiod else if (sLen == -2)
22387203b09Smiod sLen = -2;
22487203b09Smiod else if (sLen < -2) {
2255067ae9fSbeck RSAerror(RSA_R_SLEN_CHECK_FAILED);
2260dd13104Sdjm goto err;
2270dd13104Sdjm }
2280dd13104Sdjm
2290dd13104Sdjm MSBits = (BN_num_bits(rsa->n) - 1) & 0x7;
2300dd13104Sdjm emLen = RSA_size(rsa);
23187203b09Smiod if (MSBits == 0) {
2320dd13104Sdjm *EM++ = 0;
2330dd13104Sdjm emLen--;
2340dd13104Sdjm }
2350dd13104Sdjm if (sLen == -2)
2360dd13104Sdjm sLen = emLen - hLen - 2;
23787203b09Smiod else if (emLen < (hLen + sLen + 2)) {
2385067ae9fSbeck RSAerror(RSA_R_DATA_TOO_LARGE_FOR_KEY_SIZE);
2390dd13104Sdjm goto err;
2400dd13104Sdjm }
24187203b09Smiod if (sLen > 0) {
2426f3a6cb1Sbeck salt = malloc(sLen);
24387203b09Smiod if (!salt) {
2445067ae9fSbeck RSAerror(ERR_R_MALLOC_FAILURE);
2450dd13104Sdjm goto err;
2460dd13104Sdjm }
247ef624301Sjsing arc4random_buf(salt, sLen);
2480dd13104Sdjm }
2490dd13104Sdjm maskedDBLen = emLen - hLen - 1;
2500dd13104Sdjm H = EM + maskedDBLen;
251*c4bb5f42Sjoshua if (!EVP_DigestInit_ex(md_ctx, Hash, NULL) ||
252*c4bb5f42Sjoshua !EVP_DigestUpdate(md_ctx, zeroes, sizeof zeroes) ||
253*c4bb5f42Sjoshua !EVP_DigestUpdate(md_ctx, mHash, hLen))
254ec07fdf1Sdjm goto err;
255*c4bb5f42Sjoshua if (sLen && !EVP_DigestUpdate(md_ctx, salt, sLen))
256ec07fdf1Sdjm goto err;
257*c4bb5f42Sjoshua if (!EVP_DigestFinal_ex(md_ctx, H, NULL))
258ec07fdf1Sdjm goto err;
2590dd13104Sdjm
2600dd13104Sdjm /* Generate dbMask in place then perform XOR on it */
261ec07fdf1Sdjm if (PKCS1_MGF1(EM, maskedDBLen, H, hLen, mgf1Hash))
262f1535dc8Sdjm goto err;
2630dd13104Sdjm
2640dd13104Sdjm p = EM;
2650dd13104Sdjm
26687203b09Smiod /*
26787203b09Smiod * Initial PS XORs with all zeroes which is a NOP so just update
2680dd13104Sdjm * pointer. Note from a test above this value is guaranteed to
2690dd13104Sdjm * be non-negative.
2700dd13104Sdjm */
2710dd13104Sdjm p += emLen - sLen - hLen - 2;
2720dd13104Sdjm *p++ ^= 0x1;
27387203b09Smiod if (sLen > 0) {
2740dd13104Sdjm for (i = 0; i < sLen; i++)
2750dd13104Sdjm *p++ ^= salt[i];
2760dd13104Sdjm }
2770dd13104Sdjm if (MSBits)
2780dd13104Sdjm EM[0] &= 0xFF >> (8 - MSBits);
2790dd13104Sdjm
2800dd13104Sdjm /* H is already in place so just set final 0xbc */
2810dd13104Sdjm EM[emLen - 1] = 0xbc;
2820dd13104Sdjm
2830dd13104Sdjm ret = 1;
2840dd13104Sdjm
2850dd13104Sdjm err:
2866f3a6cb1Sbeck free(salt);
287*c4bb5f42Sjoshua EVP_MD_CTX_free(md_ctx);
2880dd13104Sdjm
2890dd13104Sdjm return ret;
2900dd13104Sdjm }
2911da36015Sbeck LCRYPTO_ALIAS(RSA_padding_add_PKCS1_PSS_mgf1);
292