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

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.  * CMS signedData methods.
  35.  *
  36.  * $Id: cmssigdata.c,v 1.10 2000/10/06 23:26:10 nelsonb%netscape.com Exp $
  37.  */
  38. #include "cmslocal.h"
  39. #include "cert.h"
  40. #include "cdbhdl.h"
  41. #include "secasn1.h"
  42. #include "secitem.h"
  43. #include "secoid.h"
  44. #include "pk11func.h"
  45. #include "secerr.h"
  46. NSSCMSSignedData *
  47. NSS_CMSSignedData_Create(NSSCMSMessage *cmsg)
  48. {
  49.     void *mark;
  50.     NSSCMSSignedData *sigd;
  51.     PLArenaPool *poolp;
  52.     poolp = cmsg->poolp;
  53.     mark = PORT_ArenaMark(poolp);
  54.     sigd = (NSSCMSSignedData *)PORT_ArenaZAlloc (poolp, sizeof(NSSCMSSignedData));
  55.     if (sigd == NULL)
  56. goto loser;
  57.     sigd->cmsg = cmsg;
  58.     /* signerInfos, certs, certlists, crls are all empty */
  59.     /* version is set in NSS_CMSSignedData_Finalize() */
  60.     PORT_ArenaUnmark(poolp, mark);
  61.     return sigd;
  62. loser:
  63.     PORT_ArenaRelease(poolp, mark);
  64.     return NULL;
  65. }
  66. void
  67. NSS_CMSSignedData_Destroy(NSSCMSSignedData *sigd)
  68. {
  69.     CERTCertificate **certs, *cert;
  70.     CERTCertificateList **certlists, *certlist;
  71.     NSSCMSSignerInfo **signerinfos, *si;
  72.     if (sigd == NULL)
  73. return;
  74.     certs = sigd->certs;
  75.     certlists = sigd->certLists;
  76.     signerinfos = sigd->signerInfos;
  77.     if (certs != NULL) {
  78. while ((cert = *certs++) != NULL)
  79.     CERT_DestroyCertificate (cert);
  80.     }
  81.     if (certlists != NULL) {
  82. while ((certlist = *certlists++) != NULL)
  83.     CERT_DestroyCertificateList (certlist);
  84.     }
  85.     if (signerinfos != NULL) {
  86. while ((si = *signerinfos++) != NULL)
  87.     NSS_CMSSignerInfo_Destroy(si);
  88.     }
  89.     /* everything's in a pool, so don't worry about the storage */
  90. }
  91. /*
  92.  * NSS_CMSSignedData_Encode_BeforeStart - do all the necessary things to a SignedData
  93.  *     before start of encoding.
  94.  *
  95.  * In detail:
  96.  *  - find out about the right value to put into sigd->version
  97.  *  - come up with a list of digestAlgorithms (which should be the union of the algorithms
  98.  *         in the signerinfos).
  99.  *         If we happen to have a pre-set list of algorithms (and digest values!), we
  100.  *         check if we have all the signerinfos' algorithms. If not, this is an error.
  101.  */
  102. SECStatus
  103. NSS_CMSSignedData_Encode_BeforeStart(NSSCMSSignedData *sigd)
  104. {
  105.     NSSCMSSignerInfo *signerinfo;
  106.     SECOidTag digestalgtag;
  107.     SECItem *dummy;
  108.     int version;
  109.     SECStatus rv;
  110.     PRBool haveDigests = PR_FALSE;
  111.     int n, i;
  112.     PLArenaPool *poolp;
  113.     poolp = sigd->cmsg->poolp;
  114.     /* we assume that we have precomputed digests if there is a list of algorithms, and */
  115.     /* a chunk of data for each of those algorithms */
  116.     if (sigd->digestAlgorithms != NULL && sigd->digests != NULL) {
  117. for (i=0; sigd->digestAlgorithms[i] != NULL; i++) {
  118.     if (sigd->digests[i] == NULL)
  119. break;
  120. }
  121. if (sigd->digestAlgorithms[i] == NULL) /* reached the end of the array? */
  122.     haveDigests = PR_TRUE; /* yes: we must have all the digests */
  123.     }
  124.     
  125.     version = NSS_CMS_SIGNED_DATA_VERSION_BASIC;
  126.     /* RFC2630 5.1 "version is the syntax version number..." */
  127.     if (NSS_CMSContentInfo_GetContentTypeTag(&(sigd->contentInfo)) != SEC_OID_PKCS7_DATA)
  128. version = NSS_CMS_SIGNED_DATA_VERSION_EXT;
  129.     /* prepare all the SignerInfos (there may be none) */
  130.     for (i=0; i < NSS_CMSSignedData_SignerInfoCount(sigd); i++) {
  131. signerinfo = NSS_CMSSignedData_GetSignerInfo(sigd, i);
  132. /* RFC2630 5.1 "version is the syntax version number..." */
  133. if (NSS_CMSSignerInfo_GetVersion(signerinfo) != NSS_CMS_SIGNER_INFO_VERSION_ISSUERSN)
  134.     version = NSS_CMS_SIGNED_DATA_VERSION_EXT;
  135. /* collect digestAlgorithms from SignerInfos */
  136. /* (we need to know which algorithms we have when the content comes in) */
  137. /* do not overwrite any existing digestAlgorithms (and digest) */
  138. digestalgtag = NSS_CMSSignerInfo_GetDigestAlgTag(signerinfo);
  139. n = NSS_CMSAlgArray_GetIndexByAlgTag(sigd->digestAlgorithms, digestalgtag);
  140. if (n < 0 && haveDigests) {
  141.     /* oops, there is a digestalg we do not have a digest for */
  142.     /* but we were supposed to have all the digests already... */
  143.     goto loser;
  144. } else if (n < 0) {
  145.     /* add the digestAlgorithm & a NULL digest */
  146.     rv = NSS_CMSSignedData_AddDigest(poolp, sigd, digestalgtag, NULL);
  147.     if (rv != SECSuccess)
  148. goto loser;
  149. } else {
  150.     /* found it, nothing to do */
  151. }
  152.     }
  153.     dummy = SEC_ASN1EncodeInteger(poolp, &(sigd->version), (long)version);
  154.     if (dummy == NULL)
  155. return SECFailure;
  156.     /* this is a SET OF, so we need to sort them guys */
  157.     rv = NSS_CMSArray_SortByDER((void **)sigd->digestAlgorithms, SECOID_AlgorithmIDTemplate,
  158. (void **)sigd->digests);
  159.     if (rv != SECSuccess)
  160. return SECFailure;
  161.     
  162.     return SECSuccess;
  163. loser:
  164.     return SECFailure;
  165. }
  166. SECStatus
  167. NSS_CMSSignedData_Encode_BeforeData(NSSCMSSignedData *sigd)
  168. {
  169.     /* set up the digests */
  170.     if (sigd->digestAlgorithms != NULL) {
  171. sigd->contentInfo.digcx = NSS_CMSDigestContext_StartMultiple(sigd->digestAlgorithms);
  172. if (sigd->contentInfo.digcx == NULL)
  173.     return SECFailure;
  174.     }
  175.     return SECSuccess;
  176. }
  177. /*
  178.  * NSS_CMSSignedData_Encode_AfterData - do all the necessary things to a SignedData
  179.  *     after all the encapsulated data was passed through the encoder.
  180.  *
  181.  * In detail:
  182.  *  - create the signatures in all the SignerInfos
  183.  *
  184.  * Please note that nothing is done to the Certificates and CRLs in the message - this
  185.  * is entirely the responsibility of our callers.
  186.  */
  187. SECStatus
  188. NSS_CMSSignedData_Encode_AfterData(NSSCMSSignedData *sigd)
  189. {
  190.     NSSCMSSignerInfo **signerinfos, *signerinfo;
  191.     NSSCMSContentInfo *cinfo;
  192.     SECOidTag digestalgtag;
  193.     SECStatus ret = SECFailure;
  194.     SECStatus rv;
  195.     SECItem *contentType;
  196.     int certcount;
  197.     int i, ci, cli, n, rci, si;
  198.     PLArenaPool *poolp;
  199.     CERTCertificateList *certlist;
  200.     extern const SEC_ASN1Template NSSCMSSignerInfoTemplate[];
  201.     poolp = sigd->cmsg->poolp;
  202.     cinfo = &(sigd->contentInfo);
  203.     /* did we have digest calculation going on? */
  204.     if (cinfo->digcx) {
  205. rv = NSS_CMSDigestContext_FinishMultiple(cinfo->digcx, poolp, &(sigd->digests));
  206. if (rv != SECSuccess)
  207.     goto loser; /* error has been set by NSS_CMSDigestContext_FinishMultiple */
  208. cinfo->digcx = NULL;
  209.     }
  210.     signerinfos = sigd->signerInfos;
  211.     certcount = 0;
  212.     /* prepare all the SignerInfos (there may be none) */
  213.     for (i=0; i < NSS_CMSSignedData_SignerInfoCount(sigd); i++) {
  214. signerinfo = NSS_CMSSignedData_GetSignerInfo(sigd, i);
  215. /* find correct digest for this signerinfo */
  216. digestalgtag = NSS_CMSSignerInfo_GetDigestAlgTag(signerinfo);
  217. n = NSS_CMSAlgArray_GetIndexByAlgTag(sigd->digestAlgorithms, digestalgtag);
  218. if (n < 0 || sigd->digests == NULL || sigd->digests[n] == NULL) {
  219.     /* oops - digest not found */
  220.     PORT_SetError(SEC_ERROR_DIGEST_NOT_FOUND);
  221.     goto loser;
  222. }
  223. /* XXX if our content is anything else but data, we need to force the
  224.  * presence of signed attributes (RFC2630 5.3 "signedAttributes is a
  225.  * collection...") */
  226. /* pass contentType here as we want a contentType attribute */
  227. if ((contentType = NSS_CMSContentInfo_GetContentTypeOID(cinfo)) == NULL)
  228.     goto loser;
  229. /* sign the thing */
  230. rv = NSS_CMSSignerInfo_Sign(signerinfo, sigd->digests[n], contentType);
  231. if (rv != SECSuccess)
  232.     goto loser;
  233. /* while we're at it, count number of certs in certLists */
  234. certlist = NSS_CMSSignerInfo_GetCertList(signerinfo);
  235. if (certlist)
  236.     certcount += certlist->len;
  237.     }
  238.     /* this is a SET OF, so we need to sort them guys */
  239.     rv = NSS_CMSArray_SortByDER((void **)signerinfos, NSSCMSSignerInfoTemplate, NULL);
  240.     if (rv != SECSuccess)
  241. goto loser;
  242.     /*
  243.      * now prepare certs & crls
  244.      */
  245.     /* count the rest of the certs */
  246.     if (sigd->certs != NULL) {
  247. for (ci = 0; sigd->certs[ci] != NULL; ci++)
  248.     certcount++;
  249.     }
  250.     if (sigd->certLists != NULL) {
  251. for (cli = 0; sigd->certLists[cli] != NULL; cli++)
  252.     certcount += sigd->certLists[cli]->len;
  253.     }
  254.     if (certcount == 0) {
  255. sigd->rawCerts = NULL;
  256.     } else {
  257. /*
  258.  * Combine all of the certs and cert chains into rawcerts.
  259.  * Note: certcount is an upper bound; we may not need that many slots
  260.  * but we will allocate anyway to avoid having to do another pass.
  261.  * (The temporary space saving is not worth it.)
  262.  *
  263.  * XXX ARGH - this NEEDS to be fixed. need to come up with a decent
  264.  *  SetOfDERcertficates implementation
  265.  */
  266. sigd->rawCerts = (SECItem **)PORT_ArenaAlloc(poolp, (certcount + 1) * sizeof(SECItem *));
  267. if (sigd->rawCerts == NULL)
  268.     return SECFailure;
  269. /*
  270.  * XXX Want to check for duplicates and not add *any* cert that is
  271.  * already in the set.  This will be more important when we start
  272.  * dealing with larger sets of certs, dual-key certs (signing and
  273.  * encryption), etc.  For the time being we can slide by...
  274.  *
  275.  * XXX ARGH - this NEEDS to be fixed. need to come up with a decent
  276.  *  SetOfDERcertficates implementation
  277.  */
  278. rci = 0;
  279. if (signerinfos != NULL) {
  280.     for (si = 0; signerinfos[si] != NULL; si++) {
  281. signerinfo = signerinfos[si];
  282. for (ci = 0; ci < signerinfo->certList->len; ci++)
  283.     sigd->rawCerts[rci++] = &(signerinfo->certList->certs[ci]);
  284.     }
  285. }
  286. if (sigd->certs != NULL) {
  287.     for (ci = 0; sigd->certs[ci] != NULL; ci++)
  288. sigd->rawCerts[rci++] = &(sigd->certs[ci]->derCert);
  289. }
  290. if (sigd->certLists != NULL) {
  291.     for (cli = 0; sigd->certLists[cli] != NULL; cli++) {
  292. for (ci = 0; ci < sigd->certLists[cli]->len; ci++)
  293.     sigd->rawCerts[rci++] = &(sigd->certLists[cli]->certs[ci]);
  294.     }
  295. }
  296. sigd->rawCerts[rci] = NULL;
  297. /* this is a SET OF, so we need to sort them guys - we have the DER already, though */
  298. NSS_CMSArray_Sort((void **)sigd->rawCerts, NSS_CMSUtil_DERCompare, NULL, NULL);
  299.     }
  300.     ret = SECSuccess;
  301. loser:
  302.     return ret;
  303. }
  304. SECStatus
  305. NSS_CMSSignedData_Decode_BeforeData(NSSCMSSignedData *sigd)
  306. {
  307.     /* set up the digests */
  308.     if (sigd->digestAlgorithms != NULL && sigd->digests == NULL) {
  309. /* if digests are already there, do nothing */
  310. sigd->contentInfo.digcx = NSS_CMSDigestContext_StartMultiple(sigd->digestAlgorithms);
  311. if (sigd->contentInfo.digcx == NULL)
  312.     return SECFailure;
  313.     }
  314.     return SECSuccess;
  315. }
  316. /*
  317.  * NSS_CMSSignedData_Decode_AfterData - do all the necessary things to a SignedData
  318.  *     after all the encapsulated data was passed through the decoder.
  319.  */
  320. SECStatus
  321. NSS_CMSSignedData_Decode_AfterData(NSSCMSSignedData *sigd)
  322. {
  323.     /* did we have digest calculation going on? */
  324.     if (sigd->contentInfo.digcx) {
  325. if (NSS_CMSDigestContext_FinishMultiple(sigd->contentInfo.digcx, sigd->cmsg->poolp, &(sigd->digests)) != SECSuccess)
  326.     return SECFailure; /* error has been set by NSS_CMSDigestContext_FinishMultiple */
  327. sigd->contentInfo.digcx = NULL;
  328.     }
  329.     return SECSuccess;
  330. }
  331. /*
  332.  * NSS_CMSSignedData_Decode_AfterEnd - do all the necessary things to a SignedData
  333.  *     after all decoding is finished.
  334.  */
  335. SECStatus
  336. NSS_CMSSignedData_Decode_AfterEnd(NSSCMSSignedData *sigd)
  337. {
  338.     NSSCMSSignerInfo **signerinfos;
  339.     int i;
  340.     /* set cmsg for all the signerinfos */
  341.     signerinfos = sigd->signerInfos;
  342.     /* set cmsg for all the signerinfos */
  343.     if (signerinfos) {
  344. for (i = 0; signerinfos[i] != NULL; i++)
  345.     signerinfos[i]->cmsg = sigd->cmsg;
  346.     }
  347.     return SECSuccess;
  348. }
  349. /* 
  350.  * NSS_CMSSignedData_GetSignerInfos - retrieve the SignedData's signer list
  351.  */
  352. NSSCMSSignerInfo **
  353. NSS_CMSSignedData_GetSignerInfos(NSSCMSSignedData *sigd)
  354. {
  355.     return sigd->signerInfos;
  356. }
  357. int
  358. NSS_CMSSignedData_SignerInfoCount(NSSCMSSignedData *sigd)
  359. {
  360.     return NSS_CMSArray_Count((void **)sigd->signerInfos);
  361. }
  362. NSSCMSSignerInfo *
  363. NSS_CMSSignedData_GetSignerInfo(NSSCMSSignedData *sigd, int i)
  364. {
  365.     return sigd->signerInfos[i];
  366. }
  367. /* 
  368.  * NSS_CMSSignedData_GetDigestAlgs - retrieve the SignedData's digest algorithm list
  369.  */
  370. SECAlgorithmID **
  371. NSS_CMSSignedData_GetDigestAlgs(NSSCMSSignedData *sigd)
  372. {
  373.     return sigd->digestAlgorithms;
  374. }
  375. /*
  376.  * NSS_CMSSignedData_GetContentInfo - return pointer to this signedData's contentinfo
  377.  */
  378. NSSCMSContentInfo *
  379. NSS_CMSSignedData_GetContentInfo(NSSCMSSignedData *sigd)
  380. {
  381.     return &(sigd->contentInfo);
  382. }
  383. /* 
  384.  * NSS_CMSSignedData_GetCertificateList - retrieve the SignedData's certificate list
  385.  */
  386. SECItem **
  387. NSS_CMSSignedData_GetCertificateList(NSSCMSSignedData *sigd)
  388. {
  389.     return sigd->rawCerts;
  390. }
  391. SECStatus
  392. NSS_CMSSignedData_ImportCerts(NSSCMSSignedData *sigd, CERTCertDBHandle *certdb,
  393. SECCertUsage certusage, PRBool keepcerts)
  394. {
  395.     int certcount;
  396.     SECStatus rv;
  397.     int i;
  398.     certcount = NSS_CMSArray_Count((void **)sigd->rawCerts);
  399.     rv = CERT_ImportCerts(certdb, certusage, certcount, sigd->rawCerts, NULL,
  400.   keepcerts, PR_FALSE, NULL);
  401.     /* XXX CRL handling */
  402.     if (sigd->signerInfos != NULL) {
  403. /* fill in all signerinfo's certs */
  404. for (i = 0; sigd->signerInfos[i] != NULL; i++)
  405.     (void)NSS_CMSSignerInfo_GetSigningCertificate(sigd->signerInfos[i], certdb);
  406.     }
  407.     return rv;
  408. }
  409. /*
  410.  * XXX the digests need to be passed in BETWEEN the decoding and the verification in case
  411.  *     of external signatures!
  412.  */
  413. /*
  414.  * NSS_CMSSignedData_VerifySignerInfo - check the signatures.
  415.  *
  416.  * The digests were either calculated during decoding (and are stored in the
  417.  * signedData itself) or set after decoding using NSS_CMSSignedData_SetDigests.
  418.  *
  419.  * The verification checks if the signing cert is valid and has a trusted chain
  420.  * for the purpose specified by "certusage".
  421.  */
  422. SECStatus
  423. NSS_CMSSignedData_VerifySignerInfo(NSSCMSSignedData *sigd, int i, 
  424.     CERTCertDBHandle *certdb, SECCertUsage certusage)
  425. {
  426.     NSSCMSSignerInfo *signerinfo;
  427.     NSSCMSContentInfo *cinfo;
  428.     SECOidData *algiddata;
  429.     SECItem *contentType, *digest;
  430.     cinfo = &(sigd->contentInfo);
  431.     signerinfo = sigd->signerInfos[i];
  432.     /* verify certificate */
  433.     if (NSS_CMSSignerInfo_VerifyCertificate(signerinfo, certdb, certusage) != SECSuccess)
  434. return SECFailure; /* error is set by NSS_CMSSignerInfo_VerifyCertificate */
  435.     /* find digest and contentType for signerinfo */
  436.     algiddata = NSS_CMSSignerInfo_GetDigestAlg(signerinfo);
  437.     digest = NSS_CMSSignedData_GetDigestByAlgTag(sigd, algiddata->offset);
  438.     contentType = NSS_CMSContentInfo_GetContentTypeOID(cinfo);
  439.     /* now verify signature */
  440.     return NSS_CMSSignerInfo_Verify(signerinfo, digest, contentType);
  441. }
  442. /*
  443.  * NSS_CMSSignedData_VerifyCertsOnly - verify the certs in a certs-only message
  444.  */
  445. SECStatus
  446. NSS_CMSSignedData_VerifyCertsOnly(NSSCMSSignedData *sigd, 
  447.                                   CERTCertDBHandle *certdb, 
  448.                                   SECCertUsage usage)
  449. {
  450.     CERTCertificate *cert;
  451.     SECStatus rv = SECSuccess;
  452.     int i;
  453.     int count;
  454.     if (!sigd || !certdb || !sigd->rawCerts) {
  455. PORT_SetError(SEC_ERROR_INVALID_ARGS);
  456. return SECFailure;
  457.     }
  458.     count = NSS_CMSArray_Count((void**)sigd->rawCerts);
  459.     for (i=0; i < count; i++) {
  460. if (sigd->certs && sigd->certs[i]) {
  461.     cert = sigd->certs[i];
  462. } else {
  463.     cert = CERT_FindCertByDERCert(certdb, sigd->rawCerts[i]);
  464.     if (!cert) {
  465. rv = SECFailure;
  466. break;
  467.     }
  468. }
  469. rv |= CERT_VerifyCert(certdb, cert, PR_TRUE, usage, PR_Now(), 
  470.                               NULL, NULL);
  471.     }
  472.     return rv;
  473. }
  474. /*
  475.  * NSS_CMSSignedData_HasDigests - see if we have digests in place
  476.  */
  477. PRBool
  478. NSS_CMSSignedData_HasDigests(NSSCMSSignedData *sigd)
  479. {
  480.     return (sigd->digests != NULL);
  481. }
  482. SECStatus
  483. NSS_CMSSignedData_AddCertList(NSSCMSSignedData *sigd, CERTCertificateList *certlist)
  484. {
  485.     SECStatus rv;
  486.     PORT_Assert(certlist != NULL);
  487.     if (certlist == NULL)
  488. return SECFailure;
  489.     /* XXX memory?? a certlist has an arena of its own and is not refcounted!?!? */
  490.     rv = NSS_CMSArray_Add(sigd->cmsg->poolp, (void ***)&(sigd->certLists), (void *)certlist);
  491.     return rv;
  492. }
  493. /*
  494.  * NSS_CMSSignedData_AddCertChain - add cert and its entire chain to the set of certs 
  495.  */
  496. SECStatus
  497. NSS_CMSSignedData_AddCertChain(NSSCMSSignedData *sigd, CERTCertificate *cert)
  498. {
  499.     CERTCertificateList *certlist;
  500.     SECCertUsage usage;
  501.     SECStatus rv;
  502.     usage = certUsageEmailSigner;
  503.     /* do not include root */
  504.     certlist = CERT_CertChainFromCert(cert, usage, PR_FALSE);
  505.     if (certlist == NULL)
  506. return SECFailure;
  507.     rv = NSS_CMSSignedData_AddCertList(sigd, certlist);
  508.     return rv;
  509. }
  510. SECStatus
  511. NSS_CMSSignedData_AddCertificate(NSSCMSSignedData *sigd, CERTCertificate *cert)
  512. {
  513.     CERTCertificate *c;
  514.     SECStatus rv;
  515.     PORT_Assert(cert != NULL);
  516.     if (cert == NULL)
  517. return SECFailure;
  518.     c = CERT_DupCertificate(cert);
  519.     rv = NSS_CMSArray_Add(sigd->cmsg->poolp, (void ***)&(sigd->certs), (void *)c);
  520.     return rv;
  521. }
  522. PRBool
  523. NSS_CMSSignedData_ContainsCertsOrCrls(NSSCMSSignedData *sigd)
  524. {
  525.     if (sigd->rawCerts != NULL && sigd->rawCerts[0] != NULL)
  526. return PR_TRUE;
  527.     else if (sigd->crls != NULL && sigd->crls[0] != NULL)
  528. return PR_TRUE;
  529.     else
  530. return PR_FALSE;
  531. }
  532. SECStatus
  533. NSS_CMSSignedData_AddSignerInfo(NSSCMSSignedData *sigd,
  534. NSSCMSSignerInfo *signerinfo)
  535. {
  536.     void *mark;
  537.     SECStatus rv;
  538.     SECOidTag digestalgtag;
  539.     PLArenaPool *poolp;
  540.     poolp = sigd->cmsg->poolp;
  541.     mark = PORT_ArenaMark(poolp);
  542.     /* add signerinfo */
  543.     rv = NSS_CMSArray_Add(poolp, (void ***)&(sigd->signerInfos), (void *)signerinfo);
  544.     if (rv != SECSuccess)
  545. goto loser;
  546.     /*
  547.      * add empty digest
  548.      * Empty because we don't have it yet. Either it gets created during encoding
  549.      * (if the data is present) or has to be set externally.
  550.      * XXX maybe pass it in optionally?
  551.      */
  552.     digestalgtag = NSS_CMSSignerInfo_GetDigestAlgTag(signerinfo);
  553.     rv = NSS_CMSSignedData_SetDigestValue(sigd, digestalgtag, NULL);
  554.     if (rv != SECSuccess)
  555. goto loser;
  556.     /*
  557.      * The last thing to get consistency would be adding the digest.
  558.      */
  559.     PORT_ArenaUnmark(poolp, mark);
  560.     return SECSuccess;
  561. loser:
  562.     PORT_ArenaRelease (poolp, mark);
  563.     return SECFailure;
  564. }
  565. SECItem *
  566. NSS_CMSSignedData_GetDigestByAlgTag(NSSCMSSignedData *sigd, SECOidTag algtag)
  567. {
  568.     int idx;
  569.     idx = NSS_CMSAlgArray_GetIndexByAlgTag(sigd->digestAlgorithms, algtag);
  570.     return sigd->digests[idx];
  571. }
  572. /*
  573.  * NSS_CMSSignedData_SetDigests - set a signedData's digests member
  574.  *
  575.  * "digestalgs" - array of digest algorithm IDs
  576.  * "digests"    - array of digests corresponding to the digest algorithms
  577.  */
  578. SECStatus
  579. NSS_CMSSignedData_SetDigests(NSSCMSSignedData *sigd,
  580. SECAlgorithmID **digestalgs,
  581. SECItem **digests)
  582. {
  583.     int cnt, i, idx;
  584.     if (sigd->digestAlgorithms == NULL) {
  585. PORT_SetError(SEC_ERROR_INVALID_ARGS);
  586. return SECFailure;
  587.     }
  588.     /* we assume that the digests array is just not there yet */
  589.     PORT_Assert(sigd->digests == NULL);
  590.     if (sigd->digests != NULL) {
  591. PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
  592. return SECFailure;
  593.     }
  594.     /* now allocate one (same size as digestAlgorithms) */
  595.     cnt = NSS_CMSArray_Count((void **)sigd->digestAlgorithms);
  596.     sigd->digests = PORT_ArenaZAlloc(sigd->cmsg->poolp, (cnt + 1) * sizeof(SECItem *));
  597.     if (sigd->digests == NULL) {
  598. PORT_SetError(SEC_ERROR_NO_MEMORY);
  599. return SECFailure;
  600.     }
  601.     for (i = 0; sigd->digestAlgorithms[i] != NULL; i++) {
  602. /* try to find the sigd's i'th digest algorithm in the array we passed in */
  603. idx = NSS_CMSAlgArray_GetIndexByAlgID(digestalgs, sigd->digestAlgorithms[i]);
  604. if (idx < 0) {
  605.     PORT_SetError(SEC_ERROR_DIGEST_NOT_FOUND);
  606.     return SECFailure;
  607. }
  608. /* found it - now set it */
  609. if ((sigd->digests[i] = SECITEM_AllocItem(sigd->cmsg->poolp, NULL, 0)) == NULL ||
  610.     SECITEM_CopyItem(sigd->cmsg->poolp, sigd->digests[i], digests[idx]) != SECSuccess)
  611. {
  612.     PORT_SetError(SEC_ERROR_NO_MEMORY);
  613.     return SECFailure;
  614. }
  615.     }
  616.     return SECSuccess;
  617. }
  618. SECStatus
  619. NSS_CMSSignedData_SetDigestValue(NSSCMSSignedData *sigd,
  620. SECOidTag digestalgtag,
  621. SECItem *digestdata)
  622. {
  623.     SECItem *digest = NULL;
  624.     PLArenaPool *poolp;
  625.     void *mark;
  626.     int n;
  627.     poolp = sigd->cmsg->poolp;
  628.     mark = PORT_ArenaMark(poolp);
  629.     if (digestdata) {
  630. /* copy digestdata item to arena (in case we have it and are not only making room) */
  631. if (SECITEM_CopyItem(poolp, digest, digestdata) != SECSuccess)
  632.     goto loser;
  633.     }
  634.     n = -1;
  635.     if (sigd->digestAlgorithms != NULL)
  636. n = NSS_CMSAlgArray_GetIndexByAlgTag(sigd->digestAlgorithms, digestalgtag);
  637.     /* if not found, add a digest */
  638.     if (n < 0) {
  639. if (NSS_CMSSignedData_AddDigest(poolp, sigd, digestalgtag, digest) != SECSuccess)
  640.     goto loser;
  641.     } else {
  642. /* replace NULL pointer with digest item (and leak previous value) */
  643. sigd->digests[n] = digest;
  644.     }
  645.     PORT_ArenaUnmark(poolp, mark);
  646.     return SECSuccess;
  647. loser:
  648.     PORT_ArenaRelease(poolp, mark);
  649.     return SECFailure;
  650. }
  651. SECStatus
  652. NSS_CMSSignedData_AddDigest(PRArenaPool *poolp,
  653. NSSCMSSignedData *sigd,
  654. SECOidTag digestalgtag,
  655. SECItem *digest)
  656. {
  657.     SECAlgorithmID *digestalg;
  658.     void *mark;
  659.     mark = PORT_ArenaMark(poolp);
  660.     digestalg = PORT_ArenaZAlloc(poolp, sizeof(SECAlgorithmID));
  661.     if (digestalg == NULL)
  662. goto loser;
  663.     if (SECOID_SetAlgorithmID (poolp, digestalg, digestalgtag, NULL) != SECSuccess) /* no params */
  664. goto loser;
  665.     if (NSS_CMSArray_Add(poolp, (void ***)&(sigd->digestAlgorithms), (void *)digestalg) != SECSuccess ||
  666. /* even if digest is NULL, add dummy to have same-size array */
  667. NSS_CMSArray_Add(poolp, (void ***)&(sigd->digests), (void *)digest) != SECSuccess)
  668.     {
  669. goto loser;
  670.     }
  671.     PORT_ArenaUnmark(poolp, mark);
  672.     return SECSuccess;
  673. loser:
  674.     PORT_ArenaRelease(poolp, mark);
  675.     return SECFailure;
  676. }
  677. SECItem *
  678. NSS_CMSSignedData_GetDigestValue(NSSCMSSignedData *sigd, SECOidTag digestalgtag)
  679. {
  680.     int n;
  681.     if (sigd->digestAlgorithms == NULL)
  682. return NULL;
  683.     n = NSS_CMSAlgArray_GetIndexByAlgTag(sigd->digestAlgorithms, digestalgtag);
  684.     return (n < 0) ? NULL : sigd->digests[n];
  685. }
  686. /* =============================================================================
  687.  * Misc. utility functions
  688.  */
  689. /*
  690.  * NSS_CMSSignedData_CreateCertsOnly - create a certs-only SignedData.
  691.  *
  692.  * cert          - base certificates that will be included
  693.  * include_chain - if true, include the complete cert chain for cert
  694.  *
  695.  * More certs and chains can be added via AddCertificate and AddCertChain.
  696.  *
  697.  * An error results in a return value of NULL and an error set.
  698.  *
  699.  * XXXX CRLs
  700.  */
  701. NSSCMSSignedData *
  702. NSS_CMSSignedData_CreateCertsOnly(NSSCMSMessage *cmsg, CERTCertificate *cert, PRBool include_chain)
  703. {
  704.     NSSCMSSignedData *sigd;
  705.     void *mark;
  706.     PLArenaPool *poolp;
  707.     SECStatus rv;
  708.     poolp = cmsg->poolp;
  709.     mark = PORT_ArenaMark(poolp);
  710.     sigd = NSS_CMSSignedData_Create(cmsg);
  711.     if (sigd == NULL)
  712. goto loser;
  713.     /* no signerinfos, thus no digestAlgorithms */
  714.     /* but certs */
  715.     if (include_chain) {
  716. rv = NSS_CMSSignedData_AddCertChain(sigd, cert);
  717.     } else {
  718. rv = NSS_CMSSignedData_AddCertificate(sigd, cert);
  719.     }
  720.     if (rv != SECSuccess)
  721. goto loser;
  722.     /* RFC2630 5.2 sez:
  723.      * In the degenerate case where there are no signers, the
  724.      * EncapsulatedContentInfo value being "signed" is irrelevant.  In this
  725.      * case, the content type within the EncapsulatedContentInfo value being
  726.      * "signed" should be id-data (as defined in section 4), and the content
  727.      * field of the EncapsulatedContentInfo value should be omitted.
  728.      */
  729.     rv = NSS_CMSContentInfo_SetContent_Data(cmsg, &(sigd->contentInfo), NULL, PR_TRUE);
  730.     if (rv != SECSuccess)
  731. goto loser;
  732.     PORT_ArenaUnmark(poolp, mark);
  733.     return sigd;
  734. loser:
  735.     if (sigd)
  736. NSS_CMSSignedData_Destroy(sigd);
  737.     PORT_ArenaRelease(poolp, mark);
  738.     return NULL;
  739. }
  740. /* TODO:
  741.  * NSS_CMSSignerInfo_GetReceiptRequest()
  742.  * NSS_CMSSignedData_HasReceiptRequest()
  743.  * easy way to iterate over signers
  744.  */