1 /* ***** BEGIN LICENSE BLOCK *****
2 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
4 * The contents of this file are subject to the Mozilla Public License Version
5 * 1.1 (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 * http://www.mozilla.org/MPL/
9 * Software distributed under the License is distributed on an "AS IS" basis,
10 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
11 * for the specific language governing rights and limitations under the
14 * The Original Code is the Netscape security libraries.
16 * The Initial Developer of the Original Code is
17 * Netscape Communications Corporation.
18 * Portions created by the Initial Developer are Copyright (C) 1994-2000
19 * the Initial Developer. All Rights Reserved.
23 * Alternatively, the contents of this file may be used under the terms of
24 * either the GNU General Public License Version 2 or later (the "GPL"), or
25 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
26 * in which case the provisions of the GPL or the LGPL are applicable instead
27 * of those above. If you wish to allow use of your version of this file only
28 * under the terms of either the GPL or the LGPL, and not to allow others to
29 * use your version of this file under the terms of the MPL, indicate your
30 * decision by deleting the provisions above and replace them with the notice
31 * and other provisions required by the GPL or the LGPL. If you do not delete
32 * the provisions above, a recipient may use your version of this file under
33 * the terms of any one of the MPL, the GPL or the LGPL.
35 * ***** END LICENSE BLOCK ***** */
40 * $Id: p7create.c,v 1.10 2012/03/19 22:16:34 kaie%kuix.de Exp $
55 const int NSS_PBE_DEFAULT_ITERATION_COUNT = 2000; /* used in p12e.c too */
58 sec_pkcs7_init_content_info (SEC_PKCS7ContentInfo *cinfo, PRArenaPool *poolp,
59 SECOidTag kind, PRBool detached)
66 PORT_Assert (cinfo != NULL && poolp != NULL);
67 if (cinfo == NULL || poolp == NULL)
70 cinfo->contentTypeTag = SECOID_FindOIDByTag (kind);
71 PORT_Assert (cinfo->contentTypeTag
72 && cinfo->contentTypeTag->offset == kind);
74 rv = SECITEM_CopyItem (poolp, &(cinfo->contentType),
75 &(cinfo->contentTypeTag->oid));
84 case SEC_OID_PKCS7_DATA:
85 thing = PORT_ArenaZAlloc (poolp, sizeof(SECItem));
86 cinfo->content.data = (SECItem*)thing;
90 case SEC_OID_PKCS7_DIGESTED_DATA:
91 thing = PORT_ArenaZAlloc (poolp, sizeof(SEC_PKCS7DigestedData));
92 cinfo->content.digestedData = (SEC_PKCS7DigestedData*)thing;
93 versionp = &(cinfo->content.digestedData->version);
94 version = SEC_PKCS7_DIGESTED_DATA_VERSION;
96 case SEC_OID_PKCS7_ENCRYPTED_DATA:
97 thing = PORT_ArenaZAlloc (poolp, sizeof(SEC_PKCS7EncryptedData));
98 cinfo->content.encryptedData = (SEC_PKCS7EncryptedData*)thing;
99 versionp = &(cinfo->content.encryptedData->version);
100 version = SEC_PKCS7_ENCRYPTED_DATA_VERSION;
102 case SEC_OID_PKCS7_ENVELOPED_DATA:
103 thing = PORT_ArenaZAlloc (poolp, sizeof(SEC_PKCS7EnvelopedData));
104 cinfo->content.envelopedData =
105 (SEC_PKCS7EnvelopedData*)thing;
106 versionp = &(cinfo->content.envelopedData->version);
107 version = SEC_PKCS7_ENVELOPED_DATA_VERSION;
109 case SEC_OID_PKCS7_SIGNED_DATA:
110 thing = PORT_ArenaZAlloc (poolp, sizeof(SEC_PKCS7SignedData));
111 cinfo->content.signedData =
112 (SEC_PKCS7SignedData*)thing;
113 versionp = &(cinfo->content.signedData->version);
114 version = SEC_PKCS7_SIGNED_DATA_VERSION;
116 case SEC_OID_PKCS7_SIGNED_ENVELOPED_DATA:
117 thing = PORT_ArenaZAlloc(poolp,sizeof(SEC_PKCS7SignedAndEnvelopedData));
118 cinfo->content.signedAndEnvelopedData =
119 (SEC_PKCS7SignedAndEnvelopedData*)thing;
120 versionp = &(cinfo->content.signedAndEnvelopedData->version);
121 version = SEC_PKCS7_SIGNED_AND_ENVELOPED_DATA_VERSION;
128 if (versionp != NULL) {
131 PORT_Assert (version >= 0);
132 dummy = SEC_ASN1EncodeInteger (poolp, versionp, version);
135 PORT_Assert (dummy == versionp);
142 static SEC_PKCS7ContentInfo *
143 sec_pkcs7_create_content_info (SECOidTag kind, PRBool detached,
144 SECKEYGetPasswordKey pwfn, void *pwfn_arg)
146 SEC_PKCS7ContentInfo *cinfo;
150 poolp = PORT_NewArena (1024); /* XXX what is right value? */
154 cinfo = (SEC_PKCS7ContentInfo*)PORT_ArenaZAlloc (poolp, sizeof(*cinfo));
156 PORT_FreeArena (poolp, PR_FALSE);
160 cinfo->poolp = poolp;
162 cinfo->pwfn_arg = pwfn_arg;
163 cinfo->created = PR_TRUE;
166 rv = sec_pkcs7_init_content_info (cinfo, poolp, kind, detached);
167 if (rv != SECSuccess) {
168 PORT_FreeArena (poolp, PR_FALSE);
177 * Add a signer to a PKCS7 thing, verifying the signature cert first.
178 * Any error returns SECFailure.
180 * XXX Right now this only adds the *first* signer. It fails if you try
181 * to add a second one -- this needs to be fixed.
184 sec_pkcs7_add_signer (SEC_PKCS7ContentInfo *cinfo,
185 CERTCertificate * cert,
186 SECCertUsage certusage,
187 CERTCertDBHandle * certdb,
188 SECOidTag digestalgtag,
189 SECItem * digestdata)
191 SEC_PKCS7SignerInfo *signerinfo, **signerinfos, ***signerinfosp;
192 SECAlgorithmID *digestalg, **digestalgs, ***digestalgsp;
193 SECItem *digest, **digests, ***digestsp;
199 kind = SEC_PKCS7ContentType (cinfo);
201 case SEC_OID_PKCS7_SIGNED_DATA:
203 SEC_PKCS7SignedData *sdp;
205 sdp = cinfo->content.signedData;
206 digestalgsp = &(sdp->digestAlgorithms);
207 digestsp = &(sdp->digests);
208 signerinfosp = &(sdp->signerInfos);
211 case SEC_OID_PKCS7_SIGNED_ENVELOPED_DATA:
213 SEC_PKCS7SignedAndEnvelopedData *saedp;
215 saedp = cinfo->content.signedAndEnvelopedData;
216 digestalgsp = &(saedp->digestAlgorithms);
217 digestsp = &(saedp->digests);
218 signerinfosp = &(saedp->signerInfos);
222 return SECFailure; /* XXX set an error? */
226 * XXX I think that CERT_VerifyCert should do this if *it* is passed
229 if (certdb == NULL) {
230 certdb = CERT_GetDefaultCertDB();
232 return SECFailure; /* XXX set an error? */
235 if (CERT_VerifyCert (certdb, cert, PR_TRUE, certusage, PR_Now(),
236 cinfo->pwfn_arg, NULL) != SECSuccess)
238 /* XXX Did CERT_VerifyCert set an error? */
243 * XXX This is the check that we do not already have a signer.
244 * This is not what we really want -- we want to allow this
245 * and *add* the new signer.
247 PORT_Assert (*signerinfosp == NULL
248 && *digestalgsp == NULL && *digestsp == NULL);
249 if (*signerinfosp != NULL || *digestalgsp != NULL || *digestsp != NULL)
252 mark = PORT_ArenaMark (cinfo->poolp);
254 signerinfo = (SEC_PKCS7SignerInfo*)PORT_ArenaZAlloc (cinfo->poolp,
255 sizeof(SEC_PKCS7SignerInfo));
256 if (signerinfo == NULL) {
257 PORT_ArenaRelease (cinfo->poolp, mark);
261 dummy = SEC_ASN1EncodeInteger (cinfo->poolp, &signerinfo->version,
262 SEC_PKCS7_SIGNER_INFO_VERSION);
264 PORT_ArenaRelease (cinfo->poolp, mark);
267 PORT_Assert (dummy == &signerinfo->version);
269 signerinfo->cert = CERT_DupCertificate (cert);
270 if (signerinfo->cert == NULL) {
271 PORT_ArenaRelease (cinfo->poolp, mark);
275 signerinfo->issuerAndSN = CERT_GetCertIssuerAndSN (cinfo->poolp, cert);
276 if (signerinfo->issuerAndSN == NULL) {
277 PORT_ArenaRelease (cinfo->poolp, mark);
281 rv = SECOID_SetAlgorithmID (cinfo->poolp, &signerinfo->digestAlg,
283 if (rv != SECSuccess) {
284 PORT_ArenaRelease (cinfo->poolp, mark);
289 * Okay, now signerinfo is all set. We just need to put it and its
290 * companions (another copy of the digest algorithm, and the digest
291 * itself if given) into the main structure.
293 * XXX If we are handling more than one signer, the following code
294 * needs to look through the digest algorithms already specified
295 * and see if the same one is there already. If it is, it does not
296 * need to be added again. Also, if it is there *and* the digest
297 * is not null, then the digest given should match the digest already
298 * specified -- if not, that is an error. Finally, the new signerinfo
299 * should be *added* to the set already found.
302 signerinfos = (SEC_PKCS7SignerInfo**)PORT_ArenaAlloc (cinfo->poolp,
303 2 * sizeof(SEC_PKCS7SignerInfo *));
304 if (signerinfos == NULL) {
305 PORT_ArenaRelease (cinfo->poolp, mark);
308 signerinfos[0] = signerinfo;
309 signerinfos[1] = NULL;
311 digestalg = PORT_ArenaZAlloc (cinfo->poolp, sizeof(SECAlgorithmID));
312 digestalgs = PORT_ArenaAlloc (cinfo->poolp, 2 * sizeof(SECAlgorithmID *));
313 if (digestalg == NULL || digestalgs == NULL) {
314 PORT_ArenaRelease (cinfo->poolp, mark);
317 rv = SECOID_SetAlgorithmID (cinfo->poolp, digestalg, digestalgtag, NULL);
318 if (rv != SECSuccess) {
319 PORT_ArenaRelease (cinfo->poolp, mark);
322 digestalgs[0] = digestalg;
323 digestalgs[1] = NULL;
325 if (digestdata != NULL) {
326 digest = (SECItem*)PORT_ArenaAlloc (cinfo->poolp, sizeof(SECItem));
327 digests = (SECItem**)PORT_ArenaAlloc (cinfo->poolp,
328 2 * sizeof(SECItem *));
329 if (digest == NULL || digests == NULL) {
330 PORT_ArenaRelease (cinfo->poolp, mark);
333 rv = SECITEM_CopyItem (cinfo->poolp, digest, digestdata);
334 if (rv != SECSuccess) {
335 PORT_ArenaRelease (cinfo->poolp, mark);
344 *signerinfosp = signerinfos;
345 *digestalgsp = digestalgs;
348 PORT_ArenaUnmark(cinfo->poolp, mark);
354 * Helper function for creating an empty signedData.
356 static SEC_PKCS7ContentInfo *
357 sec_pkcs7_create_signed_data (SECKEYGetPasswordKey pwfn, void *pwfn_arg)
359 SEC_PKCS7ContentInfo *cinfo;
360 SEC_PKCS7SignedData *sigd;
363 cinfo = sec_pkcs7_create_content_info (SEC_OID_PKCS7_SIGNED_DATA, PR_FALSE,
368 sigd = cinfo->content.signedData;
369 PORT_Assert (sigd != NULL);
372 * XXX Might we want to allow content types other than data?
373 * If so, via what interface?
375 rv = sec_pkcs7_init_content_info (&(sigd->contentInfo), cinfo->poolp,
376 SEC_OID_PKCS7_DATA, PR_TRUE);
377 if (rv != SECSuccess) {
378 SEC_PKCS7DestroyContentInfo (cinfo);
387 * Start a PKCS7 signing context.
389 * "cert" is the cert that will be used to sign the data. It will be
390 * checked for validity.
392 * "certusage" describes the signing usage (e.g. certUsageEmailSigner)
393 * XXX Maybe SECCertUsage should be split so that our caller just says
394 * "email" and *we* add the "signing" part -- otherwise our caller
395 * could be lying about the usage; we do not want to allow encryption
396 * certs for signing or vice versa.
398 * "certdb" is the cert database to use for verifying the cert.
399 * It can be NULL if a default database is available (like in the client).
401 * "digestalg" names the digest algorithm (e.g. SEC_OID_SHA1).
403 * "digest" is the actual digest of the data. It must be provided in
404 * the case of detached data or NULL if the content will be included.
406 * The return value can be passed to functions which add things to
407 * it like attributes, then eventually to SEC_PKCS7Encode() or to
408 * SEC_PKCS7EncoderStart() to create the encoded data, and finally to
409 * SEC_PKCS7DestroyContentInfo().
411 * An error results in a return value of NULL and an error set.
412 * (Retrieve specific errors via PORT_GetError()/XP_GetError().)
414 SEC_PKCS7ContentInfo *
415 SEC_PKCS7CreateSignedData (CERTCertificate *cert,
416 SECCertUsage certusage,
417 CERTCertDBHandle *certdb,
420 SECKEYGetPasswordKey pwfn, void *pwfn_arg)
422 SEC_PKCS7ContentInfo *cinfo;
425 cinfo = sec_pkcs7_create_signed_data (pwfn, pwfn_arg);
429 rv = sec_pkcs7_add_signer (cinfo, cert, certusage, certdb,
431 if (rv != SECSuccess) {
432 SEC_PKCS7DestroyContentInfo (cinfo);
440 static SEC_PKCS7Attribute *
441 sec_pkcs7_create_attribute (PRArenaPool *poolp, SECOidTag oidtag,
442 SECItem *value, PRBool encoded)
444 SEC_PKCS7Attribute *attr;
448 PORT_Assert (poolp != NULL);
449 mark = PORT_ArenaMark (poolp);
451 attr = (SEC_PKCS7Attribute*)PORT_ArenaAlloc (poolp,
452 sizeof(SEC_PKCS7Attribute));
456 attr->typeTag = SECOID_FindOIDByTag (oidtag);
457 if (attr->typeTag == NULL)
460 if (SECITEM_CopyItem (poolp, &(attr->type),
461 &(attr->typeTag->oid)) != SECSuccess)
464 values = (SECItem**)PORT_ArenaAlloc (poolp, 2 * sizeof(SECItem *));
471 copy = (SECItem*)PORT_ArenaAlloc (poolp, sizeof(SECItem));
475 if (SECITEM_CopyItem (poolp, copy, value) != SECSuccess)
483 attr->values = values;
484 attr->encoded = encoded;
486 PORT_ArenaUnmark (poolp, mark);
490 PORT_Assert (mark != NULL);
491 PORT_ArenaRelease (poolp, mark);
497 sec_pkcs7_add_attribute (SEC_PKCS7ContentInfo *cinfo,
498 SEC_PKCS7Attribute ***attrsp,
499 SEC_PKCS7Attribute *attr)
501 SEC_PKCS7Attribute **attrs;
505 PORT_Assert (SEC_PKCS7ContentType (cinfo) == SEC_OID_PKCS7_SIGNED_DATA);
506 if (SEC_PKCS7ContentType (cinfo) != SEC_OID_PKCS7_SIGNED_DATA)
514 * We already have some attributes, and just need to add this
519 * We should already have the *required* attributes, which were
520 * created/added at the same time the first attribute was added.
522 PORT_Assert (sec_PKCS7FindAttribute (attrs,
523 SEC_OID_PKCS9_CONTENT_TYPE,
525 PORT_Assert (sec_PKCS7FindAttribute (attrs,
526 SEC_OID_PKCS9_MESSAGE_DIGEST,
529 for (count = 0; attrs[count] != NULL; count++)
531 attrs = (SEC_PKCS7Attribute**)PORT_ArenaGrow (cinfo->poolp, attrs,
532 (count + 1) * sizeof(SEC_PKCS7Attribute *),
533 (count + 2) * sizeof(SEC_PKCS7Attribute *));
538 attrs[count+1] = NULL;
545 * This is the first time an attribute is going in.
546 * We need to create and add the required attributes, and then
547 * we will also add in the one our caller gave us.
551 * There are 2 required attributes, plus the one our caller wants
552 * to add, plus we always end with a NULL one. Thus, four slots.
554 attrs = (SEC_PKCS7Attribute**)PORT_ArenaAlloc (cinfo->poolp,
555 4 * sizeof(SEC_PKCS7Attribute *));
559 mark = PORT_ArenaMark (cinfo->poolp);
562 * First required attribute is the content type of the data
565 ct_value = &(cinfo->content.signedData->contentInfo.contentType);
566 attrs[0] = sec_pkcs7_create_attribute (cinfo->poolp,
567 SEC_OID_PKCS9_CONTENT_TYPE,
570 * Second required attribute is the message digest of the data
571 * being signed; we leave the value NULL for now (just create
572 * the place for it to go), and the encoder will fill it in later.
574 attrs[1] = sec_pkcs7_create_attribute (cinfo->poolp,
575 SEC_OID_PKCS9_MESSAGE_DIGEST,
577 if (attrs[0] == NULL || attrs[1] == NULL) {
578 PORT_ArenaRelease (cinfo->poolp, mark);
586 PORT_ArenaUnmark (cinfo->poolp, mark);
592 * Add the signing time to the authenticated (i.e. signed) attributes
593 * of "cinfo". This is expected to be included in outgoing signed
594 * messages for email (S/MIME) but is likely useful in other situations.
596 * This should only be added once; a second call will either do
597 * nothing or replace an old signing time with a newer one.
599 * XXX This will probably just shove the current time into "cinfo"
600 * but it will not actually get signed until the entire item is
601 * processed for encoding. Is this (expected to be small) delay okay?
603 * "cinfo" should be of type signedData (the only kind of pkcs7 data
604 * that is allowed authenticated attributes); SECFailure will be returned
608 SEC_PKCS7AddSigningTime (SEC_PKCS7ContentInfo *cinfo)
610 SEC_PKCS7SignerInfo **signerinfos;
611 SEC_PKCS7Attribute *attr;
616 PORT_Assert (SEC_PKCS7ContentType (cinfo) == SEC_OID_PKCS7_SIGNED_DATA);
617 if (SEC_PKCS7ContentType (cinfo) != SEC_OID_PKCS7_SIGNED_DATA)
620 signerinfos = cinfo->content.signedData->signerInfos;
622 /* There has to be a signer, or it makes no sense. */
623 if (signerinfos == NULL || signerinfos[0] == NULL)
626 rv = DER_EncodeTimeChoice(NULL, &stime, PR_Now());
627 if (rv != SECSuccess)
630 attr = sec_pkcs7_create_attribute (cinfo->poolp,
631 SEC_OID_PKCS9_SIGNING_TIME,
633 SECITEM_FreeItem (&stime, PR_FALSE);
639 for (si = 0; signerinfos[si] != NULL; si++) {
640 SEC_PKCS7Attribute *oattr;
642 oattr = sec_PKCS7FindAttribute (signerinfos[si]->authAttr,
643 SEC_OID_PKCS9_SIGNING_TIME, PR_FALSE);
644 PORT_Assert (oattr == NULL);
646 continue; /* XXX or would it be better to replace it? */
648 rv = sec_pkcs7_add_attribute (cinfo, &(signerinfos[si]->authAttr),
650 if (rv != SECSuccess)
651 break; /* could try to continue, but may as well give up now */
659 * Add the specified attribute to the authenticated (i.e. signed) attributes
660 * of "cinfo" -- "oidtag" describes the attribute and "value" is the
661 * value to be associated with it. NOTE! "value" must already be encoded;
662 * no interpretation of "oidtag" is done. Also, it is assumed that this
663 * signedData has only one signer -- if we ever need to add attributes
664 * when there is more than one signature, we need a way to specify *which*
665 * signature should get the attribute.
667 * XXX Technically, a signed attribute can have multiple values; if/when
668 * we ever need to support an attribute which takes multiple values, we
669 * either need to change this interface or create an AddSignedAttributeValue
670 * which can be called subsequently, and would then append a value.
672 * "cinfo" should be of type signedData (the only kind of pkcs7 data
673 * that is allowed authenticated attributes); SECFailure will be returned
677 SEC_PKCS7AddSignedAttribute (SEC_PKCS7ContentInfo *cinfo,
681 SEC_PKCS7SignerInfo **signerinfos;
682 SEC_PKCS7Attribute *attr;
684 PORT_Assert (SEC_PKCS7ContentType (cinfo) == SEC_OID_PKCS7_SIGNED_DATA);
685 if (SEC_PKCS7ContentType (cinfo) != SEC_OID_PKCS7_SIGNED_DATA)
688 signerinfos = cinfo->content.signedData->signerInfos;
691 * No signature or more than one means no deal.
693 if (signerinfos == NULL || signerinfos[0] == NULL || signerinfos[1] != NULL)
696 attr = sec_pkcs7_create_attribute (cinfo->poolp, oidtag, value, PR_TRUE);
700 return sec_pkcs7_add_attribute (cinfo, &(signerinfos[0]->authAttr), attr);
705 * Mark that the signer certificates and their issuing chain should
706 * be included in the encoded data. This is expected to be used
707 * in outgoing signed messages for email (S/MIME).
709 * "certdb" is the cert database to use for finding the chain.
710 * It can be NULL, meaning use the default database.
712 * "cinfo" should be of type signedData or signedAndEnvelopedData;
713 * SECFailure will be returned if it is not.
716 SEC_PKCS7IncludeCertChain (SEC_PKCS7ContentInfo *cinfo,
717 CERTCertDBHandle *certdb)
720 SEC_PKCS7SignerInfo *signerinfo, **signerinfos;
722 kind = SEC_PKCS7ContentType (cinfo);
724 case SEC_OID_PKCS7_SIGNED_DATA:
725 signerinfos = cinfo->content.signedData->signerInfos;
727 case SEC_OID_PKCS7_SIGNED_ENVELOPED_DATA:
728 signerinfos = cinfo->content.signedAndEnvelopedData->signerInfos;
731 return SECFailure; /* XXX set an error? */
734 if (signerinfos == NULL) /* no signer, no certs? */
735 return SECFailure; /* XXX set an error? */
737 if (certdb == NULL) {
738 certdb = CERT_GetDefaultCertDB();
739 if (certdb == NULL) {
740 PORT_SetError (SEC_ERROR_BAD_DATABASE);
745 /* XXX Should it be an error if we find no signerinfo or no certs? */
746 while ((signerinfo = *signerinfos++) != NULL) {
747 if (signerinfo->cert != NULL)
748 /* get the cert chain. don't send the root to avoid contamination
749 * of old clients with a new root that they don't trust
751 signerinfo->certList = CERT_CertChainFromCert (signerinfo->cert,
752 certUsageEmailSigner,
761 * Helper function to add a certificate chain for inclusion in the
762 * bag of certificates in a signedData.
765 sec_pkcs7_add_cert_chain (SEC_PKCS7ContentInfo *cinfo,
766 CERTCertificate *cert,
767 CERTCertDBHandle *certdb)
770 CERTCertificateList *certlist, **certlists, ***certlistsp;
773 kind = SEC_PKCS7ContentType (cinfo);
775 case SEC_OID_PKCS7_SIGNED_DATA:
777 SEC_PKCS7SignedData *sdp;
779 sdp = cinfo->content.signedData;
780 certlistsp = &(sdp->certLists);
783 case SEC_OID_PKCS7_SIGNED_ENVELOPED_DATA:
785 SEC_PKCS7SignedAndEnvelopedData *saedp;
787 saedp = cinfo->content.signedAndEnvelopedData;
788 certlistsp = &(saedp->certLists);
792 return SECFailure; /* XXX set an error? */
795 if (certdb == NULL) {
796 certdb = CERT_GetDefaultCertDB();
797 if (certdb == NULL) {
798 PORT_SetError (SEC_ERROR_BAD_DATABASE);
803 certlist = CERT_CertChainFromCert (cert, certUsageEmailSigner, PR_FALSE);
804 if (certlist == NULL)
807 certlists = *certlistsp;
808 if (certlists == NULL) {
810 certlists = (CERTCertificateList**)PORT_ArenaAlloc (cinfo->poolp,
811 2 * sizeof(CERTCertificateList *));
813 for (count = 0; certlists[count] != NULL; count++)
815 PORT_Assert (count); /* should be at least one already */
816 certlists = (CERTCertificateList**)PORT_ArenaGrow (cinfo->poolp,
818 (count + 1) * sizeof(CERTCertificateList *),
819 (count + 2) * sizeof(CERTCertificateList *));
822 if (certlists == NULL) {
823 CERT_DestroyCertificateList (certlist);
827 certlists[count] = certlist;
828 certlists[count + 1] = NULL;
830 *certlistsp = certlists;
837 * Helper function to add a certificate for inclusion in the bag of
838 * certificates in a signedData.
841 sec_pkcs7_add_certificate (SEC_PKCS7ContentInfo *cinfo,
842 CERTCertificate *cert)
845 CERTCertificate **certs, ***certsp;
848 kind = SEC_PKCS7ContentType (cinfo);
850 case SEC_OID_PKCS7_SIGNED_DATA:
852 SEC_PKCS7SignedData *sdp;
854 sdp = cinfo->content.signedData;
855 certsp = &(sdp->certs);
858 case SEC_OID_PKCS7_SIGNED_ENVELOPED_DATA:
860 SEC_PKCS7SignedAndEnvelopedData *saedp;
862 saedp = cinfo->content.signedAndEnvelopedData;
863 certsp = &(saedp->certs);
867 return SECFailure; /* XXX set an error? */
870 cert = CERT_DupCertificate (cert);
877 certs = (CERTCertificate**)PORT_ArenaAlloc (cinfo->poolp,
878 2 * sizeof(CERTCertificate *));
880 for (count = 0; certs[count] != NULL; count++)
882 PORT_Assert (count); /* should be at least one already */
883 certs = (CERTCertificate**)PORT_ArenaGrow (cinfo->poolp, certs,
884 (count + 1) * sizeof(CERTCertificate *),
885 (count + 2) * sizeof(CERTCertificate *));
889 CERT_DestroyCertificate (cert);
894 certs[count + 1] = NULL;
903 * Create a PKCS7 certs-only container.
905 * "cert" is the (first) cert that will be included.
907 * "include_chain" specifies whether the entire chain for "cert" should
910 * "certdb" is the cert database to use for finding the chain.
911 * It can be NULL in when "include_chain" is false, or when meaning
912 * use the default database.
914 * More certs and chains can be added via AddCertificate and AddCertChain.
916 * An error results in a return value of NULL and an error set.
917 * (Retrieve specific errors via PORT_GetError()/XP_GetError().)
919 SEC_PKCS7ContentInfo *
920 SEC_PKCS7CreateCertsOnly (CERTCertificate *cert,
921 PRBool include_chain,
922 CERTCertDBHandle *certdb)
924 SEC_PKCS7ContentInfo *cinfo;
927 cinfo = sec_pkcs7_create_signed_data (NULL, NULL);
932 rv = sec_pkcs7_add_cert_chain (cinfo, cert, certdb);
934 rv = sec_pkcs7_add_certificate (cinfo, cert);
936 if (rv != SECSuccess) {
937 SEC_PKCS7DestroyContentInfo (cinfo);
946 * Add "cert" and its entire chain to the set of certs included in "cinfo".
948 * "certdb" is the cert database to use for finding the chain.
949 * It can be NULL, meaning use the default database.
951 * "cinfo" should be of type signedData or signedAndEnvelopedData;
952 * SECFailure will be returned if it is not.
955 SEC_PKCS7AddCertChain (SEC_PKCS7ContentInfo *cinfo,
956 CERTCertificate *cert,
957 CERTCertDBHandle *certdb)
961 kind = SEC_PKCS7ContentType (cinfo);
962 if (kind != SEC_OID_PKCS7_SIGNED_DATA
963 && kind != SEC_OID_PKCS7_SIGNED_ENVELOPED_DATA)
964 return SECFailure; /* XXX set an error? */
966 return sec_pkcs7_add_cert_chain (cinfo, cert, certdb);
971 * Add "cert" to the set of certs included in "cinfo".
973 * "cinfo" should be of type signedData or signedAndEnvelopedData;
974 * SECFailure will be returned if it is not.
977 SEC_PKCS7AddCertificate (SEC_PKCS7ContentInfo *cinfo, CERTCertificate *cert)
981 kind = SEC_PKCS7ContentType (cinfo);
982 if (kind != SEC_OID_PKCS7_SIGNED_DATA
983 && kind != SEC_OID_PKCS7_SIGNED_ENVELOPED_DATA)
984 return SECFailure; /* XXX set an error? */
986 return sec_pkcs7_add_certificate (cinfo, cert);
991 sec_pkcs7_init_encrypted_content_info (SEC_PKCS7EncryptedContentInfo *enccinfo,
993 SECOidTag kind, PRBool detached,
994 SECOidTag encalg, int keysize)
998 PORT_Assert (enccinfo != NULL && poolp != NULL);
999 if (enccinfo == NULL || poolp == NULL)
1003 * XXX Some day we may want to allow for other kinds. That needs
1004 * more work and modifications to the creation interface, etc.
1005 * For now, allow but notice callers who pass in other kinds.
1006 * They are responsible for creating the inner type and encoding,
1007 * if it is other than DATA.
1009 PORT_Assert (kind == SEC_OID_PKCS7_DATA);
1011 enccinfo->contentTypeTag = SECOID_FindOIDByTag (kind);
1012 PORT_Assert (enccinfo->contentTypeTag
1013 && enccinfo->contentTypeTag->offset == kind);
1015 rv = SECITEM_CopyItem (poolp, &(enccinfo->contentType),
1016 &(enccinfo->contentTypeTag->oid));
1017 if (rv != SECSuccess)
1020 /* Save keysize and algorithm for later. */
1021 enccinfo->keysize = keysize;
1022 enccinfo->encalg = encalg;
1029 * Add a recipient to a PKCS7 thing, verifying their cert first.
1030 * Any error returns SECFailure.
1033 sec_pkcs7_add_recipient (SEC_PKCS7ContentInfo *cinfo,
1034 CERTCertificate *cert,
1035 SECCertUsage certusage,
1036 CERTCertDBHandle *certdb)
1039 SEC_PKCS7RecipientInfo *recipientinfo, **recipientinfos, ***recipientinfosp;
1044 kind = SEC_PKCS7ContentType (cinfo);
1046 case SEC_OID_PKCS7_ENVELOPED_DATA:
1048 SEC_PKCS7EnvelopedData *edp;
1050 edp = cinfo->content.envelopedData;
1051 recipientinfosp = &(edp->recipientInfos);
1054 case SEC_OID_PKCS7_SIGNED_ENVELOPED_DATA:
1056 SEC_PKCS7SignedAndEnvelopedData *saedp;
1058 saedp = cinfo->content.signedAndEnvelopedData;
1059 recipientinfosp = &(saedp->recipientInfos);
1063 return SECFailure; /* XXX set an error? */
1067 * XXX I think that CERT_VerifyCert should do this if *it* is passed
1070 if (certdb == NULL) {
1071 certdb = CERT_GetDefaultCertDB();
1073 return SECFailure; /* XXX set an error? */
1076 if (CERT_VerifyCert (certdb, cert, PR_TRUE, certusage, PR_Now(),
1077 cinfo->pwfn_arg, NULL) != SECSuccess)
1079 /* XXX Did CERT_VerifyCert set an error? */
1083 mark = PORT_ArenaMark (cinfo->poolp);
1085 recipientinfo = (SEC_PKCS7RecipientInfo*)PORT_ArenaZAlloc (cinfo->poolp,
1086 sizeof(SEC_PKCS7RecipientInfo));
1087 if (recipientinfo == NULL) {
1088 PORT_ArenaRelease (cinfo->poolp, mark);
1092 dummy = SEC_ASN1EncodeInteger (cinfo->poolp, &recipientinfo->version,
1093 SEC_PKCS7_RECIPIENT_INFO_VERSION);
1094 if (dummy == NULL) {
1095 PORT_ArenaRelease (cinfo->poolp, mark);
1098 PORT_Assert (dummy == &recipientinfo->version);
1100 recipientinfo->cert = CERT_DupCertificate (cert);
1101 if (recipientinfo->cert == NULL) {
1102 PORT_ArenaRelease (cinfo->poolp, mark);
1106 recipientinfo->issuerAndSN = CERT_GetCertIssuerAndSN (cinfo->poolp, cert);
1107 if (recipientinfo->issuerAndSN == NULL) {
1108 PORT_ArenaRelease (cinfo->poolp, mark);
1113 * Okay, now recipientinfo is all set. We just need to put it into
1114 * the main structure.
1116 * If this is the first recipient, allocate a new recipientinfos array;
1117 * otherwise, reallocate the array, making room for the new entry.
1119 recipientinfos = *recipientinfosp;
1120 if (recipientinfos == NULL) {
1122 recipientinfos = (SEC_PKCS7RecipientInfo **)PORT_ArenaAlloc (
1124 2 * sizeof(SEC_PKCS7RecipientInfo *));
1126 for (count = 0; recipientinfos[count] != NULL; count++)
1128 PORT_Assert (count); /* should be at least one already */
1129 recipientinfos = (SEC_PKCS7RecipientInfo **)PORT_ArenaGrow (
1130 cinfo->poolp, recipientinfos,
1131 (count + 1) * sizeof(SEC_PKCS7RecipientInfo *),
1132 (count + 2) * sizeof(SEC_PKCS7RecipientInfo *));
1135 if (recipientinfos == NULL) {
1136 PORT_ArenaRelease (cinfo->poolp, mark);
1140 recipientinfos[count] = recipientinfo;
1141 recipientinfos[count + 1] = NULL;
1143 *recipientinfosp = recipientinfos;
1145 PORT_ArenaUnmark (cinfo->poolp, mark);
1151 * Start a PKCS7 enveloping context.
1153 * "cert" is the cert for the recipient. It will be checked for validity.
1155 * "certusage" describes the encryption usage (e.g. certUsageEmailRecipient)
1156 * XXX Maybe SECCertUsage should be split so that our caller just says
1157 * "email" and *we* add the "recipient" part -- otherwise our caller
1158 * could be lying about the usage; we do not want to allow encryption
1159 * certs for signing or vice versa.
1161 * "certdb" is the cert database to use for verifying the cert.
1162 * It can be NULL if a default database is available (like in the client).
1164 * "encalg" specifies the bulk encryption algorithm to use (e.g. SEC_OID_RC2).
1166 * "keysize" specifies the bulk encryption key size, in bits.
1168 * The return value can be passed to functions which add things to
1169 * it like more recipients, then eventually to SEC_PKCS7Encode() or to
1170 * SEC_PKCS7EncoderStart() to create the encoded data, and finally to
1171 * SEC_PKCS7DestroyContentInfo().
1173 * An error results in a return value of NULL and an error set.
1174 * (Retrieve specific errors via PORT_GetError()/XP_GetError().)
1176 extern SEC_PKCS7ContentInfo *
1177 SEC_PKCS7CreateEnvelopedData (CERTCertificate *cert,
1178 SECCertUsage certusage,
1179 CERTCertDBHandle *certdb,
1182 SECKEYGetPasswordKey pwfn, void *pwfn_arg)
1184 SEC_PKCS7ContentInfo *cinfo;
1185 SEC_PKCS7EnvelopedData *envd;
1188 cinfo = sec_pkcs7_create_content_info (SEC_OID_PKCS7_ENVELOPED_DATA,
1189 PR_FALSE, pwfn, pwfn_arg);
1193 rv = sec_pkcs7_add_recipient (cinfo, cert, certusage, certdb);
1194 if (rv != SECSuccess) {
1195 SEC_PKCS7DestroyContentInfo (cinfo);
1199 envd = cinfo->content.envelopedData;
1200 PORT_Assert (envd != NULL);
1203 * XXX Might we want to allow content types other than data?
1204 * If so, via what interface?
1206 rv = sec_pkcs7_init_encrypted_content_info (&(envd->encContentInfo),
1208 SEC_OID_PKCS7_DATA, PR_FALSE,
1210 if (rv != SECSuccess) {
1211 SEC_PKCS7DestroyContentInfo (cinfo);
1215 /* XXX Anything more to do here? */
1222 * Add another recipient to an encrypted message.
1224 * "cinfo" should be of type envelopedData or signedAndEnvelopedData;
1225 * SECFailure will be returned if it is not.
1227 * "cert" is the cert for the recipient. It will be checked for validity.
1229 * "certusage" describes the encryption usage (e.g. certUsageEmailRecipient)
1230 * XXX Maybe SECCertUsage should be split so that our caller just says
1231 * "email" and *we* add the "recipient" part -- otherwise our caller
1232 * could be lying about the usage; we do not want to allow encryption
1233 * certs for signing or vice versa.
1235 * "certdb" is the cert database to use for verifying the cert.
1236 * It can be NULL if a default database is available (like in the client).
1239 SEC_PKCS7AddRecipient (SEC_PKCS7ContentInfo *cinfo,
1240 CERTCertificate *cert,
1241 SECCertUsage certusage,
1242 CERTCertDBHandle *certdb)
1244 return sec_pkcs7_add_recipient (cinfo, cert, certusage, certdb);
1249 * Create an empty PKCS7 data content info.
1251 * An error results in a return value of NULL and an error set.
1252 * (Retrieve specific errors via PORT_GetError()/XP_GetError().)
1254 SEC_PKCS7ContentInfo *
1255 SEC_PKCS7CreateData (void)
1257 return sec_pkcs7_create_content_info (SEC_OID_PKCS7_DATA, PR_FALSE,
1263 * Create an empty PKCS7 encrypted content info.
1265 * "algorithm" specifies the bulk encryption algorithm to use.
1267 * An error results in a return value of NULL and an error set.
1268 * (Retrieve specific errors via PORT_GetError()/XP_GetError().)
1270 SEC_PKCS7ContentInfo *
1271 SEC_PKCS7CreateEncryptedData (SECOidTag algorithm, int keysize,
1272 SECKEYGetPasswordKey pwfn, void *pwfn_arg)
1274 SEC_PKCS7ContentInfo *cinfo;
1275 SECAlgorithmID *algid;
1276 SEC_PKCS7EncryptedData *enc_data;
1279 cinfo = sec_pkcs7_create_content_info (SEC_OID_PKCS7_ENCRYPTED_DATA,
1280 PR_FALSE, pwfn, pwfn_arg);
1284 enc_data = cinfo->content.encryptedData;
1285 algid = &(enc_data->encContentInfo.contentEncAlg);
1287 if (!SEC_PKCS5IsAlgorithmPBEAlgTag(algorithm)) {
1288 rv = SECOID_SetAlgorithmID (cinfo->poolp, algid, algorithm, NULL);
1290 /* Assume password-based-encryption.
1291 * Note: we can't generate pkcs5v2 from this interface.
1292 * PK11_CreateBPEAlgorithmID generates pkcs5v2 by accepting
1293 * non-PBE oids and assuming that they are pkcs5v2 oids, but
1294 * NSS_CMSEncryptedData_Create accepts non-PBE oids as regular
1295 * CMS encrypted data, so we can't tell SEC_PKCS7CreateEncryptedtedData
1296 * to create pkcs5v2 PBEs */
1297 SECAlgorithmID *pbe_algid;
1298 pbe_algid = PK11_CreatePBEAlgorithmID(algorithm,
1299 NSS_PBE_DEFAULT_ITERATION_COUNT,
1301 if (pbe_algid == NULL) {
1304 rv = SECOID_CopyAlgorithmID (cinfo->poolp, algid, pbe_algid);
1305 SECOID_DestroyAlgorithmID (pbe_algid, PR_TRUE);
1309 if (rv != SECSuccess) {
1310 SEC_PKCS7DestroyContentInfo (cinfo);
1314 rv = sec_pkcs7_init_encrypted_content_info (&(enc_data->encContentInfo),
1316 SEC_OID_PKCS7_DATA, PR_FALSE,
1317 algorithm, keysize);
1318 if (rv != SECSuccess) {
1319 SEC_PKCS7DestroyContentInfo (cinfo);