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 encoding.
7  */
8 
9 #include "p7local.h"
10 
11 #include "cert.h"
12 #include "cryptohi.h"
13 #include "keyhi.h"
14 #include "secasn1.h"
15 #include "secoid.h"
16 #include "secitem.h"
17 #include "pk11func.h"
18 #include "secerr.h"
19 #include "sechash.h" /* for HASH_GetHashObject() */
20 
21 struct sec_pkcs7_encoder_output {
22     SEC_PKCS7EncoderOutputCallback outputfn;
23     void *outputarg;
24 };
25 
26 struct SEC_PKCS7EncoderContextStr {
27     SEC_ASN1EncoderContext *ecx;
28     SEC_PKCS7ContentInfo *cinfo;
29     struct sec_pkcs7_encoder_output output;
30     sec_PKCS7CipherObject *encryptobj;
31     const SECHashObject *digestobj;
32     void *digestcx;
33 };
34 
35 /*
36  * The little output function that the ASN.1 encoder calls to hand
37  * us bytes which we in turn hand back to our caller (via the callback
38  * they gave us).
39  */
40 static void
sec_pkcs7_encoder_out(void * arg,const char * buf,unsigned long len,int depth,SEC_ASN1EncodingPart data_kind)41 sec_pkcs7_encoder_out(void *arg, const char *buf, unsigned long len,
42                       int depth, SEC_ASN1EncodingPart data_kind)
43 {
44     struct sec_pkcs7_encoder_output *output;
45 
46     output = (struct sec_pkcs7_encoder_output *)arg;
47     output->outputfn(output->outputarg, buf, len);
48 }
49 
50 static sec_PKCS7CipherObject *
sec_pkcs7_encoder_start_encrypt(SEC_PKCS7ContentInfo * cinfo,PK11SymKey * orig_bulkkey)51 sec_pkcs7_encoder_start_encrypt(SEC_PKCS7ContentInfo *cinfo,
52                                 PK11SymKey *orig_bulkkey)
53 {
54     SECOidTag kind;
55     sec_PKCS7CipherObject *encryptobj;
56     SEC_PKCS7RecipientInfo **recipientinfos, *ri;
57     SEC_PKCS7EncryptedContentInfo *enccinfo;
58     SECKEYPublicKey *publickey = NULL;
59     SECKEYPrivateKey *ourPrivKey = NULL;
60     PK11SymKey *bulkkey;
61     void *mark;
62     int i;
63     PLArenaPool *arena = NULL;
64 
65     kind = SEC_PKCS7ContentType(cinfo);
66     switch (kind) {
67         default:
68         case SEC_OID_PKCS7_DATA:
69         case SEC_OID_PKCS7_DIGESTED_DATA:
70         case SEC_OID_PKCS7_SIGNED_DATA:
71             recipientinfos = NULL;
72             enccinfo = NULL;
73             break;
74         case SEC_OID_PKCS7_ENCRYPTED_DATA: {
75             SEC_PKCS7EncryptedData *encdp;
76 
77             /* To do EncryptedData we *must* be given a bulk key. */
78             PORT_Assert(orig_bulkkey != NULL);
79             if (orig_bulkkey == NULL) {
80                 /* XXX error? */
81                 return NULL;
82             }
83 
84             encdp = cinfo->content.encryptedData;
85             recipientinfos = NULL;
86             enccinfo = &(encdp->encContentInfo);
87         } break;
88         case SEC_OID_PKCS7_ENVELOPED_DATA: {
89             SEC_PKCS7EnvelopedData *envdp;
90 
91             envdp = cinfo->content.envelopedData;
92             recipientinfos = envdp->recipientInfos;
93             enccinfo = &(envdp->encContentInfo);
94         } break;
95         case SEC_OID_PKCS7_SIGNED_ENVELOPED_DATA: {
96             SEC_PKCS7SignedAndEnvelopedData *saedp;
97 
98             saedp = cinfo->content.signedAndEnvelopedData;
99             recipientinfos = saedp->recipientInfos;
100             enccinfo = &(saedp->encContentInfo);
101         } break;
102     }
103 
104     if (enccinfo == NULL)
105         return NULL;
106 
107     bulkkey = orig_bulkkey;
108     if (bulkkey == NULL) {
109         CK_MECHANISM_TYPE type = PK11_AlgtagToMechanism(enccinfo->encalg);
110         PK11SlotInfo *slot;
111 
112         slot = PK11_GetBestSlot(type, cinfo->pwfn_arg);
113         if (slot == NULL) {
114             return NULL;
115         }
116         bulkkey = PK11_KeyGen(slot, type, NULL, enccinfo->keysize / 8,
117                               cinfo->pwfn_arg);
118         PK11_FreeSlot(slot);
119         if (bulkkey == NULL) {
120             return NULL;
121         }
122     }
123 
124     encryptobj = NULL;
125     mark = PORT_ArenaMark(cinfo->poolp);
126 
127     /*
128      * Encrypt the bulk key with the public key of each recipient.
129      */
130     for (i = 0; recipientinfos && (ri = recipientinfos[i]) != NULL; i++) {
131         CERTCertificate *cert;
132         SECOidTag certalgtag, encalgtag;
133         SECStatus rv;
134         int data_len;
135         SECItem *params = NULL;
136 
137         cert = ri->cert;
138         PORT_Assert(cert != NULL);
139         if (cert == NULL)
140             continue;
141 
142         /*
143          * XXX Want an interface that takes a cert and some data and
144          * fills in an algorithmID and encrypts the data with the public
145          * key from the cert.  Or, give me two interfaces -- one which
146          * gets the algorithm tag from a cert (I should not have to go
147          * down into the subjectPublicKeyInfo myself) and another which
148          * takes a public key and algorithm tag and data and encrypts
149          * the data.  Or something like that.  The point is that all
150          * of the following hardwired RSA stuff should be done elsewhere.
151          */
152 
153         certalgtag = SECOID_GetAlgorithmTag(&(cert->subjectPublicKeyInfo.algorithm));
154 
155         switch (certalgtag) {
156             case SEC_OID_PKCS1_RSA_ENCRYPTION:
157                 encalgtag = certalgtag;
158                 publickey = CERT_ExtractPublicKey(cert);
159                 if (publickey == NULL)
160                     goto loser;
161 
162                 data_len = SECKEY_PublicKeyStrength(publickey);
163                 ri->encKey.data =
164                     (unsigned char *)PORT_ArenaAlloc(cinfo->poolp, data_len);
165                 ri->encKey.len = data_len;
166                 if (ri->encKey.data == NULL)
167                     goto loser;
168 
169                 rv = PK11_PubWrapSymKey(PK11_AlgtagToMechanism(certalgtag), publickey,
170                                         bulkkey, &ri->encKey);
171 
172                 SECKEY_DestroyPublicKey(publickey);
173                 publickey = NULL;
174                 if (rv != SECSuccess)
175                     goto loser;
176                 params = NULL; /* paranoia */
177                 break;
178             default:
179                 PORT_SetError(SEC_ERROR_INVALID_ALGORITHM);
180                 goto loser;
181         }
182 
183         rv = SECOID_SetAlgorithmID(cinfo->poolp, &ri->keyEncAlg, encalgtag,
184                                    params);
185         if (rv != SECSuccess)
186             goto loser;
187         if (arena)
188             PORT_FreeArena(arena, PR_FALSE);
189         arena = NULL;
190     }
191 
192     encryptobj = sec_PKCS7CreateEncryptObject(cinfo->poolp, bulkkey,
193                                               enccinfo->encalg,
194                                               &(enccinfo->contentEncAlg));
195     if (encryptobj != NULL) {
196         PORT_ArenaUnmark(cinfo->poolp, mark);
197         mark = NULL; /* good one; do not want to release */
198     }
199 /* fallthru */
200 
201 loser:
202     if (arena) {
203         PORT_FreeArena(arena, PR_FALSE);
204     }
205     if (publickey) {
206         SECKEY_DestroyPublicKey(publickey);
207     }
208     if (ourPrivKey) {
209         SECKEY_DestroyPrivateKey(ourPrivKey);
210     }
211     if (mark != NULL) {
212         PORT_ArenaRelease(cinfo->poolp, mark);
213     }
214     if (orig_bulkkey == NULL) {
215         if (bulkkey)
216             PK11_FreeSymKey(bulkkey);
217     }
218 
219     return encryptobj;
220 }
221 
222 static void
sec_pkcs7_encoder_notify(void * arg,PRBool before,void * dest,int depth)223 sec_pkcs7_encoder_notify(void *arg, PRBool before, void *dest, int depth)
224 {
225     SEC_PKCS7EncoderContext *p7ecx;
226     SEC_PKCS7ContentInfo *cinfo;
227     SECOidTag kind;
228     PRBool before_content;
229 
230     /*
231      * We want to notice just before the content field.  After fields are
232      * not interesting to us.
233      */
234     if (!before)
235         return;
236 
237     p7ecx = (SEC_PKCS7EncoderContext *)arg;
238     cinfo = p7ecx->cinfo;
239 
240     before_content = PR_FALSE;
241 
242     /*
243      * Watch for the content field, at which point we want to instruct
244      * the ASN.1 encoder to start taking bytes from the buffer.
245      *
246      * XXX The following assumes the inner content type is data;
247      * if/when we want to handle fully nested types, this will have
248      * to recurse until reaching the innermost data content.
249      */
250     kind = SEC_PKCS7ContentType(cinfo);
251     switch (kind) {
252         default:
253         case SEC_OID_PKCS7_DATA:
254             if (dest == &(cinfo->content.data))
255                 before_content = PR_TRUE;
256             break;
257 
258         case SEC_OID_PKCS7_DIGESTED_DATA: {
259             SEC_PKCS7DigestedData *digd;
260 
261             digd = cinfo->content.digestedData;
262             if (digd == NULL)
263                 break;
264 
265             if (dest == &(digd->contentInfo.content))
266                 before_content = PR_TRUE;
267         } break;
268 
269         case SEC_OID_PKCS7_ENCRYPTED_DATA: {
270             SEC_PKCS7EncryptedData *encd;
271 
272             encd = cinfo->content.encryptedData;
273             if (encd == NULL)
274                 break;
275 
276             if (dest == &(encd->encContentInfo.encContent))
277                 before_content = PR_TRUE;
278         } break;
279 
280         case SEC_OID_PKCS7_ENVELOPED_DATA: {
281             SEC_PKCS7EnvelopedData *envd;
282 
283             envd = cinfo->content.envelopedData;
284             if (envd == NULL)
285                 break;
286 
287             if (dest == &(envd->encContentInfo.encContent))
288                 before_content = PR_TRUE;
289         } break;
290 
291         case SEC_OID_PKCS7_SIGNED_DATA: {
292             SEC_PKCS7SignedData *sigd;
293 
294             sigd = cinfo->content.signedData;
295             if (sigd == NULL)
296                 break;
297 
298             if (dest == &(sigd->contentInfo.content))
299                 before_content = PR_TRUE;
300         } break;
301 
302         case SEC_OID_PKCS7_SIGNED_ENVELOPED_DATA: {
303             SEC_PKCS7SignedAndEnvelopedData *saed;
304 
305             saed = cinfo->content.signedAndEnvelopedData;
306             if (saed == NULL)
307                 break;
308 
309             if (dest == &(saed->encContentInfo.encContent))
310                 before_content = PR_TRUE;
311         } break;
312     }
313 
314     if (before_content) {
315         /*
316          * This will cause the next SEC_ASN1EncoderUpdate to take the
317          * contents bytes from the passed-in buffer.
318          */
319         SEC_ASN1EncoderSetTakeFromBuf(p7ecx->ecx);
320         /*
321          * And that is all we needed this notify function for.
322          */
323         SEC_ASN1EncoderClearNotifyProc(p7ecx->ecx);
324     }
325 }
326 
327 static SEC_PKCS7EncoderContext *
sec_pkcs7_encoder_start_contexts(SEC_PKCS7ContentInfo * cinfo,PK11SymKey * bulkkey)328 sec_pkcs7_encoder_start_contexts(SEC_PKCS7ContentInfo *cinfo,
329                                  PK11SymKey *bulkkey)
330 {
331     SEC_PKCS7EncoderContext *p7ecx;
332     SECOidTag kind;
333     PRBool encrypt;
334     SECItem **digests;
335     SECAlgorithmID *digestalg, **digestalgs;
336 
337     p7ecx =
338         (SEC_PKCS7EncoderContext *)PORT_ZAlloc(sizeof(SEC_PKCS7EncoderContext));
339     if (p7ecx == NULL)
340         return NULL;
341 
342     digests = NULL;
343     digestalg = NULL;
344     digestalgs = NULL;
345     encrypt = PR_FALSE;
346 
347     kind = SEC_PKCS7ContentType(cinfo);
348     switch (kind) {
349         default:
350         case SEC_OID_PKCS7_DATA:
351             break;
352         case SEC_OID_PKCS7_DIGESTED_DATA:
353             digestalg = &(cinfo->content.digestedData->digestAlg);
354             break;
355         case SEC_OID_PKCS7_SIGNED_DATA:
356             digests = cinfo->content.signedData->digests;
357             digestalgs = cinfo->content.signedData->digestAlgorithms;
358             break;
359         case SEC_OID_PKCS7_ENCRYPTED_DATA:
360         case SEC_OID_PKCS7_ENVELOPED_DATA:
361             encrypt = PR_TRUE;
362             break;
363         case SEC_OID_PKCS7_SIGNED_ENVELOPED_DATA:
364             digests = cinfo->content.signedAndEnvelopedData->digests;
365             digestalgs = cinfo->content.signedAndEnvelopedData->digestAlgorithms;
366             encrypt = PR_TRUE;
367             break;
368     }
369 
370     if (encrypt) {
371         p7ecx->encryptobj = sec_pkcs7_encoder_start_encrypt(cinfo, bulkkey);
372         if (p7ecx->encryptobj == NULL) {
373             PORT_Free(p7ecx);
374             return NULL;
375         }
376     }
377 
378     if (digestalgs != NULL) {
379         if (digests != NULL) {
380             /* digests already created (probably for detached data) */
381             digestalg = NULL;
382         } else {
383             /*
384              * XXX Some day we should handle multiple digests; for now,
385              * assume only one will be done.
386              */
387             PORT_Assert(digestalgs[0] != NULL && digestalgs[1] == NULL);
388             digestalg = digestalgs[0];
389         }
390     }
391 
392     if (digestalg != NULL) {
393         SECOidTag oidTag = SECOID_FindOIDTag(&(digestalg->algorithm));
394 
395         p7ecx->digestobj = HASH_GetHashObjectByOidTag(oidTag);
396         if (p7ecx->digestobj != NULL) {
397             p7ecx->digestcx = (*p7ecx->digestobj->create)();
398             if (p7ecx->digestcx == NULL)
399                 p7ecx->digestobj = NULL;
400             else
401                 (*p7ecx->digestobj->begin)(p7ecx->digestcx);
402         }
403         if (p7ecx->digestobj == NULL) {
404             if (p7ecx->encryptobj != NULL)
405                 sec_PKCS7DestroyEncryptObject(p7ecx->encryptobj);
406             PORT_Free(p7ecx);
407             return NULL;
408         }
409     }
410 
411     p7ecx->cinfo = cinfo;
412     return p7ecx;
413 }
414 
415 SEC_PKCS7EncoderContext *
SEC_PKCS7EncoderStart(SEC_PKCS7ContentInfo * cinfo,SEC_PKCS7EncoderOutputCallback outputfn,void * outputarg,PK11SymKey * bulkkey)416 SEC_PKCS7EncoderStart(SEC_PKCS7ContentInfo *cinfo,
417                       SEC_PKCS7EncoderOutputCallback outputfn,
418                       void *outputarg,
419                       PK11SymKey *bulkkey)
420 {
421     SEC_PKCS7EncoderContext *p7ecx;
422     SECStatus rv;
423 
424     p7ecx = sec_pkcs7_encoder_start_contexts(cinfo, bulkkey);
425     if (p7ecx == NULL)
426         return NULL;
427 
428     p7ecx->output.outputfn = outputfn;
429     p7ecx->output.outputarg = outputarg;
430 
431     /*
432      * Initialize the BER encoder.
433      */
434     p7ecx->ecx = SEC_ASN1EncoderStart(cinfo, sec_PKCS7ContentInfoTemplate,
435                                       sec_pkcs7_encoder_out, &(p7ecx->output));
436     if (p7ecx->ecx == NULL) {
437         PORT_Free(p7ecx);
438         return NULL;
439     }
440 
441     /*
442      * Indicate that we are streaming.  We will be streaming until we
443      * get past the contents bytes.
444      */
445     SEC_ASN1EncoderSetStreaming(p7ecx->ecx);
446 
447     /*
448      * The notify function will watch for the contents field.
449      */
450     SEC_ASN1EncoderSetNotifyProc(p7ecx->ecx, sec_pkcs7_encoder_notify, p7ecx);
451 
452     /*
453      * This will encode everything up to the content bytes.  (The notify
454      * function will then cause the encoding to stop there.)  Then our
455      * caller can start passing contents bytes to our Update, which we
456      * will pass along.
457      */
458     rv = SEC_ASN1EncoderUpdate(p7ecx->ecx, NULL, 0);
459     if (rv != SECSuccess) {
460         PORT_Free(p7ecx);
461         return NULL;
462     }
463 
464     return p7ecx;
465 }
466 
467 /*
468  * XXX If/when we support nested contents, this needs to be revised.
469  */
470 static SECStatus
sec_pkcs7_encoder_work_data(SEC_PKCS7EncoderContext * p7ecx,SECItem * dest,const unsigned char * data,unsigned long len,PRBool final)471 sec_pkcs7_encoder_work_data(SEC_PKCS7EncoderContext *p7ecx, SECItem *dest,
472                             const unsigned char *data, unsigned long len,
473                             PRBool final)
474 {
475     unsigned char *buf = NULL;
476     SECStatus rv;
477 
478     rv = SECSuccess; /* may as well be optimistic */
479 
480     /*
481      * We should really have data to process, or we should be trying
482      * to finish/flush the last block.  (This is an overly paranoid
483      * check since all callers are in this file and simple inspection
484      * proves they do it right.  But it could find a bug in future
485      * modifications/development, that is why it is here.)
486      */
487     PORT_Assert((data != NULL && len) || final);
488 
489     /*
490      * Update the running digest.
491      * XXX This needs modification if/when we handle multiple digests.
492      */
493     if (len && p7ecx->digestobj != NULL) {
494         (*p7ecx->digestobj->update)(p7ecx->digestcx, data, len);
495     }
496 
497     /*
498      * Encrypt this chunk.
499      */
500     if (p7ecx->encryptobj != NULL) {
501         /* XXX the following lengths should all be longs? */
502         unsigned int inlen;  /* length of data being encrypted */
503         unsigned int outlen; /* length of encrypted data */
504         unsigned int buflen; /* length available for encrypted data */
505 
506         inlen = len;
507         buflen = sec_PKCS7EncryptLength(p7ecx->encryptobj, inlen, final);
508         if (buflen == 0) {
509             /*
510              * No output is expected, but the input data may be buffered
511              * so we still have to call Encrypt.
512              */
513             rv = sec_PKCS7Encrypt(p7ecx->encryptobj, NULL, NULL, 0,
514                                   data, inlen, final);
515             if (final) {
516                 len = 0;
517                 goto done;
518             }
519             return rv;
520         }
521 
522         if (dest != NULL)
523             buf = (unsigned char *)PORT_ArenaAlloc(p7ecx->cinfo->poolp, buflen);
524         else
525             buf = (unsigned char *)PORT_Alloc(buflen);
526 
527         if (buf == NULL) {
528             rv = SECFailure;
529         } else {
530             rv = sec_PKCS7Encrypt(p7ecx->encryptobj, buf, &outlen, buflen,
531                                   data, inlen, final);
532             data = buf;
533             len = outlen;
534         }
535         if (rv != SECSuccess) {
536             if (final)
537                 goto done;
538             return rv;
539         }
540     }
541 
542     if (p7ecx->ecx != NULL) {
543         /*
544          * Encode the contents bytes.
545          */
546         if (len) {
547             rv = SEC_ASN1EncoderUpdate(p7ecx->ecx, (const char *)data, len);
548         }
549     }
550 
551 done:
552     if (p7ecx->encryptobj != NULL) {
553         if (final)
554             sec_PKCS7DestroyEncryptObject(p7ecx->encryptobj);
555         if (dest != NULL) {
556             dest->data = buf;
557             dest->len = len;
558         } else if (buf != NULL) {
559             PORT_Free(buf);
560         }
561     }
562 
563     if (final && p7ecx->digestobj != NULL) {
564         SECItem *digest, **digests, ***digestsp;
565         unsigned char *digdata;
566         SECOidTag kind;
567 
568         kind = SEC_PKCS7ContentType(p7ecx->cinfo);
569         switch (kind) {
570             default:
571                 PORT_Assert(0);
572                 return SECFailure;
573             case SEC_OID_PKCS7_DIGESTED_DATA:
574                 digest = &(p7ecx->cinfo->content.digestedData->digest);
575                 digestsp = NULL;
576                 break;
577             case SEC_OID_PKCS7_SIGNED_DATA:
578                 digest = NULL;
579                 digestsp = &(p7ecx->cinfo->content.signedData->digests);
580                 break;
581             case SEC_OID_PKCS7_SIGNED_ENVELOPED_DATA:
582                 digest = NULL;
583                 digestsp = &(p7ecx->cinfo->content.signedAndEnvelopedData->digests);
584                 break;
585         }
586 
587         digdata = (unsigned char *)PORT_ArenaAlloc(p7ecx->cinfo->poolp,
588                                                    p7ecx->digestobj->length);
589         if (digdata == NULL)
590             return SECFailure;
591 
592         if (digestsp != NULL) {
593             PORT_Assert(digest == NULL);
594 
595             digest = (SECItem *)PORT_ArenaAlloc(p7ecx->cinfo->poolp,
596                                                 sizeof(SECItem));
597             digests = (SECItem **)PORT_ArenaAlloc(p7ecx->cinfo->poolp,
598                                                   2 * sizeof(SECItem *));
599             if (digests == NULL || digest == NULL)
600                 return SECFailure;
601 
602             digests[0] = digest;
603             digests[1] = NULL;
604 
605             *digestsp = digests;
606         }
607 
608         PORT_Assert(digest != NULL);
609 
610         digest->data = digdata;
611         digest->len = p7ecx->digestobj->length;
612 
613         (*p7ecx->digestobj->end)(p7ecx->digestcx, digest->data,
614                                  &(digest->len), digest->len);
615         (*p7ecx->digestobj->destroy)(p7ecx->digestcx, PR_TRUE);
616     }
617 
618     return rv;
619 }
620 
621 SECStatus
SEC_PKCS7EncoderUpdate(SEC_PKCS7EncoderContext * p7ecx,const char * data,unsigned long len)622 SEC_PKCS7EncoderUpdate(SEC_PKCS7EncoderContext *p7ecx,
623                        const char *data, unsigned long len)
624 {
625     /* XXX Error handling needs help.  Return what?  Do "Finish" on failure? */
626     return sec_pkcs7_encoder_work_data(p7ecx, NULL,
627                                        (const unsigned char *)data, len,
628                                        PR_FALSE);
629 }
630 
631 static SECStatus
sec_pkcs7_encoder_sig_and_certs(SEC_PKCS7ContentInfo * cinfo,SECKEYGetPasswordKey pwfn,void * pwfnarg)632 sec_pkcs7_encoder_sig_and_certs(SEC_PKCS7ContentInfo *cinfo,
633                                 SECKEYGetPasswordKey pwfn, void *pwfnarg)
634 {
635     SECOidTag kind;
636     CERTCertificate **certs;
637     CERTCertificateList **certlists;
638     SECAlgorithmID **digestalgs;
639     SECItem **digests;
640     SEC_PKCS7SignerInfo *signerinfo, **signerinfos;
641     SECItem **rawcerts, ***rawcertsp;
642     PLArenaPool *poolp;
643     int certcount;
644     int ci, cli, rci, si;
645 
646     kind = SEC_PKCS7ContentType(cinfo);
647     switch (kind) {
648         default:
649         case SEC_OID_PKCS7_DATA:
650         case SEC_OID_PKCS7_DIGESTED_DATA:
651         case SEC_OID_PKCS7_ENCRYPTED_DATA:
652         case SEC_OID_PKCS7_ENVELOPED_DATA:
653             certs = NULL;
654             certlists = NULL;
655             digestalgs = NULL;
656             digests = NULL;
657             signerinfos = NULL;
658             rawcertsp = NULL;
659             break;
660         case SEC_OID_PKCS7_SIGNED_DATA: {
661             SEC_PKCS7SignedData *sdp;
662 
663             sdp = cinfo->content.signedData;
664             certs = sdp->certs;
665             certlists = sdp->certLists;
666             digestalgs = sdp->digestAlgorithms;
667             digests = sdp->digests;
668             signerinfos = sdp->signerInfos;
669             rawcertsp = &(sdp->rawCerts);
670         } break;
671         case SEC_OID_PKCS7_SIGNED_ENVELOPED_DATA: {
672             SEC_PKCS7SignedAndEnvelopedData *saedp;
673 
674             saedp = cinfo->content.signedAndEnvelopedData;
675             certs = saedp->certs;
676             certlists = saedp->certLists;
677             digestalgs = saedp->digestAlgorithms;
678             digests = saedp->digests;
679             signerinfos = saedp->signerInfos;
680             rawcertsp = &(saedp->rawCerts);
681         } break;
682     }
683 
684     if (certs == NULL && certlists == NULL && signerinfos == NULL)
685         return SECSuccess; /* nothing for us to do! */
686 
687     poolp = cinfo->poolp;
688     certcount = 0;
689 
690     if (signerinfos != NULL) {
691         SECOidTag digestalgtag;
692         int di;
693         SECStatus rv;
694         CERTCertificate *cert;
695         SECKEYPrivateKey *privkey;
696         SECItem signature;
697         SECOidTag signalgtag;
698 
699         PORT_Assert(digestalgs != NULL && digests != NULL);
700 
701         /*
702          * If one fails, we bail right then.  If we want to continue and
703          * try to do subsequent signatures, this loop, and the departures
704          * from it, will need to be reworked.
705          */
706         for (si = 0; signerinfos[si] != NULL; si++) {
707 
708             signerinfo = signerinfos[si];
709 
710             /* find right digest */
711             digestalgtag = SECOID_GetAlgorithmTag(&(signerinfo->digestAlg));
712             for (di = 0; digestalgs[di] != NULL; di++) {
713                 /* XXX Should I be comparing more than the tag? */
714                 if (digestalgtag == SECOID_GetAlgorithmTag(digestalgs[di]))
715                     break;
716             }
717             if (digestalgs[di] == NULL) {
718                 /* XXX oops; do what? set an error? */
719                 return SECFailure;
720             }
721             PORT_Assert(digests[di] != NULL);
722 
723             cert = signerinfo->cert;
724             privkey = PK11_FindKeyByAnyCert(cert, pwfnarg);
725             if (privkey == NULL)
726                 return SECFailure;
727 
728             /*
729              * XXX I think there should be a cert-level interface for this,
730              * so that I do not have to know about subjectPublicKeyInfo...
731              */
732             signalgtag = SECOID_GetAlgorithmTag(&(cert->subjectPublicKeyInfo.algorithm));
733 
734             if (signerinfo->authAttr != NULL) {
735                 SEC_PKCS7Attribute *attr;
736                 SECItem encoded_attrs;
737                 SECItem *dummy;
738                 SECOidTag algid;
739 
740                 /*
741                  * First, find and fill in the message digest attribute.
742                  */
743                 attr = sec_PKCS7FindAttribute(signerinfo->authAttr,
744                                               SEC_OID_PKCS9_MESSAGE_DIGEST,
745                                               PR_TRUE);
746                 PORT_Assert(attr != NULL);
747                 if (attr == NULL) {
748                     SECKEY_DestroyPrivateKey(privkey);
749                     return SECFailure;
750                 }
751 
752                 /*
753                  * XXX The second half of the following assertion prevents
754                  * the encoder from being called twice on the same content.
755                  * Either just remove the second half the assertion, or
756                  * change the code to check if the value already there is
757                  * the same as digests[di], whichever seems more right.
758                  */
759                 PORT_Assert(attr->values != NULL && attr->values[0] == NULL);
760                 attr->values[0] = digests[di];
761 
762                 /*
763                  * Before encoding, reorder the attributes so that when they
764                  * are encoded, they will be conforming DER, which is required
765                  * to have a specific order and that is what must be used for
766                  * the hash/signature.  We do this here, rather than building
767                  * it into EncodeAttributes, because we do not want to do
768                  * such reordering on incoming messages (which also uses
769                  * EncodeAttributes) or our old signatures (and other "broken"
770                  * implementations) will not verify.  So, we want to guarantee
771                  * that we send out good DER encodings of attributes, but not
772                  * to expect to receive them.
773                  */
774                 rv = sec_PKCS7ReorderAttributes(signerinfo->authAttr);
775                 if (rv != SECSuccess) {
776                     SECKEY_DestroyPrivateKey(privkey);
777                     return SECFailure;
778                 }
779 
780                 encoded_attrs.data = NULL;
781                 encoded_attrs.len = 0;
782                 dummy = sec_PKCS7EncodeAttributes(NULL, &encoded_attrs,
783                                                   &(signerinfo->authAttr));
784                 if (dummy == NULL) {
785                     SECKEY_DestroyPrivateKey(privkey);
786                     return SECFailure;
787                 }
788 
789                 algid = SEC_GetSignatureAlgorithmOidTag(privkey->keyType,
790                                                         digestalgtag);
791                 if (algid == SEC_OID_UNKNOWN) {
792                     PORT_SetError(SEC_ERROR_INVALID_ALGORITHM);
793                     SECKEY_DestroyPrivateKey(privkey);
794                     return SECFailure;
795                 }
796                 rv = SEC_SignData(&signature,
797                                   encoded_attrs.data, encoded_attrs.len,
798                                   privkey,
799                                   algid);
800                 SECITEM_FreeItem(&encoded_attrs, PR_FALSE);
801             } else {
802                 rv = SGN_Digest(privkey, digestalgtag, &signature,
803                                 digests[di]);
804             }
805 
806             SECKEY_DestroyPrivateKey(privkey);
807 
808             if (rv != SECSuccess)
809                 return rv;
810 
811             rv = SECITEM_CopyItem(poolp, &(signerinfo->encDigest), &signature);
812             if (rv != SECSuccess)
813                 return rv;
814 
815             SECITEM_FreeItem(&signature, PR_FALSE);
816 
817             rv = SECOID_SetAlgorithmID(poolp, &(signerinfo->digestEncAlg),
818                                        signalgtag, NULL);
819             if (rv != SECSuccess)
820                 return SECFailure;
821 
822             /*
823              * Count the cert chain for this signer.
824              */
825             if (signerinfo->certList != NULL)
826                 certcount += signerinfo->certList->len;
827         }
828     }
829 
830     if (certs != NULL) {
831         for (ci = 0; certs[ci] != NULL; ci++)
832             certcount++;
833     }
834 
835     if (certlists != NULL) {
836         for (cli = 0; certlists[cli] != NULL; cli++)
837             certcount += certlists[cli]->len;
838     }
839 
840     if (certcount == 0)
841         return SECSuccess; /* signing done; no certs */
842 
843     /*
844      * Combine all of the certs and cert chains into rawcerts.
845      * Note: certcount is an upper bound; we may not need that many slots
846      * but we will allocate anyway to avoid having to do another pass.
847      * (The temporary space saving is not worth it.)
848      */
849     rawcerts = (SECItem **)PORT_ArenaAlloc(poolp,
850                                            (certcount + 1) * sizeof(SECItem *));
851     if (rawcerts == NULL)
852         return SECFailure;
853 
854     /*
855      * XXX Want to check for duplicates and not add *any* cert that is
856      * already in the set.  This will be more important when we start
857      * dealing with larger sets of certs, dual-key certs (signing and
858      * encryption), etc.  For the time being we can slide by...
859      */
860     rci = 0;
861     if (signerinfos != NULL) {
862         for (si = 0; signerinfos[si] != NULL; si++) {
863             signerinfo = signerinfos[si];
864             for (ci = 0; ci < signerinfo->certList->len; ci++)
865                 rawcerts[rci++] = &(signerinfo->certList->certs[ci]);
866         }
867     }
868 
869     if (certs != NULL) {
870         for (ci = 0; certs[ci] != NULL; ci++)
871             rawcerts[rci++] = &(certs[ci]->derCert);
872     }
873 
874     if (certlists != NULL) {
875         for (cli = 0; certlists[cli] != NULL; cli++) {
876             for (ci = 0; ci < certlists[cli]->len; ci++)
877                 rawcerts[rci++] = &(certlists[cli]->certs[ci]);
878         }
879     }
880 
881     rawcerts[rci] = NULL;
882     *rawcertsp = rawcerts;
883 
884     return SECSuccess;
885 }
886 
887 SECStatus
SEC_PKCS7EncoderFinish(SEC_PKCS7EncoderContext * p7ecx,SECKEYGetPasswordKey pwfn,void * pwfnarg)888 SEC_PKCS7EncoderFinish(SEC_PKCS7EncoderContext *p7ecx,
889                        SECKEYGetPasswordKey pwfn, void *pwfnarg)
890 {
891     SECStatus rv;
892 
893     /*
894      * Flush out any remaining data.
895      */
896     rv = sec_pkcs7_encoder_work_data(p7ecx, NULL, NULL, 0, PR_TRUE);
897 
898     /*
899      * Turn off streaming stuff.
900      */
901     SEC_ASN1EncoderClearTakeFromBuf(p7ecx->ecx);
902     SEC_ASN1EncoderClearStreaming(p7ecx->ecx);
903 
904     if (rv != SECSuccess)
905         goto loser;
906 
907     rv = sec_pkcs7_encoder_sig_and_certs(p7ecx->cinfo, pwfn, pwfnarg);
908     if (rv != SECSuccess)
909         goto loser;
910 
911     rv = SEC_ASN1EncoderUpdate(p7ecx->ecx, NULL, 0);
912 
913 loser:
914     SEC_ASN1EncoderFinish(p7ecx->ecx);
915     PORT_Free(p7ecx);
916     return rv;
917 }
918 
919 /*
920  * Abort the ASN.1 stream. Used by pkcs 12
921  */
922 void
SEC_PKCS7EncoderAbort(SEC_PKCS7EncoderContext * p7ecx,int error)923 SEC_PKCS7EncoderAbort(SEC_PKCS7EncoderContext *p7ecx, int error)
924 {
925     PORT_Assert(p7ecx);
926     SEC_ASN1EncoderAbort(p7ecx->ecx, error);
927 }
928 
929 /*
930  * After this routine is called, the entire PKCS7 contentInfo is ready
931  * to be encoded.  This is used internally, but can also be called from
932  * elsewhere for those who want to be able to just have pointers to
933  * the ASN1 template for pkcs7 contentInfo built into their own encodings.
934  */
935 SECStatus
SEC_PKCS7PrepareForEncode(SEC_PKCS7ContentInfo * cinfo,PK11SymKey * bulkkey,SECKEYGetPasswordKey pwfn,void * pwfnarg)936 SEC_PKCS7PrepareForEncode(SEC_PKCS7ContentInfo *cinfo,
937                           PK11SymKey *bulkkey,
938                           SECKEYGetPasswordKey pwfn,
939                           void *pwfnarg)
940 {
941     SEC_PKCS7EncoderContext *p7ecx;
942     SECItem *content, *enc_content;
943     SECStatus rv;
944 
945     p7ecx = sec_pkcs7_encoder_start_contexts(cinfo, bulkkey);
946     if (p7ecx == NULL)
947         return SECFailure;
948 
949     content = SEC_PKCS7GetContent(cinfo);
950 
951     if (p7ecx->encryptobj != NULL) {
952         SECOidTag kind;
953         SEC_PKCS7EncryptedContentInfo *enccinfo;
954 
955         kind = SEC_PKCS7ContentType(p7ecx->cinfo);
956         switch (kind) {
957             default:
958                 PORT_Assert(0);
959                 rv = SECFailure;
960                 goto loser;
961             case SEC_OID_PKCS7_ENCRYPTED_DATA:
962                 enccinfo = &(p7ecx->cinfo->content.encryptedData->encContentInfo);
963                 break;
964             case SEC_OID_PKCS7_ENVELOPED_DATA:
965                 enccinfo = &(p7ecx->cinfo->content.envelopedData->encContentInfo);
966                 break;
967             case SEC_OID_PKCS7_SIGNED_ENVELOPED_DATA:
968                 enccinfo = &(p7ecx->cinfo->content.signedAndEnvelopedData->encContentInfo);
969                 break;
970         }
971         enc_content = &(enccinfo->encContent);
972     } else {
973         enc_content = NULL;
974     }
975 
976     if (content != NULL && content->data != NULL && content->len) {
977         rv = sec_pkcs7_encoder_work_data(p7ecx, enc_content,
978                                          content->data, content->len, PR_TRUE);
979         if (rv != SECSuccess)
980             goto loser;
981     }
982 
983     rv = sec_pkcs7_encoder_sig_and_certs(cinfo, pwfn, pwfnarg);
984 
985 loser:
986     PORT_Free(p7ecx);
987     return rv;
988 }
989 
990 /*
991  * Encode a PKCS7 object, in one shot.  All necessary components
992  * of the object must already be specified.  Either the data has
993  * already been included (via SetContent), or the data is detached,
994  * or there is no data at all (certs-only).
995  *
996  * "cinfo" specifies the object to be encoded.
997  *
998  * "outputfn" is where the encoded bytes will be passed.
999  *
1000  * "outputarg" is an opaque argument to the above callback.
1001  *
1002  * "bulkkey" specifies the bulk encryption key to use.   This argument
1003  * can be NULL if no encryption is being done, or if the bulk key should
1004  * be generated internally (usually the case for EnvelopedData but never
1005  * for EncryptedData, which *must* provide a bulk encryption key).
1006  *
1007  * "pwfn" is a callback for getting the password which protects the
1008  * private key of the signer.  This argument can be NULL if it is known
1009  * that no signing is going to be done.
1010  *
1011  * "pwfnarg" is an opaque argument to the above callback.
1012  */
1013 SECStatus
SEC_PKCS7Encode(SEC_PKCS7ContentInfo * cinfo,SEC_PKCS7EncoderOutputCallback outputfn,void * outputarg,PK11SymKey * bulkkey,SECKEYGetPasswordKey pwfn,void * pwfnarg)1014 SEC_PKCS7Encode(SEC_PKCS7ContentInfo *cinfo,
1015                 SEC_PKCS7EncoderOutputCallback outputfn,
1016                 void *outputarg,
1017                 PK11SymKey *bulkkey,
1018                 SECKEYGetPasswordKey pwfn,
1019                 void *pwfnarg)
1020 {
1021     SECStatus rv;
1022 
1023     rv = SEC_PKCS7PrepareForEncode(cinfo, bulkkey, pwfn, pwfnarg);
1024     if (rv == SECSuccess) {
1025         struct sec_pkcs7_encoder_output outputcx;
1026 
1027         outputcx.outputfn = outputfn;
1028         outputcx.outputarg = outputarg;
1029 
1030         rv = SEC_ASN1Encode(cinfo, sec_PKCS7ContentInfoTemplate,
1031                             sec_pkcs7_encoder_out, &outputcx);
1032     }
1033 
1034     return rv;
1035 }
1036 
1037 /*
1038  * Encode a PKCS7 object, in one shot.  All necessary components
1039  * of the object must already be specified.  Either the data has
1040  * already been included (via SetContent), or the data is detached,
1041  * or there is no data at all (certs-only).  The output, rather than
1042  * being passed to an output function as is done above, is all put
1043  * into a SECItem.
1044  *
1045  * "pool" specifies a pool from which to allocate the result.
1046  * It can be NULL, in which case memory is allocated generically.
1047  *
1048  * "dest" specifies a SECItem in which to put the result data.
1049  * It can be NULL, in which case the entire item is allocated, too.
1050  *
1051  * "cinfo" specifies the object to be encoded.
1052  *
1053  * "bulkkey" specifies the bulk encryption key to use.   This argument
1054  * can be NULL if no encryption is being done, or if the bulk key should
1055  * be generated internally (usually the case for EnvelopedData but never
1056  * for EncryptedData, which *must* provide a bulk encryption key).
1057  *
1058  * "pwfn" is a callback for getting the password which protects the
1059  * private key of the signer.  This argument can be NULL if it is known
1060  * that no signing is going to be done.
1061  *
1062  * "pwfnarg" is an opaque argument to the above callback.
1063  */
1064 SECItem *
SEC_PKCS7EncodeItem(PLArenaPool * pool,SECItem * dest,SEC_PKCS7ContentInfo * cinfo,PK11SymKey * bulkkey,SECKEYGetPasswordKey pwfn,void * pwfnarg)1065 SEC_PKCS7EncodeItem(PLArenaPool *pool,
1066                     SECItem *dest,
1067                     SEC_PKCS7ContentInfo *cinfo,
1068                     PK11SymKey *bulkkey,
1069                     SECKEYGetPasswordKey pwfn,
1070                     void *pwfnarg)
1071 {
1072     SECStatus rv;
1073 
1074     rv = SEC_PKCS7PrepareForEncode(cinfo, bulkkey, pwfn, pwfnarg);
1075     if (rv != SECSuccess)
1076         return NULL;
1077 
1078     return SEC_ASN1EncodeItem(pool, dest, cinfo, sec_PKCS7ContentInfoTemplate);
1079 }
1080