1 /*
2 * PKCS#1 encoding and decoding functions.
3 * This file is believed to contain no code licensed from other parties.
4 *
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
8
9 #include "seccomon.h"
10 #include "secerr.h"
11 #include "sechash.h"
12
13 /* Needed for RSA-PSS functions */
14 static const unsigned char eightZeros[] = { 0, 0, 0, 0, 0, 0, 0, 0 };
15
16 /*
17 * Mask generation function MGF1 as defined in PKCS #1 v2.1 / RFC 3447.
18 */
19 static SECStatus
MGF1(HASH_HashType hashAlg,unsigned char * mask,unsigned int maskLen,const unsigned char * mgfSeed,unsigned int mgfSeedLen)20 MGF1(HASH_HashType hashAlg, unsigned char *mask, unsigned int maskLen,
21 const unsigned char *mgfSeed, unsigned int mgfSeedLen)
22 {
23 unsigned int digestLen;
24 PRUint32 counter, rounds;
25 unsigned char *tempHash, *temp;
26 const SECHashObject *hash;
27 void *hashContext;
28 unsigned char C[4];
29
30 hash = HASH_GetHashObject(hashAlg);
31 if (hash == NULL)
32 return SECFailure;
33
34 hashContext = (*hash->create)();
35 rounds = (maskLen + hash->length - 1) / hash->length;
36 for (counter = 0; counter < rounds; counter++) {
37 C[0] = (unsigned char)((counter >> 24) & 0xff);
38 C[1] = (unsigned char)((counter >> 16) & 0xff);
39 C[2] = (unsigned char)((counter >> 8) & 0xff);
40 C[3] = (unsigned char)(counter & 0xff);
41
42 /* This could be optimized when the clone functions in
43 * rawhash.c are implemented. */
44 (*hash->begin)(hashContext);
45 (*hash->update)(hashContext, mgfSeed, mgfSeedLen);
46 (*hash->update)(hashContext, C, sizeof C);
47
48 tempHash = mask + counter * hash->length;
49 if (counter != (rounds-1)) {
50 (*hash->end)(hashContext, tempHash, &digestLen, hash->length);
51 } else { /* we're in the last round and need to cut the hash */
52 temp = (unsigned char *)PORT_Alloc(hash->length);
53 (*hash->end)(hashContext, temp, &digestLen, hash->length);
54 PORT_Memcpy(tempHash, temp, maskLen - counter * hash->length);
55 PORT_Free(temp);
56 }
57 }
58 (*hash->destroy)(hashContext, PR_TRUE);
59
60 return SECSuccess;
61 }
62
63 /*
64 * Verify a RSA-PSS signature.
65 * Described in RFC 3447, section 9.1.2.
66 * We use mHash instead of M as input.
67 * emBits from the RFC is just modBits - 1, see section 8.1.2.
68 * We only support MGF1 as the MGF.
69 *
70 * NOTE: this code assumes modBits is a multiple of 8.
71 */
72 SECStatus
emsa_pss_verify(const unsigned char * mHash,const unsigned char * em,unsigned int emLen,HASH_HashType hashAlg,HASH_HashType maskHashAlg,unsigned int sLen)73 emsa_pss_verify(const unsigned char *mHash,
74 const unsigned char *em, unsigned int emLen,
75 HASH_HashType hashAlg, HASH_HashType maskHashAlg,
76 unsigned int sLen)
77 {
78 const SECHashObject *hash;
79 void *hash_context;
80 unsigned char *db;
81 unsigned char *H_; /* H' from the RFC */
82 unsigned int i, dbMaskLen;
83 SECStatus rv;
84
85 hash = HASH_GetHashObject(hashAlg);
86 dbMaskLen = emLen - hash->length - 1;
87
88 /* Step 3 + 4 + 6 */
89 if ((emLen < (hash->length + sLen + 2)) ||
90 (em[emLen - 1] != 0xbc) ||
91 ((em[0] & 0x80) != 0)) {
92 PORT_SetError(SEC_ERROR_BAD_SIGNATURE);
93 return SECFailure;
94 }
95
96 /* Step 7 */
97 db = (unsigned char *)PORT_Alloc(dbMaskLen);
98 if (db == NULL) {
99 PORT_SetError(SEC_ERROR_NO_MEMORY);
100 return SECFailure;
101 }
102 /* &em[dbMaskLen] points to H, used as mgfSeed */
103 MGF1(maskHashAlg, db, dbMaskLen, &em[dbMaskLen], hash->length);
104
105 /* Step 8 */
106 for (i = 0; i < dbMaskLen; i++) {
107 db[i] ^= em[i];
108 }
109
110 /* Step 9 */
111 db[0] &= 0x7f;
112
113 /* Step 10 */
114 for (i = 0; i < (dbMaskLen - sLen - 1); i++) {
115 if (db[i] != 0) {
116 PORT_Free(db);
117 PORT_SetError(SEC_ERROR_BAD_SIGNATURE);
118 return SECFailure;
119 }
120 }
121 if (db[dbMaskLen - sLen - 1] != 0x01) {
122 PORT_Free(db);
123 PORT_SetError(SEC_ERROR_BAD_SIGNATURE);
124 return SECFailure;
125 }
126
127 /* Step 12 + 13 */
128 H_ = (unsigned char *)PORT_Alloc(hash->length);
129 if (H_ == NULL) {
130 PORT_Free(db);
131 PORT_SetError(SEC_ERROR_NO_MEMORY);
132 return SECFailure;
133 }
134 hash_context = (*hash->create)();
135 if (hash_context == NULL) {
136 PORT_Free(db);
137 PORT_Free(H_);
138 PORT_SetError(SEC_ERROR_NO_MEMORY);
139 return SECFailure;
140 }
141 (*hash->begin)(hash_context);
142 (*hash->update)(hash_context, eightZeros, 8);
143 (*hash->update)(hash_context, mHash, hash->length);
144 (*hash->update)(hash_context, &db[dbMaskLen - sLen], sLen);
145 (*hash->end)(hash_context, H_, &i, hash->length);
146 (*hash->destroy)(hash_context, PR_TRUE);
147
148 PORT_Free(db);
149
150 /* Step 14 */
151 if (PORT_Memcmp(H_, &em[dbMaskLen], hash->length) != 0) {
152 PORT_SetError(SEC_ERROR_BAD_SIGNATURE);
153 rv = SECFailure;
154 } else {
155 rv = SECSuccess;
156 }
157
158 PORT_Free(H_);
159 return rv;
160 }
161