xref: /freebsd/contrib/bearssl/src/rsa/rsa_pss_sig_unpad.c (revision 9c474dc51b0b09ff81339caee6772e454dd470e4)
10957b409SSimon J. Gerraty /*
20957b409SSimon J. Gerraty  * Copyright (c) 2018 Thomas Pornin <pornin@bolet.org>
30957b409SSimon J. Gerraty  *
40957b409SSimon J. Gerraty  * Permission is hereby granted, free of charge, to any person obtaining
50957b409SSimon J. Gerraty  * a copy of this software and associated documentation files (the
60957b409SSimon J. Gerraty  * "Software"), to deal in the Software without restriction, including
70957b409SSimon J. Gerraty  * without limitation the rights to use, copy, modify, merge, publish,
80957b409SSimon J. Gerraty  * distribute, sublicense, and/or sell copies of the Software, and to
90957b409SSimon J. Gerraty  * permit persons to whom the Software is furnished to do so, subject to
100957b409SSimon J. Gerraty  * the following conditions:
110957b409SSimon J. Gerraty  *
120957b409SSimon J. Gerraty  * The above copyright notice and this permission notice shall be
130957b409SSimon J. Gerraty  * included in all copies or substantial portions of the Software.
140957b409SSimon J. Gerraty  *
150957b409SSimon J. Gerraty  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
160957b409SSimon J. Gerraty  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
170957b409SSimon J. Gerraty  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
180957b409SSimon J. Gerraty  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
190957b409SSimon J. Gerraty  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
200957b409SSimon J. Gerraty  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
210957b409SSimon J. Gerraty  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
220957b409SSimon J. Gerraty  * SOFTWARE.
230957b409SSimon J. Gerraty  */
240957b409SSimon J. Gerraty 
250957b409SSimon J. Gerraty #include "inner.h"
260957b409SSimon J. Gerraty 
270957b409SSimon J. Gerraty /* see inner.h */
280957b409SSimon J. Gerraty uint32_t
br_rsa_pss_sig_unpad(const br_hash_class * hf_data,const br_hash_class * hf_mgf1,const unsigned char * hash,size_t salt_len,const br_rsa_public_key * pk,unsigned char * x)290957b409SSimon J. Gerraty br_rsa_pss_sig_unpad(const br_hash_class *hf_data,
300957b409SSimon J. Gerraty 	const br_hash_class *hf_mgf1,
310957b409SSimon J. Gerraty 	const unsigned char *hash, size_t salt_len,
320957b409SSimon J. Gerraty 	const br_rsa_public_key *pk, unsigned char *x)
330957b409SSimon J. Gerraty {
340957b409SSimon J. Gerraty 	size_t u, xlen, hash_len;
350957b409SSimon J. Gerraty 	br_hash_compat_context hc;
360957b409SSimon J. Gerraty 	unsigned char *seed, *salt;
370957b409SSimon J. Gerraty 	unsigned char tmp[64];
380957b409SSimon J. Gerraty 	uint32_t r, n_bitlen;
390957b409SSimon J. Gerraty 
400957b409SSimon J. Gerraty 	hash_len = br_digest_size(hf_data);
410957b409SSimon J. Gerraty 
420957b409SSimon J. Gerraty 	/*
430957b409SSimon J. Gerraty 	 * Value r will be set to a non-zero value is any test fails.
440957b409SSimon J. Gerraty 	 */
450957b409SSimon J. Gerraty 	r = 0;
460957b409SSimon J. Gerraty 
470957b409SSimon J. Gerraty 	/*
480957b409SSimon J. Gerraty 	 * The value bit length (as an integer) must be strictly less than
490957b409SSimon J. Gerraty 	 * that of the modulus.
500957b409SSimon J. Gerraty 	 */
510957b409SSimon J. Gerraty 	for (u = 0; u < pk->nlen; u ++) {
520957b409SSimon J. Gerraty 		if (pk->n[u] != 0) {
530957b409SSimon J. Gerraty 			break;
540957b409SSimon J. Gerraty 		}
550957b409SSimon J. Gerraty 	}
560957b409SSimon J. Gerraty 	if (u == pk->nlen) {
570957b409SSimon J. Gerraty 		return 0;
580957b409SSimon J. Gerraty 	}
590957b409SSimon J. Gerraty 	n_bitlen = BIT_LENGTH(pk->n[u]) + ((uint32_t)(pk->nlen - u - 1) << 3);
600957b409SSimon J. Gerraty 	n_bitlen --;
610957b409SSimon J. Gerraty 	if ((n_bitlen & 7) == 0) {
620957b409SSimon J. Gerraty 		r |= *x ++;
630957b409SSimon J. Gerraty 	} else {
640957b409SSimon J. Gerraty 		r |= x[0] & (0xFF << (n_bitlen & 7));
650957b409SSimon J. Gerraty 	}
660957b409SSimon J. Gerraty 	xlen = (n_bitlen + 7) >> 3;
670957b409SSimon J. Gerraty 
680957b409SSimon J. Gerraty 	/*
690957b409SSimon J. Gerraty 	 * Check that the modulus is large enough for the hash value
700957b409SSimon J. Gerraty 	 * length combined with the intended salt length.
710957b409SSimon J. Gerraty 	 */
720957b409SSimon J. Gerraty 	if (hash_len > xlen || salt_len > xlen
730957b409SSimon J. Gerraty 		|| (hash_len + salt_len + 2) > xlen)
740957b409SSimon J. Gerraty 	{
750957b409SSimon J. Gerraty 		return 0;
760957b409SSimon J. Gerraty 	}
770957b409SSimon J. Gerraty 
780957b409SSimon J. Gerraty 	/*
790957b409SSimon J. Gerraty 	 * Check value of rightmost byte.
800957b409SSimon J. Gerraty 	 */
810957b409SSimon J. Gerraty 	r |= x[xlen - 1] ^ 0xBC;
820957b409SSimon J. Gerraty 
830957b409SSimon J. Gerraty 	/*
840957b409SSimon J. Gerraty 	 * Generate the mask and XOR it into the first bytes to reveal PS;
850957b409SSimon J. Gerraty 	 * we must also mask out the leading bits.
860957b409SSimon J. Gerraty 	 */
870957b409SSimon J. Gerraty 	seed = x + xlen - hash_len - 1;
880957b409SSimon J. Gerraty 	br_mgf1_xor(x, xlen - hash_len - 1, hf_mgf1, seed, hash_len);
890957b409SSimon J. Gerraty 	if ((n_bitlen & 7) != 0) {
900957b409SSimon J. Gerraty 		x[0] &= 0xFF >> (8 - (n_bitlen & 7));
910957b409SSimon J. Gerraty 	}
920957b409SSimon J. Gerraty 
930957b409SSimon J. Gerraty 	/*
940957b409SSimon J. Gerraty 	 * Check that all padding bytes have the expected value.
950957b409SSimon J. Gerraty 	 */
960957b409SSimon J. Gerraty 	for (u = 0; u < (xlen - hash_len - salt_len - 2); u ++) {
970957b409SSimon J. Gerraty 		r |= x[u];
980957b409SSimon J. Gerraty 	}
990957b409SSimon J. Gerraty 	r |= x[xlen - hash_len - salt_len - 2] ^ 0x01;
1000957b409SSimon J. Gerraty 
1010957b409SSimon J. Gerraty 	/*
1020957b409SSimon J. Gerraty 	 * Recompute H.
1030957b409SSimon J. Gerraty 	 */
1040957b409SSimon J. Gerraty 	salt = x + xlen - hash_len - salt_len - 1;
1050957b409SSimon J. Gerraty 	hf_data->init(&hc.vtable);
1060957b409SSimon J. Gerraty 	memset(tmp, 0, 8);
1070957b409SSimon J. Gerraty 	hf_data->update(&hc.vtable, tmp, 8);
1080957b409SSimon J. Gerraty 	hf_data->update(&hc.vtable, hash, hash_len);
1090957b409SSimon J. Gerraty 	hf_data->update(&hc.vtable, salt, salt_len);
1100957b409SSimon J. Gerraty 	hf_data->out(&hc.vtable, tmp);
1110957b409SSimon J. Gerraty 
1120957b409SSimon J. Gerraty 	/*
1130957b409SSimon J. Gerraty 	 * Check that the recomputed H value matches the one appearing
1140957b409SSimon J. Gerraty 	 * in the string.
1150957b409SSimon J. Gerraty 	 */
1160957b409SSimon J. Gerraty 	for (u = 0; u < hash_len; u ++) {
117*9c474dc5SSimon J. Gerraty 		r |= tmp[u] ^ x[(xlen - hash_len - 1) + u];
1180957b409SSimon J. Gerraty 	}
1190957b409SSimon J. Gerraty 
1200957b409SSimon J. Gerraty 	return EQ0(r);
1210957b409SSimon J. Gerraty }
122