1 /* This Source Code Form is subject to the terms of the Mozilla Public
2  * License, v. 2.0. If a copy of the MPL was not distributed with this
3  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4 
5 /*
6  * PKCS7 decoding, verification.
7  */
8 
9 #include "p7local.h"
10 
11 #include "cert.h"
12 /* XXX do not want to have to include */
13 #include "certdb.h" /* certdb.h -- the trust stuff needed by */
14                     /* the add certificate code needs to get */
15                     /* rewritten/abstracted and then this */
16                     /* include should be removed! */
17 /*#include "cdbhdl.h" */
18 #include "cryptohi.h"
19 #include "key.h"
20 #include "secasn1.h"
21 #include "secitem.h"
22 #include "secoid.h"
23 #include "pk11func.h"
24 #include "prtime.h"
25 #include "secerr.h"
26 #include "sechash.h" /* for HASH_GetHashObject() */
27 #include "secder.h"
28 #include "secpkcs5.h"
29 
30 struct sec_pkcs7_decoder_worker {
31     int depth;
32     int digcnt;
33     void **digcxs;
34     const SECHashObject **digobjs;
35     sec_PKCS7CipherObject *decryptobj;
36     PRBool saw_contents;
37 };
38 
39 struct SEC_PKCS7DecoderContextStr {
40     SEC_ASN1DecoderContext *dcx;
41     SEC_PKCS7ContentInfo *cinfo;
42     SEC_PKCS7DecoderContentCallback cb;
43     void *cb_arg;
44     SECKEYGetPasswordKey pwfn;
45     void *pwfn_arg;
46     struct sec_pkcs7_decoder_worker worker;
47     PLArenaPool *tmp_poolp;
48     int error;
49     SEC_PKCS7GetDecryptKeyCallback dkcb;
50     void *dkcb_arg;
51     SEC_PKCS7DecryptionAllowedCallback decrypt_allowed_cb;
52 };
53 
54 /*
55  * Handle one worker, decrypting and digesting the data as necessary.
56  *
57  * XXX If/when we support nested contents, this probably needs to be
58  * revised somewhat to get passed the content-info (which unfortunately
59  * can be two different types depending on whether it is encrypted or not)
60  * corresponding to the given worker.
61  */
62 static void
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         SECStatus rv;
1600 
1601         /*
1602          * No authenticated attributes.
1603          * The signature is based on the plain message digest.
1604          */
1605 
1606         sig = &(signerinfo->encDigest);
1607         if (sig->len == 0) { /* bad signature */
1608             PORT_SetError(SEC_ERROR_PKCS7_BAD_SIGNATURE);
1609             goto done;
1610         }
1611 
1612         if (sigkey != NULL) {
1613             sec_PKCS7CipherObject *decryptobj;
1614             unsigned int buflen;
1615 
1616             /*
1617              * For signedAndEnvelopedData, we first must decrypt the encrypted
1618              * digest with the bulk encryption key.  The result is the normal
1619              * encrypted digest (aka the signature).
1620              */
1621             decryptobj = sec_PKCS7CreateDecryptObject(sigkey, bulkid);
1622             if (decryptobj == NULL)
1623                 goto done;
1624 
1625             buflen = sec_PKCS7DecryptLength(decryptobj, sig->len, PR_TRUE);
1626             PORT_Assert(buflen);
1627             if (buflen == 0) { /* something is wrong */
1628                 sec_PKCS7DestroyDecryptObject(decryptobj);
1629                 goto done;
1630             }
1631 
1632             holder.data = (unsigned char *)PORT_Alloc(buflen);
1633             if (holder.data == NULL) {
1634                 sec_PKCS7DestroyDecryptObject(decryptobj);
1635                 goto done;
1636             }
1637 
1638             rv = sec_PKCS7Decrypt(decryptobj, holder.data, &holder.len, buflen,
1639                                   sig->data, sig->len, PR_TRUE);
1640             sec_PKCS7DestroyDecryptObject(decryptobj);
1641             if (rv != SECSuccess) {
1642                 goto done;
1643             }
1644 
1645             sig = &holder;
1646         }
1647 
1648         goodsig = (PRBool)(VFY_VerifyDigestDirect(digest, publickey, sig,
1649                                                   encTag, digestTag, cinfo->pwfn_arg) == SECSuccess);
1650 
1651         if (sigkey != NULL) {
1652             PORT_Assert(sig == &holder);
1653             PORT_ZFree(holder.data, holder.len);
1654         }
1655     }
1656 
1657     if (!goodsig) {
1658         /*
1659          * XXX Change the generic error into our specific one, because
1660          * in that case we get a better explanation out of the Security
1661          * Advisor.  This is really a bug in our error strings (the
1662          * "generic" error has a lousy/wrong message associated with it
1663          * which assumes the signature verification was done for the
1664          * purposes of checking the issuer signature on a certificate)
1665          * but this is at least an easy workaround and/or in the
1666          * Security Advisor, which specifically checks for the error
1667          * SEC_ERROR_PKCS7_BAD_SIGNATURE and gives more explanation
1668          * in that case but does not similarly check for
1669          * SEC_ERROR_BAD_SIGNATURE.  It probably should, but then would
1670          * probably say the wrong thing in the case that it *was* the
1671          * certificate signature check that failed during the cert
1672          * verification done above.  Our error handling is really a mess.
1673          */
1674         if (PORT_GetError() == SEC_ERROR_BAD_SIGNATURE)
1675             PORT_SetError(SEC_ERROR_PKCS7_BAD_SIGNATURE);
1676     }
1677 
1678 savecert:
1679     /*
1680      * Only save the smime profile if we are checking an email message and
1681      * the cert has an email address in it.
1682      */
1683     if (cert->emailAddr && cert->emailAddr[0] &&
1684         ((certusage == certUsageEmailSigner) ||
1685          (certusage == certUsageEmailRecipient))) {
1686         SECItem *profile = NULL;
1687         int save_error;
1688 
1689         /*
1690          * Remember the current error set because we do not care about
1691          * anything set by the functions we are about to call.
1692          */
1693         save_error = PORT_GetError();
1694 
1695         if (goodsig && (signerinfo->authAttr != NULL)) {
1696             /*
1697              * If the signature is good, then we can save the S/MIME profile,
1698              * if we have one.
1699              */
1700             SEC_PKCS7Attribute *attr;
1701 
1702             attr = sec_PKCS7FindAttribute(signerinfo->authAttr,
1703                                           SEC_OID_PKCS9_SMIME_CAPABILITIES,
1704                                           PR_TRUE);
1705             profile = sec_PKCS7AttributeValue(attr);
1706         }
1707 
1708         rv = CERT_SaveSMimeProfile(cert, profile, encoded_stime);
1709 
1710         /*
1711          * Restore the saved error in case the calls above set a new
1712          * one that we do not actually care about.
1713          */
1714         PORT_SetError(save_error);
1715 
1716         /*
1717          * XXX Failure is not indicated anywhere -- the signature
1718          * verification itself is unaffected by whether or not the
1719          * profile was successfully saved.
1720          */
1721     }
1722 
1723 done:
1724 
1725     /*
1726      * See comment above about why we do not want to destroy cert
1727      * itself here.
1728      */
1729 
1730     if (certs != NULL)
1731         CERT_DestroyCertArray(certs, certcount);
1732 
1733     if (publickey != NULL)
1734         SECKEY_DestroyPublicKey(publickey);
1735 
1736     return goodsig;
1737 }
1738 
1739 /*
1740  * SEC_PKCS7VerifySignature
1741  *      Look at a PKCS7 contentInfo and check if the signature is good.
1742  *      The verification checks that the signing cert is valid and trusted
1743  *      for the purpose specified by "certusage".
1744  *
1745  *      In addition, if "keepcerts" is true, add any new certificates found
1746  *      into our local database.
1747  */
1748 PRBool
SEC_PKCS7VerifySignature(SEC_PKCS7ContentInfo * cinfo,SECCertUsage certusage,PRBool keepcerts)1749 SEC_PKCS7VerifySignature(SEC_PKCS7ContentInfo *cinfo,
1750                          SECCertUsage certusage,
1751                          PRBool keepcerts)
1752 {
1753     return sec_pkcs7_verify_signature(cinfo, certusage,
1754                                       NULL, HASH_AlgNULL, keepcerts, NULL);
1755 }
1756 
1757 /*
1758  * SEC_PKCS7VerifyDetachedSignature
1759  *      Look at a PKCS7 contentInfo and check if the signature matches
1760  *      a passed-in digest (calculated, supposedly, from detached contents).
1761  *      The verification checks that the signing cert is valid and trusted
1762  *      for the purpose specified by "certusage".
1763  *
1764  *      In addition, if "keepcerts" is true, add any new certificates found
1765  *      into our local database.
1766  */
1767 PRBool
SEC_PKCS7VerifyDetachedSignature(SEC_PKCS7ContentInfo * cinfo,SECCertUsage certusage,const SECItem * detached_digest,HASH_HashType digest_type,PRBool keepcerts)1768 SEC_PKCS7VerifyDetachedSignature(SEC_PKCS7ContentInfo *cinfo,
1769                                  SECCertUsage certusage,
1770                                  const SECItem *detached_digest,
1771                                  HASH_HashType digest_type,
1772                                  PRBool keepcerts)
1773 {
1774     return sec_pkcs7_verify_signature(cinfo, certusage,
1775                                       detached_digest, digest_type,
1776                                       keepcerts, NULL);
1777 }
1778 
1779 /*
1780  * SEC_PKCS7VerifyDetachedSignatureAtTime
1781  *      Look at a PKCS7 contentInfo and check if the signature matches
1782  *      a passed-in digest (calculated, supposedly, from detached contents).
1783  *      The verification checks that the signing cert is valid and trusted
1784  *      for the purpose specified by "certusage" at time "atTime".
1785  *
1786  *      In addition, if "keepcerts" is true, add any new certificates found
1787  *      into our local database.
1788  */
1789 PRBool
SEC_PKCS7VerifyDetachedSignatureAtTime(SEC_PKCS7ContentInfo * cinfo,SECCertUsage certusage,const SECItem * detached_digest,HASH_HashType digest_type,PRBool keepcerts,PRTime atTime)1790 SEC_PKCS7VerifyDetachedSignatureAtTime(SEC_PKCS7ContentInfo *cinfo,
1791                                        SECCertUsage certusage,
1792                                        const SECItem *detached_digest,
1793                                        HASH_HashType digest_type,
1794                                        PRBool keepcerts,
1795                                        PRTime atTime)
1796 {
1797     return sec_pkcs7_verify_signature(cinfo, certusage,
1798                                       detached_digest, digest_type,
1799                                       keepcerts, &atTime);
1800 }
1801 
1802 /*
1803  * Return the asked-for portion of the name of the signer of a PKCS7
1804  * signed object.
1805  *
1806  * Returns a pointer to allocated memory, which must be freed.
1807  * A NULL return value is an error.
1808  */
1809 
1810 #define sec_common_name 1
1811 #define sec_email_address 2
1812 
1813 static char *
sec_pkcs7_get_signer_cert_info(SEC_PKCS7ContentInfo * cinfo,int selector)1814 sec_pkcs7_get_signer_cert_info(SEC_PKCS7ContentInfo *cinfo, int selector)
1815 {
1816     SECOidTag kind;
1817     SEC_PKCS7SignerInfo **signerinfos;
1818     CERTCertificate *signercert;
1819     char *container;
1820 
1821     kind = SEC_PKCS7ContentType(cinfo);
1822     switch (kind) {
1823         default:
1824         case SEC_OID_PKCS7_DATA:
1825         case SEC_OID_PKCS7_DIGESTED_DATA:
1826         case SEC_OID_PKCS7_ENVELOPED_DATA:
1827         case SEC_OID_PKCS7_ENCRYPTED_DATA:
1828             PORT_Assert(0);
1829             return NULL;
1830         case SEC_OID_PKCS7_SIGNED_DATA: {
1831             SEC_PKCS7SignedData *sdp;
1832 
1833             sdp = cinfo->content.signedData;
1834             signerinfos = sdp->signerInfos;
1835         } break;
1836         case SEC_OID_PKCS7_SIGNED_ENVELOPED_DATA: {
1837             SEC_PKCS7SignedAndEnvelopedData *saedp;
1838 
1839             saedp = cinfo->content.signedAndEnvelopedData;
1840             signerinfos = saedp->signerInfos;
1841         } break;
1842     }
1843 
1844     if (signerinfos == NULL || signerinfos[0] == NULL)
1845         return NULL;
1846 
1847     signercert = signerinfos[0]->cert;
1848 
1849     /*
1850      * No cert there; see if we can find one by calling verify ourselves.
1851      */
1852     if (signercert == NULL) {
1853         /*
1854          * The cert usage does not matter in this case, because we do not
1855          * actually care about the verification itself, but we have to pick
1856          * some valid usage to pass in.
1857          */
1858         (void)sec_pkcs7_verify_signature(cinfo, certUsageEmailSigner,
1859                                          NULL, HASH_AlgNULL, PR_FALSE, NULL);
1860         signercert = signerinfos[0]->cert;
1861         if (signercert == NULL)
1862             return NULL;
1863     }
1864 
1865     switch (selector) {
1866         case sec_common_name:
1867             container = CERT_GetCommonName(&signercert->subject);
1868             break;
1869         case sec_email_address:
1870             if (signercert->emailAddr && signercert->emailAddr[0]) {
1871                 container = PORT_Strdup(signercert->emailAddr);
1872             } else {
1873                 container = NULL;
1874             }
1875             break;
1876         default:
1877             PORT_Assert(0);
1878             container = NULL;
1879             break;
1880     }
1881 
1882     return container;
1883 }
1884 
1885 char *
SEC_PKCS7GetSignerCommonName(SEC_PKCS7ContentInfo * cinfo)1886 SEC_PKCS7GetSignerCommonName(SEC_PKCS7ContentInfo *cinfo)
1887 {
1888     return sec_pkcs7_get_signer_cert_info(cinfo, sec_common_name);
1889 }
1890 
1891 char *
SEC_PKCS7GetSignerEmailAddress(SEC_PKCS7ContentInfo * cinfo)1892 SEC_PKCS7GetSignerEmailAddress(SEC_PKCS7ContentInfo *cinfo)
1893 {
1894     return sec_pkcs7_get_signer_cert_info(cinfo, sec_email_address);
1895 }
1896 
1897 /*
1898  * Return the signing time, in UTCTime format, of a PKCS7 contentInfo.
1899  */
1900 SECItem *
SEC_PKCS7GetSigningTime(SEC_PKCS7ContentInfo * cinfo)1901 SEC_PKCS7GetSigningTime(SEC_PKCS7ContentInfo *cinfo)
1902 {
1903     SEC_PKCS7SignerInfo **signerinfos;
1904     SEC_PKCS7Attribute *attr;
1905 
1906     if (SEC_PKCS7ContentType(cinfo) != SEC_OID_PKCS7_SIGNED_DATA)
1907         return NULL;
1908 
1909     signerinfos = cinfo->content.signedData->signerInfos;
1910 
1911     /*
1912      * No signature, or more than one, means no deal.
1913      */
1914     if (signerinfos == NULL || signerinfos[0] == NULL || signerinfos[1] != NULL)
1915         return NULL;
1916 
1917     attr = sec_PKCS7FindAttribute(signerinfos[0]->authAttr,
1918                                   SEC_OID_PKCS9_SIGNING_TIME, PR_TRUE);
1919     return sec_PKCS7AttributeValue(attr);
1920 }
1921