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