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