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