Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(327)

Side by Side Diff: nss/lib/pkcs7/p7decode.c

Issue 2078763002: Delete bundled copy of NSS and replace with README. (Closed) Base URL: https://chromium.googlesource.com/chromium/deps/nss@master
Patch Set: Delete bundled copy of NSS and replace with README. Created 4 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « nss/lib/pkcs7/p7create.c ('k') | nss/lib/pkcs7/p7encode.c » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 /* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4
5 /*
6 * PKCS7 decoding, verification.
7 */
8
9 #include "p7local.h"
10
11 #include "cert.h"
12 /* XXX do not want to have to include */
13 #include "certdb.h" /* certdb.h -- the trust stuff needed by */
14 /* the add certificate code needs to get */
15 /* rewritten/abstracted and then this */
16 /* include should be removed! */
17 /*#include "cdbhdl.h" */
18 #include "cryptohi.h"
19 #include "key.h"
20 #include "secasn1.h"
21 #include "secitem.h"
22 #include "secoid.h"
23 #include "pk11func.h"
24 #include "prtime.h"
25 #include "secerr.h"
26 #include "sechash.h" /* for HASH_GetHashObject() */
27 #include "secder.h"
28 #include "secpkcs5.h"
29
30 struct sec_pkcs7_decoder_worker {
31 int depth;
32 int digcnt;
33 void **digcxs;
34 const SECHashObject **digobjs;
35 sec_PKCS7CipherObject *decryptobj;
36 PRBool saw_contents;
37 };
38
39 struct SEC_PKCS7DecoderContextStr {
40 SEC_ASN1DecoderContext *dcx;
41 SEC_PKCS7ContentInfo *cinfo;
42 SEC_PKCS7DecoderContentCallback cb;
43 void *cb_arg;
44 SECKEYGetPasswordKey pwfn;
45 void *pwfn_arg;
46 struct sec_pkcs7_decoder_worker worker;
47 PLArenaPool *tmp_poolp;
48 int error;
49 SEC_PKCS7GetDecryptKeyCallback dkcb;
50 void *dkcb_arg;
51 SEC_PKCS7DecryptionAllowedCallback decrypt_allowed_cb;
52 };
53
54 /*
55 * Handle one worker, decrypting and digesting the data as necessary.
56 *
57 * XXX If/when we support nested contents, this probably needs to be
58 * revised somewhat to get passed the content-info (which unfortunately
59 * can be two different types depending on whether it is encrypted or not)
60 * corresponding to the given worker.
61 */
62 static void
63 sec_pkcs7_decoder_work_data (SEC_PKCS7DecoderContext *p7dcx,
64 struct sec_pkcs7_decoder_worker *worker,
65 const unsigned char *data, unsigned long len,
66 PRBool final)
67 {
68 unsigned char *buf = NULL;
69 SECStatus rv;
70 int i;
71
72 /*
73 * We should really have data to process, or we should be trying
74 * to finish/flush the last block. (This is an overly paranoid
75 * check since all callers are in this file and simple inspection
76 * proves they do it right. But it could find a bug in future
77 * modifications/development, that is why it is here.)
78 */
79 PORT_Assert ((data != NULL && len) || final);
80
81 /*
82 * Decrypt this chunk.
83 *
84 * XXX If we get an error, we do not want to do the digest or callback,
85 * but we want to keep decoding. Or maybe we want to stop decoding
86 * altogether if there is a callback, because obviously we are not
87 * sending the data back and they want to know that.
88 */
89 if (worker->decryptobj != NULL) {
90 /* XXX the following lengths should all be longs? */
91 unsigned int inlen; /* length of data being decrypted */
92 unsigned int outlen; /* length of decrypted data */
93 unsigned int buflen; /* length available for decrypted data */
94 SECItem *plain;
95
96 inlen = len;
97 buflen = sec_PKCS7DecryptLength (worker->decryptobj, inlen, final);
98 if (buflen == 0) {
99 if (inlen == 0) /* no input and no output */
100 return;
101 /*
102 * No output is expected, but the input data may be buffered
103 * so we still have to call Decrypt.
104 */
105 rv = sec_PKCS7Decrypt (worker->decryptobj, NULL, NULL, 0,
106 data, inlen, final);
107 if (rv != SECSuccess) {
108 p7dcx->error = PORT_GetError();
109 return; /* XXX indicate error? */
110 }
111 return;
112 }
113
114 if (p7dcx->cb != NULL) {
115 buf = (unsigned char *) PORT_Alloc (buflen);
116 plain = NULL;
117 } else {
118 unsigned long oldlen;
119
120 /*
121 * XXX This assumes one level of content only.
122 * See comment above about nested content types.
123 * XXX Also, it should work for signedAndEnvelopedData, too!
124 */
125 plain = &(p7dcx->cinfo->
126 content.envelopedData->encContentInfo.plainContent);
127
128 oldlen = plain->len;
129 if (oldlen == 0) {
130 buf = (unsigned char*)PORT_ArenaAlloc (p7dcx->cinfo->poolp,
131 buflen);
132 } else {
133 buf = (unsigned char*)PORT_ArenaGrow (p7dcx->cinfo->poolp,
134 plain->data,
135 oldlen, oldlen + buflen);
136 if (buf != NULL)
137 buf += oldlen;
138 }
139 plain->data = buf;
140 }
141 if (buf == NULL) {
142 p7dcx->error = SEC_ERROR_NO_MEMORY;
143 return; /* XXX indicate error? */
144 }
145 rv = sec_PKCS7Decrypt (worker->decryptobj, buf, &outlen, buflen,
146 data, inlen, final);
147 if (rv != SECSuccess) {
148 p7dcx->error = PORT_GetError();
149 return; /* XXX indicate error? */
150 }
151 if (plain != NULL) {
152 PORT_Assert (final || outlen == buflen);
153 plain->len += outlen;
154 }
155 data = buf;
156 len = outlen;
157 }
158
159 /*
160 * Update the running digests.
161 */
162 if (len) {
163 for (i = 0; i < worker->digcnt; i++) {
164 (* worker->digobjs[i]->update) (worker->digcxs[i], data, len);
165 }
166 }
167
168 /*
169 * Pass back the contents bytes, and free the temporary buffer.
170 */
171 if (p7dcx->cb != NULL) {
172 if (len)
173 (* p7dcx->cb) (p7dcx->cb_arg, (const char *)data, len);
174 if (worker->decryptobj != NULL) {
175 PORT_Assert (buf != NULL);
176 PORT_Free (buf);
177 }
178 }
179 }
180
181 static void
182 sec_pkcs7_decoder_filter (void *arg, const char *data, unsigned long len,
183 int depth, SEC_ASN1EncodingPart data_kind)
184 {
185 SEC_PKCS7DecoderContext *p7dcx;
186 struct sec_pkcs7_decoder_worker *worker;
187
188 /*
189 * Since we do not handle any nested contents, the only bytes we
190 * are really interested in are the actual contents bytes (not
191 * the identifier, length, or end-of-contents bytes). If we were
192 * handling nested types we would probably need to do something
193 * smarter based on depth and data_kind.
194 */
195 if (data_kind != SEC_ASN1_Contents)
196 return;
197
198 /*
199 * The ASN.1 decoder should not even call us with a length of 0.
200 * Just being paranoid.
201 */
202 PORT_Assert (len);
203 if (len == 0)
204 return;
205
206 p7dcx = (SEC_PKCS7DecoderContext*)arg;
207
208 /*
209 * Handling nested contents would mean that there is a chain
210 * of workers -- one per each level of content. The following
211 * would start with the first worker and loop over them.
212 */
213 worker = &(p7dcx->worker);
214
215 worker->saw_contents = PR_TRUE;
216
217 sec_pkcs7_decoder_work_data (p7dcx, worker,
218 (const unsigned char *) data, len, PR_FALSE);
219 }
220
221
222 /*
223 * Create digest contexts for each algorithm in "digestalgs".
224 * No algorithms is not an error, we just do not do anything.
225 * An error (like trouble allocating memory), marks the error
226 * in "p7dcx" and returns SECFailure, which means that our caller
227 * should just give up altogether.
228 */
229 static SECStatus
230 sec_pkcs7_decoder_start_digests (SEC_PKCS7DecoderContext *p7dcx, int depth,
231 SECAlgorithmID **digestalgs)
232 {
233 int i, digcnt;
234
235 if (digestalgs == NULL)
236 return SECSuccess;
237
238 /*
239 * Count the algorithms.
240 */
241 digcnt = 0;
242 while (digestalgs[digcnt] != NULL)
243 digcnt++;
244
245 /*
246 * No algorithms means no work to do.
247 * Just act as if there were no algorithms specified.
248 */
249 if (digcnt == 0)
250 return SECSuccess;
251
252 p7dcx->worker.digcxs = (void**)PORT_ArenaAlloc (p7dcx->tmp_poolp,
253 digcnt * sizeof (void *));
254 p7dcx->worker.digobjs = (const SECHashObject**)PORT_ArenaAlloc (p7dcx->tmp_p oolp,
255 digcnt * sizeof (SECHashObject *));
256 if (p7dcx->worker.digcxs == NULL || p7dcx->worker.digobjs == NULL) {
257 p7dcx->error = SEC_ERROR_NO_MEMORY;
258 return SECFailure;
259 }
260
261 p7dcx->worker.depth = depth;
262 p7dcx->worker.digcnt = 0;
263
264 /*
265 * Create a digest context for each algorithm.
266 */
267 for (i = 0; i < digcnt; i++) {
268 SECAlgorithmID * algid = digestalgs[i];
269 SECOidTag oidTag = SECOID_FindOIDTag(&(algid->algorithm));
270 const SECHashObject *digobj = HASH_GetHashObjectByOidTag(oidTag);
271 void *digcx;
272
273 /*
274 * Skip any algorithm we do not even recognize; obviously,
275 * this could be a problem, but if it is critical then the
276 * result will just be that the signature does not verify.
277 * We do not necessarily want to error out here, because
278 * the particular algorithm may not actually be important,
279 * but we cannot know that until later.
280 */
281 if (digobj == NULL) {
282 p7dcx->worker.digcnt--;
283 continue;
284 }
285
286 digcx = (* digobj->create)();
287 if (digcx != NULL) {
288 (* digobj->begin) (digcx);
289 p7dcx->worker.digobjs[p7dcx->worker.digcnt] = digobj;
290 p7dcx->worker.digcxs[p7dcx->worker.digcnt] = digcx;
291 p7dcx->worker.digcnt++;
292 }
293 }
294
295 if (p7dcx->worker.digcnt != 0)
296 SEC_ASN1DecoderSetFilterProc (p7dcx->dcx,
297 sec_pkcs7_decoder_filter,
298 p7dcx,
299 (PRBool)(p7dcx->cb != NULL));
300 return SECSuccess;
301 }
302
303
304 /*
305 * Close out all of the digest contexts, storing the results in "digestsp".
306 */
307 static SECStatus
308 sec_pkcs7_decoder_finish_digests (SEC_PKCS7DecoderContext *p7dcx,
309 PLArenaPool *poolp,
310 SECItem ***digestsp)
311 {
312 struct sec_pkcs7_decoder_worker *worker;
313 const SECHashObject *digobj;
314 void *digcx;
315 SECItem **digests, *digest;
316 int i;
317 void *mark;
318
319 /*
320 * XXX Handling nested contents would mean that there is a chain
321 * of workers -- one per each level of content. The following
322 * would want to find the last worker in the chain.
323 */
324 worker = &(p7dcx->worker);
325
326 /*
327 * If no digests, then we have nothing to do.
328 */
329 if (worker->digcnt == 0)
330 return SECSuccess;
331
332 /*
333 * No matter what happens after this, we want to stop filtering.
334 * XXX If we handle nested contents, we only want to stop filtering
335 * if we are finishing off the *last* worker.
336 */
337 SEC_ASN1DecoderClearFilterProc (p7dcx->dcx);
338
339 /*
340 * If we ended up with no contents, just destroy each
341 * digest context -- they are meaningless and potentially
342 * confusing, because their presence would imply some content
343 * was digested.
344 */
345 if (! worker->saw_contents) {
346 for (i = 0; i < worker->digcnt; i++) {
347 digcx = worker->digcxs[i];
348 digobj = worker->digobjs[i];
349 (* digobj->destroy) (digcx, PR_TRUE);
350 }
351 return SECSuccess;
352 }
353
354 mark = PORT_ArenaMark (poolp);
355
356 /*
357 * Close out each digest context, saving digest away.
358 */
359 digests =
360 (SECItem**)PORT_ArenaAlloc (poolp,(worker->digcnt+1)*sizeof(SECItem *));
361 digest = (SECItem*)PORT_ArenaAlloc (poolp, worker->digcnt*sizeof(SECItem));
362 if (digests == NULL || digest == NULL) {
363 p7dcx->error = PORT_GetError();
364 PORT_ArenaRelease (poolp, mark);
365 return SECFailure;
366 }
367
368 for (i = 0; i < worker->digcnt; i++, digest++) {
369 digcx = worker->digcxs[i];
370 digobj = worker->digobjs[i];
371
372 digest->data = (unsigned char*)PORT_ArenaAlloc (poolp, digobj->length);
373 if (digest->data == NULL) {
374 p7dcx->error = PORT_GetError();
375 PORT_ArenaRelease (poolp, mark);
376 return SECFailure;
377 }
378
379 digest->len = digobj->length;
380 (* digobj->end) (digcx, digest->data, &(digest->len), digest->len);
381 (* digobj->destroy) (digcx, PR_TRUE);
382
383 digests[i] = digest;
384 }
385 digests[i] = NULL;
386 *digestsp = digests;
387
388 PORT_ArenaUnmark (poolp, mark);
389 return SECSuccess;
390 }
391
392 /*
393 * XXX Need comment explaining following helper function (which is used
394 * by sec_pkcs7_decoder_start_decrypt).
395 */
396
397 static PK11SymKey *
398 sec_pkcs7_decoder_get_recipient_key (SEC_PKCS7DecoderContext *p7dcx,
399 SEC_PKCS7RecipientInfo **recipientinfos,
400 SEC_PKCS7EncryptedContentInfo *enccinfo)
401 {
402 SEC_PKCS7RecipientInfo *ri;
403 CERTCertificate *cert = NULL;
404 SECKEYPrivateKey *privkey = NULL;
405 PK11SymKey *bulkkey = NULL;
406 SECOidTag keyalgtag, bulkalgtag, encalgtag;
407 PK11SlotInfo *slot = NULL;
408
409 if (recipientinfos == NULL || recipientinfos[0] == NULL) {
410 p7dcx->error = SEC_ERROR_NOT_A_RECIPIENT;
411 goto no_key_found;
412 }
413
414 cert = PK11_FindCertAndKeyByRecipientList(&slot,recipientinfos,&ri,
415 &privkey, p7dcx->pwfn_arg);
416 if (cert == NULL) {
417 p7dcx->error = SEC_ERROR_NOT_A_RECIPIENT;
418 goto no_key_found;
419 }
420
421 ri->cert = cert; /* so we can find it later */
422 PORT_Assert(privkey != NULL);
423
424 keyalgtag = SECOID_GetAlgorithmTag(&(cert->subjectPublicKeyInfo.algorithm));
425 encalgtag = SECOID_GetAlgorithmTag (&(ri->keyEncAlg));
426 if (keyalgtag != encalgtag) {
427 p7dcx->error = SEC_ERROR_PKCS7_KEYALG_MISMATCH;
428 goto no_key_found;
429 }
430 bulkalgtag = SECOID_GetAlgorithmTag (&(enccinfo->contentEncAlg));
431
432 switch (encalgtag) {
433 case SEC_OID_PKCS1_RSA_ENCRYPTION:
434 bulkkey = PK11_PubUnwrapSymKey (privkey, &ri->encKey,
435 PK11_AlgtagToMechanism (bulkalgtag),
436 CKA_DECRYPT, 0);
437 if (bulkkey == NULL) {
438 p7dcx->error = PORT_GetError();
439 PORT_SetError(0);
440 goto no_key_found;
441 }
442 break;
443 default:
444 p7dcx->error = SEC_ERROR_UNSUPPORTED_KEYALG;
445 break;
446 }
447
448 no_key_found:
449 if (privkey != NULL)
450 SECKEY_DestroyPrivateKey (privkey);
451 if (slot != NULL)
452 PK11_FreeSlot(slot);
453
454 return bulkkey;
455 }
456
457 /*
458 * XXX The following comment is old -- the function used to only handle
459 * EnvelopedData or SignedAndEnvelopedData but now handles EncryptedData
460 * as well (and it had all of the code of the helper function above
461 * built into it), though the comment was left as is. Fix it...
462 *
463 * We are just about to decode the content of an EnvelopedData.
464 * Set up a decryption context so we can decrypt as we go.
465 * Presumably we are one of the recipients listed in "recipientinfos".
466 * (XXX And if we are not, or if we have trouble, what should we do?
467 * It would be nice to let the decoding still work. Maybe it should
468 * be an error if there is a content callback, but not an error otherwise?)
469 * The encryption key and related information can be found in "enccinfo".
470 */
471 static SECStatus
472 sec_pkcs7_decoder_start_decrypt (SEC_PKCS7DecoderContext *p7dcx, int depth,
473 SEC_PKCS7RecipientInfo **recipientinfos,
474 SEC_PKCS7EncryptedContentInfo *enccinfo,
475 PK11SymKey **copy_key_for_signature)
476 {
477 PK11SymKey *bulkkey = NULL;
478 sec_PKCS7CipherObject *decryptobj;
479
480 /*
481 * If a callback is supplied to retrieve the encryption key,
482 * for instance, for Encrypted Content infos, then retrieve
483 * the bulkkey from the callback. Otherwise, assume that
484 * we are processing Enveloped or SignedAndEnveloped data
485 * content infos.
486 *
487 * XXX Put an assert here?
488 */
489 if (SEC_PKCS7ContentType(p7dcx->cinfo) == SEC_OID_PKCS7_ENCRYPTED_DATA) {
490 if (p7dcx->dkcb != NULL) {
491 bulkkey = (*p7dcx->dkcb)(p7dcx->dkcb_arg,
492 &(enccinfo->contentEncAlg));
493 }
494 enccinfo->keysize = 0;
495 } else {
496 bulkkey = sec_pkcs7_decoder_get_recipient_key (p7dcx, recipientinfos,
497 enccinfo);
498 if (bulkkey == NULL) goto no_decryption;
499 enccinfo->keysize = PK11_GetKeyStrength(bulkkey,
500 &(enccinfo->contentEncAlg));
501
502 }
503
504 /*
505 * XXX I think following should set error in p7dcx and clear set error
506 * (as used to be done here, or as is done in get_receipient_key above.
507 */
508 if(bulkkey == NULL) {
509 goto no_decryption;
510 }
511
512 /*
513 * We want to make sure decryption is allowed. This is done via
514 * a callback specified in SEC_PKCS7DecoderStart().
515 */
516 if (p7dcx->decrypt_allowed_cb) {
517 if ((*p7dcx->decrypt_allowed_cb) (&(enccinfo->contentEncAlg),
518 bulkkey) == PR_FALSE) {
519 p7dcx->error = SEC_ERROR_DECRYPTION_DISALLOWED;
520 goto no_decryption;
521 }
522 } else {
523 p7dcx->error = SEC_ERROR_DECRYPTION_DISALLOWED;
524 goto no_decryption;
525 }
526
527 /*
528 * When decrypting a signedAndEnvelopedData, the signature also has
529 * to be decrypted with the bulk encryption key; to avoid having to
530 * get it all over again later (and do another potentially expensive
531 * RSA operation), copy it for later signature verification to use.
532 */
533 if (copy_key_for_signature != NULL)
534 *copy_key_for_signature = PK11_ReferenceSymKey (bulkkey);
535
536 /*
537 * Now we have the bulk encryption key (in bulkkey) and the
538 * the algorithm (in enccinfo->contentEncAlg). Using those,
539 * create a decryption context.
540 */
541 decryptobj = sec_PKCS7CreateDecryptObject (bulkkey,
542 &(enccinfo->contentEncAlg));
543
544 /*
545 * We are done with (this) bulkkey now.
546 */
547 PK11_FreeSymKey (bulkkey);
548
549 if (decryptobj == NULL) {
550 p7dcx->error = PORT_GetError();
551 PORT_SetError(0);
552 goto no_decryption;
553 }
554
555 SEC_ASN1DecoderSetFilterProc (p7dcx->dcx,
556 sec_pkcs7_decoder_filter,
557 p7dcx,
558 (PRBool)(p7dcx->cb != NULL));
559
560 p7dcx->worker.depth = depth;
561 p7dcx->worker.decryptobj = decryptobj;
562
563 return SECSuccess;
564
565 no_decryption:
566 /*
567 * For some reason (error set already, if appropriate), we cannot
568 * decrypt the content. I am not sure what exactly is the right
569 * thing to do here; in some cases we want to just stop, and in
570 * others we want to let the decoding finish even though we cannot
571 * decrypt the content. My current thinking is that if the caller
572 * set up a content callback, then they are really interested in
573 * getting (decrypted) content, and if they cannot they will want
574 * to know about it. However, if no callback was specified, then
575 * maybe it is not important that the decryption failed.
576 */
577 if (p7dcx->cb != NULL)
578 return SECFailure;
579 else
580 return SECSuccess; /* Let the decoding continue. */
581 }
582
583
584 static SECStatus
585 sec_pkcs7_decoder_finish_decrypt (SEC_PKCS7DecoderContext *p7dcx,
586 PLArenaPool *poolp,
587 SEC_PKCS7EncryptedContentInfo *enccinfo)
588 {
589 struct sec_pkcs7_decoder_worker *worker;
590
591 /*
592 * XXX Handling nested contents would mean that there is a chain
593 * of workers -- one per each level of content. The following
594 * would want to find the last worker in the chain.
595 */
596 worker = &(p7dcx->worker);
597
598 /*
599 * If no decryption context, then we have nothing to do.
600 */
601 if (worker->decryptobj == NULL)
602 return SECSuccess;
603
604 /*
605 * No matter what happens after this, we want to stop filtering.
606 * XXX If we handle nested contents, we only want to stop filtering
607 * if we are finishing off the *last* worker.
608 */
609 SEC_ASN1DecoderClearFilterProc (p7dcx->dcx);
610
611 /*
612 * Handle the last block.
613 */
614 sec_pkcs7_decoder_work_data (p7dcx, worker, NULL, 0, PR_TRUE);
615
616 /*
617 * All done, destroy it.
618 */
619 sec_PKCS7DestroyDecryptObject (worker->decryptobj);
620 worker->decryptobj = NULL;
621
622 return SECSuccess;
623 }
624
625
626 static void
627 sec_pkcs7_decoder_notify (void *arg, PRBool before, void *dest, int depth)
628 {
629 SEC_PKCS7DecoderContext *p7dcx;
630 SEC_PKCS7ContentInfo *cinfo;
631 SEC_PKCS7SignedData *sigd;
632 SEC_PKCS7EnvelopedData *envd;
633 SEC_PKCS7SignedAndEnvelopedData *saed;
634 SEC_PKCS7EncryptedData *encd;
635 SEC_PKCS7DigestedData *digd;
636 PRBool after;
637 SECStatus rv;
638
639 /*
640 * Just to make the code easier to read, create an "after" variable
641 * that is equivalent to "not before".
642 * (This used to be just the statement "after = !before", but that
643 * causes a warning on the mac; to avoid that, we do it the long way.)
644 */
645 if (before)
646 after = PR_FALSE;
647 else
648 after = PR_TRUE;
649
650 p7dcx = (SEC_PKCS7DecoderContext*)arg;
651 cinfo = p7dcx->cinfo;
652
653 if (cinfo->contentTypeTag == NULL) {
654 if (after && dest == &(cinfo->contentType))
655 cinfo->contentTypeTag = SECOID_FindOID(&(cinfo->contentType));
656 return;
657 }
658
659 switch (cinfo->contentTypeTag->offset) {
660 case SEC_OID_PKCS7_SIGNED_DATA:
661 sigd = cinfo->content.signedData;
662 if (sigd == NULL)
663 break;
664
665 if (sigd->contentInfo.contentTypeTag == NULL) {
666 if (after && dest == &(sigd->contentInfo.contentType))
667 sigd->contentInfo.contentTypeTag =
668 SECOID_FindOID(&(sigd->contentInfo.contentType));
669 break;
670 }
671
672 /*
673 * We only set up a filtering digest if the content is
674 * plain DATA; anything else needs more work because a
675 * second pass is required to produce a DER encoding from
676 * an input that can be BER encoded. (This is a requirement
677 * of PKCS7 that is unfortunate, but there you have it.)
678 *
679 * XXX Also, since we stop here if this is not DATA, the
680 * inner content is not getting processed at all. Someday
681 * we may want to fix that.
682 */
683 if (sigd->contentInfo.contentTypeTag->offset != SEC_OID_PKCS7_DATA) {
684 /* XXX Set an error in p7dcx->error */
685 SEC_ASN1DecoderClearNotifyProc (p7dcx->dcx);
686 break;
687 }
688
689 /*
690 * Just before the content, we want to set up a digest context
691 * for each digest algorithm listed, and start a filter which
692 * will run all of the contents bytes through that digest.
693 */
694 if (before && dest == &(sigd->contentInfo.content)) {
695 rv = sec_pkcs7_decoder_start_digests (p7dcx, depth,
696 sigd->digestAlgorithms);
697 if (rv != SECSuccess)
698 SEC_ASN1DecoderClearNotifyProc (p7dcx->dcx);
699
700 break;
701 }
702
703 /*
704 * XXX To handle nested types, here is where we would want
705 * to check for inner boundaries that need handling.
706 */
707
708 /*
709 * Are we done?
710 */
711 if (after && dest == &(sigd->contentInfo.content)) {
712 /*
713 * Close out the digest contexts. We ignore any error
714 * because we are stopping anyway; the error status left
715 * behind in p7dcx will be seen by outer functions.
716 */
717 (void) sec_pkcs7_decoder_finish_digests (p7dcx, cinfo->poolp,
718 &(sigd->digests));
719
720 /*
721 * XXX To handle nested contents, we would need to remove
722 * the worker from the chain (and free it).
723 */
724
725 /*
726 * Stop notify.
727 */
728 SEC_ASN1DecoderClearNotifyProc (p7dcx->dcx);
729 }
730 break;
731
732 case SEC_OID_PKCS7_ENVELOPED_DATA:
733 envd = cinfo->content.envelopedData;
734 if (envd == NULL)
735 break;
736
737 if (envd->encContentInfo.contentTypeTag == NULL) {
738 if (after && dest == &(envd->encContentInfo.contentType))
739 envd->encContentInfo.contentTypeTag =
740 SECOID_FindOID(&(envd->encContentInfo.contentType));
741 break;
742 }
743
744 /*
745 * Just before the content, we want to set up a decryption
746 * context, and start a filter which will run all of the
747 * contents bytes through it to determine the plain content.
748 */
749 if (before && dest == &(envd->encContentInfo.encContent)) {
750 rv = sec_pkcs7_decoder_start_decrypt (p7dcx, depth,
751 envd->recipientInfos,
752 &(envd->encContentInfo),
753 NULL);
754 if (rv != SECSuccess)
755 SEC_ASN1DecoderClearNotifyProc (p7dcx->dcx);
756
757 break;
758 }
759
760 /*
761 * Are we done?
762 */
763 if (after && dest == &(envd->encContentInfo.encContent)) {
764 /*
765 * Close out the decryption context. We ignore any error
766 * because we are stopping anyway; the error status left
767 * behind in p7dcx will be seen by outer functions.
768 */
769 (void) sec_pkcs7_decoder_finish_decrypt (p7dcx, cinfo->poolp,
770 &(envd->encContentInfo));
771
772 /*
773 * XXX To handle nested contents, we would need to remove
774 * the worker from the chain (and free it).
775 */
776
777 /*
778 * Stop notify.
779 */
780 SEC_ASN1DecoderClearNotifyProc (p7dcx->dcx);
781 }
782 break;
783
784 case SEC_OID_PKCS7_SIGNED_ENVELOPED_DATA:
785 saed = cinfo->content.signedAndEnvelopedData;
786 if (saed == NULL)
787 break;
788
789 if (saed->encContentInfo.contentTypeTag == NULL) {
790 if (after && dest == &(saed->encContentInfo.contentType))
791 saed->encContentInfo.contentTypeTag =
792 SECOID_FindOID(&(saed->encContentInfo.contentType));
793 break;
794 }
795
796 /*
797 * Just before the content, we want to set up a decryption
798 * context *and* digest contexts, and start a filter which
799 * will run all of the contents bytes through both.
800 */
801 if (before && dest == &(saed->encContentInfo.encContent)) {
802 rv = sec_pkcs7_decoder_start_decrypt (p7dcx, depth,
803 saed->recipientInfos,
804 &(saed->encContentInfo),
805 &(saed->sigKey));
806 if (rv == SECSuccess)
807 rv = sec_pkcs7_decoder_start_digests (p7dcx, depth,
808 saed->digestAlgorithms);
809 if (rv != SECSuccess)
810 SEC_ASN1DecoderClearNotifyProc (p7dcx->dcx);
811
812 break;
813 }
814
815 /*
816 * Are we done?
817 */
818 if (after && dest == &(saed->encContentInfo.encContent)) {
819 /*
820 * Close out the decryption and digests contexts.
821 * We ignore any errors because we are stopping anyway;
822 * the error status left behind in p7dcx will be seen by
823 * outer functions.
824 *
825 * Note that the decrypt stuff must be called first;
826 * it may have a last buffer to do which in turn has
827 * to be added to the digest.
828 */
829 (void) sec_pkcs7_decoder_finish_decrypt (p7dcx, cinfo->poolp,
830 &(saed->encContentInfo));
831 (void) sec_pkcs7_decoder_finish_digests (p7dcx, cinfo->poolp,
832 &(saed->digests));
833
834 /*
835 * XXX To handle nested contents, we would need to remove
836 * the worker from the chain (and free it).
837 */
838
839 /*
840 * Stop notify.
841 */
842 SEC_ASN1DecoderClearNotifyProc (p7dcx->dcx);
843 }
844 break;
845
846 case SEC_OID_PKCS7_DIGESTED_DATA:
847 digd = cinfo->content.digestedData;
848
849 /*
850 * XXX Want to do the digest or not? Maybe future enhancement...
851 */
852 if (before && dest == &(digd->contentInfo.content.data)) {
853 SEC_ASN1DecoderSetFilterProc (p7dcx->dcx, sec_pkcs7_decoder_filter,
854 p7dcx,
855 (PRBool)(p7dcx->cb != NULL));
856 break;
857 }
858
859 /*
860 * Are we done?
861 */
862 if (after && dest == &(digd->contentInfo.content.data)) {
863 SEC_ASN1DecoderClearFilterProc (p7dcx->dcx);
864 }
865 break;
866
867 case SEC_OID_PKCS7_ENCRYPTED_DATA:
868 encd = cinfo->content.encryptedData;
869
870 /*
871 * XXX If the decryption key callback is set, we want to start
872 * the decryption. If the callback is not set, we will treat the
873 * content as plain data, since we do not have the key.
874 *
875 * Is this the proper thing to do?
876 */
877 if (before && dest == &(encd->encContentInfo.encContent)) {
878 /*
879 * Start the encryption process if the decryption key callback
880 * is present. Otherwise, treat the content like plain data.
881 */
882 rv = SECSuccess;
883 if (p7dcx->dkcb != NULL) {
884 rv = sec_pkcs7_decoder_start_decrypt (p7dcx, depth, NULL,
885 &(encd->encContentInfo),
886 NULL);
887 }
888
889 if (rv != SECSuccess)
890 SEC_ASN1DecoderClearNotifyProc (p7dcx->dcx);
891
892 break;
893 }
894
895 /*
896 * Are we done?
897 */
898 if (after && dest == &(encd->encContentInfo.encContent)) {
899 /*
900 * Close out the decryption context. We ignore any error
901 * because we are stopping anyway; the error status left
902 * behind in p7dcx will be seen by outer functions.
903 */
904 (void) sec_pkcs7_decoder_finish_decrypt (p7dcx, cinfo->poolp,
905 &(encd->encContentInfo));
906
907 /*
908 * Stop notify.
909 */
910 SEC_ASN1DecoderClearNotifyProc (p7dcx->dcx);
911 }
912 break;
913
914 case SEC_OID_PKCS7_DATA:
915 /*
916 * If a output callback has been specified, we want to set the filter
917 * to call the callback. This is taken care of in
918 * sec_pkcs7_decoder_start_decrypt() or
919 * sec_pkcs7_decoder_start_digests() for the other content types.
920 */
921
922 if (before && dest == &(cinfo->content.data)) {
923
924 /*
925 * Set the filter proc up.
926 */
927 SEC_ASN1DecoderSetFilterProc (p7dcx->dcx,
928 sec_pkcs7_decoder_filter,
929 p7dcx,
930 (PRBool)(p7dcx->cb != NULL));
931 break;
932 }
933
934 if (after && dest == &(cinfo->content.data)) {
935 /*
936 * Time to clean up after ourself, stop the Notify and Filter
937 * procedures.
938 */
939 SEC_ASN1DecoderClearNotifyProc (p7dcx->dcx);
940 SEC_ASN1DecoderClearFilterProc (p7dcx->dcx);
941 }
942 break;
943
944 default:
945 SEC_ASN1DecoderClearNotifyProc (p7dcx->dcx);
946 break;
947 }
948 }
949
950
951 SEC_PKCS7DecoderContext *
952 SEC_PKCS7DecoderStart(SEC_PKCS7DecoderContentCallback cb, void *cb_arg,
953 SECKEYGetPasswordKey pwfn, void *pwfn_arg,
954 SEC_PKCS7GetDecryptKeyCallback decrypt_key_cb,
955 void *decrypt_key_cb_arg,
956 SEC_PKCS7DecryptionAllowedCallback decrypt_allowed_cb)
957 {
958 SEC_PKCS7DecoderContext *p7dcx;
959 SEC_ASN1DecoderContext *dcx;
960 SEC_PKCS7ContentInfo *cinfo;
961 PLArenaPool *poolp;
962
963 poolp = PORT_NewArena (1024); /* XXX what is right value? */
964 if (poolp == NULL)
965 return NULL;
966
967 cinfo = (SEC_PKCS7ContentInfo*)PORT_ArenaZAlloc (poolp, sizeof(*cinfo));
968 if (cinfo == NULL) {
969 PORT_FreeArena (poolp, PR_FALSE);
970 return NULL;
971 }
972
973 cinfo->poolp = poolp;
974 cinfo->pwfn = pwfn;
975 cinfo->pwfn_arg = pwfn_arg;
976 cinfo->created = PR_FALSE;
977 cinfo->refCount = 1;
978
979 p7dcx =
980 (SEC_PKCS7DecoderContext*)PORT_ZAlloc (sizeof(SEC_PKCS7DecoderContext));
981 if (p7dcx == NULL) {
982 PORT_FreeArena (poolp, PR_FALSE);
983 return NULL;
984 }
985
986 p7dcx->tmp_poolp = PORT_NewArena (1024); /* XXX what is right value? */
987 if (p7dcx->tmp_poolp == NULL) {
988 PORT_Free (p7dcx);
989 PORT_FreeArena (poolp, PR_FALSE);
990 return NULL;
991 }
992
993 dcx = SEC_ASN1DecoderStart (poolp, cinfo, sec_PKCS7ContentInfoTemplate);
994 if (dcx == NULL) {
995 PORT_FreeArena (p7dcx->tmp_poolp, PR_FALSE);
996 PORT_Free (p7dcx);
997 PORT_FreeArena (poolp, PR_FALSE);
998 return NULL;
999 }
1000
1001 SEC_ASN1DecoderSetNotifyProc (dcx, sec_pkcs7_decoder_notify, p7dcx);
1002
1003 p7dcx->dcx = dcx;
1004 p7dcx->cinfo = cinfo;
1005 p7dcx->cb = cb;
1006 p7dcx->cb_arg = cb_arg;
1007 p7dcx->pwfn = pwfn;
1008 p7dcx->pwfn_arg = pwfn_arg;
1009 p7dcx->dkcb = decrypt_key_cb;
1010 p7dcx->dkcb_arg = decrypt_key_cb_arg;
1011 p7dcx->decrypt_allowed_cb = decrypt_allowed_cb;
1012
1013 return p7dcx;
1014 }
1015
1016
1017 /*
1018 * Do the next chunk of PKCS7 decoding. If there is a problem, set
1019 * an error and return a failure status. Note that in the case of
1020 * an error, this routine is still prepared to be called again and
1021 * again in case that is the easiest route for our caller to take.
1022 * We simply detect it and do not do anything except keep setting
1023 * that error in case our caller has not noticed it yet...
1024 */
1025 SECStatus
1026 SEC_PKCS7DecoderUpdate(SEC_PKCS7DecoderContext *p7dcx,
1027 const char *buf, unsigned long len)
1028 {
1029 if (p7dcx->cinfo != NULL && p7dcx->dcx != NULL) {
1030 PORT_Assert (p7dcx->error == 0);
1031 if (p7dcx->error == 0) {
1032 if (SEC_ASN1DecoderUpdate (p7dcx->dcx, buf, len) != SECSuccess) {
1033 p7dcx->error = PORT_GetError();
1034 PORT_Assert (p7dcx->error);
1035 if (p7dcx->error == 0)
1036 p7dcx->error = -1;
1037 }
1038 }
1039 }
1040
1041 if (p7dcx->error) {
1042 if (p7dcx->dcx != NULL) {
1043 (void) SEC_ASN1DecoderFinish (p7dcx->dcx);
1044 p7dcx->dcx = NULL;
1045 }
1046 if (p7dcx->cinfo != NULL) {
1047 SEC_PKCS7DestroyContentInfo (p7dcx->cinfo);
1048 p7dcx->cinfo = NULL;
1049 }
1050 PORT_SetError (p7dcx->error);
1051 return SECFailure;
1052 }
1053
1054 return SECSuccess;
1055 }
1056
1057
1058 SEC_PKCS7ContentInfo *
1059 SEC_PKCS7DecoderFinish(SEC_PKCS7DecoderContext *p7dcx)
1060 {
1061 SEC_PKCS7ContentInfo *cinfo;
1062
1063 cinfo = p7dcx->cinfo;
1064 if (p7dcx->dcx != NULL) {
1065 if (SEC_ASN1DecoderFinish (p7dcx->dcx) != SECSuccess) {
1066 SEC_PKCS7DestroyContentInfo (cinfo);
1067 cinfo = NULL;
1068 }
1069 }
1070 /* free any NSS data structures */
1071 if (p7dcx->worker.decryptobj) {
1072 sec_PKCS7DestroyDecryptObject (p7dcx->worker.decryptobj);
1073 }
1074 PORT_FreeArena (p7dcx->tmp_poolp, PR_FALSE);
1075 PORT_Free (p7dcx);
1076 return cinfo;
1077 }
1078
1079
1080 SEC_PKCS7ContentInfo *
1081 SEC_PKCS7DecodeItem(SECItem *p7item,
1082 SEC_PKCS7DecoderContentCallback cb, void *cb_arg,
1083 SECKEYGetPasswordKey pwfn, void *pwfn_arg,
1084 SEC_PKCS7GetDecryptKeyCallback decrypt_key_cb,
1085 void *decrypt_key_cb_arg,
1086 SEC_PKCS7DecryptionAllowedCallback decrypt_allowed_cb)
1087 {
1088 SEC_PKCS7DecoderContext *p7dcx;
1089
1090 p7dcx = SEC_PKCS7DecoderStart(cb, cb_arg, pwfn, pwfn_arg, decrypt_key_cb,
1091 decrypt_key_cb_arg, decrypt_allowed_cb);
1092 if (!p7dcx) {
1093 /* error code is set */
1094 return NULL;
1095 }
1096 (void) SEC_PKCS7DecoderUpdate(p7dcx, (char *) p7item->data, p7item->len);
1097 return SEC_PKCS7DecoderFinish(p7dcx);
1098 }
1099
1100 /*
1101 * Abort the ASN.1 stream. Used by pkcs 12
1102 */
1103 void
1104 SEC_PKCS7DecoderAbort(SEC_PKCS7DecoderContext *p7dcx, int error)
1105 {
1106 PORT_Assert(p7dcx);
1107 SEC_ASN1DecoderAbort(p7dcx->dcx, error);
1108 }
1109
1110
1111 /*
1112 * If the thing contains any certs or crls return true; false otherwise.
1113 */
1114 PRBool
1115 SEC_PKCS7ContainsCertsOrCrls(SEC_PKCS7ContentInfo *cinfo)
1116 {
1117 SECOidTag kind;
1118 SECItem **certs;
1119 CERTSignedCrl **crls;
1120
1121 kind = SEC_PKCS7ContentType (cinfo);
1122 switch (kind) {
1123 default:
1124 case SEC_OID_PKCS7_DATA:
1125 case SEC_OID_PKCS7_DIGESTED_DATA:
1126 case SEC_OID_PKCS7_ENVELOPED_DATA:
1127 case SEC_OID_PKCS7_ENCRYPTED_DATA:
1128 return PR_FALSE;
1129 case SEC_OID_PKCS7_SIGNED_DATA:
1130 certs = cinfo->content.signedData->rawCerts;
1131 crls = cinfo->content.signedData->crls;
1132 break;
1133 case SEC_OID_PKCS7_SIGNED_ENVELOPED_DATA:
1134 certs = cinfo->content.signedAndEnvelopedData->rawCerts;
1135 crls = cinfo->content.signedAndEnvelopedData->crls;
1136 break;
1137 }
1138
1139 /*
1140 * I know this could be collapsed, but I was in a mood to be explicit.
1141 */
1142 if (certs != NULL && certs[0] != NULL)
1143 return PR_TRUE;
1144 else if (crls != NULL && crls[0] != NULL)
1145 return PR_TRUE;
1146 else
1147 return PR_FALSE;
1148 }
1149
1150 /* return the content length...could use GetContent, however we
1151 * need the encrypted content length
1152 */
1153 PRBool
1154 SEC_PKCS7IsContentEmpty(SEC_PKCS7ContentInfo *cinfo, unsigned int minLen)
1155 {
1156 SECItem *item = NULL;
1157
1158 if(cinfo == NULL) {
1159 return PR_TRUE;
1160 }
1161
1162 switch(SEC_PKCS7ContentType(cinfo))
1163 {
1164 case SEC_OID_PKCS7_DATA:
1165 item = cinfo->content.data;
1166 break;
1167 case SEC_OID_PKCS7_ENCRYPTED_DATA:
1168 item = &cinfo->content.encryptedData->encContentInfo.encContent;
1169 break;
1170 default:
1171 /* add other types */
1172 return PR_FALSE;
1173 }
1174
1175 if(!item) {
1176 return PR_TRUE;
1177 } else if(item->len <= minLen) {
1178 return PR_TRUE;
1179 }
1180
1181 return PR_FALSE;
1182 }
1183
1184
1185 PRBool
1186 SEC_PKCS7ContentIsEncrypted(SEC_PKCS7ContentInfo *cinfo)
1187 {
1188 SECOidTag kind;
1189
1190 kind = SEC_PKCS7ContentType (cinfo);
1191 switch (kind) {
1192 default:
1193 case SEC_OID_PKCS7_DATA:
1194 case SEC_OID_PKCS7_DIGESTED_DATA:
1195 case SEC_OID_PKCS7_SIGNED_DATA:
1196 return PR_FALSE;
1197 case SEC_OID_PKCS7_ENCRYPTED_DATA:
1198 case SEC_OID_PKCS7_ENVELOPED_DATA:
1199 case SEC_OID_PKCS7_SIGNED_ENVELOPED_DATA:
1200 return PR_TRUE;
1201 }
1202 }
1203
1204
1205 /*
1206 * If the PKCS7 content has a signature (not just *could* have a signature)
1207 * return true; false otherwise. This can/should be called before calling
1208 * VerifySignature, which will always indicate failure if no signature is
1209 * present, but that does not mean there even was a signature!
1210 * Note that the content itself can be empty (detached content was sent
1211 * another way); it is the presence of the signature that matters.
1212 */
1213 PRBool
1214 SEC_PKCS7ContentIsSigned(SEC_PKCS7ContentInfo *cinfo)
1215 {
1216 SECOidTag kind;
1217 SEC_PKCS7SignerInfo **signerinfos;
1218
1219 kind = SEC_PKCS7ContentType (cinfo);
1220 switch (kind) {
1221 default:
1222 case SEC_OID_PKCS7_DATA:
1223 case SEC_OID_PKCS7_DIGESTED_DATA:
1224 case SEC_OID_PKCS7_ENVELOPED_DATA:
1225 case SEC_OID_PKCS7_ENCRYPTED_DATA:
1226 return PR_FALSE;
1227 case SEC_OID_PKCS7_SIGNED_DATA:
1228 signerinfos = cinfo->content.signedData->signerInfos;
1229 break;
1230 case SEC_OID_PKCS7_SIGNED_ENVELOPED_DATA:
1231 signerinfos = cinfo->content.signedAndEnvelopedData->signerInfos;
1232 break;
1233 }
1234
1235 /*
1236 * I know this could be collapsed; but I kind of think it will get
1237 * more complicated before I am finished, so...
1238 */
1239 if (signerinfos != NULL && signerinfos[0] != NULL)
1240 return PR_TRUE;
1241 else
1242 return PR_FALSE;
1243 }
1244
1245
1246 /*
1247 * sec_pkcs7_verify_signature
1248 *
1249 * Look at a PKCS7 contentInfo and check if the signature is good.
1250 * The digest was either calculated earlier (and is stored in the
1251 * contentInfo itself) or is passed in via "detached_digest".
1252 *
1253 * The verification checks that the signing cert is valid and trusted
1254 * for the purpose specified by "certusage" at
1255 * - "*atTime" if "atTime" is not null, or
1256 * - the signing time if the signing time is available in "cinfo", or
1257 * - the current time (as returned by PR_Now).
1258 *
1259 * In addition, if "keepcerts" is true, add any new certificates found
1260 * into our local database.
1261 *
1262 * XXX Each place which returns PR_FALSE should be sure to have a good
1263 * error set for inspection by the caller. Alternatively, we could create
1264 * an enumeration of success and each type of failure and return that
1265 * instead of a boolean. For now, the default in a bad situation is to
1266 * set the error to SEC_ERROR_PKCS7_BAD_SIGNATURE. But this should be
1267 * reviewed; better (more specific) errors should be possible (to distinguish
1268 * a signature failure from a badly-formed pkcs7 signedData, for example).
1269 * Some of the errors should probably just be SEC_ERROR_BAD_SIGNATURE,
1270 * but that has a less helpful error string associated with it right now;
1271 * if/when that changes, review and change these as needed.
1272 *
1273 * XXX This is broken wrt signedAndEnvelopedData. In that case, the
1274 * message digest is doubly encrypted -- first encrypted with the signer
1275 * private key but then again encrypted with the bulk encryption key used
1276 * to encrypt the content. So before we can pass the digest to VerifyDigest,
1277 * we need to decrypt it with the bulk encryption key. Also, in this case,
1278 * there should be NO authenticatedAttributes (signerinfo->authAttr should
1279 * be NULL).
1280 */
1281 static PRBool
1282 sec_pkcs7_verify_signature(SEC_PKCS7ContentInfo *cinfo,
1283 SECCertUsage certusage,
1284 const SECItem *detached_digest,
1285 HASH_HashType digest_type,
1286 PRBool keepcerts,
1287 const PRTime *atTime)
1288 {
1289 SECAlgorithmID **digestalgs, *bulkid;
1290 const SECItem *digest;
1291 SECItem **digests;
1292 SECItem **rawcerts;
1293 SEC_PKCS7SignerInfo **signerinfos, *signerinfo;
1294 CERTCertificate *cert, **certs;
1295 PRBool goodsig;
1296 CERTCertDBHandle *certdb, *defaultdb;
1297 SECOidTag encTag,digestTag;
1298 HASH_HashType found_type;
1299 int i, certcount;
1300 SECKEYPublicKey *publickey;
1301 SECItem *content_type;
1302 PK11SymKey *sigkey;
1303 SECItem *encoded_stime;
1304 PRTime stime;
1305 PRTime verificationTime;
1306 SECStatus rv;
1307
1308 /*
1309 * Everything needed in order to "goto done" safely.
1310 */
1311 goodsig = PR_FALSE;
1312 certcount = 0;
1313 cert = NULL;
1314 certs = NULL;
1315 certdb = NULL;
1316 defaultdb = CERT_GetDefaultCertDB();
1317 publickey = NULL;
1318
1319 if (! SEC_PKCS7ContentIsSigned(cinfo)) {
1320 PORT_SetError (SEC_ERROR_PKCS7_BAD_SIGNATURE);
1321 goto done;
1322 }
1323
1324 PORT_Assert (cinfo->contentTypeTag != NULL);
1325
1326 switch (cinfo->contentTypeTag->offset) {
1327 default:
1328 case SEC_OID_PKCS7_DATA:
1329 case SEC_OID_PKCS7_DIGESTED_DATA:
1330 case SEC_OID_PKCS7_ENVELOPED_DATA:
1331 case SEC_OID_PKCS7_ENCRYPTED_DATA:
1332 /* Could only get here if SEC_PKCS7ContentIsSigned is broken. */
1333 PORT_Assert (0);
1334 case SEC_OID_PKCS7_SIGNED_DATA:
1335 {
1336 SEC_PKCS7SignedData *sdp;
1337
1338 sdp = cinfo->content.signedData;
1339 digestalgs = sdp->digestAlgorithms;
1340 digests = sdp->digests;
1341 rawcerts = sdp->rawCerts;
1342 signerinfos = sdp->signerInfos;
1343 content_type = &(sdp->contentInfo.contentType);
1344 sigkey = NULL;
1345 bulkid = NULL;
1346 }
1347 break;
1348 case SEC_OID_PKCS7_SIGNED_ENVELOPED_DATA:
1349 {
1350 SEC_PKCS7SignedAndEnvelopedData *saedp;
1351
1352 saedp = cinfo->content.signedAndEnvelopedData;
1353 digestalgs = saedp->digestAlgorithms;
1354 digests = saedp->digests;
1355 rawcerts = saedp->rawCerts;
1356 signerinfos = saedp->signerInfos;
1357 content_type = &(saedp->encContentInfo.contentType);
1358 sigkey = saedp->sigKey;
1359 bulkid = &(saedp->encContentInfo.contentEncAlg);
1360 }
1361 break;
1362 }
1363
1364 if ((signerinfos == NULL) || (signerinfos[0] == NULL)) {
1365 PORT_SetError (SEC_ERROR_PKCS7_BAD_SIGNATURE);
1366 goto done;
1367 }
1368
1369 /*
1370 * XXX Need to handle multiple signatures; checking them is easy,
1371 * but what should be the semantics here (like, return value)?
1372 */
1373 if (signerinfos[1] != NULL) {
1374 PORT_SetError (SEC_ERROR_PKCS7_BAD_SIGNATURE);
1375 goto done;
1376 }
1377
1378 signerinfo = signerinfos[0];
1379
1380 /*
1381 * XXX I would like to just pass the issuerAndSN, along with the rawcerts
1382 * and crls, to some function that did all of this certificate stuff
1383 * (open/close the database if necessary, verifying the certs, etc.)
1384 * and gave me back a cert pointer if all was good.
1385 */
1386 certdb = defaultdb;
1387 if (certdb == NULL) {
1388 goto done;
1389 }
1390
1391 certcount = 0;
1392 if (rawcerts != NULL) {
1393 for (; rawcerts[certcount] != NULL; certcount++) {
1394 /* just counting */
1395 }
1396 }
1397
1398 /*
1399 * Note that the result of this is that each cert in "certs"
1400 * needs to be destroyed.
1401 */
1402 rv = CERT_ImportCerts(certdb, certusage, certcount, rawcerts, &certs,
1403 keepcerts, PR_FALSE, NULL);
1404 if ( rv != SECSuccess ) {
1405 goto done;
1406 }
1407
1408 /*
1409 * This cert will also need to be freed, but since we save it
1410 * in signerinfo for later, we do not want to destroy it when
1411 * we leave this function -- we let the clean-up of the entire
1412 * cinfo structure later do the destroy of this cert.
1413 */
1414 cert = CERT_FindCertByIssuerAndSN(certdb, signerinfo->issuerAndSN);
1415 if (cert == NULL) {
1416 goto done;
1417 }
1418
1419 signerinfo->cert = cert;
1420
1421 /*
1422 * Get and convert the signing time; if available, it will be used
1423 * both on the cert verification and for importing the sender
1424 * email profile.
1425 */
1426 encoded_stime = SEC_PKCS7GetSigningTime (cinfo);
1427 if (encoded_stime != NULL) {
1428 if (DER_DecodeTimeChoice (&stime, encoded_stime) != SECSuccess)
1429 encoded_stime = NULL; /* conversion failed, so pretend none */
1430 }
1431
1432 /*
1433 * XXX This uses the signing time, if available. Additionally, we
1434 * might want to, if there is no signing time, get the message time
1435 * from the mail header itself, and use that. That would require
1436 * a change to our interface though, and for S/MIME callers to pass
1437 * in a time (and for non-S/MIME callers to pass in nothing, or
1438 * maybe make them pass in the current time, always?).
1439 */
1440 if (atTime) {
1441 verificationTime = *atTime;
1442 } else if (encoded_stime != NULL) {
1443 verificationTime = stime;
1444 } else {
1445 verificationTime = PR_Now();
1446 }
1447 if (CERT_VerifyCert (certdb, cert, PR_TRUE, certusage, verificationTime,
1448 cinfo->pwfn_arg, NULL) != SECSuccess)
1449 {
1450 /*
1451 * XXX Give the user an option to check the signature anyway?
1452 * If we want to do this, need to give a way to leave and display
1453 * some dialog and get the answer and come back through (or do
1454 * the rest of what we do below elsewhere, maybe by putting it
1455 * in a function that we call below and could call from a dialog
1456 * finish handler).
1457 */
1458 goto savecert;
1459 }
1460
1461 publickey = CERT_ExtractPublicKey (cert);
1462 if (publickey == NULL)
1463 goto done;
1464
1465 /*
1466 * XXX No! If digests is empty, see if we can create it now by
1467 * digesting the contents. This is necessary if we want to allow
1468 * somebody to do a simple decode (without filtering, etc.) and
1469 * then later call us here to do the verification.
1470 * OR, we can just specify that the interface to this routine
1471 * *requires* that the digest(s) be done before calling and either
1472 * stashed in the struct itself or passed in explicitly (as would
1473 * be done for detached contents).
1474 */
1475 if ((digests == NULL || digests[0] == NULL)
1476 && (detached_digest == NULL || detached_digest->data == NULL))
1477 goto done;
1478
1479 /*
1480 * Find and confirm digest algorithm.
1481 */
1482 digestTag = SECOID_FindOIDTag(&(signerinfo->digestAlg.algorithm));
1483
1484 /* make sure we understand the digest type first */
1485 found_type = HASH_GetHashTypeByOidTag(digestTag);
1486 if ((digestTag == SEC_OID_UNKNOWN) || (found_type == HASH_AlgNULL)) {
1487 PORT_SetError (SEC_ERROR_PKCS7_BAD_SIGNATURE);
1488 goto done;
1489 }
1490
1491 if (detached_digest != NULL) {
1492 unsigned int hashLen = HASH_ResultLen(found_type);
1493
1494 if (digest_type != found_type ||
1495 detached_digest->len != hashLen) {
1496 PORT_SetError (SEC_ERROR_PKCS7_BAD_SIGNATURE);
1497 goto done;
1498 }
1499 digest = detached_digest;
1500 } else {
1501 PORT_Assert (digestalgs != NULL && digestalgs[0] != NULL);
1502 if (digestalgs == NULL || digestalgs[0] == NULL) {
1503 PORT_SetError (SEC_ERROR_PKCS7_BAD_SIGNATURE);
1504 goto done;
1505 }
1506
1507 /*
1508 * pick digest matching signerinfo->digestAlg from digests
1509 */
1510 for (i = 0; digestalgs[i] != NULL; i++) {
1511 if (SECOID_FindOIDTag(&(digestalgs[i]->algorithm)) == digestTag)
1512 break;
1513 }
1514 if (digestalgs[i] == NULL) {
1515 PORT_SetError (SEC_ERROR_PKCS7_BAD_SIGNATURE);
1516 goto done;
1517 }
1518
1519 digest = digests[i];
1520 }
1521
1522 encTag = SECOID_FindOIDTag(&(signerinfo->digestEncAlg.algorithm));
1523 if (encTag == SEC_OID_UNKNOWN) {
1524 PORT_SetError (SEC_ERROR_PKCS7_BAD_SIGNATURE);
1525 goto done;
1526 }
1527
1528 if (signerinfo->authAttr != NULL) {
1529 SEC_PKCS7Attribute *attr;
1530 SECItem *value;
1531 SECItem encoded_attrs;
1532
1533 /*
1534 * We have a sigkey only for signedAndEnvelopedData, which is
1535 * not supposed to have any authenticated attributes.
1536 */
1537 if (sigkey != NULL) {
1538 PORT_SetError (SEC_ERROR_PKCS7_BAD_SIGNATURE);
1539 goto done;
1540 }
1541
1542 /*
1543 * PKCS #7 says that if there are any authenticated attributes,
1544 * then there must be one for content type which matches the
1545 * content type of the content being signed, and there must
1546 * be one for message digest which matches our message digest.
1547 * So check these things first.
1548 * XXX Might be nice to have a compare-attribute-value function
1549 * which could collapse the following nicely.
1550 */
1551 attr = sec_PKCS7FindAttribute (signerinfo->authAttr,
1552 SEC_OID_PKCS9_CONTENT_TYPE, PR_TRUE);
1553 value = sec_PKCS7AttributeValue (attr);
1554 if (value == NULL || value->len != content_type->len) {
1555 PORT_SetError (SEC_ERROR_PKCS7_BAD_SIGNATURE);
1556 goto done;
1557 }
1558 if (PORT_Memcmp (value->data, content_type->data, value->len) != 0) {
1559 PORT_SetError (SEC_ERROR_PKCS7_BAD_SIGNATURE);
1560 goto done;
1561 }
1562
1563 attr = sec_PKCS7FindAttribute (signerinfo->authAttr,
1564 SEC_OID_PKCS9_MESSAGE_DIGEST, PR_TRUE);
1565 value = sec_PKCS7AttributeValue (attr);
1566 if (value == NULL || value->len != digest->len) {
1567 PORT_SetError (SEC_ERROR_PKCS7_BAD_SIGNATURE);
1568 goto done;
1569 }
1570 if (PORT_Memcmp (value->data, digest->data, value->len) != 0) {
1571 PORT_SetError (SEC_ERROR_PKCS7_BAD_SIGNATURE);
1572 goto done;
1573 }
1574
1575 /*
1576 * Okay, we met the constraints of the basic attributes.
1577 * Now check the signature, which is based on a digest of
1578 * the DER-encoded authenticated attributes. So, first we
1579 * encode and then we digest/verify.
1580 */
1581 encoded_attrs.data = NULL;
1582 encoded_attrs.len = 0;
1583 if (sec_PKCS7EncodeAttributes (NULL, &encoded_attrs,
1584 &(signerinfo->authAttr)) == NULL)
1585 goto done;
1586
1587 if (encoded_attrs.data == NULL || encoded_attrs.len == 0) {
1588 PORT_SetError (SEC_ERROR_PKCS7_BAD_SIGNATURE);
1589 goto done;
1590 }
1591
1592 goodsig = (PRBool)(VFY_VerifyDataDirect(encoded_attrs.data,
1593 encoded_attrs.len,
1594 publickey, &(signerinfo->encDigest),
1595 encTag, digestTag, NULL,
1596 cinfo->pwfn_arg) == SECSuccess);
1597 PORT_Free (encoded_attrs.data);
1598 } else {
1599 SECItem *sig;
1600 SECItem holder;
1601 SECStatus rv;
1602
1603 /*
1604 * No authenticated attributes.
1605 * The signature is based on the plain message digest.
1606 */
1607
1608 sig = &(signerinfo->encDigest);
1609 if (sig->len == 0) { /* bad signature */
1610 PORT_SetError (SEC_ERROR_PKCS7_BAD_SIGNATURE);
1611 goto done;
1612 }
1613
1614 if (sigkey != NULL) {
1615 sec_PKCS7CipherObject *decryptobj;
1616 unsigned int buflen;
1617
1618 /*
1619 * For signedAndEnvelopedData, we first must decrypt the encrypted
1620 * digest with the bulk encryption key. The result is the normal
1621 * encrypted digest (aka the signature).
1622 */
1623 decryptobj = sec_PKCS7CreateDecryptObject (sigkey, bulkid);
1624 if (decryptobj == NULL)
1625 goto done;
1626
1627 buflen = sec_PKCS7DecryptLength (decryptobj, sig->len, PR_TRUE);
1628 PORT_Assert (buflen);
1629 if (buflen == 0) { /* something is wrong */
1630 sec_PKCS7DestroyDecryptObject (decryptobj);
1631 goto done;
1632 }
1633
1634 holder.data = (unsigned char*)PORT_Alloc (buflen);
1635 if (holder.data == NULL) {
1636 sec_PKCS7DestroyDecryptObject (decryptobj);
1637 goto done;
1638 }
1639
1640 rv = sec_PKCS7Decrypt (decryptobj, holder.data, &holder.len, buflen,
1641 sig->data, sig->len, PR_TRUE);
1642 sec_PKCS7DestroyDecryptObject (decryptobj);
1643 if (rv != SECSuccess) {
1644 goto done;
1645 }
1646
1647 sig = &holder;
1648 }
1649
1650 goodsig = (PRBool)(VFY_VerifyDigestDirect(digest, publickey, sig,
1651 encTag, digestTag, cinfo->pwfn_arg)
1652 == SECSuccess);
1653
1654 if (sigkey != NULL) {
1655 PORT_Assert (sig == &holder);
1656 PORT_ZFree (holder.data, holder.len);
1657 }
1658 }
1659
1660 if (! goodsig) {
1661 /*
1662 * XXX Change the generic error into our specific one, because
1663 * in that case we get a better explanation out of the Security
1664 * Advisor. This is really a bug in our error strings (the
1665 * "generic" error has a lousy/wrong message associated with it
1666 * which assumes the signature verification was done for the
1667 * purposes of checking the issuer signature on a certificate)
1668 * but this is at least an easy workaround and/or in the
1669 * Security Advisor, which specifically checks for the error
1670 * SEC_ERROR_PKCS7_BAD_SIGNATURE and gives more explanation
1671 * in that case but does not similarly check for
1672 * SEC_ERROR_BAD_SIGNATURE. It probably should, but then would
1673 * probably say the wrong thing in the case that it *was* the
1674 * certificate signature check that failed during the cert
1675 * verification done above. Our error handling is really a mess.
1676 */
1677 if (PORT_GetError() == SEC_ERROR_BAD_SIGNATURE)
1678 PORT_SetError (SEC_ERROR_PKCS7_BAD_SIGNATURE);
1679 }
1680
1681 savecert:
1682 /*
1683 * Only save the smime profile if we are checking an email message and
1684 * the cert has an email address in it.
1685 */
1686 if ( cert->emailAddr && cert->emailAddr[0] &&
1687 ( ( certusage == certUsageEmailSigner ) ||
1688 ( certusage == certUsageEmailRecipient ) ) ) {
1689 SECItem *profile = NULL;
1690 int save_error;
1691
1692 /*
1693 * Remember the current error set because we do not care about
1694 * anything set by the functions we are about to call.
1695 */
1696 save_error = PORT_GetError();
1697
1698 if (goodsig && (signerinfo->authAttr != NULL)) {
1699 /*
1700 * If the signature is good, then we can save the S/MIME profile,
1701 * if we have one.
1702 */
1703 SEC_PKCS7Attribute *attr;
1704
1705 attr = sec_PKCS7FindAttribute (signerinfo->authAttr,
1706 SEC_OID_PKCS9_SMIME_CAPABILITIES,
1707 PR_TRUE);
1708 profile = sec_PKCS7AttributeValue (attr);
1709 }
1710
1711 rv = CERT_SaveSMimeProfile (cert, profile, encoded_stime);
1712
1713 /*
1714 * Restore the saved error in case the calls above set a new
1715 * one that we do not actually care about.
1716 */
1717 PORT_SetError (save_error);
1718
1719 /*
1720 * XXX Failure is not indicated anywhere -- the signature
1721 * verification itself is unaffected by whether or not the
1722 * profile was successfully saved.
1723 */
1724 }
1725
1726
1727 done:
1728
1729 /*
1730 * See comment above about why we do not want to destroy cert
1731 * itself here.
1732 */
1733
1734 if (certs != NULL)
1735 CERT_DestroyCertArray (certs, certcount);
1736
1737 if (publickey != NULL)
1738 SECKEY_DestroyPublicKey (publickey);
1739
1740 return goodsig;
1741 }
1742
1743 /*
1744 * SEC_PKCS7VerifySignature
1745 * Look at a PKCS7 contentInfo and check if the signature is good.
1746 * The verification checks that the signing cert is valid and trusted
1747 * for the purpose specified by "certusage".
1748 *
1749 * In addition, if "keepcerts" is true, add any new certificates found
1750 * into our local database.
1751 */
1752 PRBool
1753 SEC_PKCS7VerifySignature(SEC_PKCS7ContentInfo *cinfo,
1754 SECCertUsage certusage,
1755 PRBool keepcerts)
1756 {
1757 return sec_pkcs7_verify_signature (cinfo, certusage,
1758 NULL, HASH_AlgNULL, keepcerts, NULL);
1759 }
1760
1761 /*
1762 * SEC_PKCS7VerifyDetachedSignature
1763 * Look at a PKCS7 contentInfo and check if the signature matches
1764 * a passed-in digest (calculated, supposedly, from detached contents).
1765 * The verification checks that the signing cert is valid and trusted
1766 * for the purpose specified by "certusage".
1767 *
1768 * In addition, if "keepcerts" is true, add any new certificates found
1769 * into our local database.
1770 */
1771 PRBool
1772 SEC_PKCS7VerifyDetachedSignature(SEC_PKCS7ContentInfo *cinfo,
1773 SECCertUsage certusage,
1774 const SECItem *detached_digest,
1775 HASH_HashType digest_type,
1776 PRBool keepcerts)
1777 {
1778 return sec_pkcs7_verify_signature (cinfo, certusage,
1779 detached_digest, digest_type,
1780 keepcerts, NULL);
1781 }
1782
1783 /*
1784 * SEC_PKCS7VerifyDetachedSignatureAtTime
1785 * Look at a PKCS7 contentInfo and check if the signature matches
1786 * a passed-in digest (calculated, supposedly, from detached contents).
1787 * The verification checks that the signing cert is valid and trusted
1788 * for the purpose specified by "certusage" at time "atTime".
1789 *
1790 * In addition, if "keepcerts" is true, add any new certificates found
1791 * into our local database.
1792 */
1793 PRBool
1794 SEC_PKCS7VerifyDetachedSignatureAtTime(SEC_PKCS7ContentInfo *cinfo,
1795 SECCertUsage certusage,
1796 const SECItem *detached_digest,
1797 HASH_HashType digest_type,
1798 PRBool keepcerts,
1799 PRTime atTime)
1800 {
1801 return sec_pkcs7_verify_signature (cinfo, certusage,
1802 detached_digest, digest_type,
1803 keepcerts, &atTime);
1804 }
1805
1806 /*
1807 * Return the asked-for portion of the name of the signer of a PKCS7
1808 * signed object.
1809 *
1810 * Returns a pointer to allocated memory, which must be freed.
1811 * A NULL return value is an error.
1812 */
1813
1814 #define sec_common_name 1
1815 #define sec_email_address 2
1816
1817 static char *
1818 sec_pkcs7_get_signer_cert_info(SEC_PKCS7ContentInfo *cinfo, int selector)
1819 {
1820 SECOidTag kind;
1821 SEC_PKCS7SignerInfo **signerinfos;
1822 CERTCertificate *signercert;
1823 char *container;
1824
1825 kind = SEC_PKCS7ContentType (cinfo);
1826 switch (kind) {
1827 default:
1828 case SEC_OID_PKCS7_DATA:
1829 case SEC_OID_PKCS7_DIGESTED_DATA:
1830 case SEC_OID_PKCS7_ENVELOPED_DATA:
1831 case SEC_OID_PKCS7_ENCRYPTED_DATA:
1832 PORT_Assert (0);
1833 return NULL;
1834 case SEC_OID_PKCS7_SIGNED_DATA:
1835 {
1836 SEC_PKCS7SignedData *sdp;
1837
1838 sdp = cinfo->content.signedData;
1839 signerinfos = sdp->signerInfos;
1840 }
1841 break;
1842 case SEC_OID_PKCS7_SIGNED_ENVELOPED_DATA:
1843 {
1844 SEC_PKCS7SignedAndEnvelopedData *saedp;
1845
1846 saedp = cinfo->content.signedAndEnvelopedData;
1847 signerinfos = saedp->signerInfos;
1848 }
1849 break;
1850 }
1851
1852 if (signerinfos == NULL || signerinfos[0] == NULL)
1853 return NULL;
1854
1855 signercert = signerinfos[0]->cert;
1856
1857 /*
1858 * No cert there; see if we can find one by calling verify ourselves.
1859 */
1860 if (signercert == NULL) {
1861 /*
1862 * The cert usage does not matter in this case, because we do not
1863 * actually care about the verification itself, but we have to pick
1864 * some valid usage to pass in.
1865 */
1866 (void) sec_pkcs7_verify_signature (cinfo, certUsageEmailSigner,
1867 NULL, HASH_AlgNULL, PR_FALSE, NULL);
1868 signercert = signerinfos[0]->cert;
1869 if (signercert == NULL)
1870 return NULL;
1871 }
1872
1873 switch (selector) {
1874 case sec_common_name:
1875 container = CERT_GetCommonName (&signercert->subject);
1876 break;
1877 case sec_email_address:
1878 if(signercert->emailAddr && signercert->emailAddr[0]) {
1879 container = PORT_Strdup(signercert->emailAddr);
1880 } else {
1881 container = NULL;
1882 }
1883 break;
1884 default:
1885 PORT_Assert (0);
1886 container = NULL;
1887 break;
1888 }
1889
1890 return container;
1891 }
1892
1893 char *
1894 SEC_PKCS7GetSignerCommonName(SEC_PKCS7ContentInfo *cinfo)
1895 {
1896 return sec_pkcs7_get_signer_cert_info(cinfo, sec_common_name);
1897 }
1898
1899 char *
1900 SEC_PKCS7GetSignerEmailAddress(SEC_PKCS7ContentInfo *cinfo)
1901 {
1902 return sec_pkcs7_get_signer_cert_info(cinfo, sec_email_address);
1903 }
1904
1905
1906 /*
1907 * Return the signing time, in UTCTime format, of a PKCS7 contentInfo.
1908 */
1909 SECItem *
1910 SEC_PKCS7GetSigningTime(SEC_PKCS7ContentInfo *cinfo)
1911 {
1912 SEC_PKCS7SignerInfo **signerinfos;
1913 SEC_PKCS7Attribute *attr;
1914
1915 if (SEC_PKCS7ContentType (cinfo) != SEC_OID_PKCS7_SIGNED_DATA)
1916 return NULL;
1917
1918 signerinfos = cinfo->content.signedData->signerInfos;
1919
1920 /*
1921 * No signature, or more than one, means no deal.
1922 */
1923 if (signerinfos == NULL || signerinfos[0] == NULL || signerinfos[1] != NULL)
1924 return NULL;
1925
1926 attr = sec_PKCS7FindAttribute (signerinfos[0]->authAttr,
1927 SEC_OID_PKCS9_SIGNING_TIME, PR_TRUE);
1928 return sec_PKCS7AttributeValue (attr);
1929 }
OLDNEW
« no previous file with comments | « nss/lib/pkcs7/p7create.c ('k') | nss/lib/pkcs7/p7encode.c » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698