xref: /freebsd-src/contrib/bearssl/src/rsa/rsa_pss_sig_unpad.c (revision 0957b409a90fd597c1e9124cbaf3edd2b488f4ac)
1*0957b409SSimon J. Gerraty /*
2*0957b409SSimon J. Gerraty  * Copyright (c) 2018 Thomas Pornin <pornin@bolet.org>
3*0957b409SSimon J. Gerraty  *
4*0957b409SSimon J. Gerraty  * Permission is hereby granted, free of charge, to any person obtaining
5*0957b409SSimon J. Gerraty  * a copy of this software and associated documentation files (the
6*0957b409SSimon J. Gerraty  * "Software"), to deal in the Software without restriction, including
7*0957b409SSimon J. Gerraty  * without limitation the rights to use, copy, modify, merge, publish,
8*0957b409SSimon J. Gerraty  * distribute, sublicense, and/or sell copies of the Software, and to
9*0957b409SSimon J. Gerraty  * permit persons to whom the Software is furnished to do so, subject to
10*0957b409SSimon J. Gerraty  * the following conditions:
11*0957b409SSimon J. Gerraty  *
12*0957b409SSimon J. Gerraty  * The above copyright notice and this permission notice shall be
13*0957b409SSimon J. Gerraty  * included in all copies or substantial portions of the Software.
14*0957b409SSimon J. Gerraty  *
15*0957b409SSimon J. Gerraty  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16*0957b409SSimon J. Gerraty  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17*0957b409SSimon J. Gerraty  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18*0957b409SSimon J. Gerraty  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
19*0957b409SSimon J. Gerraty  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
20*0957b409SSimon J. Gerraty  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
21*0957b409SSimon J. Gerraty  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22*0957b409SSimon J. Gerraty  * SOFTWARE.
23*0957b409SSimon J. Gerraty  */
24*0957b409SSimon J. Gerraty 
25*0957b409SSimon J. Gerraty #include "inner.h"
26*0957b409SSimon J. Gerraty 
27*0957b409SSimon J. Gerraty /* see inner.h */
28*0957b409SSimon J. Gerraty uint32_t
29*0957b409SSimon J. Gerraty br_rsa_pss_sig_unpad(const br_hash_class *hf_data,
30*0957b409SSimon J. Gerraty 	const br_hash_class *hf_mgf1,
31*0957b409SSimon J. Gerraty 	const unsigned char *hash, size_t salt_len,
32*0957b409SSimon J. Gerraty 	const br_rsa_public_key *pk, unsigned char *x)
33*0957b409SSimon J. Gerraty {
34*0957b409SSimon J. Gerraty 	size_t u, xlen, hash_len;
35*0957b409SSimon J. Gerraty 	br_hash_compat_context hc;
36*0957b409SSimon J. Gerraty 	unsigned char *seed, *salt;
37*0957b409SSimon J. Gerraty 	unsigned char tmp[64];
38*0957b409SSimon J. Gerraty 	uint32_t r, n_bitlen;
39*0957b409SSimon J. Gerraty 
40*0957b409SSimon J. Gerraty 	hash_len = br_digest_size(hf_data);
41*0957b409SSimon J. Gerraty 
42*0957b409SSimon J. Gerraty 	/*
43*0957b409SSimon J. Gerraty 	 * Value r will be set to a non-zero value is any test fails.
44*0957b409SSimon J. Gerraty 	 */
45*0957b409SSimon J. Gerraty 	r = 0;
46*0957b409SSimon J. Gerraty 
47*0957b409SSimon J. Gerraty 	/*
48*0957b409SSimon J. Gerraty 	 * The value bit length (as an integer) must be strictly less than
49*0957b409SSimon J. Gerraty 	 * that of the modulus.
50*0957b409SSimon J. Gerraty 	 */
51*0957b409SSimon J. Gerraty 	for (u = 0; u < pk->nlen; u ++) {
52*0957b409SSimon J. Gerraty 		if (pk->n[u] != 0) {
53*0957b409SSimon J. Gerraty 			break;
54*0957b409SSimon J. Gerraty 		}
55*0957b409SSimon J. Gerraty 	}
56*0957b409SSimon J. Gerraty 	if (u == pk->nlen) {
57*0957b409SSimon J. Gerraty 		return 0;
58*0957b409SSimon J. Gerraty 	}
59*0957b409SSimon J. Gerraty 	n_bitlen = BIT_LENGTH(pk->n[u]) + ((uint32_t)(pk->nlen - u - 1) << 3);
60*0957b409SSimon J. Gerraty 	n_bitlen --;
61*0957b409SSimon J. Gerraty 	if ((n_bitlen & 7) == 0) {
62*0957b409SSimon J. Gerraty 		r |= *x ++;
63*0957b409SSimon J. Gerraty 	} else {
64*0957b409SSimon J. Gerraty 		r |= x[0] & (0xFF << (n_bitlen & 7));
65*0957b409SSimon J. Gerraty 	}
66*0957b409SSimon J. Gerraty 	xlen = (n_bitlen + 7) >> 3;
67*0957b409SSimon J. Gerraty 
68*0957b409SSimon J. Gerraty 	/*
69*0957b409SSimon J. Gerraty 	 * Check that the modulus is large enough for the hash value
70*0957b409SSimon J. Gerraty 	 * length combined with the intended salt length.
71*0957b409SSimon J. Gerraty 	 */
72*0957b409SSimon J. Gerraty 	if (hash_len > xlen || salt_len > xlen
73*0957b409SSimon J. Gerraty 		|| (hash_len + salt_len + 2) > xlen)
74*0957b409SSimon J. Gerraty 	{
75*0957b409SSimon J. Gerraty 		return 0;
76*0957b409SSimon J. Gerraty 	}
77*0957b409SSimon J. Gerraty 
78*0957b409SSimon J. Gerraty 	/*
79*0957b409SSimon J. Gerraty 	 * Check value of rightmost byte.
80*0957b409SSimon J. Gerraty 	 */
81*0957b409SSimon J. Gerraty 	r |= x[xlen - 1] ^ 0xBC;
82*0957b409SSimon J. Gerraty 
83*0957b409SSimon J. Gerraty 	/*
84*0957b409SSimon J. Gerraty 	 * Generate the mask and XOR it into the first bytes to reveal PS;
85*0957b409SSimon J. Gerraty 	 * we must also mask out the leading bits.
86*0957b409SSimon J. Gerraty 	 */
87*0957b409SSimon J. Gerraty 	seed = x + xlen - hash_len - 1;
88*0957b409SSimon J. Gerraty 	br_mgf1_xor(x, xlen - hash_len - 1, hf_mgf1, seed, hash_len);
89*0957b409SSimon J. Gerraty 	if ((n_bitlen & 7) != 0) {
90*0957b409SSimon J. Gerraty 		x[0] &= 0xFF >> (8 - (n_bitlen & 7));
91*0957b409SSimon J. Gerraty 	}
92*0957b409SSimon J. Gerraty 
93*0957b409SSimon J. Gerraty 	/*
94*0957b409SSimon J. Gerraty 	 * Check that all padding bytes have the expected value.
95*0957b409SSimon J. Gerraty 	 */
96*0957b409SSimon J. Gerraty 	for (u = 0; u < (xlen - hash_len - salt_len - 2); u ++) {
97*0957b409SSimon J. Gerraty 		r |= x[u];
98*0957b409SSimon J. Gerraty 	}
99*0957b409SSimon J. Gerraty 	r |= x[xlen - hash_len - salt_len - 2] ^ 0x01;
100*0957b409SSimon J. Gerraty 
101*0957b409SSimon J. Gerraty 	/*
102*0957b409SSimon J. Gerraty 	 * Recompute H.
103*0957b409SSimon J. Gerraty 	 */
104*0957b409SSimon J. Gerraty 	salt = x + xlen - hash_len - salt_len - 1;
105*0957b409SSimon J. Gerraty 	hf_data->init(&hc.vtable);
106*0957b409SSimon J. Gerraty 	memset(tmp, 0, 8);
107*0957b409SSimon J. Gerraty 	hf_data->update(&hc.vtable, tmp, 8);
108*0957b409SSimon J. Gerraty 	hf_data->update(&hc.vtable, hash, hash_len);
109*0957b409SSimon J. Gerraty 	hf_data->update(&hc.vtable, salt, salt_len);
110*0957b409SSimon J. Gerraty 	hf_data->out(&hc.vtable, tmp);
111*0957b409SSimon J. Gerraty 
112*0957b409SSimon J. Gerraty 	/*
113*0957b409SSimon J. Gerraty 	 * Check that the recomputed H value matches the one appearing
114*0957b409SSimon J. Gerraty 	 * in the string.
115*0957b409SSimon J. Gerraty 	 */
116*0957b409SSimon J. Gerraty 	for (u = 0; u < hash_len; u ++) {
117*0957b409SSimon J. Gerraty 		r |= tmp[u] ^ x[(xlen - salt_len - 1) + u];
118*0957b409SSimon J. Gerraty 	}
119*0957b409SSimon J. Gerraty 
120*0957b409SSimon J. Gerraty 	return EQ0(r);
121*0957b409SSimon J. Gerraty }
122