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

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

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

Powered by Google App Engine
This is Rietveld 408576698