/security/nss/lib/smime/cmssigdata.c

http://github.com/zpao/v8monkey · C · 1175 lines · 756 code · 175 blank · 244 comment · 253 complexity · fb14197687a33aee9f49679fedf3355e MD5 · raw file

  1. /* ***** BEGIN LICENSE BLOCK *****
  2. * Version: MPL 1.1/GPL 2.0/LGPL 2.1
  3. *
  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/
  8. *
  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
  12. * License.
  13. *
  14. * The Original Code is the Netscape security libraries.
  15. *
  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.
  20. *
  21. * Contributor(s):
  22. *
  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.
  34. *
  35. * ***** END LICENSE BLOCK ***** */
  36. /*
  37. * CMS signedData methods.
  38. *
  39. * $Id: cmssigdata.c,v 1.32 2011/09/30 19:42:09 rrelyea%redhat.com Exp $
  40. */
  41. #include "cmslocal.h"
  42. #include "cert.h"
  43. /*#include "cdbhdl.h"*/
  44. #include "secasn1.h"
  45. #include "secitem.h"
  46. #include "secoid.h"
  47. #include "pk11func.h"
  48. #include "secerr.h"
  49. NSSCMSSignedData *
  50. NSS_CMSSignedData_Create(NSSCMSMessage *cmsg)
  51. {
  52. void *mark;
  53. NSSCMSSignedData *sigd;
  54. PLArenaPool *poolp;
  55. if (!cmsg) {
  56. PORT_SetError(SEC_ERROR_INVALID_ARGS);
  57. return NULL;
  58. }
  59. poolp = cmsg->poolp;
  60. mark = PORT_ArenaMark(poolp);
  61. sigd = (NSSCMSSignedData *)PORT_ArenaZAlloc (poolp, sizeof(NSSCMSSignedData));
  62. if (sigd == NULL)
  63. goto loser;
  64. sigd->cmsg = cmsg;
  65. /* signerInfos, certs, certlists, crls are all empty */
  66. /* version is set in NSS_CMSSignedData_Finalize() */
  67. PORT_ArenaUnmark(poolp, mark);
  68. return sigd;
  69. loser:
  70. PORT_ArenaRelease(poolp, mark);
  71. return NULL;
  72. }
  73. void
  74. NSS_CMSSignedData_Destroy(NSSCMSSignedData *sigd)
  75. {
  76. CERTCertificate **certs, **tempCerts, *cert;
  77. CERTCertificateList **certlists, *certlist;
  78. NSSCMSSignerInfo **signerinfos, *si;
  79. if (sigd == NULL)
  80. return;
  81. certs = sigd->certs;
  82. tempCerts = sigd->tempCerts;
  83. certlists = sigd->certLists;
  84. signerinfos = sigd->signerInfos;
  85. if (certs != NULL) {
  86. while ((cert = *certs++) != NULL)
  87. CERT_DestroyCertificate (cert);
  88. }
  89. if (tempCerts != NULL) {
  90. while ((cert = *tempCerts++) != NULL)
  91. CERT_DestroyCertificate (cert);
  92. }
  93. if (certlists != NULL) {
  94. while ((certlist = *certlists++) != NULL)
  95. CERT_DestroyCertificateList (certlist);
  96. }
  97. if (signerinfos != NULL) {
  98. while ((si = *signerinfos++) != NULL)
  99. NSS_CMSSignerInfo_Destroy(si);
  100. }
  101. /* everything's in a pool, so don't worry about the storage */
  102. NSS_CMSContentInfo_Destroy(&(sigd->contentInfo));
  103. }
  104. /*
  105. * NSS_CMSSignedData_Encode_BeforeStart - do all the necessary things to a SignedData
  106. * before start of encoding.
  107. *
  108. * In detail:
  109. * - find out about the right value to put into sigd->version
  110. * - come up with a list of digestAlgorithms (which should be the union of the algorithms
  111. * in the signerinfos).
  112. * If we happen to have a pre-set list of algorithms (and digest values!), we
  113. * check if we have all the signerinfos' algorithms. If not, this is an error.
  114. */
  115. SECStatus
  116. NSS_CMSSignedData_Encode_BeforeStart(NSSCMSSignedData *sigd)
  117. {
  118. NSSCMSSignerInfo *signerinfo;
  119. SECOidTag digestalgtag;
  120. SECItem *dummy;
  121. int version;
  122. SECStatus rv;
  123. PRBool haveDigests = PR_FALSE;
  124. int n, i;
  125. PLArenaPool *poolp;
  126. if (!sigd) {
  127. PORT_SetError(SEC_ERROR_INVALID_ARGS);
  128. return SECFailure;
  129. }
  130. poolp = sigd->cmsg->poolp;
  131. /* we assume that we have precomputed digests if there is a list of algorithms, and */
  132. /* a chunk of data for each of those algorithms */
  133. if (sigd->digestAlgorithms != NULL && sigd->digests != NULL) {
  134. for (i=0; sigd->digestAlgorithms[i] != NULL; i++) {
  135. if (sigd->digests[i] == NULL)
  136. break;
  137. }
  138. if (sigd->digestAlgorithms[i] == NULL) /* reached the end of the array? */
  139. haveDigests = PR_TRUE; /* yes: we must have all the digests */
  140. }
  141. version = NSS_CMS_SIGNED_DATA_VERSION_BASIC;
  142. /* RFC2630 5.1 "version is the syntax version number..." */
  143. if (NSS_CMSContentInfo_GetContentTypeTag(&(sigd->contentInfo)) != SEC_OID_PKCS7_DATA)
  144. version = NSS_CMS_SIGNED_DATA_VERSION_EXT;
  145. /* prepare all the SignerInfos (there may be none) */
  146. for (i=0; i < NSS_CMSSignedData_SignerInfoCount(sigd); i++) {
  147. signerinfo = NSS_CMSSignedData_GetSignerInfo(sigd, i);
  148. /* RFC2630 5.1 "version is the syntax version number..." */
  149. if (NSS_CMSSignerInfo_GetVersion(signerinfo) != NSS_CMS_SIGNER_INFO_VERSION_ISSUERSN)
  150. version = NSS_CMS_SIGNED_DATA_VERSION_EXT;
  151. /* collect digestAlgorithms from SignerInfos */
  152. /* (we need to know which algorithms we have when the content comes in) */
  153. /* do not overwrite any existing digestAlgorithms (and digest) */
  154. digestalgtag = NSS_CMSSignerInfo_GetDigestAlgTag(signerinfo);
  155. n = NSS_CMSAlgArray_GetIndexByAlgTag(sigd->digestAlgorithms, digestalgtag);
  156. if (n < 0 && haveDigests) {
  157. /* oops, there is a digestalg we do not have a digest for */
  158. /* but we were supposed to have all the digests already... */
  159. goto loser;
  160. } else if (n < 0) {
  161. /* add the digestAlgorithm & a NULL digest */
  162. rv = NSS_CMSSignedData_AddDigest(poolp, sigd, digestalgtag, NULL);
  163. if (rv != SECSuccess)
  164. goto loser;
  165. } else {
  166. /* found it, nothing to do */
  167. }
  168. }
  169. dummy = SEC_ASN1EncodeInteger(poolp, &(sigd->version), (long)version);
  170. if (dummy == NULL)
  171. return SECFailure;
  172. /* this is a SET OF, so we need to sort them guys */
  173. rv = NSS_CMSArray_SortByDER((void **)sigd->digestAlgorithms,
  174. SEC_ASN1_GET(SECOID_AlgorithmIDTemplate),
  175. (void **)sigd->digests);
  176. if (rv != SECSuccess)
  177. return SECFailure;
  178. return SECSuccess;
  179. loser:
  180. return SECFailure;
  181. }
  182. SECStatus
  183. NSS_CMSSignedData_Encode_BeforeData(NSSCMSSignedData *sigd)
  184. {
  185. SECStatus rv;
  186. if (!sigd) {
  187. PORT_SetError(SEC_ERROR_INVALID_ARGS);
  188. return SECFailure;
  189. }
  190. rv = NSS_CMSContentInfo_Private_Init(&sigd->contentInfo);
  191. if (rv != SECSuccess) {
  192. return SECFailure;
  193. }
  194. /* set up the digests */
  195. if (sigd->digests && sigd->digests[0]) {
  196. sigd->contentInfo.privateInfo->digcx = NULL; /* don't attempt to make new ones. */
  197. } else if (sigd->digestAlgorithms != NULL) {
  198. sigd->contentInfo.privateInfo->digcx =
  199. NSS_CMSDigestContext_StartMultiple(sigd->digestAlgorithms);
  200. if (sigd->contentInfo.privateInfo->digcx == NULL)
  201. return SECFailure;
  202. }
  203. return SECSuccess;
  204. }
  205. /*
  206. * NSS_CMSSignedData_Encode_AfterData - do all the necessary things to a SignedData
  207. * after all the encapsulated data was passed through the encoder.
  208. *
  209. * In detail:
  210. * - create the signatures in all the SignerInfos
  211. *
  212. * Please note that nothing is done to the Certificates and CRLs in the message - this
  213. * is entirely the responsibility of our callers.
  214. */
  215. SECStatus
  216. NSS_CMSSignedData_Encode_AfterData(NSSCMSSignedData *sigd)
  217. {
  218. NSSCMSSignerInfo **signerinfos, *signerinfo;
  219. NSSCMSContentInfo *cinfo;
  220. SECOidTag digestalgtag;
  221. SECStatus ret = SECFailure;
  222. SECStatus rv;
  223. SECItem *contentType;
  224. int certcount;
  225. int i, ci, cli, n, rci, si;
  226. PLArenaPool *poolp;
  227. CERTCertificateList *certlist;
  228. extern const SEC_ASN1Template NSSCMSSignerInfoTemplate[];
  229. if (!sigd) {
  230. PORT_SetError(SEC_ERROR_INVALID_ARGS);
  231. return SECFailure;
  232. }
  233. poolp = sigd->cmsg->poolp;
  234. cinfo = &(sigd->contentInfo);
  235. /* did we have digest calculation going on? */
  236. if (cinfo->privateInfo && cinfo->privateInfo->digcx) {
  237. rv = NSS_CMSDigestContext_FinishMultiple(cinfo->privateInfo->digcx, poolp,
  238. &(sigd->digests));
  239. /* error has been set by NSS_CMSDigestContext_FinishMultiple */
  240. cinfo->privateInfo->digcx = NULL;
  241. if (rv != SECSuccess)
  242. goto loser;
  243. }
  244. signerinfos = sigd->signerInfos;
  245. certcount = 0;
  246. /* prepare all the SignerInfos (there may be none) */
  247. for (i=0; i < NSS_CMSSignedData_SignerInfoCount(sigd); i++) {
  248. signerinfo = NSS_CMSSignedData_GetSignerInfo(sigd, i);
  249. /* find correct digest for this signerinfo */
  250. digestalgtag = NSS_CMSSignerInfo_GetDigestAlgTag(signerinfo);
  251. n = NSS_CMSAlgArray_GetIndexByAlgTag(sigd->digestAlgorithms, digestalgtag);
  252. if (n < 0 || sigd->digests == NULL || sigd->digests[n] == NULL) {
  253. /* oops - digest not found */
  254. PORT_SetError(SEC_ERROR_DIGEST_NOT_FOUND);
  255. goto loser;
  256. }
  257. /* XXX if our content is anything else but data, we need to force the
  258. * presence of signed attributes (RFC2630 5.3 "signedAttributes is a
  259. * collection...") */
  260. /* pass contentType here as we want a contentType attribute */
  261. if ((contentType = NSS_CMSContentInfo_GetContentTypeOID(cinfo)) == NULL)
  262. goto loser;
  263. /* sign the thing */
  264. rv = NSS_CMSSignerInfo_Sign(signerinfo, sigd->digests[n], contentType);
  265. if (rv != SECSuccess)
  266. goto loser;
  267. /* while we're at it, count number of certs in certLists */
  268. certlist = NSS_CMSSignerInfo_GetCertList(signerinfo);
  269. if (certlist)
  270. certcount += certlist->len;
  271. }
  272. /* this is a SET OF, so we need to sort them guys */
  273. rv = NSS_CMSArray_SortByDER((void **)signerinfos, NSSCMSSignerInfoTemplate, NULL);
  274. if (rv != SECSuccess)
  275. goto loser;
  276. /*
  277. * now prepare certs & crls
  278. */
  279. /* count the rest of the certs */
  280. if (sigd->certs != NULL) {
  281. for (ci = 0; sigd->certs[ci] != NULL; ci++)
  282. certcount++;
  283. }
  284. if (sigd->certLists != NULL) {
  285. for (cli = 0; sigd->certLists[cli] != NULL; cli++)
  286. certcount += sigd->certLists[cli]->len;
  287. }
  288. if (certcount == 0) {
  289. sigd->rawCerts = NULL;
  290. } else {
  291. /*
  292. * Combine all of the certs and cert chains into rawcerts.
  293. * Note: certcount is an upper bound; we may not need that many slots
  294. * but we will allocate anyway to avoid having to do another pass.
  295. * (The temporary space saving is not worth it.)
  296. *
  297. * XXX ARGH - this NEEDS to be fixed. need to come up with a decent
  298. * SetOfDERcertficates implementation
  299. */
  300. sigd->rawCerts = (SECItem **)PORT_ArenaAlloc(poolp, (certcount + 1) * sizeof(SECItem *));
  301. if (sigd->rawCerts == NULL)
  302. return SECFailure;
  303. /*
  304. * XXX Want to check for duplicates and not add *any* cert that is
  305. * already in the set. This will be more important when we start
  306. * dealing with larger sets of certs, dual-key certs (signing and
  307. * encryption), etc. For the time being we can slide by...
  308. *
  309. * XXX ARGH - this NEEDS to be fixed. need to come up with a decent
  310. * SetOfDERcertficates implementation
  311. */
  312. rci = 0;
  313. if (signerinfos != NULL) {
  314. for (si = 0; signerinfos[si] != NULL; si++) {
  315. signerinfo = signerinfos[si];
  316. for (ci = 0; ci < signerinfo->certList->len; ci++)
  317. sigd->rawCerts[rci++] = &(signerinfo->certList->certs[ci]);
  318. }
  319. }
  320. if (sigd->certs != NULL) {
  321. for (ci = 0; sigd->certs[ci] != NULL; ci++)
  322. sigd->rawCerts[rci++] = &(sigd->certs[ci]->derCert);
  323. }
  324. if (sigd->certLists != NULL) {
  325. for (cli = 0; sigd->certLists[cli] != NULL; cli++) {
  326. for (ci = 0; ci < sigd->certLists[cli]->len; ci++)
  327. sigd->rawCerts[rci++] = &(sigd->certLists[cli]->certs[ci]);
  328. }
  329. }
  330. sigd->rawCerts[rci] = NULL;
  331. /* this is a SET OF, so we need to sort them guys - we have the DER already, though */
  332. NSS_CMSArray_Sort((void **)sigd->rawCerts, NSS_CMSUtil_DERCompare, NULL, NULL);
  333. }
  334. ret = SECSuccess;
  335. loser:
  336. return ret;
  337. }
  338. SECStatus
  339. NSS_CMSSignedData_Decode_BeforeData(NSSCMSSignedData *sigd)
  340. {
  341. SECStatus rv;
  342. if (!sigd) {
  343. PORT_SetError(SEC_ERROR_INVALID_ARGS);
  344. return SECFailure;
  345. }
  346. rv = NSS_CMSContentInfo_Private_Init(&sigd->contentInfo);
  347. if (rv != SECSuccess) {
  348. return SECFailure;
  349. }
  350. /* handle issue with Windows 2003 servers and kerberos */
  351. if (sigd->digestAlgorithms != NULL) {
  352. int i;
  353. for (i=0; sigd->digestAlgorithms[i] != NULL; i++) {
  354. SECAlgorithmID *algid = sigd->digestAlgorithms[i];
  355. SECOidTag senttag= SECOID_FindOIDTag(&algid->algorithm);
  356. SECOidTag maptag = NSS_CMSUtil_MapSignAlgs(senttag);
  357. if (maptag != senttag) {
  358. SECOidData *hashoid = SECOID_FindOIDByTag(maptag);
  359. rv = SECITEM_CopyItem(sigd->cmsg->poolp, &algid->algorithm
  360. ,&hashoid->oid);
  361. if (rv != SECSuccess) {
  362. return rv;
  363. }
  364. }
  365. }
  366. }
  367. /* set up the digests */
  368. if (sigd->digestAlgorithms != NULL && sigd->digests == NULL) {
  369. /* if digests are already there, do nothing */
  370. sigd->contentInfo.privateInfo->digcx = NSS_CMSDigestContext_StartMultiple(sigd->digestAlgorithms);
  371. if (sigd->contentInfo.privateInfo->digcx == NULL)
  372. return SECFailure;
  373. }
  374. return SECSuccess;
  375. }
  376. /*
  377. * NSS_CMSSignedData_Decode_AfterData - do all the necessary things to a
  378. * SignedData after all the encapsulated data was passed through the decoder.
  379. */
  380. SECStatus
  381. NSS_CMSSignedData_Decode_AfterData(NSSCMSSignedData *sigd)
  382. {
  383. SECStatus rv = SECSuccess;
  384. if (!sigd) {
  385. PORT_SetError(SEC_ERROR_INVALID_ARGS);
  386. return SECFailure;
  387. }
  388. /* did we have digest calculation going on? */
  389. if (sigd->contentInfo.privateInfo && sigd->contentInfo.privateInfo->digcx) {
  390. rv = NSS_CMSDigestContext_FinishMultiple(sigd->contentInfo.privateInfo->digcx,
  391. sigd->cmsg->poolp, &(sigd->digests));
  392. /* error set by NSS_CMSDigestContext_FinishMultiple */
  393. sigd->contentInfo.privateInfo->digcx = NULL;
  394. }
  395. return rv;
  396. }
  397. /*
  398. * NSS_CMSSignedData_Decode_AfterEnd - do all the necessary things to a SignedData
  399. * after all decoding is finished.
  400. */
  401. SECStatus
  402. NSS_CMSSignedData_Decode_AfterEnd(NSSCMSSignedData *sigd)
  403. {
  404. NSSCMSSignerInfo **signerinfos = NULL;
  405. int i;
  406. if (!sigd) {
  407. PORT_SetError(SEC_ERROR_INVALID_ARGS);
  408. return SECFailure;
  409. }
  410. /* set cmsg for all the signerinfos */
  411. signerinfos = sigd->signerInfos;
  412. /* set cmsg for all the signerinfos */
  413. if (signerinfos) {
  414. for (i = 0; signerinfos[i] != NULL; i++)
  415. signerinfos[i]->cmsg = sigd->cmsg;
  416. }
  417. return SECSuccess;
  418. }
  419. /*
  420. * NSS_CMSSignedData_GetSignerInfos - retrieve the SignedData's signer list
  421. */
  422. NSSCMSSignerInfo **
  423. NSS_CMSSignedData_GetSignerInfos(NSSCMSSignedData *sigd)
  424. {
  425. if (!sigd) {
  426. PORT_SetError(SEC_ERROR_INVALID_ARGS);
  427. return NULL;
  428. }
  429. return sigd->signerInfos;
  430. }
  431. int
  432. NSS_CMSSignedData_SignerInfoCount(NSSCMSSignedData *sigd)
  433. {
  434. if (!sigd) {
  435. PORT_SetError(SEC_ERROR_INVALID_ARGS);
  436. return 0;
  437. }
  438. return NSS_CMSArray_Count((void **)sigd->signerInfos);
  439. }
  440. NSSCMSSignerInfo *
  441. NSS_CMSSignedData_GetSignerInfo(NSSCMSSignedData *sigd, int i)
  442. {
  443. if (!sigd) {
  444. PORT_SetError(SEC_ERROR_INVALID_ARGS);
  445. return NULL;
  446. }
  447. return sigd->signerInfos[i];
  448. }
  449. /*
  450. * NSS_CMSSignedData_GetDigestAlgs - retrieve the SignedData's digest algorithm list
  451. */
  452. SECAlgorithmID **
  453. NSS_CMSSignedData_GetDigestAlgs(NSSCMSSignedData *sigd)
  454. {
  455. if (!sigd) {
  456. PORT_SetError(SEC_ERROR_INVALID_ARGS);
  457. return NULL;
  458. }
  459. return sigd->digestAlgorithms;
  460. }
  461. /*
  462. * NSS_CMSSignedData_GetContentInfo - return pointer to this signedData's contentinfo
  463. */
  464. NSSCMSContentInfo *
  465. NSS_CMSSignedData_GetContentInfo(NSSCMSSignedData *sigd)
  466. {
  467. if (!sigd) {
  468. PORT_SetError(SEC_ERROR_INVALID_ARGS);
  469. return NULL;
  470. }
  471. return &(sigd->contentInfo);
  472. }
  473. /*
  474. * NSS_CMSSignedData_GetCertificateList - retrieve the SignedData's certificate list
  475. */
  476. SECItem **
  477. NSS_CMSSignedData_GetCertificateList(NSSCMSSignedData *sigd)
  478. {
  479. if (!sigd) {
  480. PORT_SetError(SEC_ERROR_INVALID_ARGS);
  481. return NULL;
  482. }
  483. return sigd->rawCerts;
  484. }
  485. SECStatus
  486. NSS_CMSSignedData_ImportCerts(NSSCMSSignedData *sigd, CERTCertDBHandle *certdb,
  487. SECCertUsage certusage, PRBool keepcerts)
  488. {
  489. int certcount;
  490. CERTCertificate **certArray = NULL;
  491. CERTCertList *certList = NULL;
  492. CERTCertListNode *node;
  493. SECStatus rv;
  494. SECItem **rawArray;
  495. int i;
  496. PRTime now;
  497. if (!sigd) {
  498. PORT_SetError(SEC_ERROR_INVALID_ARGS);
  499. return SECFailure;
  500. }
  501. certcount = NSS_CMSArray_Count((void **)sigd->rawCerts);
  502. /* get the certs in the temp DB */
  503. rv = CERT_ImportCerts(certdb, certusage, certcount, sigd->rawCerts,
  504. &certArray, PR_FALSE, PR_FALSE, NULL);
  505. if (rv != SECSuccess) {
  506. goto loser;
  507. }
  508. /* save the certs so they don't get destroyed */
  509. for (i=0; i < certcount; i++) {
  510. CERTCertificate *cert = certArray[i];
  511. if (cert)
  512. NSS_CMSSignedData_AddTempCertificate(sigd, cert);
  513. }
  514. if (!keepcerts) {
  515. goto done;
  516. }
  517. /* build a CertList for filtering */
  518. certList = CERT_NewCertList();
  519. if (certList == NULL) {
  520. rv = SECFailure;
  521. goto loser;
  522. }
  523. for (i=0; i < certcount; i++) {
  524. CERTCertificate *cert = certArray[i];
  525. if (cert)
  526. cert = CERT_DupCertificate(cert);
  527. if (cert)
  528. CERT_AddCertToListTail(certList,cert);
  529. }
  530. /* filter out the certs we don't want */
  531. rv = CERT_FilterCertListByUsage(certList,certusage, PR_FALSE);
  532. if (rv != SECSuccess) {
  533. goto loser;
  534. }
  535. /* go down the remaining list of certs and verify that they have
  536. * valid chains, then import them.
  537. */
  538. now = PR_Now();
  539. for (node = CERT_LIST_HEAD(certList) ; !CERT_LIST_END(node,certList);
  540. node= CERT_LIST_NEXT(node)) {
  541. CERTCertificateList *certChain;
  542. if (CERT_VerifyCert(certdb, node->cert,
  543. PR_TRUE, certusage, now, NULL, NULL) != SECSuccess) {
  544. continue;
  545. }
  546. certChain = CERT_CertChainFromCert(node->cert, certusage, PR_FALSE);
  547. if (!certChain) {
  548. continue;
  549. }
  550. /*
  551. * CertChain returns an array of SECItems, import expects an array of
  552. * SECItem pointers. Create the SECItem Pointers from the array of
  553. * SECItems.
  554. */
  555. rawArray = (SECItem **)PORT_Alloc(certChain->len*sizeof (SECItem *));
  556. if (!rawArray) {
  557. CERT_DestroyCertificateList(certChain);
  558. continue;
  559. }
  560. for (i=0; i < certChain->len; i++) {
  561. rawArray[i] = &certChain->certs[i];
  562. }
  563. (void )CERT_ImportCerts(certdb, certusage, certChain->len,
  564. rawArray, NULL, keepcerts, PR_FALSE, NULL);
  565. PORT_Free(rawArray);
  566. CERT_DestroyCertificateList(certChain);
  567. }
  568. rv = SECSuccess;
  569. /* XXX CRL handling */
  570. done:
  571. if (sigd->signerInfos != NULL) {
  572. /* fill in all signerinfo's certs */
  573. for (i = 0; sigd->signerInfos[i] != NULL; i++)
  574. (void)NSS_CMSSignerInfo_GetSigningCertificate(
  575. sigd->signerInfos[i], certdb);
  576. }
  577. loser:
  578. /* now free everything */
  579. if (certArray) {
  580. CERT_DestroyCertArray(certArray,certcount);
  581. }
  582. if (certList) {
  583. CERT_DestroyCertList(certList);
  584. }
  585. return rv;
  586. }
  587. /*
  588. * XXX the digests need to be passed in BETWEEN the decoding and the verification in case
  589. * of external signatures!
  590. */
  591. /*
  592. * NSS_CMSSignedData_VerifySignerInfo - check the signatures.
  593. *
  594. * The digests were either calculated during decoding (and are stored in the
  595. * signedData itself) or set after decoding using NSS_CMSSignedData_SetDigests.
  596. *
  597. * The verification checks if the signing cert is valid and has a trusted chain
  598. * for the purpose specified by "certusage".
  599. */
  600. SECStatus
  601. NSS_CMSSignedData_VerifySignerInfo(NSSCMSSignedData *sigd, int i,
  602. CERTCertDBHandle *certdb, SECCertUsage certusage)
  603. {
  604. NSSCMSSignerInfo *signerinfo;
  605. NSSCMSContentInfo *cinfo;
  606. SECOidData *algiddata;
  607. SECItem *contentType, *digest;
  608. SECOidTag oidTag;
  609. SECStatus rv;
  610. if (!sigd) {
  611. PORT_SetError(SEC_ERROR_INVALID_ARGS);
  612. return SECFailure;
  613. }
  614. cinfo = &(sigd->contentInfo);
  615. signerinfo = sigd->signerInfos[i];
  616. /* verify certificate */
  617. rv = NSS_CMSSignerInfo_VerifyCertificate(signerinfo, certdb, certusage);
  618. if (rv != SECSuccess)
  619. return rv; /* error is set */
  620. /* find digest and contentType for signerinfo */
  621. algiddata = NSS_CMSSignerInfo_GetDigestAlg(signerinfo);
  622. oidTag = algiddata ? algiddata->offset : SEC_OID_UNKNOWN;
  623. digest = NSS_CMSSignedData_GetDigestValue(sigd, oidTag);
  624. /* NULL digest is acceptable. */
  625. contentType = NSS_CMSContentInfo_GetContentTypeOID(cinfo);
  626. /* NULL contentType is acceptable. */
  627. /* now verify signature */
  628. rv = NSS_CMSSignerInfo_Verify(signerinfo, digest, contentType);
  629. return rv;
  630. }
  631. /*
  632. * NSS_CMSSignedData_VerifyCertsOnly - verify the certs in a certs-only message
  633. */
  634. SECStatus
  635. NSS_CMSSignedData_VerifyCertsOnly(NSSCMSSignedData *sigd,
  636. CERTCertDBHandle *certdb,
  637. SECCertUsage usage)
  638. {
  639. CERTCertificate *cert;
  640. SECStatus rv = SECSuccess;
  641. int i;
  642. int count;
  643. PRTime now;
  644. if (!sigd || !certdb || !sigd->rawCerts) {
  645. PORT_SetError(SEC_ERROR_INVALID_ARGS);
  646. return SECFailure;
  647. }
  648. count = NSS_CMSArray_Count((void**)sigd->rawCerts);
  649. now = PR_Now();
  650. for (i=0; i < count; i++) {
  651. if (sigd->certs && sigd->certs[i]) {
  652. cert = CERT_DupCertificate(sigd->certs[i]);
  653. } else {
  654. cert = CERT_FindCertByDERCert(certdb, sigd->rawCerts[i]);
  655. if (!cert) {
  656. rv = SECFailure;
  657. break;
  658. }
  659. }
  660. rv |= CERT_VerifyCert(certdb, cert, PR_TRUE, usage, now,
  661. NULL, NULL);
  662. CERT_DestroyCertificate(cert);
  663. }
  664. return rv;
  665. }
  666. /*
  667. * NSS_CMSSignedData_HasDigests - see if we have digests in place
  668. */
  669. PRBool
  670. NSS_CMSSignedData_HasDigests(NSSCMSSignedData *sigd)
  671. {
  672. if (!sigd) {
  673. PORT_SetError(SEC_ERROR_INVALID_ARGS);
  674. return PR_FALSE;
  675. }
  676. return (sigd->digests != NULL);
  677. }
  678. SECStatus
  679. NSS_CMSSignedData_AddCertList(NSSCMSSignedData *sigd, CERTCertificateList *certlist)
  680. {
  681. SECStatus rv;
  682. if (!sigd || !certlist) {
  683. PORT_SetError(SEC_ERROR_INVALID_ARGS);
  684. return SECFailure;
  685. }
  686. /* XXX memory?? a certlist has an arena of its own and is not refcounted!?!? */
  687. rv = NSS_CMSArray_Add(sigd->cmsg->poolp, (void ***)&(sigd->certLists), (void *)certlist);
  688. return rv;
  689. }
  690. /*
  691. * NSS_CMSSignedData_AddCertChain - add cert and its entire chain to the set of certs
  692. */
  693. SECStatus
  694. NSS_CMSSignedData_AddCertChain(NSSCMSSignedData *sigd, CERTCertificate *cert)
  695. {
  696. CERTCertificateList *certlist;
  697. SECCertUsage usage;
  698. SECStatus rv;
  699. usage = certUsageEmailSigner;
  700. if (!sigd || !cert) {
  701. PORT_SetError(SEC_ERROR_INVALID_ARGS);
  702. return SECFailure;
  703. }
  704. /* do not include root */
  705. certlist = CERT_CertChainFromCert(cert, usage, PR_FALSE);
  706. if (certlist == NULL)
  707. return SECFailure;
  708. rv = NSS_CMSSignedData_AddCertList(sigd, certlist);
  709. return rv;
  710. }
  711. extern SECStatus
  712. NSS_CMSSignedData_AddTempCertificate(NSSCMSSignedData *sigd, CERTCertificate *cert)
  713. {
  714. CERTCertificate *c;
  715. SECStatus rv;
  716. if (!sigd || !cert) {
  717. PORT_SetError(SEC_ERROR_INVALID_ARGS);
  718. return SECFailure;
  719. }
  720. c = CERT_DupCertificate(cert);
  721. rv = NSS_CMSArray_Add(sigd->cmsg->poolp, (void ***)&(sigd->tempCerts), (void *)c);
  722. return rv;
  723. }
  724. SECStatus
  725. NSS_CMSSignedData_AddCertificate(NSSCMSSignedData *sigd, CERTCertificate *cert)
  726. {
  727. CERTCertificate *c;
  728. SECStatus rv;
  729. if (!sigd || !cert) {
  730. PORT_SetError(SEC_ERROR_INVALID_ARGS);
  731. return SECFailure;
  732. }
  733. c = CERT_DupCertificate(cert);
  734. rv = NSS_CMSArray_Add(sigd->cmsg->poolp, (void ***)&(sigd->certs), (void *)c);
  735. return rv;
  736. }
  737. PRBool
  738. NSS_CMSSignedData_ContainsCertsOrCrls(NSSCMSSignedData *sigd)
  739. {
  740. if (!sigd) {
  741. PORT_SetError(SEC_ERROR_INVALID_ARGS);
  742. return PR_FALSE;
  743. }
  744. if (sigd->rawCerts != NULL && sigd->rawCerts[0] != NULL)
  745. return PR_TRUE;
  746. else if (sigd->crls != NULL && sigd->crls[0] != NULL)
  747. return PR_TRUE;
  748. else
  749. return PR_FALSE;
  750. }
  751. SECStatus
  752. NSS_CMSSignedData_AddSignerInfo(NSSCMSSignedData *sigd,
  753. NSSCMSSignerInfo *signerinfo)
  754. {
  755. void *mark;
  756. SECStatus rv;
  757. SECOidTag digestalgtag;
  758. PLArenaPool *poolp;
  759. if (!sigd || !signerinfo) {
  760. PORT_SetError(SEC_ERROR_INVALID_ARGS);
  761. return SECFailure;
  762. }
  763. poolp = sigd->cmsg->poolp;
  764. mark = PORT_ArenaMark(poolp);
  765. /* add signerinfo */
  766. rv = NSS_CMSArray_Add(poolp, (void ***)&(sigd->signerInfos), (void *)signerinfo);
  767. if (rv != SECSuccess)
  768. goto loser;
  769. /*
  770. * add empty digest
  771. * Empty because we don't have it yet. Either it gets created during encoding
  772. * (if the data is present) or has to be set externally.
  773. * XXX maybe pass it in optionally?
  774. */
  775. digestalgtag = NSS_CMSSignerInfo_GetDigestAlgTag(signerinfo);
  776. rv = NSS_CMSSignedData_SetDigestValue(sigd, digestalgtag, NULL);
  777. if (rv != SECSuccess)
  778. goto loser;
  779. /*
  780. * The last thing to get consistency would be adding the digest.
  781. */
  782. PORT_ArenaUnmark(poolp, mark);
  783. return SECSuccess;
  784. loser:
  785. PORT_ArenaRelease (poolp, mark);
  786. return SECFailure;
  787. }
  788. /*
  789. * NSS_CMSSignedData_SetDigests - set a signedData's digests member
  790. *
  791. * "digestalgs" - array of digest algorithm IDs
  792. * "digests" - array of digests corresponding to the digest algorithms
  793. */
  794. SECStatus
  795. NSS_CMSSignedData_SetDigests(NSSCMSSignedData *sigd,
  796. SECAlgorithmID **digestalgs,
  797. SECItem **digests)
  798. {
  799. int cnt, i, idx;
  800. if (!sigd || !digestalgs || !digests) {
  801. PORT_SetError(SEC_ERROR_INVALID_ARGS);
  802. return SECFailure;
  803. }
  804. if (sigd->digestAlgorithms == NULL) {
  805. PORT_SetError(SEC_ERROR_INVALID_ARGS);
  806. return SECFailure;
  807. }
  808. /* we assume that the digests array is just not there yet */
  809. PORT_Assert(sigd->digests == NULL);
  810. if (sigd->digests != NULL) {
  811. PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
  812. return SECFailure;
  813. }
  814. /* now allocate one (same size as digestAlgorithms) */
  815. cnt = NSS_CMSArray_Count((void **)sigd->digestAlgorithms);
  816. sigd->digests = PORT_ArenaZAlloc(sigd->cmsg->poolp, (cnt + 1) * sizeof(SECItem *));
  817. if (sigd->digests == NULL) {
  818. PORT_SetError(SEC_ERROR_NO_MEMORY);
  819. return SECFailure;
  820. }
  821. for (i = 0; sigd->digestAlgorithms[i] != NULL; i++) {
  822. /* try to find the sigd's i'th digest algorithm in the array we passed in */
  823. idx = NSS_CMSAlgArray_GetIndexByAlgID(digestalgs, sigd->digestAlgorithms[i]);
  824. if (idx < 0) {
  825. PORT_SetError(SEC_ERROR_DIGEST_NOT_FOUND);
  826. return SECFailure;
  827. }
  828. if (!digests[idx]) {
  829. /* We have no digest for this algorithm, probably because it is
  830. ** unrecognized or unsupported. We'll ignore this here. If this
  831. ** digest is needed later, an error will be be generated then.
  832. */
  833. continue;
  834. }
  835. /* found it - now set it */
  836. if ((sigd->digests[i] = SECITEM_AllocItem(sigd->cmsg->poolp, NULL, 0)) == NULL ||
  837. SECITEM_CopyItem(sigd->cmsg->poolp, sigd->digests[i], digests[idx]) != SECSuccess)
  838. {
  839. PORT_SetError(SEC_ERROR_NO_MEMORY);
  840. return SECFailure;
  841. }
  842. }
  843. return SECSuccess;
  844. }
  845. SECStatus
  846. NSS_CMSSignedData_SetDigestValue(NSSCMSSignedData *sigd,
  847. SECOidTag digestalgtag,
  848. SECItem *digestdata)
  849. {
  850. SECItem *digest = NULL;
  851. PLArenaPool *poolp;
  852. void *mark;
  853. int n, cnt;
  854. if (!sigd) {
  855. PORT_SetError(SEC_ERROR_INVALID_ARGS);
  856. return SECFailure;
  857. }
  858. poolp = sigd->cmsg->poolp;
  859. mark = PORT_ArenaMark(poolp);
  860. if (digestdata) {
  861. digest = (SECItem *) PORT_ArenaZAlloc(poolp,sizeof(SECItem));
  862. /* copy digestdata item to arena (in case we have it and are not only making room) */
  863. if (SECITEM_CopyItem(poolp, digest, digestdata) != SECSuccess)
  864. goto loser;
  865. }
  866. /* now allocate one (same size as digestAlgorithms) */
  867. if (sigd->digests == NULL) {
  868. cnt = NSS_CMSArray_Count((void **)sigd->digestAlgorithms);
  869. sigd->digests = PORT_ArenaZAlloc(sigd->cmsg->poolp, (cnt + 1) * sizeof(SECItem *));
  870. if (sigd->digests == NULL) {
  871. PORT_SetError(SEC_ERROR_NO_MEMORY);
  872. return SECFailure;
  873. }
  874. }
  875. n = -1;
  876. if (sigd->digestAlgorithms != NULL)
  877. n = NSS_CMSAlgArray_GetIndexByAlgTag(sigd->digestAlgorithms, digestalgtag);
  878. /* if not found, add a digest */
  879. if (n < 0) {
  880. if (NSS_CMSSignedData_AddDigest(poolp, sigd, digestalgtag, digest) != SECSuccess)
  881. goto loser;
  882. } else {
  883. /* replace NULL pointer with digest item (and leak previous value) */
  884. sigd->digests[n] = digest;
  885. }
  886. PORT_ArenaUnmark(poolp, mark);
  887. return SECSuccess;
  888. loser:
  889. PORT_ArenaRelease(poolp, mark);
  890. return SECFailure;
  891. }
  892. SECStatus
  893. NSS_CMSSignedData_AddDigest(PRArenaPool *poolp,
  894. NSSCMSSignedData *sigd,
  895. SECOidTag digestalgtag,
  896. SECItem *digest)
  897. {
  898. SECAlgorithmID *digestalg;
  899. void *mark;
  900. if (!sigd || !poolp) {
  901. PORT_SetError(SEC_ERROR_INVALID_ARGS);
  902. return SECFailure;
  903. }
  904. mark = PORT_ArenaMark(poolp);
  905. digestalg = PORT_ArenaZAlloc(poolp, sizeof(SECAlgorithmID));
  906. if (digestalg == NULL)
  907. goto loser;
  908. if (SECOID_SetAlgorithmID (poolp, digestalg, digestalgtag, NULL) != SECSuccess) /* no params */
  909. goto loser;
  910. if (NSS_CMSArray_Add(poolp, (void ***)&(sigd->digestAlgorithms), (void *)digestalg) != SECSuccess ||
  911. /* even if digest is NULL, add dummy to have same-size array */
  912. NSS_CMSArray_Add(poolp, (void ***)&(sigd->digests), (void *)digest) != SECSuccess)
  913. {
  914. goto loser;
  915. }
  916. PORT_ArenaUnmark(poolp, mark);
  917. return SECSuccess;
  918. loser:
  919. PORT_ArenaRelease(poolp, mark);
  920. return SECFailure;
  921. }
  922. /* XXX This function doesn't set the error code on failure. */
  923. SECItem *
  924. NSS_CMSSignedData_GetDigestValue(NSSCMSSignedData *sigd, SECOidTag digestalgtag)
  925. {
  926. int n;
  927. if (!sigd) {
  928. PORT_SetError(SEC_ERROR_INVALID_ARGS);
  929. return NULL;
  930. }
  931. if (sigd->digestAlgorithms == NULL || sigd->digests == NULL) {
  932. PORT_SetError(SEC_ERROR_DIGEST_NOT_FOUND);
  933. return NULL;
  934. }
  935. n = NSS_CMSAlgArray_GetIndexByAlgTag(sigd->digestAlgorithms, digestalgtag);
  936. return (n < 0) ? NULL : sigd->digests[n];
  937. }
  938. /* =============================================================================
  939. * Misc. utility functions
  940. */
  941. /*
  942. * NSS_CMSSignedData_CreateCertsOnly - create a certs-only SignedData.
  943. *
  944. * cert - base certificates that will be included
  945. * include_chain - if true, include the complete cert chain for cert
  946. *
  947. * More certs and chains can be added via AddCertificate and AddCertChain.
  948. *
  949. * An error results in a return value of NULL and an error set.
  950. *
  951. * XXXX CRLs
  952. */
  953. NSSCMSSignedData *
  954. NSS_CMSSignedData_CreateCertsOnly(NSSCMSMessage *cmsg, CERTCertificate *cert, PRBool include_chain)
  955. {
  956. NSSCMSSignedData *sigd;
  957. void *mark;
  958. PLArenaPool *poolp;
  959. SECStatus rv;
  960. if (!cmsg || !cert) {
  961. PORT_SetError(SEC_ERROR_INVALID_ARGS);
  962. return NULL;
  963. }
  964. poolp = cmsg->poolp;
  965. mark = PORT_ArenaMark(poolp);
  966. sigd = NSS_CMSSignedData_Create(cmsg);
  967. if (sigd == NULL)
  968. goto loser;
  969. /* no signerinfos, thus no digestAlgorithms */
  970. /* but certs */
  971. if (include_chain) {
  972. rv = NSS_CMSSignedData_AddCertChain(sigd, cert);
  973. } else {
  974. rv = NSS_CMSSignedData_AddCertificate(sigd, cert);
  975. }
  976. if (rv != SECSuccess)
  977. goto loser;
  978. /* RFC2630 5.2 sez:
  979. * In the degenerate case where there are no signers, the
  980. * EncapsulatedContentInfo value being "signed" is irrelevant. In this
  981. * case, the content type within the EncapsulatedContentInfo value being
  982. * "signed" should be id-data (as defined in section 4), and the content
  983. * field of the EncapsulatedContentInfo value should be omitted.
  984. */
  985. rv = NSS_CMSContentInfo_SetContent_Data(cmsg, &(sigd->contentInfo), NULL, PR_TRUE);
  986. if (rv != SECSuccess)
  987. goto loser;
  988. PORT_ArenaUnmark(poolp, mark);
  989. return sigd;
  990. loser:
  991. if (sigd)
  992. NSS_CMSSignedData_Destroy(sigd);
  993. PORT_ArenaRelease(poolp, mark);
  994. return NULL;
  995. }
  996. /* TODO:
  997. * NSS_CMSSignerInfo_GetReceiptRequest()
  998. * NSS_CMSSignedData_HasReceiptRequest()
  999. * easy way to iterate over signers
  1000. */