p7create.c
上传用户:lyxiangda
上传日期:2007-01-12
资源大小:3042k
文件大小:37k
源码类别:

CA认证

开发平台:

WINDOWS

  1. /*
  2.  * The contents of this file are subject to the Mozilla Public
  3.  * License Version 1.1 (the "License"); you may not use this file
  4.  * except in compliance with the License. You may obtain a copy of
  5.  * the License at http://www.mozilla.org/MPL/
  6.  * 
  7.  * Software distributed under the License is distributed on an "AS
  8.  * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
  9.  * implied. See the License for the specific language governing
  10.  * rights and limitations under the License.
  11.  * 
  12.  * The Original Code is the Netscape security libraries.
  13.  * 
  14.  * The Initial Developer of the Original Code is Netscape
  15.  * Communications Corporation.  Portions created by Netscape are 
  16.  * Copyright (C) 1994-2000 Netscape Communications Corporation.  All
  17.  * Rights Reserved.
  18.  * 
  19.  * Contributor(s):
  20.  * 
  21.  * Alternatively, the contents of this file may be used under the
  22.  * terms of the GNU General Public License Version 2 or later (the
  23.  * "GPL"), in which case the provisions of the GPL are applicable 
  24.  * instead of those above.  If you wish to allow use of your 
  25.  * version of this file only under the terms of the GPL and not to
  26.  * allow others to use your version of this file under the MPL,
  27.  * indicate your decision by deleting the provisions above and
  28.  * replace them with the notice and other provisions required by
  29.  * the GPL.  If you do not delete the provisions above, a recipient
  30.  * may use your version of this file under either the MPL or the
  31.  * GPL.
  32.  */
  33. /*
  34.  * PKCS7 creation.
  35.  *
  36.  * $Id: p7create.c,v 1.1 2000/03/31 19:16:04 relyea%netscape.com Exp $
  37.  */
  38. #include "p7local.h"
  39. #include "cert.h"
  40. #include "secasn1.h"
  41. #include "secitem.h"
  42. #include "secoid.h"
  43. #include "secpkcs5.h"
  44. #include "pk11func.h"
  45. #include "prtime.h"
  46. #include "secerr.h"
  47. static SECStatus
  48. sec_pkcs7_init_content_info (SEC_PKCS7ContentInfo *cinfo, PRArenaPool *poolp,
  49.      SECOidTag kind, PRBool detached)
  50. {
  51.     void *thing;
  52.     int version;
  53.     SECItem *versionp;
  54.     SECStatus rv;
  55.     PORT_Assert (cinfo != NULL && poolp != NULL);
  56.     if (cinfo == NULL || poolp == NULL)
  57. return SECFailure;
  58.     cinfo->contentTypeTag = SECOID_FindOIDByTag (kind);
  59.     PORT_Assert (cinfo->contentTypeTag
  60.  && cinfo->contentTypeTag->offset == kind);
  61.     rv = SECITEM_CopyItem (poolp, &(cinfo->contentType),
  62.    &(cinfo->contentTypeTag->oid));
  63.     if (rv != SECSuccess)
  64. return rv;
  65.     if (detached)
  66. return SECSuccess;
  67.     switch (kind) {
  68.       default:
  69.       case SEC_OID_PKCS7_DATA:
  70. thing = PORT_ArenaZAlloc (poolp, sizeof(SECItem));
  71. cinfo->content.data = (SECItem*)thing;
  72. versionp = NULL;
  73. version = -1;
  74. break;
  75.       case SEC_OID_PKCS7_DIGESTED_DATA:
  76. thing = PORT_ArenaZAlloc (poolp, sizeof(SEC_PKCS7DigestedData));
  77. cinfo->content.digestedData = (SEC_PKCS7DigestedData*)thing;
  78. versionp = &(cinfo->content.digestedData->version);
  79. version = SEC_PKCS7_DIGESTED_DATA_VERSION;
  80. break;
  81.       case SEC_OID_PKCS7_ENCRYPTED_DATA:
  82. thing = PORT_ArenaZAlloc (poolp, sizeof(SEC_PKCS7EncryptedData));
  83. cinfo->content.encryptedData = (SEC_PKCS7EncryptedData*)thing;
  84. versionp = &(cinfo->content.encryptedData->version);
  85. version = SEC_PKCS7_ENCRYPTED_DATA_VERSION;
  86. break;
  87.       case SEC_OID_PKCS7_ENVELOPED_DATA:
  88. thing = PORT_ArenaZAlloc (poolp, sizeof(SEC_PKCS7EnvelopedData));
  89. cinfo->content.envelopedData = 
  90.   (SEC_PKCS7EnvelopedData*)thing;
  91. versionp = &(cinfo->content.envelopedData->version);
  92. version = SEC_PKCS7_ENVELOPED_DATA_VERSION;
  93. break;
  94.       case SEC_OID_PKCS7_SIGNED_DATA:
  95. thing = PORT_ArenaZAlloc (poolp, sizeof(SEC_PKCS7SignedData));
  96. cinfo->content.signedData = 
  97.   (SEC_PKCS7SignedData*)thing;
  98. versionp = &(cinfo->content.signedData->version);
  99. version = SEC_PKCS7_SIGNED_DATA_VERSION;
  100. break;
  101.       case SEC_OID_PKCS7_SIGNED_ENVELOPED_DATA:
  102. thing = PORT_ArenaZAlloc(poolp,sizeof(SEC_PKCS7SignedAndEnvelopedData));
  103. cinfo->content.signedAndEnvelopedData = 
  104.   (SEC_PKCS7SignedAndEnvelopedData*)thing;
  105. versionp = &(cinfo->content.signedAndEnvelopedData->version);
  106. version = SEC_PKCS7_SIGNED_AND_ENVELOPED_DATA_VERSION;
  107. break;
  108.     }
  109.     if (thing == NULL)
  110. return SECFailure;
  111.     if (versionp != NULL) {
  112. SECItem *dummy;
  113. PORT_Assert (version >= 0);
  114. dummy = SEC_ASN1EncodeInteger (poolp, versionp, version);
  115. if (dummy == NULL)
  116.     return SECFailure;
  117. PORT_Assert (dummy == versionp);
  118.     }
  119.     return SECSuccess;
  120. }
  121. static SEC_PKCS7ContentInfo *
  122. sec_pkcs7_create_content_info (SECOidTag kind, PRBool detached,
  123.        SECKEYGetPasswordKey pwfn, void *pwfn_arg)
  124. {
  125.     SEC_PKCS7ContentInfo *cinfo;
  126.     PRArenaPool *poolp;
  127.     SECStatus rv;
  128.     poolp = PORT_NewArena (1024); /* XXX what is right value? */
  129.     if (poolp == NULL)
  130. return NULL;
  131.     cinfo = (SEC_PKCS7ContentInfo*)PORT_ArenaZAlloc (poolp, sizeof(*cinfo));
  132.     if (cinfo == NULL) {
  133. PORT_FreeArena (poolp, PR_FALSE);
  134. return NULL;
  135.     }
  136.     cinfo->poolp = poolp;
  137.     cinfo->pwfn = pwfn;
  138.     cinfo->pwfn_arg = pwfn_arg;
  139.     cinfo->created = PR_TRUE;
  140.     cinfo->refCount = 1;
  141.     rv = sec_pkcs7_init_content_info (cinfo, poolp, kind, detached);
  142.     if (rv != SECSuccess) {
  143. PORT_FreeArena (poolp, PR_FALSE);
  144. return NULL;
  145.     }
  146.     return cinfo;
  147. }
  148. /*
  149.  * Add a signer to a PKCS7 thing, verifying the signature cert first.
  150.  * Any error returns SECFailure.
  151.  *
  152.  * XXX Right now this only adds the *first* signer.  It fails if you try
  153.  * to add a second one -- this needs to be fixed.
  154.  */
  155. static SECStatus
  156. sec_pkcs7_add_signer (SEC_PKCS7ContentInfo *cinfo,
  157.       CERTCertificate *     cert,
  158.       SECCertUsage          certusage,
  159.       CERTCertDBHandle *    certdb,
  160.       SECOidTag             digestalgtag,
  161.       SECItem *             digestdata)
  162. {
  163.     SEC_PKCS7SignerInfo *signerinfo, **signerinfos, ***signerinfosp;
  164.     SECAlgorithmID      *digestalg,  **digestalgs,  ***digestalgsp;
  165.     SECItem             *digest,     **digests,     ***digestsp;
  166.     SECItem *            dummy;
  167.     void *               mark;
  168.     SECStatus            rv;
  169.     SECOidTag            kind;
  170.     kind = SEC_PKCS7ContentType (cinfo);
  171.     switch (kind) {
  172.       case SEC_OID_PKCS7_SIGNED_DATA:
  173. {
  174.     SEC_PKCS7SignedData *sdp;
  175.     sdp = cinfo->content.signedData;
  176.     digestalgsp = &(sdp->digestAlgorithms);
  177.     digestsp = &(sdp->digests);
  178.     signerinfosp = &(sdp->signerInfos);
  179. }
  180. break;
  181.       case SEC_OID_PKCS7_SIGNED_ENVELOPED_DATA:
  182. {
  183.     SEC_PKCS7SignedAndEnvelopedData *saedp;
  184.     saedp = cinfo->content.signedAndEnvelopedData;
  185.     digestalgsp = &(saedp->digestAlgorithms);
  186.     digestsp = &(saedp->digests);
  187.     signerinfosp = &(saedp->signerInfos);
  188. }
  189. break;
  190.       default:
  191. return SECFailure; /* XXX set an error? */
  192.     }
  193.     /*
  194.      * XXX I think that CERT_VerifyCert should do this if *it* is passed
  195.      * a NULL database.
  196.      */
  197.     if (certdb == NULL) {
  198. certdb = CERT_GetDefaultCertDB();
  199. if (certdb == NULL)
  200.     return SECFailure; /* XXX set an error? */
  201.     }
  202.     if (CERT_VerifyCert (certdb, cert, PR_TRUE, certusage, PR_Now(),
  203.  cinfo->pwfn_arg, NULL) != SECSuccess)
  204. {
  205. /* XXX Did CERT_VerifyCert set an error? */
  206. return SECFailure;
  207.     }
  208.     /*
  209.      * XXX This is the check that we do not already have a signer.
  210.      * This is not what we really want -- we want to allow this
  211.      * and *add* the new signer.
  212.      */
  213.     PORT_Assert (*signerinfosp == NULL
  214.  && *digestalgsp == NULL && *digestsp == NULL);
  215.     if (*signerinfosp != NULL || *digestalgsp != NULL || *digestsp != NULL)
  216. return SECFailure;
  217.     mark = PORT_ArenaMark (cinfo->poolp);
  218.     signerinfo = (SEC_PKCS7SignerInfo*)PORT_ArenaZAlloc (cinfo->poolp, 
  219.   sizeof(SEC_PKCS7SignerInfo));
  220.     if (signerinfo == NULL) {
  221. PORT_ArenaRelease (cinfo->poolp, mark);
  222. return SECFailure;
  223.     }
  224.     dummy = SEC_ASN1EncodeInteger (cinfo->poolp, &signerinfo->version,
  225.    SEC_PKCS7_SIGNER_INFO_VERSION);
  226.     if (dummy == NULL) {
  227. PORT_ArenaRelease (cinfo->poolp, mark);
  228. return SECFailure;
  229.     }
  230.     PORT_Assert (dummy == &signerinfo->version);
  231.     signerinfo->cert = CERT_DupCertificate (cert);
  232.     if (signerinfo->cert == NULL) {
  233. PORT_ArenaRelease (cinfo->poolp, mark);
  234. return SECFailure;
  235.     }
  236.     signerinfo->issuerAndSN = CERT_GetCertIssuerAndSN (cinfo->poolp, cert);
  237.     if (signerinfo->issuerAndSN == NULL) {
  238. PORT_ArenaRelease (cinfo->poolp, mark);
  239. return SECFailure;
  240.     }
  241.     rv = SECOID_SetAlgorithmID (cinfo->poolp, &signerinfo->digestAlg,
  242. digestalgtag, NULL);
  243.     if (rv != SECSuccess) {
  244. PORT_ArenaRelease (cinfo->poolp, mark);
  245. return SECFailure;
  246.     }
  247.     /*
  248.      * Okay, now signerinfo is all set.  We just need to put it and its
  249.      * companions (another copy of the digest algorithm, and the digest
  250.      * itself if given) into the main structure.
  251.      *
  252.      * XXX If we are handling more than one signer, the following code
  253.      * needs to look through the digest algorithms already specified
  254.      * and see if the same one is there already.  If it is, it does not
  255.      * need to be added again.  Also, if it is there *and* the digest
  256.      * is not null, then the digest given should match the digest already
  257.      * specified -- if not, that is an error.  Finally, the new signerinfo
  258.      * should be *added* to the set already found.
  259.      */
  260.     signerinfos = (SEC_PKCS7SignerInfo**)PORT_ArenaAlloc (cinfo->poolp,
  261.    2 * sizeof(SEC_PKCS7SignerInfo *));
  262.     if (signerinfos == NULL) {
  263. PORT_ArenaRelease (cinfo->poolp, mark);
  264. return SECFailure;
  265.     }
  266.     signerinfos[0] = signerinfo;
  267.     signerinfos[1] = NULL;
  268.     digestalg = PORT_ArenaZAlloc (cinfo->poolp, sizeof(SECAlgorithmID));
  269.     digestalgs = PORT_ArenaAlloc (cinfo->poolp, 2 * sizeof(SECAlgorithmID *));
  270.     if (digestalg == NULL || digestalgs == NULL) {
  271. PORT_ArenaRelease (cinfo->poolp, mark);
  272. return SECFailure;
  273.     }
  274.     rv = SECOID_SetAlgorithmID (cinfo->poolp, digestalg, digestalgtag, NULL);
  275.     if (rv != SECSuccess) {
  276. PORT_ArenaRelease (cinfo->poolp, mark);
  277. return SECFailure;
  278.     }
  279.     digestalgs[0] = digestalg;
  280.     digestalgs[1] = NULL;
  281.     if (digestdata != NULL) {
  282. digest = (SECItem*)PORT_ArenaAlloc (cinfo->poolp, sizeof(SECItem));
  283. digests = (SECItem**)PORT_ArenaAlloc (cinfo->poolp, 
  284.       2 * sizeof(SECItem *));
  285. if (digest == NULL || digests == NULL) {
  286.     PORT_ArenaRelease (cinfo->poolp, mark);
  287.     return SECFailure;
  288. }
  289. rv = SECITEM_CopyItem (cinfo->poolp, digest, digestdata);
  290. if (rv != SECSuccess) {
  291.     PORT_ArenaRelease (cinfo->poolp, mark);
  292.     return SECFailure;
  293. }
  294. digests[0] = digest;
  295. digests[1] = NULL;
  296.     } else {
  297. digests = NULL;
  298.     }
  299.     *signerinfosp = signerinfos;
  300.     *digestalgsp = digestalgs;
  301.     *digestsp = digests;
  302.     PORT_ArenaUnmark(cinfo->poolp, mark);
  303.     return SECSuccess;
  304. }
  305. /*
  306.  * Helper function for creating an empty signedData.
  307.  */
  308. static SEC_PKCS7ContentInfo *
  309. sec_pkcs7_create_signed_data (SECKEYGetPasswordKey pwfn, void *pwfn_arg)
  310. {
  311.     SEC_PKCS7ContentInfo *cinfo;
  312.     SEC_PKCS7SignedData *sigd;
  313.     SECStatus rv;
  314.     cinfo = sec_pkcs7_create_content_info (SEC_OID_PKCS7_SIGNED_DATA, PR_FALSE,
  315.    pwfn, pwfn_arg);
  316.     if (cinfo == NULL)
  317. return NULL;
  318.     sigd = cinfo->content.signedData;
  319.     PORT_Assert (sigd != NULL);
  320.     /*
  321.      * XXX Might we want to allow content types other than data?
  322.      * If so, via what interface?
  323.      */
  324.     rv = sec_pkcs7_init_content_info (&(sigd->contentInfo), cinfo->poolp,
  325.       SEC_OID_PKCS7_DATA, PR_TRUE);
  326.     if (rv != SECSuccess) {
  327. SEC_PKCS7DestroyContentInfo (cinfo);
  328. return NULL;
  329.     }
  330.     return cinfo;
  331. }
  332. /*
  333.  * Start a PKCS7 signing context.
  334.  *
  335.  * "cert" is the cert that will be used to sign the data.  It will be
  336.  * checked for validity.
  337.  *
  338.  * "certusage" describes the signing usage (e.g. certUsageEmailSigner)
  339.  * XXX Maybe SECCertUsage should be split so that our caller just says
  340.  * "email" and *we* add the "signing" part -- otherwise our caller
  341.  * could be lying about the usage; we do not want to allow encryption
  342.  * certs for signing or vice versa.
  343.  *
  344.  * "certdb" is the cert database to use for verifying the cert.
  345.  * It can be NULL if a default database is available (like in the client).
  346.  * 
  347.  * "digestalg" names the digest algorithm (e.g. SEC_OID_SHA1).
  348.  *
  349.  * "digest" is the actual digest of the data.  It must be provided in
  350.  * the case of detached data or NULL if the content will be included.
  351.  *
  352.  * The return value can be passed to functions which add things to
  353.  * it like attributes, then eventually to SEC_PKCS7Encode() or to
  354.  * SEC_PKCS7EncoderStart() to create the encoded data, and finally to
  355.  * SEC_PKCS7DestroyContentInfo().
  356.  *
  357.  * An error results in a return value of NULL and an error set.
  358.  * (Retrieve specific errors via PORT_GetError()/XP_GetError().)
  359.  */
  360. SEC_PKCS7ContentInfo *
  361. SEC_PKCS7CreateSignedData (CERTCertificate *cert,
  362.    SECCertUsage certusage,
  363.    CERTCertDBHandle *certdb,
  364.    SECOidTag digestalg,
  365.    SECItem *digest,
  366.      SECKEYGetPasswordKey pwfn, void *pwfn_arg)
  367. {
  368.     SEC_PKCS7ContentInfo *cinfo;
  369.     SECStatus rv;
  370.     cinfo = sec_pkcs7_create_signed_data (pwfn, pwfn_arg);
  371.     if (cinfo == NULL)
  372. return NULL;
  373.     rv = sec_pkcs7_add_signer (cinfo, cert, certusage, certdb,
  374.        digestalg, digest);
  375.     if (rv != SECSuccess) {
  376. SEC_PKCS7DestroyContentInfo (cinfo);
  377. return NULL;
  378.     }
  379.     return cinfo;
  380. }
  381. static SEC_PKCS7Attribute *
  382. sec_pkcs7_create_attribute (PRArenaPool *poolp, SECOidTag oidtag,
  383.     SECItem *value, PRBool encoded)
  384. {
  385.     SEC_PKCS7Attribute *attr;
  386.     SECItem **values;
  387.     void *mark;
  388.     PORT_Assert (poolp != NULL);
  389.     mark = PORT_ArenaMark (poolp);
  390.     attr = (SEC_PKCS7Attribute*)PORT_ArenaAlloc (poolp, 
  391.  sizeof(SEC_PKCS7Attribute));
  392.     if (attr == NULL)
  393. goto loser;
  394.     attr->typeTag = SECOID_FindOIDByTag (oidtag);
  395.     if (attr->typeTag == NULL)
  396. goto loser;
  397.     if (SECITEM_CopyItem (poolp, &(attr->type),
  398.   &(attr->typeTag->oid)) != SECSuccess)
  399. goto loser;
  400.     values = (SECItem**)PORT_ArenaAlloc (poolp, 2 * sizeof(SECItem *));
  401.     if (values == NULL)
  402. goto loser;
  403.     if (value != NULL) {
  404. SECItem *copy;
  405. copy = (SECItem*)PORT_ArenaAlloc (poolp, sizeof(SECItem));
  406. if (copy == NULL)
  407.     goto loser;
  408. if (SECITEM_CopyItem (poolp, copy, value) != SECSuccess)
  409.     goto loser;
  410. value = copy;
  411.     }
  412.     values[0] = value;
  413.     values[1] = NULL;
  414.     attr->values = values;
  415.     attr->encoded = encoded;
  416.     PORT_ArenaUnmark (poolp, mark);
  417.     return attr;
  418. loser:
  419.     PORT_Assert (mark != NULL);
  420.     PORT_ArenaRelease (poolp, mark);
  421.     return NULL;
  422. }
  423. static SECStatus
  424. sec_pkcs7_add_attribute (SEC_PKCS7ContentInfo *cinfo,
  425.  SEC_PKCS7Attribute ***attrsp,
  426.  SEC_PKCS7Attribute *attr)
  427. {
  428.     SEC_PKCS7Attribute **attrs;
  429.     SECItem *ct_value;
  430.     void *mark;
  431.     PORT_Assert (SEC_PKCS7ContentType (cinfo) == SEC_OID_PKCS7_SIGNED_DATA);
  432.     if (SEC_PKCS7ContentType (cinfo) != SEC_OID_PKCS7_SIGNED_DATA)
  433. return SECFailure;
  434.     attrs = *attrsp;
  435.     if (attrs != NULL) {
  436. int count;
  437. /*
  438.  * We already have some attributes, and just need to add this
  439.  * new one.
  440.  */
  441. /*
  442.  * We should already have the *required* attributes, which were
  443.  * created/added at the same time the first attribute was added.
  444.  */
  445. PORT_Assert (sec_PKCS7FindAttribute (attrs,
  446.      SEC_OID_PKCS9_CONTENT_TYPE,
  447.      PR_FALSE) != NULL);
  448. PORT_Assert (sec_PKCS7FindAttribute (attrs,
  449.      SEC_OID_PKCS9_MESSAGE_DIGEST,
  450.      PR_FALSE) != NULL);
  451. for (count = 0; attrs[count] != NULL; count++)
  452.     ;
  453. attrs = (SEC_PKCS7Attribute**)PORT_ArenaGrow (cinfo->poolp, attrs,
  454. (count + 1) * sizeof(SEC_PKCS7Attribute *),
  455. (count + 2) * sizeof(SEC_PKCS7Attribute *));
  456. if (attrs == NULL)
  457.     return SECFailure;
  458. attrs[count] = attr;
  459. attrs[count+1] = NULL;
  460. *attrsp = attrs;
  461. return SECSuccess;
  462.     }
  463.     /*
  464.      * This is the first time an attribute is going in.
  465.      * We need to create and add the required attributes, and then
  466.      * we will also add in the one our caller gave us.
  467.      */
  468.     /*
  469.      * There are 2 required attributes, plus the one our caller wants
  470.      * to add, plus we always end with a NULL one.  Thus, four slots.
  471.      */
  472.     attrs = (SEC_PKCS7Attribute**)PORT_ArenaAlloc (cinfo->poolp, 
  473.    4 * sizeof(SEC_PKCS7Attribute *));
  474.     if (attrs == NULL)
  475. return SECFailure;
  476.     mark = PORT_ArenaMark (cinfo->poolp);
  477.     /*
  478.      * First required attribute is the content type of the data
  479.      * being signed.
  480.      */
  481.     ct_value = &(cinfo->content.signedData->contentInfo.contentType);
  482.     attrs[0] = sec_pkcs7_create_attribute (cinfo->poolp,
  483.    SEC_OID_PKCS9_CONTENT_TYPE,
  484.    ct_value, PR_FALSE);
  485.     /*
  486.      * Second required attribute is the message digest of the data
  487.      * being signed; we leave the value NULL for now (just create
  488.      * the place for it to go), and the encoder will fill it in later.
  489.      */
  490.     attrs[1] = sec_pkcs7_create_attribute (cinfo->poolp,
  491.    SEC_OID_PKCS9_MESSAGE_DIGEST,
  492.    NULL, PR_FALSE);
  493.     if (attrs[0] == NULL || attrs[1] == NULL) {
  494. PORT_ArenaRelease (cinfo->poolp, mark);
  495. return SECFailure; 
  496.     }
  497.     attrs[2] = attr;
  498.     attrs[3] = NULL;
  499.     *attrsp = attrs;
  500.     PORT_ArenaUnmark (cinfo->poolp, mark);
  501.     return SECSuccess;
  502. }
  503. /*
  504.  * Add the signing time to the authenticated (i.e. signed) attributes
  505.  * of "cinfo".  This is expected to be included in outgoing signed
  506.  * messages for email (S/MIME) but is likely useful in other situations.
  507.  *
  508.  * This should only be added once; a second call will either do
  509.  * nothing or replace an old signing time with a newer one.
  510.  *
  511.  * XXX This will probably just shove the current time into "cinfo"
  512.  * but it will not actually get signed until the entire item is
  513.  * processed for encoding.  Is this (expected to be small) delay okay?
  514.  *
  515.  * "cinfo" should be of type signedData (the only kind of pkcs7 data
  516.  * that is allowed authenticated attributes); SECFailure will be returned
  517.  * if it is not.
  518.  */
  519. SECStatus
  520. SEC_PKCS7AddSigningTime (SEC_PKCS7ContentInfo *cinfo)
  521. {
  522.     SEC_PKCS7SignerInfo **signerinfos;
  523.     SEC_PKCS7Attribute *attr;
  524.     SECItem stime;
  525.     SECStatus rv;
  526.     int si;
  527.     PORT_Assert (SEC_PKCS7ContentType (cinfo) == SEC_OID_PKCS7_SIGNED_DATA);
  528.     if (SEC_PKCS7ContentType (cinfo) != SEC_OID_PKCS7_SIGNED_DATA)
  529. return SECFailure;
  530.     signerinfos = cinfo->content.signedData->signerInfos;
  531.     /* There has to be a signer, or it makes no sense. */
  532.     if (signerinfos == NULL || signerinfos[0] == NULL)
  533. return SECFailure;
  534.     rv = DER_TimeToUTCTime (&stime, PR_Now());
  535.     if (rv != SECSuccess)
  536. return rv;
  537.     attr = sec_pkcs7_create_attribute (cinfo->poolp,
  538.        SEC_OID_PKCS9_SIGNING_TIME,
  539.        &stime, PR_FALSE);
  540.     SECITEM_FreeItem (&stime, PR_FALSE);
  541.     if (attr == NULL)
  542. return SECFailure;
  543.     rv = SECSuccess;
  544.     for (si = 0; signerinfos[si] != NULL; si++) {
  545. SEC_PKCS7Attribute *oattr;
  546. oattr = sec_PKCS7FindAttribute (signerinfos[si]->authAttr,
  547. SEC_OID_PKCS9_SIGNING_TIME, PR_FALSE);
  548. PORT_Assert (oattr == NULL);
  549. if (oattr != NULL)
  550.     continue; /* XXX or would it be better to replace it? */
  551. rv = sec_pkcs7_add_attribute (cinfo, &(signerinfos[si]->authAttr),
  552.       attr);
  553. if (rv != SECSuccess)
  554.     break; /* could try to continue, but may as well give up now */
  555.     }
  556.     return rv;
  557. }
  558. /*
  559.  * Add the specified attribute to the authenticated (i.e. signed) attributes
  560.  * of "cinfo" -- "oidtag" describes the attribute and "value" is the
  561.  * value to be associated with it.  NOTE! "value" must already be encoded;
  562.  * no interpretation of "oidtag" is done.  Also, it is assumed that this
  563.  * signedData has only one signer -- if we ever need to add attributes
  564.  * when there is more than one signature, we need a way to specify *which*
  565.  * signature should get the attribute.
  566.  *
  567.  * XXX Technically, a signed attribute can have multiple values; if/when
  568.  * we ever need to support an attribute which takes multiple values, we
  569.  * either need to change this interface or create an AddSignedAttributeValue
  570.  * which can be called subsequently, and would then append a value.
  571.  *
  572.  * "cinfo" should be of type signedData (the only kind of pkcs7 data
  573.  * that is allowed authenticated attributes); SECFailure will be returned
  574.  * if it is not.
  575.  */
  576. SECStatus
  577. SEC_PKCS7AddSignedAttribute (SEC_PKCS7ContentInfo *cinfo,
  578.      SECOidTag oidtag,
  579.      SECItem *value)
  580. {
  581.     SEC_PKCS7SignerInfo **signerinfos;
  582.     SEC_PKCS7Attribute *attr;
  583.     PORT_Assert (SEC_PKCS7ContentType (cinfo) == SEC_OID_PKCS7_SIGNED_DATA);
  584.     if (SEC_PKCS7ContentType (cinfo) != SEC_OID_PKCS7_SIGNED_DATA)
  585. return SECFailure;
  586.     signerinfos = cinfo->content.signedData->signerInfos;
  587.     /*
  588.      * No signature or more than one means no deal.
  589.      */
  590.     if (signerinfos == NULL || signerinfos[0] == NULL || signerinfos[1] != NULL)
  591. return SECFailure;
  592.     attr = sec_pkcs7_create_attribute (cinfo->poolp, oidtag, value, PR_TRUE);
  593.     if (attr == NULL)
  594. return SECFailure;
  595.     return sec_pkcs7_add_attribute (cinfo, &(signerinfos[0]->authAttr), attr);
  596. }
  597.  
  598. /*
  599.  * Mark that the signer certificates and their issuing chain should
  600.  * be included in the encoded data.  This is expected to be used
  601.  * in outgoing signed messages for email (S/MIME).
  602.  *
  603.  * "certdb" is the cert database to use for finding the chain.
  604.  * It can be NULL, meaning use the default database.
  605.  *
  606.  * "cinfo" should be of type signedData or signedAndEnvelopedData;
  607.  * SECFailure will be returned if it is not.
  608.  */
  609. SECStatus
  610. SEC_PKCS7IncludeCertChain (SEC_PKCS7ContentInfo *cinfo,
  611.    CERTCertDBHandle *certdb)
  612. {
  613.     SECOidTag kind;
  614.     SEC_PKCS7SignerInfo *signerinfo, **signerinfos;
  615.     kind = SEC_PKCS7ContentType (cinfo);
  616.     switch (kind) {
  617.       case SEC_OID_PKCS7_SIGNED_DATA:
  618. signerinfos = cinfo->content.signedData->signerInfos;
  619. break;
  620.       case SEC_OID_PKCS7_SIGNED_ENVELOPED_DATA:
  621. signerinfos = cinfo->content.signedAndEnvelopedData->signerInfos;
  622. break;
  623.       default:
  624. return SECFailure; /* XXX set an error? */
  625.     }
  626.     if (signerinfos == NULL) /* no signer, no certs? */
  627. return SECFailure; /* XXX set an error? */
  628.     if (certdb == NULL) {
  629. certdb = CERT_GetDefaultCertDB();
  630. if (certdb == NULL) {
  631.     PORT_SetError (SEC_ERROR_BAD_DATABASE);
  632.     return SECFailure;
  633. }
  634.     }
  635.     /* XXX Should it be an error if we find no signerinfo or no certs? */
  636.     while ((signerinfo = *signerinfos++) != NULL) {
  637. if (signerinfo->cert != NULL)
  638.     /* get the cert chain.  don't send the root to avoid contamination
  639.      * of old clients with a new root that they don't trust
  640.      */
  641.     signerinfo->certList = CERT_CertChainFromCert (signerinfo->cert,
  642.    certUsageEmailSigner,
  643.    PR_FALSE);
  644.     }
  645.     return SECSuccess;
  646. }
  647. /*
  648.  * Helper function to add a certificate chain for inclusion in the
  649.  * bag of certificates in a signedData.
  650.  */
  651. static SECStatus
  652. sec_pkcs7_add_cert_chain (SEC_PKCS7ContentInfo *cinfo,
  653.   CERTCertificate *cert,
  654.   CERTCertDBHandle *certdb)
  655. {
  656.     SECOidTag kind;
  657.     CERTCertificateList *certlist, **certlists, ***certlistsp;
  658.     int count;
  659.     kind = SEC_PKCS7ContentType (cinfo);
  660.     switch (kind) {
  661.       case SEC_OID_PKCS7_SIGNED_DATA:
  662. {
  663.     SEC_PKCS7SignedData *sdp;
  664.     sdp = cinfo->content.signedData;
  665.     certlistsp = &(sdp->certLists);
  666. }
  667. break;
  668.       case SEC_OID_PKCS7_SIGNED_ENVELOPED_DATA:
  669. {
  670.     SEC_PKCS7SignedAndEnvelopedData *saedp;
  671.     saedp = cinfo->content.signedAndEnvelopedData;
  672.     certlistsp = &(saedp->certLists);
  673. }
  674. break;
  675.       default:
  676. return SECFailure; /* XXX set an error? */
  677.     }
  678.     if (certdb == NULL) {
  679. certdb = CERT_GetDefaultCertDB();
  680. if (certdb == NULL) {
  681.     PORT_SetError (SEC_ERROR_BAD_DATABASE);
  682.     return SECFailure;
  683. }
  684.     }
  685.     certlist = CERT_CertChainFromCert (cert, certUsageEmailSigner, PR_FALSE);
  686.     if (certlist == NULL)
  687. return SECFailure;
  688.     certlists = *certlistsp;
  689.     if (certlists == NULL) {
  690. count = 0;
  691. certlists = (CERTCertificateList**)PORT_ArenaAlloc (cinfo->poolp,
  692.      2 * sizeof(CERTCertificateList *));
  693.     } else {
  694. for (count = 0; certlists[count] != NULL; count++)
  695.     ;
  696. PORT_Assert (count); /* should be at least one already */
  697. certlists = (CERTCertificateList**)PORT_ArenaGrow (cinfo->poolp, 
  698.  certlists,
  699. (count + 1) * sizeof(CERTCertificateList *),
  700. (count + 2) * sizeof(CERTCertificateList *));
  701.     }
  702.     if (certlists == NULL) {
  703. CERT_DestroyCertificateList (certlist);
  704. return SECFailure;
  705.     }
  706.     certlists[count] = certlist;
  707.     certlists[count + 1] = NULL;
  708.     *certlistsp = certlists;
  709.     return SECSuccess;
  710. }
  711. /*
  712.  * Helper function to add a certificate for inclusion in the bag of
  713.  * certificates in a signedData.
  714.  */
  715. static SECStatus
  716. sec_pkcs7_add_certificate (SEC_PKCS7ContentInfo *cinfo,
  717.    CERTCertificate *cert)
  718. {
  719.     SECOidTag kind;
  720.     CERTCertificate **certs, ***certsp;
  721.     int count;
  722.     kind = SEC_PKCS7ContentType (cinfo);
  723.     switch (kind) {
  724.       case SEC_OID_PKCS7_SIGNED_DATA:
  725. {
  726.     SEC_PKCS7SignedData *sdp;
  727.     sdp = cinfo->content.signedData;
  728.     certsp = &(sdp->certs);
  729. }
  730. break;
  731.       case SEC_OID_PKCS7_SIGNED_ENVELOPED_DATA:
  732. {
  733.     SEC_PKCS7SignedAndEnvelopedData *saedp;
  734.     saedp = cinfo->content.signedAndEnvelopedData;
  735.     certsp = &(saedp->certs);
  736. }
  737. break;
  738.       default:
  739. return SECFailure; /* XXX set an error? */
  740.     }
  741.     cert = CERT_DupCertificate (cert);
  742.     if (cert == NULL)
  743. return SECFailure;
  744.     certs = *certsp;
  745.     if (certs == NULL) {
  746. count = 0;
  747. certs = (CERTCertificate**)PORT_ArenaAlloc (cinfo->poolp, 
  748.       2 * sizeof(CERTCertificate *));
  749.     } else {
  750. for (count = 0; certs[count] != NULL; count++)
  751.     ;
  752. PORT_Assert (count); /* should be at least one already */
  753. certs = (CERTCertificate**)PORT_ArenaGrow (cinfo->poolp, certs,
  754. (count + 1) * sizeof(CERTCertificate *),
  755. (count + 2) * sizeof(CERTCertificate *));
  756.     }
  757.     if (certs == NULL) {
  758. CERT_DestroyCertificate (cert);
  759. return SECFailure;
  760.     }
  761.     certs[count] = cert;
  762.     certs[count + 1] = NULL;
  763.     *certsp = certs;
  764.     return SECSuccess;
  765. }
  766. /*
  767.  * Create a PKCS7 certs-only container.
  768.  *
  769.  * "cert" is the (first) cert that will be included.
  770.  *
  771.  * "include_chain" specifies whether the entire chain for "cert" should
  772.  * be included.
  773.  *
  774.  * "certdb" is the cert database to use for finding the chain.
  775.  * It can be NULL in when "include_chain" is false, or when meaning
  776.  * use the default database.
  777.  *
  778.  * More certs and chains can be added via AddCertificate and AddCertChain.
  779.  *
  780.  * An error results in a return value of NULL and an error set.
  781.  * (Retrieve specific errors via PORT_GetError()/XP_GetError().)
  782.  */
  783. SEC_PKCS7ContentInfo *
  784. SEC_PKCS7CreateCertsOnly (CERTCertificate *cert,
  785.   PRBool include_chain,
  786.   CERTCertDBHandle *certdb)
  787. {
  788.     SEC_PKCS7ContentInfo *cinfo;
  789.     SECStatus rv;
  790.     cinfo = sec_pkcs7_create_signed_data (NULL, NULL);
  791.     if (cinfo == NULL)
  792. return NULL;
  793.     if (include_chain)
  794. rv = sec_pkcs7_add_cert_chain (cinfo, cert, certdb);
  795.     else
  796. rv = sec_pkcs7_add_certificate (cinfo, cert);
  797.     if (rv != SECSuccess) {
  798. SEC_PKCS7DestroyContentInfo (cinfo);
  799. return NULL;
  800.     }
  801.     return cinfo;
  802. }
  803. /*
  804.  * Add "cert" and its entire chain to the set of certs included in "cinfo".
  805.  *
  806.  * "certdb" is the cert database to use for finding the chain.
  807.  * It can be NULL, meaning use the default database.
  808.  *
  809.  * "cinfo" should be of type signedData or signedAndEnvelopedData;
  810.  * SECFailure will be returned if it is not.
  811.  */
  812. SECStatus
  813. SEC_PKCS7AddCertChain (SEC_PKCS7ContentInfo *cinfo,
  814.        CERTCertificate *cert,
  815.        CERTCertDBHandle *certdb)
  816. {
  817.     SECOidTag kind;
  818.     kind = SEC_PKCS7ContentType (cinfo);
  819.     if (kind != SEC_OID_PKCS7_SIGNED_DATA
  820. && kind != SEC_OID_PKCS7_SIGNED_ENVELOPED_DATA)
  821. return SECFailure; /* XXX set an error? */
  822.     return sec_pkcs7_add_cert_chain (cinfo, cert, certdb);
  823. }
  824. /*
  825.  * Add "cert" to the set of certs included in "cinfo".
  826.  *
  827.  * "cinfo" should be of type signedData or signedAndEnvelopedData;
  828.  * SECFailure will be returned if it is not.
  829.  */
  830. SECStatus
  831. SEC_PKCS7AddCertificate (SEC_PKCS7ContentInfo *cinfo, CERTCertificate *cert)
  832. {
  833.     SECOidTag kind;
  834.     kind = SEC_PKCS7ContentType (cinfo);
  835.     if (kind != SEC_OID_PKCS7_SIGNED_DATA
  836. && kind != SEC_OID_PKCS7_SIGNED_ENVELOPED_DATA)
  837. return SECFailure; /* XXX set an error? */
  838.     return sec_pkcs7_add_certificate (cinfo, cert);
  839. }
  840. static SECStatus
  841. sec_pkcs7_init_encrypted_content_info (SEC_PKCS7EncryptedContentInfo *enccinfo,
  842.        PRArenaPool *poolp,
  843.        SECOidTag kind, PRBool detached,
  844.        SECOidTag encalg, int keysize)
  845. {
  846.     SECStatus rv;
  847.     PORT_Assert (enccinfo != NULL && poolp != NULL);
  848.     if (enccinfo == NULL || poolp == NULL)
  849. return SECFailure;
  850.     /*
  851.      * XXX Some day we may want to allow for other kinds.  That needs
  852.      * more work and modifications to the creation interface, etc.
  853.      * For now, allow but notice callers who pass in other kinds.
  854.      * They are responsible for creating the inner type and encoding,
  855.      * if it is other than DATA.
  856.      */
  857.     PORT_Assert (kind == SEC_OID_PKCS7_DATA);
  858.     enccinfo->contentTypeTag = SECOID_FindOIDByTag (kind);
  859.     PORT_Assert (enccinfo->contentTypeTag
  860.        && enccinfo->contentTypeTag->offset == kind);
  861.     rv = SECITEM_CopyItem (poolp, &(enccinfo->contentType),
  862.    &(enccinfo->contentTypeTag->oid));
  863.     if (rv != SECSuccess)
  864. return rv;
  865.     /* Save keysize and algorithm for later. */
  866.     enccinfo->keysize = keysize;
  867.     enccinfo->encalg = encalg;
  868.     return SECSuccess;
  869. }
  870. /*
  871.  * Add a recipient to a PKCS7 thing, verifying their cert first.
  872.  * Any error returns SECFailure.
  873.  */
  874. static SECStatus
  875. sec_pkcs7_add_recipient (SEC_PKCS7ContentInfo *cinfo,
  876.  CERTCertificate *cert,
  877.  SECCertUsage certusage,
  878.  CERTCertDBHandle *certdb)
  879. {
  880.     SECOidTag kind;
  881.     SEC_PKCS7RecipientInfo *recipientinfo, **recipientinfos, ***recipientinfosp;
  882.     SECItem *dummy;
  883.     void *mark;
  884.     int count;
  885.     kind = SEC_PKCS7ContentType (cinfo);
  886.     switch (kind) {
  887.       case SEC_OID_PKCS7_ENVELOPED_DATA:
  888. {
  889.     SEC_PKCS7EnvelopedData *edp;
  890.     edp = cinfo->content.envelopedData;
  891.     recipientinfosp = &(edp->recipientInfos);
  892. }
  893. break;
  894.       case SEC_OID_PKCS7_SIGNED_ENVELOPED_DATA:
  895. {
  896.     SEC_PKCS7SignedAndEnvelopedData *saedp;
  897.     saedp = cinfo->content.signedAndEnvelopedData;
  898.     recipientinfosp = &(saedp->recipientInfos);
  899. }
  900. break;
  901.       default:
  902. return SECFailure; /* XXX set an error? */
  903.     }
  904.     /*
  905.      * XXX I think that CERT_VerifyCert should do this if *it* is passed
  906.      * a NULL database.
  907.      */
  908.     if (certdb == NULL) {
  909. certdb = CERT_GetDefaultCertDB();
  910. if (certdb == NULL)
  911.     return SECFailure; /* XXX set an error? */
  912.     }
  913.     if (CERT_VerifyCert (certdb, cert, PR_TRUE, certusage, PR_Now(),
  914.  cinfo->pwfn_arg, NULL) != SECSuccess)
  915. {
  916. /* XXX Did CERT_VerifyCert set an error? */
  917. return SECFailure;
  918.     }
  919.     mark = PORT_ArenaMark (cinfo->poolp);
  920.     recipientinfo = (SEC_PKCS7RecipientInfo*)PORT_ArenaZAlloc (cinfo->poolp,
  921.       sizeof(SEC_PKCS7RecipientInfo));
  922.     if (recipientinfo == NULL) {
  923. PORT_ArenaRelease (cinfo->poolp, mark);
  924. return SECFailure;
  925.     }
  926.     dummy = SEC_ASN1EncodeInteger (cinfo->poolp, &recipientinfo->version,
  927.    SEC_PKCS7_RECIPIENT_INFO_VERSION);
  928.     if (dummy == NULL) {
  929. PORT_ArenaRelease (cinfo->poolp, mark);
  930. return SECFailure;
  931.     }
  932.     PORT_Assert (dummy == &recipientinfo->version);
  933.     recipientinfo->cert = CERT_DupCertificate (cert);
  934.     if (recipientinfo->cert == NULL) {
  935. PORT_ArenaRelease (cinfo->poolp, mark);
  936. return SECFailure;
  937.     }
  938.     recipientinfo->issuerAndSN = CERT_GetCertIssuerAndSN (cinfo->poolp, cert);
  939.     if (recipientinfo->issuerAndSN == NULL) {
  940. PORT_ArenaRelease (cinfo->poolp, mark);
  941. return SECFailure;
  942.     }
  943.     /*
  944.      * Okay, now recipientinfo is all set.  We just need to put it into
  945.      * the main structure.
  946.      *
  947.      * If this is the first recipient, allocate a new recipientinfos array;
  948.      * otherwise, reallocate the array, making room for the new entry.
  949.      */
  950.     recipientinfos = *recipientinfosp;
  951.     if (recipientinfos == NULL) {
  952. count = 0;
  953. recipientinfos = (SEC_PKCS7RecipientInfo **)PORT_ArenaAlloc (
  954.   cinfo->poolp,
  955.   2 * sizeof(SEC_PKCS7RecipientInfo *));
  956.     } else {
  957. for (count = 0; recipientinfos[count] != NULL; count++)
  958.     ;
  959. PORT_Assert (count); /* should be at least one already */
  960. recipientinfos = (SEC_PKCS7RecipientInfo **)PORT_ArenaGrow (
  961.  cinfo->poolp, recipientinfos,
  962. (count + 1) * sizeof(SEC_PKCS7RecipientInfo *),
  963. (count + 2) * sizeof(SEC_PKCS7RecipientInfo *));
  964.     }
  965.     if (recipientinfos == NULL) {
  966. PORT_ArenaRelease (cinfo->poolp, mark);
  967. return SECFailure;
  968.     }
  969.     recipientinfos[count] = recipientinfo;
  970.     recipientinfos[count + 1] = NULL;
  971.     *recipientinfosp = recipientinfos;
  972.     PORT_ArenaUnmark (cinfo->poolp, mark);
  973.     return SECSuccess;
  974. }
  975. /*
  976.  * Start a PKCS7 enveloping context.
  977.  *
  978.  * "cert" is the cert for the recipient.  It will be checked for validity.
  979.  *
  980.  * "certusage" describes the encryption usage (e.g. certUsageEmailRecipient)
  981.  * XXX Maybe SECCertUsage should be split so that our caller just says
  982.  * "email" and *we* add the "recipient" part -- otherwise our caller
  983.  * could be lying about the usage; we do not want to allow encryption
  984.  * certs for signing or vice versa.
  985.  *
  986.  * "certdb" is the cert database to use for verifying the cert.
  987.  * It can be NULL if a default database is available (like in the client).
  988.  *
  989.  * "encalg" specifies the bulk encryption algorithm to use (e.g. SEC_OID_RC2).
  990.  *
  991.  * "keysize" specifies the bulk encryption key size, in bits.
  992.  *
  993.  * The return value can be passed to functions which add things to
  994.  * it like more recipients, then eventually to SEC_PKCS7Encode() or to
  995.  * SEC_PKCS7EncoderStart() to create the encoded data, and finally to
  996.  * SEC_PKCS7DestroyContentInfo().
  997.  *
  998.  * An error results in a return value of NULL and an error set.
  999.  * (Retrieve specific errors via PORT_GetError()/XP_GetError().)
  1000.  */
  1001. extern SEC_PKCS7ContentInfo *
  1002. SEC_PKCS7CreateEnvelopedData (CERTCertificate *cert,
  1003.       SECCertUsage certusage,
  1004.       CERTCertDBHandle *certdb,
  1005.       SECOidTag encalg,
  1006.       int keysize,
  1007.         SECKEYGetPasswordKey pwfn, void *pwfn_arg)
  1008. {
  1009.     SEC_PKCS7ContentInfo *cinfo;
  1010.     SEC_PKCS7EnvelopedData *envd;
  1011.     SECStatus rv;
  1012.     cinfo = sec_pkcs7_create_content_info (SEC_OID_PKCS7_ENVELOPED_DATA,
  1013.    PR_FALSE, pwfn, pwfn_arg);
  1014.     if (cinfo == NULL)
  1015. return NULL;
  1016.     rv = sec_pkcs7_add_recipient (cinfo, cert, certusage, certdb);
  1017.     if (rv != SECSuccess) {
  1018. SEC_PKCS7DestroyContentInfo (cinfo);
  1019. return NULL;
  1020.     }
  1021.     envd = cinfo->content.envelopedData;
  1022.     PORT_Assert (envd != NULL);
  1023.     /*
  1024.      * XXX Might we want to allow content types other than data?
  1025.      * If so, via what interface?
  1026.      */
  1027.     rv = sec_pkcs7_init_encrypted_content_info (&(envd->encContentInfo),
  1028. cinfo->poolp,
  1029. SEC_OID_PKCS7_DATA, PR_FALSE,
  1030. encalg, keysize);
  1031.     if (rv != SECSuccess) {
  1032. SEC_PKCS7DestroyContentInfo (cinfo);
  1033. return NULL;
  1034.     }
  1035.     /* XXX Anything more to do here? */
  1036.     return cinfo;
  1037. }
  1038. /*
  1039.  * Add another recipient to an encrypted message.
  1040.  *
  1041.  * "cinfo" should be of type envelopedData or signedAndEnvelopedData;
  1042.  * SECFailure will be returned if it is not.
  1043.  *
  1044.  * "cert" is the cert for the recipient.  It will be checked for validity.
  1045.  *
  1046.  * "certusage" describes the encryption usage (e.g. certUsageEmailRecipient)
  1047.  * XXX Maybe SECCertUsage should be split so that our caller just says
  1048.  * "email" and *we* add the "recipient" part -- otherwise our caller
  1049.  * could be lying about the usage; we do not want to allow encryption
  1050.  * certs for signing or vice versa.
  1051.  *
  1052.  * "certdb" is the cert database to use for verifying the cert.
  1053.  * It can be NULL if a default database is available (like in the client).
  1054.  */
  1055. SECStatus
  1056. SEC_PKCS7AddRecipient (SEC_PKCS7ContentInfo *cinfo,
  1057.        CERTCertificate *cert,
  1058.        SECCertUsage certusage,
  1059.        CERTCertDBHandle *certdb)
  1060. {
  1061.     return sec_pkcs7_add_recipient (cinfo, cert, certusage, certdb);
  1062. }
  1063. /*
  1064.  * Create an empty PKCS7 data content info.
  1065.  *
  1066.  * An error results in a return value of NULL and an error set.
  1067.  * (Retrieve specific errors via PORT_GetError()/XP_GetError().)
  1068.  */
  1069. SEC_PKCS7ContentInfo *
  1070. SEC_PKCS7CreateData (void)
  1071. {
  1072.     return sec_pkcs7_create_content_info (SEC_OID_PKCS7_DATA, PR_FALSE,
  1073.   NULL, NULL);
  1074. }
  1075. /*
  1076.  * Create an empty PKCS7 encrypted content info.
  1077.  *
  1078.  * "algorithm" specifies the bulk encryption algorithm to use.
  1079.  * 
  1080.  * An error results in a return value of NULL and an error set.
  1081.  * (Retrieve specific errors via PORT_GetError()/XP_GetError().)
  1082.  */
  1083. SEC_PKCS7ContentInfo *
  1084. SEC_PKCS7CreateEncryptedData (SECOidTag algorithm, int keysize,
  1085.       SECKEYGetPasswordKey pwfn, void *pwfn_arg)
  1086. {
  1087.     SEC_PKCS7ContentInfo *cinfo;
  1088.     SECAlgorithmID *algid;
  1089.     SEC_PKCS7EncryptedData *enc_data;
  1090.     SECStatus rv;
  1091.     cinfo = sec_pkcs7_create_content_info (SEC_OID_PKCS7_ENCRYPTED_DATA, 
  1092.    PR_FALSE, pwfn, pwfn_arg);
  1093.     if (cinfo == NULL)
  1094. return NULL;
  1095.     enc_data = cinfo->content.encryptedData;
  1096.     algid = &(enc_data->encContentInfo.contentEncAlg);
  1097.     switch (algorithm) {
  1098.       case SEC_OID_RC2_CBC:
  1099.       case SEC_OID_DES_EDE3_CBC:
  1100.       case SEC_OID_DES_CBC:
  1101. rv = SECOID_SetAlgorithmID (cinfo->poolp, algid, algorithm, NULL);
  1102. break;
  1103.       default:
  1104. {
  1105.     /*
  1106.      * Assume password-based-encryption.  At least, try that.
  1107.      */
  1108.     SECAlgorithmID *pbe_algid;
  1109.     pbe_algid = PK11_CreatePBEAlgorithmID (algorithm, 1, NULL);
  1110.     if (pbe_algid == NULL) {
  1111. rv = SECFailure;
  1112.     } else {
  1113. rv = SECOID_CopyAlgorithmID (cinfo->poolp, algid, pbe_algid);
  1114. SECOID_DestroyAlgorithmID (pbe_algid, PR_TRUE);
  1115.     }
  1116. }
  1117. break;
  1118.     }
  1119.     if (rv != SECSuccess) {
  1120. SEC_PKCS7DestroyContentInfo (cinfo);
  1121. return NULL;
  1122.     }
  1123.     rv = sec_pkcs7_init_encrypted_content_info (&(enc_data->encContentInfo),
  1124. cinfo->poolp,
  1125. SEC_OID_PKCS7_DATA, PR_FALSE,
  1126. algorithm, keysize);
  1127.     if (rv != SECSuccess) {
  1128. SEC_PKCS7DestroyContentInfo (cinfo);
  1129. return NULL;
  1130.     }
  1131.     return cinfo;
  1132. }