xref: /openbsd-src/lib/libcrypto/rsa/rsa_pss.c (revision c4bb5f4255b8a6682499631a2086d1d0b9e934ee)
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