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