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