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