OLD | NEW |
| (Empty) |
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 /* $Id: secvfy.c,v 1.30 2012/06/25 21:48:39 rrelyea%redhat.com Exp $ */ | |
8 | |
9 #include <stdio.h> | |
10 #include "cryptohi.h" | |
11 #include "sechash.h" | |
12 #include "keyhi.h" | |
13 #include "secasn1.h" | |
14 #include "secoid.h" | |
15 #include "pk11func.h" | |
16 #include "secdig.h" | |
17 #include "secerr.h" | |
18 #include "keyi.h" | |
19 | |
20 /* | |
21 ** Decrypt signature block using public key | |
22 ** Store the hash algorithm oid tag in *tagp | |
23 ** Store the digest in the digest buffer | |
24 ** Store the digest length in *digestlen | |
25 ** XXX this is assuming that the signature algorithm has WITH_RSA_ENCRYPTION | |
26 */ | |
27 static SECStatus | |
28 DecryptSigBlock(SECOidTag *tagp, unsigned char *digest, | |
29 unsigned int *digestlen, unsigned int maxdigestlen, | |
30 SECKEYPublicKey *key, const SECItem *sig, char *wincx) | |
31 { | |
32 SGNDigestInfo *di = NULL; | |
33 unsigned char *buf = NULL; | |
34 SECStatus rv; | |
35 SECOidTag tag; | |
36 SECItem it; | |
37 | |
38 if (key == NULL) goto loser; | |
39 | |
40 it.len = SECKEY_PublicKeyStrength(key); | |
41 if (!it.len) goto loser; | |
42 it.data = buf = (unsigned char *)PORT_Alloc(it.len); | |
43 if (!buf) goto loser; | |
44 | |
45 /* decrypt the block */ | |
46 rv = PK11_VerifyRecover(key, (SECItem *)sig, &it, wincx); | |
47 if (rv != SECSuccess) goto loser; | |
48 | |
49 di = SGN_DecodeDigestInfo(&it); | |
50 if (di == NULL) goto sigloser; | |
51 | |
52 /* | |
53 ** Finally we have the digest info; now we can extract the algorithm | |
54 ** ID and the signature block | |
55 */ | |
56 tag = SECOID_GetAlgorithmTag(&di->digestAlgorithm); | |
57 /* Check that tag is an appropriate algorithm */ | |
58 if (tag == SEC_OID_UNKNOWN) { | |
59 goto sigloser; | |
60 } | |
61 /* make sure the "parameters" are not too bogus. */ | |
62 if (di->digestAlgorithm.parameters.len > 2) { | |
63 goto sigloser; | |
64 } | |
65 if (di->digest.len > maxdigestlen) { | |
66 PORT_SetError(SEC_ERROR_OUTPUT_LEN); | |
67 goto loser; | |
68 } | |
69 PORT_Memcpy(digest, di->digest.data, di->digest.len); | |
70 *tagp = tag; | |
71 *digestlen = di->digest.len; | |
72 goto done; | |
73 | |
74 sigloser: | |
75 PORT_SetError(SEC_ERROR_BAD_SIGNATURE); | |
76 | |
77 loser: | |
78 rv = SECFailure; | |
79 | |
80 done: | |
81 if (di != NULL) SGN_DestroyDigestInfo(di); | |
82 if (buf != NULL) PORT_Free(buf); | |
83 | |
84 return rv; | |
85 } | |
86 | |
87 | |
88 struct VFYContextStr { | |
89 SECOidTag hashAlg; /* the hash algorithm */ | |
90 SECKEYPublicKey *key; | |
91 /* | |
92 * This buffer holds either the digest or the full signature | |
93 * depending on the type of the signature (key->keyType). It is | |
94 * defined as a union to make sure it always has enough space. | |
95 * | |
96 * Use the "buffer" union member to reference the buffer. | |
97 * Note: do not take the size of the "buffer" union member. Take | |
98 * the size of the union or some other union member instead. | |
99 */ | |
100 union { | |
101 unsigned char buffer[1]; | |
102 | |
103 /* the digest in the decrypted RSA signature */ | |
104 unsigned char rsadigest[HASH_LENGTH_MAX]; | |
105 /* the full DSA signature... 40 bytes */ | |
106 unsigned char dsasig[DSA_MAX_SIGNATURE_LEN]; | |
107 /* the full ECDSA signature */ | |
108 unsigned char ecdsasig[2 * MAX_ECKEY_LEN]; | |
109 } u; | |
110 unsigned int rsadigestlen; | |
111 void * wincx; | |
112 void *hashcx; | |
113 const SECHashObject *hashobj; | |
114 SECOidTag encAlg; /* enc alg */ | |
115 PRBool hasSignature; /* true if the signature was provided in the | |
116 * VFY_CreateContext call. If false, the | |
117 * signature must be provided with a | |
118 * VFY_EndWithSignature call. */ | |
119 }; | |
120 | |
121 /* | |
122 * decode the ECDSA or DSA signature from it's DER wrapping. | |
123 * The unwrapped/raw signature is placed in the buffer pointed | |
124 * to by dsig and has enough room for len bytes. | |
125 */ | |
126 static SECStatus | |
127 decodeECorDSASignature(SECOidTag algid, const SECItem *sig, unsigned char *dsig, | |
128 unsigned int len) { | |
129 SECItem *dsasig = NULL; /* also used for ECDSA */ | |
130 SECStatus rv=SECSuccess; | |
131 | |
132 if ((algid != SEC_OID_ANSIX9_DSA_SIGNATURE) && | |
133 (algid != SEC_OID_ANSIX962_EC_PUBLIC_KEY) ) { | |
134 if (sig->len != len) { | |
135 PORT_SetError(SEC_ERROR_BAD_DER); | |
136 return SECFailure; | |
137 } | |
138 | |
139 PORT_Memcpy(dsig, sig->data, sig->len); | |
140 return SECSuccess; | |
141 } | |
142 | |
143 if (algid == SEC_OID_ANSIX962_EC_PUBLIC_KEY) { | |
144 if (len > MAX_ECKEY_LEN * 2) { | |
145 PORT_SetError(SEC_ERROR_BAD_DER); | |
146 return SECFailure; | |
147 } | |
148 } | |
149 dsasig = DSAU_DecodeDerSigToLen((SECItem *)sig, len); | |
150 | |
151 if ((dsasig == NULL) || (dsasig->len != len)) { | |
152 rv = SECFailure; | |
153 } else { | |
154 PORT_Memcpy(dsig, dsasig->data, dsasig->len); | |
155 } | |
156 | |
157 if (dsasig != NULL) SECITEM_FreeItem(dsasig, PR_TRUE); | |
158 if (rv == SECFailure) PORT_SetError(SEC_ERROR_BAD_DER); | |
159 return rv; | |
160 } | |
161 | |
162 const SEC_ASN1Template hashParameterTemplate[] = | |
163 { | |
164 { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(SECItem) }, | |
165 { SEC_ASN1_OBJECT_ID, 0 }, | |
166 { SEC_ASN1_SKIP_REST }, | |
167 { 0, } | |
168 }; | |
169 | |
170 /* | |
171 * Pulls the hash algorithm, signing algorithm, and key type out of a | |
172 * composite algorithm. | |
173 * | |
174 * sigAlg: the composite algorithm to dissect. | |
175 * hashalg: address of a SECOidTag which will be set with the hash algorithm. | |
176 * encalg: address of a SECOidTag which will be set with the signing alg. | |
177 * | |
178 * Returns: SECSuccess if the algorithm was acceptable, SECFailure if the | |
179 * algorithm was not found or was not a signing algorithm. | |
180 */ | |
181 SECStatus | |
182 sec_DecodeSigAlg(const SECKEYPublicKey *key, SECOidTag sigAlg, | |
183 const SECItem *param, SECOidTag *encalg, SECOidTag *hashalg) | |
184 { | |
185 int len; | |
186 PRArenaPool *arena; | |
187 SECStatus rv; | |
188 SECItem oid; | |
189 | |
190 PR_ASSERT(hashalg!=NULL); | |
191 PR_ASSERT(encalg!=NULL); | |
192 | |
193 switch (sigAlg) { | |
194 /* We probably shouldn't be generating MD2 signatures either */ | |
195 case SEC_OID_PKCS1_MD2_WITH_RSA_ENCRYPTION: | |
196 *hashalg = SEC_OID_MD2; | |
197 break; | |
198 case SEC_OID_PKCS1_MD5_WITH_RSA_ENCRYPTION: | |
199 *hashalg = SEC_OID_MD5; | |
200 break; | |
201 case SEC_OID_PKCS1_SHA1_WITH_RSA_ENCRYPTION: | |
202 case SEC_OID_ISO_SHA_WITH_RSA_SIGNATURE: | |
203 case SEC_OID_ISO_SHA1_WITH_RSA_SIGNATURE: | |
204 *hashalg = SEC_OID_SHA1; | |
205 break; | |
206 case SEC_OID_PKCS1_RSA_ENCRYPTION: | |
207 case SEC_OID_PKCS1_RSA_PSS_SIGNATURE: | |
208 *hashalg = SEC_OID_UNKNOWN; /* get it from the RSA signature */ | |
209 break; | |
210 | |
211 case SEC_OID_ANSIX962_ECDSA_SHA224_SIGNATURE: | |
212 case SEC_OID_PKCS1_SHA224_WITH_RSA_ENCRYPTION: | |
213 case SEC_OID_NIST_DSA_SIGNATURE_WITH_SHA224_DIGEST: | |
214 *hashalg = SEC_OID_SHA224; | |
215 break; | |
216 case SEC_OID_ANSIX962_ECDSA_SHA256_SIGNATURE: | |
217 case SEC_OID_PKCS1_SHA256_WITH_RSA_ENCRYPTION: | |
218 case SEC_OID_NIST_DSA_SIGNATURE_WITH_SHA256_DIGEST: | |
219 *hashalg = SEC_OID_SHA256; | |
220 break; | |
221 case SEC_OID_ANSIX962_ECDSA_SHA384_SIGNATURE: | |
222 case SEC_OID_PKCS1_SHA384_WITH_RSA_ENCRYPTION: | |
223 *hashalg = SEC_OID_SHA384; | |
224 break; | |
225 case SEC_OID_ANSIX962_ECDSA_SHA512_SIGNATURE: | |
226 case SEC_OID_PKCS1_SHA512_WITH_RSA_ENCRYPTION: | |
227 *hashalg = SEC_OID_SHA512; | |
228 break; | |
229 | |
230 /* what about normal DSA? */ | |
231 case SEC_OID_ANSIX9_DSA_SIGNATURE_WITH_SHA1_DIGEST: | |
232 case SEC_OID_BOGUS_DSA_SIGNATURE_WITH_SHA1_DIGEST: | |
233 case SEC_OID_ANSIX962_ECDSA_SHA1_SIGNATURE: | |
234 *hashalg = SEC_OID_SHA1; | |
235 break; | |
236 case SEC_OID_MISSI_DSS: | |
237 case SEC_OID_MISSI_KEA_DSS: | |
238 case SEC_OID_MISSI_KEA_DSS_OLD: | |
239 case SEC_OID_MISSI_DSS_OLD: | |
240 *hashalg = SEC_OID_SHA1; | |
241 break; | |
242 case SEC_OID_ANSIX962_ECDSA_SIGNATURE_RECOMMENDED_DIGEST: | |
243 /* This is an EC algorithm. Recommended means the largest | |
244 * hash algorithm that is not reduced by the keysize of | |
245 * the EC algorithm. Note that key strength is in bytes and | |
246 * algorithms are specified in bits. Never use an algorithm | |
247 * weaker than sha1. */ | |
248 len = SECKEY_PublicKeyStrength(key); | |
249 if (len < 28) { /* 28 bytes == 224 bits */ | |
250 *hashalg = SEC_OID_SHA1; | |
251 } else if (len < 32) { /* 32 bytes == 256 bits */ | |
252 *hashalg = SEC_OID_SHA224; | |
253 } else if (len < 48) { /* 48 bytes == 384 bits */ | |
254 *hashalg = SEC_OID_SHA256; | |
255 } else if (len < 64) { /* 48 bytes == 512 bits */ | |
256 *hashalg = SEC_OID_SHA384; | |
257 } else { | |
258 /* use the largest in this case */ | |
259 *hashalg = SEC_OID_SHA512; | |
260 } | |
261 break; | |
262 case SEC_OID_ANSIX962_ECDSA_SIGNATURE_SPECIFIED_DIGEST: | |
263 if (param == NULL) { | |
264 PORT_SetError(SEC_ERROR_INVALID_ALGORITHM); | |
265 return SECFailure; | |
266 } | |
267 arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); | |
268 if (arena == NULL) { | |
269 return SECFailure; | |
270 } | |
271 rv = SEC_QuickDERDecodeItem(arena, &oid, hashParameterTemplate, param); | |
272 if (rv == SECSuccess) { | |
273 *hashalg = SECOID_FindOIDTag(&oid); | |
274 } | |
275 PORT_FreeArena(arena, PR_FALSE); | |
276 if (rv != SECSuccess) { | |
277 return rv; | |
278 } | |
279 /* only accept hash algorithms */ | |
280 if (HASH_GetHashTypeByOidTag(*hashalg) == HASH_AlgNULL) { | |
281 /* error set by HASH_GetHashTypeByOidTag */ | |
282 return SECFailure; | |
283 } | |
284 break; | |
285 /* we don't implement MD4 hashes */ | |
286 case SEC_OID_PKCS1_MD4_WITH_RSA_ENCRYPTION: | |
287 default: | |
288 PORT_SetError(SEC_ERROR_INVALID_ALGORITHM); | |
289 return SECFailure; | |
290 } | |
291 /* get the "encryption" algorithm */ | |
292 switch (sigAlg) { | |
293 case SEC_OID_PKCS1_RSA_ENCRYPTION: | |
294 case SEC_OID_PKCS1_MD2_WITH_RSA_ENCRYPTION: | |
295 case SEC_OID_PKCS1_MD5_WITH_RSA_ENCRYPTION: | |
296 case SEC_OID_PKCS1_SHA1_WITH_RSA_ENCRYPTION: | |
297 case SEC_OID_ISO_SHA_WITH_RSA_SIGNATURE: | |
298 case SEC_OID_ISO_SHA1_WITH_RSA_SIGNATURE: | |
299 case SEC_OID_PKCS1_SHA224_WITH_RSA_ENCRYPTION: | |
300 case SEC_OID_PKCS1_SHA256_WITH_RSA_ENCRYPTION: | |
301 case SEC_OID_PKCS1_SHA384_WITH_RSA_ENCRYPTION: | |
302 case SEC_OID_PKCS1_SHA512_WITH_RSA_ENCRYPTION: | |
303 *encalg = SEC_OID_PKCS1_RSA_ENCRYPTION; | |
304 break; | |
305 case SEC_OID_PKCS1_RSA_PSS_SIGNATURE: | |
306 *encalg = SEC_OID_PKCS1_RSA_PSS_SIGNATURE; | |
307 break; | |
308 | |
309 /* what about normal DSA? */ | |
310 case SEC_OID_ANSIX9_DSA_SIGNATURE_WITH_SHA1_DIGEST: | |
311 case SEC_OID_BOGUS_DSA_SIGNATURE_WITH_SHA1_DIGEST: | |
312 case SEC_OID_NIST_DSA_SIGNATURE_WITH_SHA224_DIGEST: | |
313 case SEC_OID_NIST_DSA_SIGNATURE_WITH_SHA256_DIGEST: | |
314 *encalg = SEC_OID_ANSIX9_DSA_SIGNATURE; | |
315 break; | |
316 case SEC_OID_MISSI_DSS: | |
317 case SEC_OID_MISSI_KEA_DSS: | |
318 case SEC_OID_MISSI_KEA_DSS_OLD: | |
319 case SEC_OID_MISSI_DSS_OLD: | |
320 *encalg = SEC_OID_MISSI_DSS; | |
321 break; | |
322 case SEC_OID_ANSIX962_ECDSA_SHA1_SIGNATURE: | |
323 case SEC_OID_ANSIX962_ECDSA_SHA224_SIGNATURE: | |
324 case SEC_OID_ANSIX962_ECDSA_SHA256_SIGNATURE: | |
325 case SEC_OID_ANSIX962_ECDSA_SHA384_SIGNATURE: | |
326 case SEC_OID_ANSIX962_ECDSA_SHA512_SIGNATURE: | |
327 case SEC_OID_ANSIX962_ECDSA_SIGNATURE_RECOMMENDED_DIGEST: | |
328 case SEC_OID_ANSIX962_ECDSA_SIGNATURE_SPECIFIED_DIGEST: | |
329 *encalg = SEC_OID_ANSIX962_EC_PUBLIC_KEY; | |
330 break; | |
331 /* we don't implement MD4 hashes */ | |
332 case SEC_OID_PKCS1_MD4_WITH_RSA_ENCRYPTION: | |
333 default: | |
334 PORT_SetError(SEC_ERROR_INVALID_ALGORITHM); | |
335 return SECFailure; | |
336 } | |
337 return SECSuccess; | |
338 } | |
339 | |
340 /* | |
341 * we can verify signatures that come from 2 different sources: | |
342 * one in with the signature contains a signature oid, and the other | |
343 * in which the signature is managed by a Public key (encAlg) oid | |
344 * and a hash oid. The latter is the more basic, so that's what | |
345 * our base vfyCreate function takes. | |
346 * | |
347 * There is one noteworthy corner case, if we are using an RSA key, and the | |
348 * signature block is provided, then the hashAlg can be specified as | |
349 * SEC_OID_UNKNOWN. In this case, verify will use the hash oid supplied | |
350 * in the RSA signature block. | |
351 */ | |
352 static VFYContext * | |
353 vfy_CreateContext(const SECKEYPublicKey *key, const SECItem *sig, | |
354 SECOidTag encAlg, SECOidTag hashAlg, SECOidTag *hash, void *wincx) | |
355 { | |
356 VFYContext *cx; | |
357 SECStatus rv; | |
358 unsigned int sigLen; | |
359 KeyType type; | |
360 | |
361 /* make sure the encryption algorithm matches the key type */ | |
362 /* RSA-PSS algorithm can be used with both rsaKey and rsaPssKey */ | |
363 type = seckey_GetKeyType(encAlg); | |
364 if ((key->keyType != type) && | |
365 ((key->keyType != rsaKey) || (type != rsaPssKey))) { | |
366 PORT_SetError(SEC_ERROR_PKCS7_KEYALG_MISMATCH); | |
367 return NULL; | |
368 } | |
369 | |
370 cx = (VFYContext*) PORT_ZAlloc(sizeof(VFYContext)); | |
371 if (cx == NULL) { | |
372 goto loser; | |
373 } | |
374 | |
375 cx->wincx = wincx; | |
376 cx->hasSignature = (sig != NULL); | |
377 cx->encAlg = encAlg; | |
378 cx->hashAlg = hashAlg; | |
379 cx->key = SECKEY_CopyPublicKey(key); | |
380 rv = SECSuccess; | |
381 if (sig) { | |
382 switch (type) { | |
383 case rsaKey: | |
384 rv = DecryptSigBlock(&cx->hashAlg, cx->u.buffer, &cx->rsadigestlen, | |
385 HASH_LENGTH_MAX, cx->key, sig, (char*)wincx); | |
386 if (cx->hashAlg != hashAlg && hashAlg != SEC_OID_UNKNOWN) { | |
387 PORT_SetError(SEC_ERROR_BAD_SIGNATURE); | |
388 rv = SECFailure; | |
389 } | |
390 break; | |
391 case dsaKey: | |
392 case ecKey: | |
393 sigLen = SECKEY_SignatureLen(key); | |
394 if (sigLen == 0) { | |
395 /* error set by SECKEY_SignatureLen */ | |
396 rv = SECFailure; | |
397 break; | |
398 } | |
399 rv = decodeECorDSASignature(encAlg, sig, cx->u.buffer, sigLen); | |
400 break; | |
401 default: | |
402 rv = SECFailure; | |
403 PORT_SetError(SEC_ERROR_UNSUPPORTED_KEYALG); | |
404 break; | |
405 } | |
406 } | |
407 | |
408 if (rv) goto loser; | |
409 | |
410 /* check hash alg again, RSA may have changed it.*/ | |
411 if (HASH_GetHashTypeByOidTag(cx->hashAlg) == HASH_AlgNULL) { | |
412 /* error set by HASH_GetHashTypeByOidTag */ | |
413 goto loser; | |
414 } | |
415 | |
416 if (hash) { | |
417 *hash = cx->hashAlg; | |
418 } | |
419 return cx; | |
420 | |
421 loser: | |
422 if (cx) { | |
423 VFY_DestroyContext(cx, PR_TRUE); | |
424 } | |
425 return 0; | |
426 } | |
427 | |
428 VFYContext * | |
429 VFY_CreateContext(SECKEYPublicKey *key, SECItem *sig, SECOidTag sigAlg, | |
430 void *wincx) | |
431 { | |
432 SECOidTag encAlg, hashAlg; | |
433 SECStatus rv = sec_DecodeSigAlg(key, sigAlg, NULL, &encAlg, &hashAlg); | |
434 if (rv != SECSuccess) { | |
435 return NULL; | |
436 } | |
437 return vfy_CreateContext(key, sig, encAlg, hashAlg, NULL, wincx); | |
438 } | |
439 | |
440 VFYContext * | |
441 VFY_CreateContextDirect(const SECKEYPublicKey *key, const SECItem *sig, | |
442 SECOidTag encAlg, SECOidTag hashAlg, | |
443 SECOidTag *hash, void *wincx) | |
444 { | |
445 return vfy_CreateContext(key, sig, encAlg, hashAlg, hash, wincx); | |
446 } | |
447 | |
448 VFYContext * | |
449 VFY_CreateContextWithAlgorithmID(const SECKEYPublicKey *key, const SECItem *sig, | |
450 const SECAlgorithmID *sigAlgorithm, SECOidTag *hash, void *wincx) | |
451 { | |
452 SECOidTag encAlg, hashAlg; | |
453 SECStatus rv = sec_DecodeSigAlg(key, | |
454 SECOID_GetAlgorithmTag((SECAlgorithmID *)sigAlgorithm), | |
455 &sigAlgorithm->parameters, &encAlg, &hashAlg); | |
456 if (rv != SECSuccess) { | |
457 return NULL; | |
458 } | |
459 return vfy_CreateContext(key, sig, encAlg, hashAlg, hash, wincx); | |
460 } | |
461 | |
462 void | |
463 VFY_DestroyContext(VFYContext *cx, PRBool freeit) | |
464 { | |
465 if (cx) { | |
466 if (cx->hashcx != NULL) { | |
467 (*cx->hashobj->destroy)(cx->hashcx, PR_TRUE); | |
468 cx->hashcx = NULL; | |
469 } | |
470 if (cx->key) { | |
471 SECKEY_DestroyPublicKey(cx->key); | |
472 } | |
473 if (freeit) { | |
474 PORT_ZFree(cx, sizeof(VFYContext)); | |
475 } | |
476 } | |
477 } | |
478 | |
479 SECStatus | |
480 VFY_Begin(VFYContext *cx) | |
481 { | |
482 if (cx->hashcx != NULL) { | |
483 (*cx->hashobj->destroy)(cx->hashcx, PR_TRUE); | |
484 cx->hashcx = NULL; | |
485 } | |
486 | |
487 cx->hashobj = HASH_GetHashObjectByOidTag(cx->hashAlg); | |
488 if (!cx->hashobj) | |
489 return SECFailure; /* error code is set */ | |
490 | |
491 cx->hashcx = (*cx->hashobj->create)(); | |
492 if (cx->hashcx == NULL) | |
493 return SECFailure; | |
494 | |
495 (*cx->hashobj->begin)(cx->hashcx); | |
496 return SECSuccess; | |
497 } | |
498 | |
499 SECStatus | |
500 VFY_Update(VFYContext *cx, const unsigned char *input, unsigned inputLen) | |
501 { | |
502 if (cx->hashcx == NULL) { | |
503 PORT_SetError(SEC_ERROR_INVALID_ARGS); | |
504 return SECFailure; | |
505 } | |
506 (*cx->hashobj->update)(cx->hashcx, input, inputLen); | |
507 return SECSuccess; | |
508 } | |
509 | |
510 SECStatus | |
511 VFY_EndWithSignature(VFYContext *cx, SECItem *sig) | |
512 { | |
513 unsigned char final[HASH_LENGTH_MAX]; | |
514 unsigned part; | |
515 SECItem hash,dsasig; /* dsasig is also used for ECDSA */ | |
516 SECStatus rv; | |
517 | |
518 if ((cx->hasSignature == PR_FALSE) && (sig == NULL)) { | |
519 PORT_SetError(SEC_ERROR_INVALID_ARGS); | |
520 return SECFailure; | |
521 } | |
522 | |
523 if (cx->hashcx == NULL) { | |
524 PORT_SetError(SEC_ERROR_INVALID_ARGS); | |
525 return SECFailure; | |
526 } | |
527 (*cx->hashobj->end)(cx->hashcx, final, &part, sizeof(final)); | |
528 switch (cx->key->keyType) { | |
529 case ecKey: | |
530 case dsaKey: | |
531 dsasig.data = cx->u.buffer; | |
532 dsasig.len = SECKEY_SignatureLen(cx->key); | |
533 if (dsasig.len == 0) { | |
534 return SECFailure; | |
535 } | |
536 if (sig) { | |
537 rv = decodeECorDSASignature(cx->encAlg, sig, dsasig.data, | |
538 dsasig.len); | |
539 if (rv != SECSuccess) { | |
540 PORT_SetError(SEC_ERROR_BAD_SIGNATURE); | |
541 return SECFailure; | |
542 } | |
543 } | |
544 hash.data = final; | |
545 hash.len = part; | |
546 if (PK11_Verify(cx->key,&dsasig,&hash,cx->wincx) != SECSuccess) { | |
547 PORT_SetError(SEC_ERROR_BAD_SIGNATURE); | |
548 return SECFailure; | |
549 } | |
550 break; | |
551 case rsaKey: | |
552 if (sig) { | |
553 SECOidTag hashid = SEC_OID_UNKNOWN; | |
554 rv = DecryptSigBlock(&hashid, cx->u.buffer, &cx->rsadigestlen, | |
555 HASH_LENGTH_MAX, cx->key, sig, (char*)cx->wincx); | |
556 if ((rv != SECSuccess) || (hashid != cx->hashAlg)) { | |
557 PORT_SetError(SEC_ERROR_BAD_SIGNATURE); | |
558 return SECFailure; | |
559 } | |
560 } | |
561 if ((part != cx->rsadigestlen) || | |
562 PORT_Memcmp(final, cx->u.buffer, part)) { | |
563 PORT_SetError(SEC_ERROR_BAD_SIGNATURE); | |
564 return SECFailure; | |
565 } | |
566 break; | |
567 default: | |
568 PORT_SetError(SEC_ERROR_BAD_SIGNATURE); | |
569 return SECFailure; /* shouldn't happen */ | |
570 } | |
571 return SECSuccess; | |
572 } | |
573 | |
574 SECStatus | |
575 VFY_End(VFYContext *cx) | |
576 { | |
577 return VFY_EndWithSignature(cx,NULL); | |
578 } | |
579 | |
580 /************************************************************************/ | |
581 /* | |
582 * Verify that a previously-computed digest matches a signature. | |
583 */ | |
584 static SECStatus | |
585 vfy_VerifyDigest(const SECItem *digest, const SECKEYPublicKey *key, | |
586 const SECItem *sig, SECOidTag encAlg, SECOidTag hashAlg, | |
587 void *wincx) | |
588 { | |
589 SECStatus rv; | |
590 VFYContext *cx; | |
591 SECItem dsasig; /* also used for ECDSA */ | |
592 | |
593 rv = SECFailure; | |
594 | |
595 cx = vfy_CreateContext(key, sig, encAlg, hashAlg, NULL, wincx); | |
596 if (cx != NULL) { | |
597 switch (key->keyType) { | |
598 case rsaKey: | |
599 if ((digest->len != cx->rsadigestlen) || | |
600 PORT_Memcmp(digest->data, cx->u.buffer, digest->len)) { | |
601 PORT_SetError(SEC_ERROR_BAD_SIGNATURE); | |
602 } else { | |
603 rv = SECSuccess; | |
604 } | |
605 break; | |
606 case dsaKey: | |
607 case ecKey: | |
608 dsasig.data = cx->u.buffer; | |
609 dsasig.len = SECKEY_SignatureLen(cx->key); | |
610 if (dsasig.len == 0) { | |
611 break; | |
612 } | |
613 if (PK11_Verify(cx->key, &dsasig, (SECItem *)digest, cx->wincx) | |
614 != SECSuccess) { | |
615 PORT_SetError(SEC_ERROR_BAD_SIGNATURE); | |
616 } else { | |
617 rv = SECSuccess; | |
618 } | |
619 break; | |
620 default: | |
621 break; | |
622 } | |
623 VFY_DestroyContext(cx, PR_TRUE); | |
624 } | |
625 return rv; | |
626 } | |
627 | |
628 SECStatus | |
629 VFY_VerifyDigestDirect(const SECItem *digest, const SECKEYPublicKey *key, | |
630 const SECItem *sig, SECOidTag encAlg, | |
631 SECOidTag hashAlg, void *wincx) | |
632 { | |
633 return vfy_VerifyDigest(digest, key, sig, encAlg, hashAlg, wincx); | |
634 } | |
635 | |
636 SECStatus | |
637 VFY_VerifyDigest(SECItem *digest, SECKEYPublicKey *key, SECItem *sig, | |
638 SECOidTag algid, void *wincx) | |
639 { | |
640 SECOidTag encAlg, hashAlg; | |
641 SECStatus rv = sec_DecodeSigAlg(key, algid, NULL, &encAlg, &hashAlg); | |
642 if (rv != SECSuccess) { | |
643 return SECFailure; | |
644 } | |
645 return vfy_VerifyDigest(digest, key, sig, encAlg, hashAlg, wincx); | |
646 } | |
647 | |
648 /* | |
649 * this function takes an optional hash oid, which the digest function | |
650 * will be compared with our target hash value. | |
651 */ | |
652 SECStatus | |
653 VFY_VerifyDigestWithAlgorithmID(const SECItem *digest, | |
654 const SECKEYPublicKey *key, const SECItem *sig, | |
655 const SECAlgorithmID *sigAlgorithm, | |
656 SECOidTag hashCmp, void *wincx) | |
657 { | |
658 SECOidTag encAlg, hashAlg; | |
659 SECStatus rv = sec_DecodeSigAlg(key, | |
660 SECOID_GetAlgorithmTag((SECAlgorithmID *)sigAlgorithm), | |
661 &sigAlgorithm->parameters, &encAlg, &hashAlg); | |
662 if (rv != SECSuccess) { | |
663 return rv; | |
664 } | |
665 if ( hashCmp != SEC_OID_UNKNOWN && | |
666 hashAlg != SEC_OID_UNKNOWN && | |
667 hashCmp != hashAlg) { | |
668 PORT_SetError(SEC_ERROR_BAD_SIGNATURE); | |
669 return SECFailure; | |
670 } | |
671 return vfy_VerifyDigest(digest, key, sig, encAlg, hashAlg, wincx); | |
672 } | |
673 | |
674 static SECStatus | |
675 vfy_VerifyData(const unsigned char *buf, int len, const SECKEYPublicKey *key, | |
676 const SECItem *sig, SECOidTag encAlg, SECOidTag hashAlg, | |
677 SECOidTag *hash, void *wincx) | |
678 { | |
679 SECStatus rv; | |
680 VFYContext *cx; | |
681 | |
682 cx = vfy_CreateContext(key, sig, encAlg, hashAlg, hash, wincx); | |
683 if (cx == NULL) | |
684 return SECFailure; | |
685 | |
686 rv = VFY_Begin(cx); | |
687 if (rv == SECSuccess) { | |
688 rv = VFY_Update(cx, (unsigned char *)buf, len); | |
689 if (rv == SECSuccess) | |
690 rv = VFY_End(cx); | |
691 } | |
692 | |
693 VFY_DestroyContext(cx, PR_TRUE); | |
694 return rv; | |
695 } | |
696 | |
697 SECStatus | |
698 VFY_VerifyDataDirect(const unsigned char *buf, int len, | |
699 const SECKEYPublicKey *key, const SECItem *sig, | |
700 SECOidTag encAlg, SECOidTag hashAlg, | |
701 SECOidTag *hash, void *wincx) | |
702 { | |
703 return vfy_VerifyData(buf, len, key, sig, encAlg, hashAlg, hash, wincx); | |
704 } | |
705 | |
706 SECStatus | |
707 VFY_VerifyData(const unsigned char *buf, int len, const SECKEYPublicKey *key, | |
708 const SECItem *sig, SECOidTag algid, void *wincx) | |
709 { | |
710 SECOidTag encAlg, hashAlg; | |
711 SECStatus rv = sec_DecodeSigAlg(key, algid, NULL, &encAlg, &hashAlg); | |
712 if (rv != SECSuccess) { | |
713 return rv; | |
714 } | |
715 return vfy_VerifyData(buf, len, key, sig, encAlg, hashAlg, NULL, wincx); | |
716 } | |
717 | |
718 SECStatus | |
719 VFY_VerifyDataWithAlgorithmID(const unsigned char *buf, int len, | |
720 const SECKEYPublicKey *key, | |
721 const SECItem *sig, | |
722 const SECAlgorithmID *sigAlgorithm, | |
723 SECOidTag *hash, void *wincx) | |
724 { | |
725 SECOidTag encAlg, hashAlg; | |
726 SECOidTag sigAlg = SECOID_GetAlgorithmTag((SECAlgorithmID *)sigAlgorithm); | |
727 SECStatus rv = sec_DecodeSigAlg(key, sigAlg, | |
728 &sigAlgorithm->parameters, &encAlg, &hashAlg); | |
729 if (rv != SECSuccess) { | |
730 return rv; | |
731 } | |
732 return vfy_VerifyData(buf, len, key, sig, encAlg, hashAlg, hash, wincx); | |
733 } | |
OLD | NEW |