/src/nss/lib/cryptohi/secvfy.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * Verification stuff. |
3 | | * |
4 | | * This Source Code Form is subject to the terms of the Mozilla Public |
5 | | * License, v. 2.0. If a copy of the MPL was not distributed with this |
6 | | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
7 | | |
8 | | #include <stdio.h> |
9 | | #include "cryptohi.h" |
10 | | #include "sechash.h" |
11 | | #include "keyhi.h" |
12 | | #include "secasn1.h" |
13 | | #include "secoid.h" |
14 | | #include "pk11func.h" |
15 | | #include "pkcs1sig.h" |
16 | | #include "secdig.h" |
17 | | #include "secerr.h" |
18 | | #include "keyi.h" |
19 | | |
20 | | /* |
21 | | ** Recover the DigestInfo from an RSA PKCS#1 signature. |
22 | | ** |
23 | | ** If givenDigestAlg != SEC_OID_UNKNOWN, copy givenDigestAlg to digestAlgOut. |
24 | | ** Otherwise, parse the DigestInfo structure and store the decoded digest |
25 | | ** algorithm into digestAlgOut. |
26 | | ** |
27 | | ** Store the encoded DigestInfo into digestInfo. |
28 | | ** Store the DigestInfo length into digestInfoLen. |
29 | | ** |
30 | | ** This function does *not* verify that the AlgorithmIdentifier in the |
31 | | ** DigestInfo identifies givenDigestAlg or that the DigestInfo is encoded |
32 | | ** correctly; verifyPKCS1DigestInfo does that. |
33 | | ** |
34 | | ** XXX this is assuming that the signature algorithm has WITH_RSA_ENCRYPTION |
35 | | */ |
36 | | static SECStatus |
37 | | recoverPKCS1DigestInfo(SECOidTag givenDigestAlg, |
38 | | /*out*/ SECOidTag *digestAlgOut, |
39 | | /*out*/ unsigned char **digestInfo, |
40 | | /*out*/ unsigned int *digestInfoLen, |
41 | | SECKEYPublicKey *key, |
42 | | const SECItem *sig, void *wincx) |
43 | 1.09k | { |
44 | 1.09k | SGNDigestInfo *di = NULL; |
45 | 1.09k | SECItem it; |
46 | 1.09k | PRBool rv = SECSuccess; |
47 | | |
48 | 1.09k | PORT_Assert(digestAlgOut); |
49 | 1.09k | PORT_Assert(digestInfo); |
50 | 1.09k | PORT_Assert(digestInfoLen); |
51 | 1.09k | PORT_Assert(key); |
52 | 1.09k | PORT_Assert(key->keyType == rsaKey); |
53 | 1.09k | PORT_Assert(sig); |
54 | | |
55 | 1.09k | it.data = NULL; |
56 | 1.09k | it.len = SECKEY_PublicKeyStrength(key); |
57 | 1.09k | if (it.len != 0) { |
58 | 1.09k | it.data = (unsigned char *)PORT_Alloc(it.len); |
59 | 1.09k | } |
60 | 1.09k | if (it.len == 0 || it.data == NULL) { |
61 | 0 | rv = SECFailure; |
62 | 0 | } |
63 | | |
64 | 1.09k | if (rv == SECSuccess) { |
65 | | /* decrypt the block */ |
66 | 1.09k | rv = PK11_VerifyRecover(key, sig, &it, wincx); |
67 | 1.09k | } |
68 | | |
69 | 1.09k | if (rv == SECSuccess) { |
70 | 9 | if (givenDigestAlg != SEC_OID_UNKNOWN) { |
71 | | /* We don't need to parse the DigestInfo if the caller gave us the |
72 | | * digest algorithm to use. Later verifyPKCS1DigestInfo will verify |
73 | | * that the DigestInfo identifies the given digest algorithm and |
74 | | * that the DigestInfo is encoded absolutely correctly. |
75 | | */ |
76 | 9 | *digestInfoLen = it.len; |
77 | 9 | *digestInfo = (unsigned char *)it.data; |
78 | 9 | *digestAlgOut = givenDigestAlg; |
79 | 9 | return SECSuccess; |
80 | 9 | } |
81 | 9 | } |
82 | | |
83 | 1.08k | if (rv == SECSuccess) { |
84 | | /* The caller didn't specify a digest algorithm to use, so choose the |
85 | | * digest algorithm by parsing the AlgorithmIdentifier within the |
86 | | * DigestInfo. |
87 | | */ |
88 | 0 | di = SGN_DecodeDigestInfo(&it); |
89 | 0 | if (!di) { |
90 | 0 | rv = SECFailure; |
91 | 0 | } |
92 | 0 | } |
93 | | |
94 | 1.08k | if (rv == SECSuccess) { |
95 | 0 | *digestAlgOut = SECOID_GetAlgorithmTag(&di->digestAlgorithm); |
96 | 0 | if (*digestAlgOut == SEC_OID_UNKNOWN) { |
97 | 0 | rv = SECFailure; |
98 | 0 | } |
99 | 0 | } |
100 | | |
101 | 1.08k | if (di) { |
102 | 0 | SGN_DestroyDigestInfo(di); |
103 | 0 | } |
104 | | |
105 | 1.08k | if (rv == SECSuccess) { |
106 | 0 | *digestInfoLen = it.len; |
107 | 0 | *digestInfo = (unsigned char *)it.data; |
108 | 1.08k | } else { |
109 | 1.08k | if (it.data) { |
110 | 1.08k | PORT_Free(it.data); |
111 | 1.08k | } |
112 | 1.08k | *digestInfo = NULL; |
113 | 1.08k | *digestInfoLen = 0; |
114 | 1.08k | PORT_SetError(SEC_ERROR_BAD_SIGNATURE); |
115 | 1.08k | } |
116 | | |
117 | 1.08k | return rv; |
118 | 1.09k | } |
119 | | |
120 | | struct VFYContextStr { |
121 | | SECOidTag hashAlg; /* the hash algorithm */ |
122 | | SECKEYPublicKey *key; |
123 | | /* |
124 | | * This buffer holds either the digest or the full signature |
125 | | * depending on the type of the signature (key->keyType). It is |
126 | | * defined as a union to make sure it always has enough space. |
127 | | * |
128 | | * Use the "buffer" union member to reference the buffer. |
129 | | * Note: do not take the size of the "buffer" union member. Take |
130 | | * the size of the union or some other union member instead. |
131 | | */ |
132 | | union { |
133 | | unsigned char buffer[1]; |
134 | | |
135 | | /* the full DSA signature... 40 bytes */ |
136 | | unsigned char dsasig[DSA_MAX_SIGNATURE_LEN]; |
137 | | /* the full ECDSA signature */ |
138 | | unsigned char ecdsasig[2 * MAX_ECKEY_LEN]; |
139 | | /* the full RSA signature, only used in RSA-PSS */ |
140 | | unsigned char rsasig[(RSA_MAX_MODULUS_BITS + 7) / 8]; |
141 | | } u; |
142 | | unsigned int pkcs1RSADigestInfoLen; |
143 | | /* the encoded DigestInfo from a RSA PKCS#1 signature */ |
144 | | unsigned char *pkcs1RSADigestInfo; |
145 | | void *wincx; |
146 | | void *hashcx; |
147 | | const SECHashObject *hashobj; |
148 | | SECOidTag encAlg; /* enc alg */ |
149 | | PRBool hasSignature; /* true if the signature was provided in the |
150 | | * VFY_CreateContext call. If false, the |
151 | | * signature must be provided with a |
152 | | * VFY_EndWithSignature call. */ |
153 | | SECItem *params; |
154 | | }; |
155 | | |
156 | | static SECStatus |
157 | | verifyPKCS1DigestInfo(const VFYContext *cx, const SECItem *digest) |
158 | 9 | { |
159 | 9 | SECItem pkcs1DigestInfo; |
160 | 9 | pkcs1DigestInfo.data = cx->pkcs1RSADigestInfo; |
161 | 9 | pkcs1DigestInfo.len = cx->pkcs1RSADigestInfoLen; |
162 | 9 | return _SGN_VerifyPKCS1DigestInfo( |
163 | 9 | cx->hashAlg, digest, &pkcs1DigestInfo, |
164 | 9 | PR_FALSE /*XXX: unsafeAllowMissingParameters*/); |
165 | 9 | } |
166 | | |
167 | | /* |
168 | | * decode the ECDSA or DSA signature from it's DER wrapping. |
169 | | * The unwrapped/raw signature is placed in the buffer pointed |
170 | | * to by dsig and has enough room for len bytes. |
171 | | */ |
172 | | static SECStatus |
173 | | decodeECorDSASignature(SECOidTag algid, const SECItem *sig, unsigned char *dsig, |
174 | | unsigned int len) |
175 | 1.52k | { |
176 | 1.52k | SECItem *dsasig = NULL; /* also used for ECDSA */ |
177 | 1.52k | SECStatus rv = SECSuccess; |
178 | | |
179 | 1.52k | if ((algid != SEC_OID_ANSIX9_DSA_SIGNATURE) && |
180 | 1.52k | (algid != SEC_OID_ANSIX962_EC_PUBLIC_KEY)) { |
181 | 0 | if (sig->len != len) { |
182 | 0 | PORT_SetError(SEC_ERROR_BAD_DER); |
183 | 0 | return SECFailure; |
184 | 0 | } |
185 | | |
186 | 0 | PORT_Memcpy(dsig, sig->data, sig->len); |
187 | 0 | return SECSuccess; |
188 | 0 | } |
189 | | |
190 | 1.52k | if (algid == SEC_OID_ANSIX962_EC_PUBLIC_KEY) { |
191 | 1.52k | if (len > MAX_ECKEY_LEN * 2) { |
192 | 0 | PORT_SetError(SEC_ERROR_BAD_DER); |
193 | 0 | return SECFailure; |
194 | 0 | } |
195 | 1.52k | } |
196 | 1.52k | dsasig = DSAU_DecodeDerSigToLen((SECItem *)sig, len); |
197 | | |
198 | 1.52k | if ((dsasig == NULL) || (dsasig->len != len)) { |
199 | 238 | rv = SECFailure; |
200 | 1.28k | } else { |
201 | 1.28k | PORT_Memcpy(dsig, dsasig->data, dsasig->len); |
202 | 1.28k | } |
203 | | |
204 | 1.52k | if (dsasig != NULL) |
205 | 1.28k | SECITEM_FreeItem(dsasig, PR_TRUE); |
206 | 1.52k | if (rv == SECFailure) |
207 | 238 | PORT_SetError(SEC_ERROR_BAD_DER); |
208 | 1.52k | return rv; |
209 | 1.52k | } |
210 | | |
211 | | const SEC_ASN1Template hashParameterTemplate[] = |
212 | | { |
213 | | { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(SECItem) }, |
214 | | { SEC_ASN1_OBJECT_ID, 0 }, |
215 | | { SEC_ASN1_SKIP_REST }, |
216 | | { 0 } |
217 | | }; |
218 | | |
219 | | /* |
220 | | * Get just the encryption algorithm from the signature algorithm |
221 | | */ |
222 | | SECOidTag |
223 | | sec_GetEncAlgFromSigAlg(SECOidTag sigAlg) |
224 | 17.4k | { |
225 | | /* get the "encryption" algorithm */ |
226 | 17.4k | switch (sigAlg) { |
227 | 0 | case SEC_OID_PKCS1_RSA_ENCRYPTION: |
228 | 0 | case SEC_OID_PKCS1_MD2_WITH_RSA_ENCRYPTION: |
229 | 0 | case SEC_OID_PKCS1_MD5_WITH_RSA_ENCRYPTION: |
230 | 13.3k | case SEC_OID_PKCS1_SHA1_WITH_RSA_ENCRYPTION: |
231 | 13.3k | case SEC_OID_ISO_SHA_WITH_RSA_SIGNATURE: |
232 | 13.3k | case SEC_OID_ISO_SHA1_WITH_RSA_SIGNATURE: |
233 | 13.3k | case SEC_OID_PKCS1_SHA224_WITH_RSA_ENCRYPTION: |
234 | 13.5k | case SEC_OID_PKCS1_SHA256_WITH_RSA_ENCRYPTION: |
235 | 13.6k | case SEC_OID_PKCS1_SHA384_WITH_RSA_ENCRYPTION: |
236 | 13.6k | case SEC_OID_PKCS1_SHA512_WITH_RSA_ENCRYPTION: |
237 | 13.6k | return SEC_OID_PKCS1_RSA_ENCRYPTION; |
238 | 0 | case SEC_OID_PKCS1_RSA_PSS_SIGNATURE: |
239 | 0 | return SEC_OID_PKCS1_RSA_PSS_SIGNATURE; |
240 | | |
241 | | /* what about normal DSA? */ |
242 | 0 | case SEC_OID_ANSIX9_DSA_SIGNATURE_WITH_SHA1_DIGEST: |
243 | 0 | case SEC_OID_BOGUS_DSA_SIGNATURE_WITH_SHA1_DIGEST: |
244 | 0 | case SEC_OID_NIST_DSA_SIGNATURE_WITH_SHA224_DIGEST: |
245 | 0 | case SEC_OID_NIST_DSA_SIGNATURE_WITH_SHA256_DIGEST: |
246 | 0 | return SEC_OID_ANSIX9_DSA_SIGNATURE; |
247 | 0 | case SEC_OID_MISSI_DSS: |
248 | 0 | case SEC_OID_MISSI_KEA_DSS: |
249 | 0 | case SEC_OID_MISSI_KEA_DSS_OLD: |
250 | 0 | case SEC_OID_MISSI_DSS_OLD: |
251 | 0 | return SEC_OID_MISSI_DSS; |
252 | 3.18k | case SEC_OID_ANSIX962_ECDSA_SHA1_SIGNATURE: |
253 | 3.19k | case SEC_OID_ANSIX962_ECDSA_SHA224_SIGNATURE: |
254 | 3.55k | case SEC_OID_ANSIX962_ECDSA_SHA256_SIGNATURE: |
255 | 3.63k | case SEC_OID_ANSIX962_ECDSA_SHA384_SIGNATURE: |
256 | 3.75k | case SEC_OID_ANSIX962_ECDSA_SHA512_SIGNATURE: |
257 | 3.75k | case SEC_OID_ANSIX962_ECDSA_SIGNATURE_RECOMMENDED_DIGEST: |
258 | 3.75k | case SEC_OID_ANSIX962_ECDSA_SIGNATURE_SPECIFIED_DIGEST: |
259 | 3.75k | return SEC_OID_ANSIX962_EC_PUBLIC_KEY; |
260 | | /* we don't implement MD4 hashes */ |
261 | 0 | case SEC_OID_PKCS1_MD4_WITH_RSA_ENCRYPTION: |
262 | 0 | default: |
263 | 0 | PORT_SetError(SEC_ERROR_INVALID_ALGORITHM); |
264 | 0 | break; |
265 | 17.4k | } |
266 | 0 | return SEC_OID_UNKNOWN; |
267 | 17.4k | } |
268 | | |
269 | | /* |
270 | | * Pulls the hash algorithm, signing algorithm, and key type out of a |
271 | | * composite algorithm. |
272 | | * |
273 | | * sigAlg: the composite algorithm to dissect. |
274 | | * hashalg: address of a SECOidTag which will be set with the hash algorithm. |
275 | | * encalg: address of a SECOidTag which will be set with the signing alg. |
276 | | * |
277 | | * Returns: SECSuccess if the algorithm was acceptable, SECFailure if the |
278 | | * algorithm was not found or was not a signing algorithm. |
279 | | */ |
280 | | SECStatus |
281 | | sec_DecodeSigAlg(const SECKEYPublicKey *key, SECOidTag sigAlg, |
282 | | const SECItem *param, SECOidTag *encalgp, SECOidTag *hashalg) |
283 | 20 | { |
284 | 20 | int len; |
285 | 20 | PLArenaPool *arena; |
286 | 20 | SECStatus rv; |
287 | 20 | SECItem oid; |
288 | 20 | SECOidTag encalg; |
289 | | |
290 | 20 | PR_ASSERT(hashalg != NULL); |
291 | 20 | PR_ASSERT(encalgp != NULL); |
292 | | |
293 | 20 | switch (sigAlg) { |
294 | | /* We probably shouldn't be generating MD2 signatures either */ |
295 | 0 | case SEC_OID_PKCS1_MD2_WITH_RSA_ENCRYPTION: |
296 | 0 | *hashalg = SEC_OID_MD2; |
297 | 0 | break; |
298 | 0 | case SEC_OID_PKCS1_MD5_WITH_RSA_ENCRYPTION: |
299 | 0 | *hashalg = SEC_OID_MD5; |
300 | 0 | break; |
301 | 0 | case SEC_OID_PKCS1_SHA1_WITH_RSA_ENCRYPTION: |
302 | 0 | case SEC_OID_ISO_SHA_WITH_RSA_SIGNATURE: |
303 | 0 | case SEC_OID_ISO_SHA1_WITH_RSA_SIGNATURE: |
304 | 0 | *hashalg = SEC_OID_SHA1; |
305 | 0 | break; |
306 | 0 | case SEC_OID_PKCS1_RSA_ENCRYPTION: |
307 | 0 | *hashalg = SEC_OID_UNKNOWN; /* get it from the RSA signature */ |
308 | 0 | break; |
309 | 0 | case SEC_OID_PKCS1_RSA_PSS_SIGNATURE: |
310 | 0 | if (param && param->data) { |
311 | 0 | PORTCheapArenaPool tmpArena; |
312 | |
|
313 | 0 | PORT_InitCheapArena(&tmpArena, DER_DEFAULT_CHUNKSIZE); |
314 | 0 | rv = sec_DecodeRSAPSSParams(&tmpArena.arena, param, |
315 | 0 | hashalg, NULL, NULL); |
316 | 0 | PORT_DestroyCheapArena(&tmpArena); |
317 | | |
318 | | /* only accept hash algorithms */ |
319 | 0 | if (HASH_GetHashTypeByOidTag(*hashalg) == HASH_AlgNULL) { |
320 | | /* error set by HASH_GetHashTypeByOidTag */ |
321 | 0 | return SECFailure; |
322 | 0 | } |
323 | 0 | } else { |
324 | 0 | *hashalg = SEC_OID_SHA1; /* default, SHA-1 */ |
325 | 0 | } |
326 | 0 | break; |
327 | | |
328 | 2 | case SEC_OID_ANSIX962_ECDSA_SHA224_SIGNATURE: |
329 | 2 | case SEC_OID_PKCS1_SHA224_WITH_RSA_ENCRYPTION: |
330 | 2 | case SEC_OID_NIST_DSA_SIGNATURE_WITH_SHA224_DIGEST: |
331 | 2 | *hashalg = SEC_OID_SHA224; |
332 | 2 | break; |
333 | 2 | case SEC_OID_ANSIX962_ECDSA_SHA256_SIGNATURE: |
334 | 6 | case SEC_OID_PKCS1_SHA256_WITH_RSA_ENCRYPTION: |
335 | 6 | case SEC_OID_NIST_DSA_SIGNATURE_WITH_SHA256_DIGEST: |
336 | 6 | *hashalg = SEC_OID_SHA256; |
337 | 6 | break; |
338 | 4 | case SEC_OID_ANSIX962_ECDSA_SHA384_SIGNATURE: |
339 | 10 | case SEC_OID_PKCS1_SHA384_WITH_RSA_ENCRYPTION: |
340 | 10 | *hashalg = SEC_OID_SHA384; |
341 | 10 | break; |
342 | 2 | case SEC_OID_ANSIX962_ECDSA_SHA512_SIGNATURE: |
343 | 2 | case SEC_OID_PKCS1_SHA512_WITH_RSA_ENCRYPTION: |
344 | 2 | *hashalg = SEC_OID_SHA512; |
345 | 2 | break; |
346 | | |
347 | | /* what about normal DSA? */ |
348 | 0 | case SEC_OID_ANSIX9_DSA_SIGNATURE_WITH_SHA1_DIGEST: |
349 | 0 | case SEC_OID_BOGUS_DSA_SIGNATURE_WITH_SHA1_DIGEST: |
350 | 0 | case SEC_OID_ANSIX962_ECDSA_SHA1_SIGNATURE: |
351 | 0 | *hashalg = SEC_OID_SHA1; |
352 | 0 | break; |
353 | 0 | case SEC_OID_MISSI_DSS: |
354 | 0 | case SEC_OID_MISSI_KEA_DSS: |
355 | 0 | case SEC_OID_MISSI_KEA_DSS_OLD: |
356 | 0 | case SEC_OID_MISSI_DSS_OLD: |
357 | 0 | *hashalg = SEC_OID_SHA1; |
358 | 0 | break; |
359 | 0 | case SEC_OID_ANSIX962_ECDSA_SIGNATURE_RECOMMENDED_DIGEST: |
360 | | /* This is an EC algorithm. Recommended means the largest |
361 | | * hash algorithm that is not reduced by the keysize of |
362 | | * the EC algorithm. Note that key strength is in bytes and |
363 | | * algorithms are specified in bits. Never use an algorithm |
364 | | * weaker than sha1. */ |
365 | 0 | len = SECKEY_PublicKeyStrength(key); |
366 | 0 | if (len < 28) { /* 28 bytes == 224 bits */ |
367 | 0 | *hashalg = SEC_OID_SHA1; |
368 | 0 | } else if (len < 32) { /* 32 bytes == 256 bits */ |
369 | 0 | *hashalg = SEC_OID_SHA224; |
370 | 0 | } else if (len < 48) { /* 48 bytes == 384 bits */ |
371 | 0 | *hashalg = SEC_OID_SHA256; |
372 | 0 | } else if (len < 64) { /* 48 bytes == 512 bits */ |
373 | 0 | *hashalg = SEC_OID_SHA384; |
374 | 0 | } else { |
375 | | /* use the largest in this case */ |
376 | 0 | *hashalg = SEC_OID_SHA512; |
377 | 0 | } |
378 | 0 | break; |
379 | 0 | case SEC_OID_ANSIX962_ECDSA_SIGNATURE_SPECIFIED_DIGEST: |
380 | 0 | if (param == NULL) { |
381 | 0 | PORT_SetError(SEC_ERROR_INVALID_ALGORITHM); |
382 | 0 | return SECFailure; |
383 | 0 | } |
384 | 0 | arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); |
385 | 0 | if (arena == NULL) { |
386 | 0 | return SECFailure; |
387 | 0 | } |
388 | 0 | rv = SEC_QuickDERDecodeItem(arena, &oid, hashParameterTemplate, param); |
389 | 0 | if (rv == SECSuccess) { |
390 | 0 | *hashalg = SECOID_FindOIDTag(&oid); |
391 | 0 | } |
392 | 0 | PORT_FreeArena(arena, PR_FALSE); |
393 | 0 | if (rv != SECSuccess) { |
394 | 0 | return rv; |
395 | 0 | } |
396 | | /* only accept hash algorithms */ |
397 | 0 | if (HASH_GetHashTypeByOidTag(*hashalg) == HASH_AlgNULL) { |
398 | | /* error set by HASH_GetHashTypeByOidTag */ |
399 | 0 | return SECFailure; |
400 | 0 | } |
401 | 0 | break; |
402 | | /* we don't implement MD4 hashes */ |
403 | 0 | case SEC_OID_PKCS1_MD4_WITH_RSA_ENCRYPTION: |
404 | 0 | default: |
405 | 0 | PORT_SetError(SEC_ERROR_INVALID_ALGORITHM); |
406 | 0 | return SECFailure; |
407 | 20 | } |
408 | | |
409 | 20 | encalg = sec_GetEncAlgFromSigAlg(sigAlg); |
410 | 20 | if (encalg == SEC_OID_UNKNOWN) { |
411 | 0 | return SECFailure; |
412 | 0 | } |
413 | 20 | *encalgp = encalg; |
414 | | |
415 | 20 | return SECSuccess; |
416 | 20 | } |
417 | | |
418 | | /* |
419 | | * we can verify signatures that come from 2 different sources: |
420 | | * one in with the signature contains a signature oid, and the other |
421 | | * in which the signature is managed by a Public key (encAlg) oid |
422 | | * and a hash oid. The latter is the more basic, so that's what |
423 | | * our base vfyCreate function takes. |
424 | | * |
425 | | * There is one noteworthy corner case, if we are using an RSA key, and the |
426 | | * signature block is provided, then the hashAlg can be specified as |
427 | | * SEC_OID_UNKNOWN. In this case, verify will use the hash oid supplied |
428 | | * in the RSA signature block. |
429 | | */ |
430 | | static VFYContext * |
431 | | vfy_CreateContext(const SECKEYPublicKey *key, const SECItem *sig, |
432 | | SECOidTag encAlg, SECOidTag hashAlg, SECOidTag *hash, void *wincx) |
433 | 2.63k | { |
434 | 2.63k | VFYContext *cx; |
435 | 2.63k | SECStatus rv; |
436 | 2.63k | unsigned int sigLen; |
437 | 2.63k | KeyType type; |
438 | 2.63k | PRUint32 policyFlags; |
439 | | |
440 | | /* make sure the encryption algorithm matches the key type */ |
441 | | /* RSA-PSS algorithm can be used with both rsaKey and rsaPssKey */ |
442 | 2.63k | type = seckey_GetKeyType(encAlg); |
443 | 2.63k | if ((key->keyType != type) && |
444 | 2.63k | ((key->keyType != rsaKey) || (type != rsaPssKey))) { |
445 | 0 | PORT_SetError(SEC_ERROR_PKCS7_KEYALG_MISMATCH); |
446 | 0 | return NULL; |
447 | 0 | } |
448 | | |
449 | | /* check the policy on the encryption algorithm */ |
450 | 2.63k | if ((NSS_GetAlgorithmPolicy(encAlg, &policyFlags) == SECFailure) || |
451 | 2.63k | !(policyFlags & NSS_USE_ALG_IN_ANY_SIGNATURE)) { |
452 | 0 | PORT_SetError(SEC_ERROR_SIGNATURE_ALGORITHM_DISABLED); |
453 | 0 | return NULL; |
454 | 0 | } |
455 | | |
456 | 2.63k | cx = (VFYContext *)PORT_ZAlloc(sizeof(VFYContext)); |
457 | 2.63k | if (cx == NULL) { |
458 | 0 | goto loser; |
459 | 0 | } |
460 | | |
461 | 2.63k | cx->wincx = wincx; |
462 | 2.63k | cx->hasSignature = (sig != NULL); |
463 | 2.63k | cx->encAlg = encAlg; |
464 | 2.63k | cx->hashAlg = hashAlg; |
465 | 2.63k | cx->key = SECKEY_CopyPublicKey(key); |
466 | 2.63k | cx->pkcs1RSADigestInfo = NULL; |
467 | 2.63k | rv = SECSuccess; |
468 | 2.63k | if (sig) { |
469 | 2.63k | switch (type) { |
470 | 1.09k | case rsaKey: |
471 | 1.09k | rv = recoverPKCS1DigestInfo(hashAlg, &cx->hashAlg, |
472 | 1.09k | &cx->pkcs1RSADigestInfo, |
473 | 1.09k | &cx->pkcs1RSADigestInfoLen, |
474 | 1.09k | cx->key, |
475 | 1.09k | sig, wincx); |
476 | 1.09k | break; |
477 | 0 | case rsaPssKey: |
478 | 0 | sigLen = SECKEY_SignatureLen(key); |
479 | 0 | if (sigLen == 0) { |
480 | | /* error set by SECKEY_SignatureLen */ |
481 | 0 | rv = SECFailure; |
482 | 0 | break; |
483 | 0 | } |
484 | 0 | if (sig->len != sigLen) { |
485 | 0 | PORT_SetError(SEC_ERROR_BAD_SIGNATURE); |
486 | 0 | rv = SECFailure; |
487 | 0 | break; |
488 | 0 | } |
489 | 0 | PORT_Memcpy(cx->u.buffer, sig->data, sigLen); |
490 | 0 | break; |
491 | 0 | case dsaKey: |
492 | 1.53k | case ecKey: |
493 | 1.53k | sigLen = SECKEY_SignatureLen(key); |
494 | 1.53k | if (sigLen == 0) { |
495 | | /* error set by SECKEY_SignatureLen */ |
496 | 12 | rv = SECFailure; |
497 | 12 | break; |
498 | 12 | } |
499 | 1.52k | rv = decodeECorDSASignature(encAlg, sig, cx->u.buffer, sigLen); |
500 | 1.52k | break; |
501 | 0 | default: |
502 | 0 | rv = SECFailure; |
503 | 0 | PORT_SetError(SEC_ERROR_UNSUPPORTED_KEYALG); |
504 | 0 | break; |
505 | 2.63k | } |
506 | 2.63k | } |
507 | | |
508 | 2.63k | if (rv) |
509 | 1.33k | goto loser; |
510 | | |
511 | | /* check hash alg again, RSA may have changed it.*/ |
512 | 1.29k | if (HASH_GetHashTypeByOidTag(cx->hashAlg) == HASH_AlgNULL) { |
513 | | /* error set by HASH_GetHashTypeByOidTag */ |
514 | 0 | goto loser; |
515 | 0 | } |
516 | | /* check the policy on the hash algorithm. Do this after |
517 | | * the rsa decode because some uses of this function get hash implicitly |
518 | | * from the RSA signature itself. */ |
519 | 1.29k | if ((NSS_GetAlgorithmPolicy(cx->hashAlg, &policyFlags) == SECFailure) || |
520 | 1.29k | !(policyFlags & NSS_USE_ALG_IN_ANY_SIGNATURE)) { |
521 | 0 | PORT_SetError(SEC_ERROR_SIGNATURE_ALGORITHM_DISABLED); |
522 | 0 | goto loser; |
523 | 0 | } |
524 | | |
525 | 1.29k | if (hash) { |
526 | 4 | *hash = cx->hashAlg; |
527 | 4 | } |
528 | 1.29k | return cx; |
529 | | |
530 | 1.33k | loser: |
531 | 1.33k | if (cx) { |
532 | 1.33k | VFY_DestroyContext(cx, PR_TRUE); |
533 | 1.33k | } |
534 | 1.33k | return 0; |
535 | 1.29k | } |
536 | | |
537 | | VFYContext * |
538 | | VFY_CreateContext(SECKEYPublicKey *key, SECItem *sig, SECOidTag sigAlg, |
539 | | void *wincx) |
540 | 0 | { |
541 | 0 | SECOidTag encAlg, hashAlg; |
542 | 0 | SECStatus rv = sec_DecodeSigAlg(key, sigAlg, NULL, &encAlg, &hashAlg); |
543 | 0 | if (rv != SECSuccess) { |
544 | 0 | return NULL; |
545 | 0 | } |
546 | 0 | return vfy_CreateContext(key, sig, encAlg, hashAlg, NULL, wincx); |
547 | 0 | } |
548 | | |
549 | | VFYContext * |
550 | | VFY_CreateContextDirect(const SECKEYPublicKey *key, const SECItem *sig, |
551 | | SECOidTag encAlg, SECOidTag hashAlg, |
552 | | SECOidTag *hash, void *wincx) |
553 | 0 | { |
554 | 0 | return vfy_CreateContext(key, sig, encAlg, hashAlg, hash, wincx); |
555 | 0 | } |
556 | | |
557 | | VFYContext * |
558 | | VFY_CreateContextWithAlgorithmID(const SECKEYPublicKey *key, const SECItem *sig, |
559 | | const SECAlgorithmID *sigAlgorithm, SECOidTag *hash, void *wincx) |
560 | 0 | { |
561 | 0 | VFYContext *cx; |
562 | 0 | SECOidTag encAlg, hashAlg; |
563 | 0 | SECStatus rv = sec_DecodeSigAlg(key, |
564 | 0 | SECOID_GetAlgorithmTag((SECAlgorithmID *)sigAlgorithm), |
565 | 0 | &sigAlgorithm->parameters, &encAlg, &hashAlg); |
566 | 0 | if (rv != SECSuccess) { |
567 | 0 | return NULL; |
568 | 0 | } |
569 | | |
570 | 0 | cx = vfy_CreateContext(key, sig, encAlg, hashAlg, hash, wincx); |
571 | 0 | if (sigAlgorithm->parameters.data) { |
572 | 0 | cx->params = SECITEM_DupItem(&sigAlgorithm->parameters); |
573 | 0 | } |
574 | |
|
575 | 0 | return cx; |
576 | 0 | } |
577 | | |
578 | | void |
579 | | VFY_DestroyContext(VFYContext *cx, PRBool freeit) |
580 | 2.63k | { |
581 | 2.63k | if (cx) { |
582 | 2.63k | if (cx->hashcx != NULL) { |
583 | 4 | (*cx->hashobj->destroy)(cx->hashcx, PR_TRUE); |
584 | 4 | cx->hashcx = NULL; |
585 | 4 | } |
586 | 2.63k | if (cx->key) { |
587 | 2.63k | SECKEY_DestroyPublicKey(cx->key); |
588 | 2.63k | } |
589 | 2.63k | if (cx->pkcs1RSADigestInfo) { |
590 | 9 | PORT_Free(cx->pkcs1RSADigestInfo); |
591 | 9 | } |
592 | 2.63k | if (cx->params) { |
593 | 4 | SECITEM_FreeItem(cx->params, PR_TRUE); |
594 | 4 | } |
595 | 2.63k | if (freeit) { |
596 | 2.63k | PORT_ZFree(cx, sizeof(VFYContext)); |
597 | 2.63k | } |
598 | 2.63k | } |
599 | 2.63k | } |
600 | | |
601 | | SECStatus |
602 | | VFY_Begin(VFYContext *cx) |
603 | 4 | { |
604 | 4 | if (cx->hashcx != NULL) { |
605 | 0 | (*cx->hashobj->destroy)(cx->hashcx, PR_TRUE); |
606 | 0 | cx->hashcx = NULL; |
607 | 0 | } |
608 | | |
609 | 4 | cx->hashobj = HASH_GetHashObjectByOidTag(cx->hashAlg); |
610 | 4 | if (!cx->hashobj) |
611 | 0 | return SECFailure; /* error code is set */ |
612 | | |
613 | 4 | cx->hashcx = (*cx->hashobj->create)(); |
614 | 4 | if (cx->hashcx == NULL) |
615 | 0 | return SECFailure; |
616 | | |
617 | 4 | (*cx->hashobj->begin)(cx->hashcx); |
618 | 4 | return SECSuccess; |
619 | 4 | } |
620 | | |
621 | | SECStatus |
622 | | VFY_Update(VFYContext *cx, const unsigned char *input, unsigned inputLen) |
623 | 4 | { |
624 | 4 | if (cx->hashcx == NULL) { |
625 | 0 | PORT_SetError(SEC_ERROR_INVALID_ARGS); |
626 | 0 | return SECFailure; |
627 | 0 | } |
628 | 4 | (*cx->hashobj->update)(cx->hashcx, input, inputLen); |
629 | 4 | return SECSuccess; |
630 | 4 | } |
631 | | |
632 | | SECStatus |
633 | | VFY_EndWithSignature(VFYContext *cx, SECItem *sig) |
634 | 4 | { |
635 | 4 | unsigned char final[HASH_LENGTH_MAX]; |
636 | 4 | unsigned part; |
637 | 4 | SECItem hash, rsasig, dsasig; /* dsasig is also used for ECDSA */ |
638 | 4 | SECStatus rv; |
639 | | |
640 | 4 | if ((cx->hasSignature == PR_FALSE) && (sig == NULL)) { |
641 | 0 | PORT_SetError(SEC_ERROR_INVALID_ARGS); |
642 | 0 | return SECFailure; |
643 | 0 | } |
644 | | |
645 | 4 | if (cx->hashcx == NULL) { |
646 | 0 | PORT_SetError(SEC_ERROR_INVALID_ARGS); |
647 | 0 | return SECFailure; |
648 | 0 | } |
649 | 4 | (*cx->hashobj->end)(cx->hashcx, final, &part, sizeof(final)); |
650 | 4 | switch (cx->key->keyType) { |
651 | 4 | case ecKey: |
652 | 4 | case dsaKey: |
653 | 4 | dsasig.data = cx->u.buffer; |
654 | 4 | dsasig.len = SECKEY_SignatureLen(cx->key); |
655 | 4 | if (dsasig.len == 0) { |
656 | 0 | return SECFailure; |
657 | 0 | } |
658 | 4 | if (sig) { |
659 | 0 | rv = decodeECorDSASignature(cx->encAlg, sig, dsasig.data, |
660 | 0 | dsasig.len); |
661 | 0 | if (rv != SECSuccess) { |
662 | 0 | PORT_SetError(SEC_ERROR_BAD_SIGNATURE); |
663 | 0 | return SECFailure; |
664 | 0 | } |
665 | 0 | } |
666 | 4 | hash.data = final; |
667 | 4 | hash.len = part; |
668 | 4 | if (PK11_Verify(cx->key, &dsasig, &hash, cx->wincx) != SECSuccess) { |
669 | 4 | PORT_SetError(SEC_ERROR_BAD_SIGNATURE); |
670 | 4 | return SECFailure; |
671 | 4 | } |
672 | 0 | break; |
673 | 0 | case rsaKey: |
674 | 0 | if (cx->encAlg == SEC_OID_PKCS1_RSA_PSS_SIGNATURE) { |
675 | 0 | CK_RSA_PKCS_PSS_PARAMS mech; |
676 | 0 | SECItem mechItem = { siBuffer, (unsigned char *)&mech, sizeof(mech) }; |
677 | 0 | PORTCheapArenaPool tmpArena; |
678 | |
|
679 | 0 | PORT_InitCheapArena(&tmpArena, DER_DEFAULT_CHUNKSIZE); |
680 | 0 | rv = sec_DecodeRSAPSSParamsToMechanism(&tmpArena.arena, |
681 | 0 | cx->params, |
682 | 0 | &mech); |
683 | 0 | PORT_DestroyCheapArena(&tmpArena); |
684 | 0 | if (rv != SECSuccess) { |
685 | 0 | return SECFailure; |
686 | 0 | } |
687 | | |
688 | 0 | rsasig.data = cx->u.buffer; |
689 | 0 | rsasig.len = SECKEY_SignatureLen(cx->key); |
690 | 0 | if (rsasig.len == 0) { |
691 | 0 | return SECFailure; |
692 | 0 | } |
693 | 0 | if (sig) { |
694 | 0 | if (sig->len != rsasig.len) { |
695 | 0 | PORT_SetError(SEC_ERROR_BAD_SIGNATURE); |
696 | 0 | return SECFailure; |
697 | 0 | } |
698 | 0 | PORT_Memcpy(rsasig.data, sig->data, rsasig.len); |
699 | 0 | } |
700 | 0 | hash.data = final; |
701 | 0 | hash.len = part; |
702 | 0 | if (PK11_VerifyWithMechanism(cx->key, CKM_RSA_PKCS_PSS, &mechItem, |
703 | 0 | &rsasig, &hash, cx->wincx) != SECSuccess) { |
704 | 0 | PORT_SetError(SEC_ERROR_BAD_SIGNATURE); |
705 | 0 | return SECFailure; |
706 | 0 | } |
707 | 0 | } else { |
708 | 0 | SECItem digest; |
709 | 0 | digest.data = final; |
710 | 0 | digest.len = part; |
711 | 0 | if (sig) { |
712 | 0 | SECOidTag hashid; |
713 | 0 | PORT_Assert(cx->hashAlg != SEC_OID_UNKNOWN); |
714 | 0 | rv = recoverPKCS1DigestInfo(cx->hashAlg, &hashid, |
715 | 0 | &cx->pkcs1RSADigestInfo, |
716 | 0 | &cx->pkcs1RSADigestInfoLen, |
717 | 0 | cx->key, |
718 | 0 | sig, cx->wincx); |
719 | 0 | if (rv != SECSuccess) { |
720 | 0 | return SECFailure; |
721 | 0 | } |
722 | 0 | PORT_Assert(cx->hashAlg == hashid); |
723 | 0 | } |
724 | 0 | return verifyPKCS1DigestInfo(cx, &digest); |
725 | 0 | } |
726 | 0 | break; |
727 | 0 | default: |
728 | 0 | PORT_SetError(SEC_ERROR_BAD_SIGNATURE); |
729 | 0 | return SECFailure; /* shouldn't happen */ |
730 | 4 | } |
731 | 0 | return SECSuccess; |
732 | 4 | } |
733 | | |
734 | | SECStatus |
735 | | VFY_End(VFYContext *cx) |
736 | 4 | { |
737 | 4 | return VFY_EndWithSignature(cx, NULL); |
738 | 4 | } |
739 | | |
740 | | /************************************************************************/ |
741 | | /* |
742 | | * Verify that a previously-computed digest matches a signature. |
743 | | */ |
744 | | static SECStatus |
745 | | vfy_VerifyDigest(const SECItem *digest, const SECKEYPublicKey *key, |
746 | | const SECItem *sig, SECOidTag encAlg, SECOidTag hashAlg, |
747 | | void *wincx) |
748 | 2.62k | { |
749 | 2.62k | SECStatus rv; |
750 | 2.62k | VFYContext *cx; |
751 | 2.62k | SECItem dsasig; /* also used for ECDSA */ |
752 | | |
753 | 2.62k | rv = SECFailure; |
754 | | |
755 | 2.62k | cx = vfy_CreateContext(key, sig, encAlg, hashAlg, NULL, wincx); |
756 | 2.62k | if (cx != NULL) { |
757 | 1.28k | switch (key->keyType) { |
758 | 9 | case rsaKey: |
759 | 9 | rv = verifyPKCS1DigestInfo(cx, digest); |
760 | 9 | break; |
761 | 0 | case dsaKey: |
762 | 1.28k | case ecKey: |
763 | 1.28k | dsasig.data = cx->u.buffer; |
764 | 1.28k | dsasig.len = SECKEY_SignatureLen(cx->key); |
765 | 1.28k | if (dsasig.len == 0) { |
766 | 0 | break; |
767 | 0 | } |
768 | 1.28k | if (PK11_Verify(cx->key, &dsasig, (SECItem *)digest, cx->wincx) != |
769 | 1.28k | SECSuccess) { |
770 | 1.28k | PORT_SetError(SEC_ERROR_BAD_SIGNATURE); |
771 | 1.28k | } else { |
772 | 0 | rv = SECSuccess; |
773 | 0 | } |
774 | 1.28k | break; |
775 | 0 | default: |
776 | 0 | break; |
777 | 1.28k | } |
778 | 1.28k | VFY_DestroyContext(cx, PR_TRUE); |
779 | 1.28k | } |
780 | 2.62k | return rv; |
781 | 2.62k | } |
782 | | |
783 | | SECStatus |
784 | | VFY_VerifyDigestDirect(const SECItem *digest, const SECKEYPublicKey *key, |
785 | | const SECItem *sig, SECOidTag encAlg, |
786 | | SECOidTag hashAlg, void *wincx) |
787 | 2.62k | { |
788 | 2.62k | return vfy_VerifyDigest(digest, key, sig, encAlg, hashAlg, wincx); |
789 | 2.62k | } |
790 | | |
791 | | SECStatus |
792 | | VFY_VerifyDigest(SECItem *digest, SECKEYPublicKey *key, SECItem *sig, |
793 | | SECOidTag algid, void *wincx) |
794 | 0 | { |
795 | 0 | SECOidTag encAlg, hashAlg; |
796 | 0 | SECStatus rv = sec_DecodeSigAlg(key, algid, NULL, &encAlg, &hashAlg); |
797 | 0 | if (rv != SECSuccess) { |
798 | 0 | return SECFailure; |
799 | 0 | } |
800 | 0 | return vfy_VerifyDigest(digest, key, sig, encAlg, hashAlg, wincx); |
801 | 0 | } |
802 | | |
803 | | /* |
804 | | * this function takes an optional hash oid, which the digest function |
805 | | * will be compared with our target hash value. |
806 | | */ |
807 | | SECStatus |
808 | | VFY_VerifyDigestWithAlgorithmID(const SECItem *digest, |
809 | | const SECKEYPublicKey *key, const SECItem *sig, |
810 | | const SECAlgorithmID *sigAlgorithm, |
811 | | SECOidTag hashCmp, void *wincx) |
812 | 0 | { |
813 | 0 | SECOidTag encAlg, hashAlg; |
814 | 0 | SECStatus rv = sec_DecodeSigAlg(key, |
815 | 0 | SECOID_GetAlgorithmTag((SECAlgorithmID *)sigAlgorithm), |
816 | 0 | &sigAlgorithm->parameters, &encAlg, &hashAlg); |
817 | 0 | if (rv != SECSuccess) { |
818 | 0 | return rv; |
819 | 0 | } |
820 | 0 | if (hashCmp != SEC_OID_UNKNOWN && |
821 | 0 | hashAlg != SEC_OID_UNKNOWN && |
822 | 0 | hashCmp != hashAlg) { |
823 | 0 | PORT_SetError(SEC_ERROR_BAD_SIGNATURE); |
824 | 0 | return SECFailure; |
825 | 0 | } |
826 | 0 | return vfy_VerifyDigest(digest, key, sig, encAlg, hashAlg, wincx); |
827 | 0 | } |
828 | | |
829 | | static SECStatus |
830 | | vfy_VerifyData(const unsigned char *buf, int len, const SECKEYPublicKey *key, |
831 | | const SECItem *sig, SECOidTag encAlg, SECOidTag hashAlg, |
832 | | const SECItem *params, SECOidTag *hash, void *wincx) |
833 | 10 | { |
834 | 10 | SECStatus rv; |
835 | 10 | VFYContext *cx; |
836 | | |
837 | 10 | cx = vfy_CreateContext(key, sig, encAlg, hashAlg, hash, wincx); |
838 | 10 | if (cx == NULL) |
839 | 6 | return SECFailure; |
840 | 4 | if (params) { |
841 | 4 | cx->params = SECITEM_DupItem(params); |
842 | 4 | } |
843 | | |
844 | 4 | rv = VFY_Begin(cx); |
845 | 4 | if (rv == SECSuccess) { |
846 | 4 | rv = VFY_Update(cx, (unsigned char *)buf, len); |
847 | 4 | if (rv == SECSuccess) |
848 | 4 | rv = VFY_End(cx); |
849 | 4 | } |
850 | | |
851 | 4 | VFY_DestroyContext(cx, PR_TRUE); |
852 | 4 | return rv; |
853 | 10 | } |
854 | | |
855 | | SECStatus |
856 | | VFY_VerifyDataDirect(const unsigned char *buf, int len, |
857 | | const SECKEYPublicKey *key, const SECItem *sig, |
858 | | SECOidTag encAlg, SECOidTag hashAlg, |
859 | | SECOidTag *hash, void *wincx) |
860 | 0 | { |
861 | 0 | return vfy_VerifyData(buf, len, key, sig, encAlg, hashAlg, NULL, hash, wincx); |
862 | 0 | } |
863 | | |
864 | | SECStatus |
865 | | VFY_VerifyData(const unsigned char *buf, int len, const SECKEYPublicKey *key, |
866 | | const SECItem *sig, SECOidTag algid, void *wincx) |
867 | 0 | { |
868 | 0 | SECOidTag encAlg, hashAlg; |
869 | 0 | SECStatus rv = sec_DecodeSigAlg(key, algid, NULL, &encAlg, &hashAlg); |
870 | 0 | if (rv != SECSuccess) { |
871 | 0 | return rv; |
872 | 0 | } |
873 | 0 | return vfy_VerifyData(buf, len, key, sig, encAlg, hashAlg, NULL, NULL, wincx); |
874 | 0 | } |
875 | | |
876 | | SECStatus |
877 | | VFY_VerifyDataWithAlgorithmID(const unsigned char *buf, int len, |
878 | | const SECKEYPublicKey *key, |
879 | | const SECItem *sig, |
880 | | const SECAlgorithmID *sigAlgorithm, |
881 | | SECOidTag *hash, void *wincx) |
882 | 10 | { |
883 | 10 | SECOidTag encAlg, hashAlg; |
884 | 10 | SECOidTag sigAlg = SECOID_GetAlgorithmTag((SECAlgorithmID *)sigAlgorithm); |
885 | 10 | SECStatus rv = sec_DecodeSigAlg(key, sigAlg, |
886 | 10 | &sigAlgorithm->parameters, &encAlg, &hashAlg); |
887 | 10 | if (rv != SECSuccess) { |
888 | 0 | return rv; |
889 | 0 | } |
890 | 10 | return vfy_VerifyData(buf, len, key, sig, encAlg, hashAlg, |
891 | 10 | &sigAlgorithm->parameters, hash, wincx); |
892 | 10 | } |