1 /* ***** BEGIN LICENSE BLOCK *****
2 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
4 * The contents of this file are subject to the Mozilla Public License Version
5 * 1.1 (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 * http://www.mozilla.org/MPL/
9 * Software distributed under the License is distributed on an "AS IS" basis,
10 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
11 * for the specific language governing rights and limitations under the
14 * The Original Code is the Netscape security libraries.
16 * The Initial Developer of the Original Code is
17 * Netscape Communications Corporation.
18 * Portions created by the Initial Developer are Copyright (C) 1994-2000
19 * the Initial Developer. All Rights Reserved.
23 * Alternatively, the contents of this file may be used under the terms of
24 * either the GNU General Public License Version 2 or later (the "GPL"), or
25 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
26 * in which case the provisions of the GPL or the LGPL are applicable instead
27 * of those above. If you wish to allow use of your version of this file only
28 * under the terms of either the GPL or the LGPL, and not to allow others to
29 * use your version of this file under the terms of the MPL, indicate your
30 * decision by deleting the provisions above and replace them with the notice
31 * and other provisions required by the GPL or the LGPL. If you do not delete
32 * the provisions above, a recipient may use your version of this file under
33 * the terms of any one of the MPL, the GPL or the LGPL.
35 * ***** END LICENSE BLOCK ***** */
38 * CMS signedData methods.
40 * $Id: cmssigdata.c,v 1.29 2005/06/27 22:21:18 julien.pierre.bugs%sun.com Exp $
46 /*#include "cdbhdl.h"*/
54 NSS_CMSSignedData_Create(NSSCMSMessage
*cmsg
)
57 NSSCMSSignedData
*sigd
;
61 PORT_SetError(SEC_ERROR_INVALID_ARGS
);
67 mark
= PORT_ArenaMark(poolp
);
69 sigd
= (NSSCMSSignedData
*)PORT_ArenaZAlloc (poolp
, sizeof(NSSCMSSignedData
));
75 /* signerInfos, certs, certlists, crls are all empty */
76 /* version is set in NSS_CMSSignedData_Finalize() */
78 PORT_ArenaUnmark(poolp
, mark
);
82 PORT_ArenaRelease(poolp
, mark
);
87 NSS_CMSSignedData_Destroy(NSSCMSSignedData
*sigd
)
89 CERTCertificate
**certs
, **tempCerts
, *cert
;
90 CERTCertificateList
**certlists
, *certlist
;
91 NSSCMSSignerInfo
**signerinfos
, *si
;
97 tempCerts
= sigd
->tempCerts
;
98 certlists
= sigd
->certLists
;
99 signerinfos
= sigd
->signerInfos
;
102 while ((cert
= *certs
++) != NULL
)
103 CERT_DestroyCertificate (cert
);
106 if (tempCerts
!= NULL
) {
107 while ((cert
= *tempCerts
++) != NULL
)
108 CERT_DestroyCertificate (cert
);
111 if (certlists
!= NULL
) {
112 while ((certlist
= *certlists
++) != NULL
)
113 CERT_DestroyCertificateList (certlist
);
116 if (signerinfos
!= NULL
) {
117 while ((si
= *signerinfos
++) != NULL
)
118 NSS_CMSSignerInfo_Destroy(si
);
121 /* everything's in a pool, so don't worry about the storage */
122 NSS_CMSContentInfo_Destroy(&(sigd
->contentInfo
));
127 * NSS_CMSSignedData_Encode_BeforeStart - do all the necessary things to a SignedData
128 * before start of encoding.
131 * - find out about the right value to put into sigd->version
132 * - come up with a list of digestAlgorithms (which should be the union of the algorithms
133 * in the signerinfos).
134 * If we happen to have a pre-set list of algorithms (and digest values!), we
135 * check if we have all the signerinfos' algorithms. If not, this is an error.
138 NSS_CMSSignedData_Encode_BeforeStart(NSSCMSSignedData
*sigd
)
140 NSSCMSSignerInfo
*signerinfo
;
141 SECOidTag digestalgtag
;
145 PRBool haveDigests
= PR_FALSE
;
150 PORT_SetError(SEC_ERROR_INVALID_ARGS
);
154 poolp
= sigd
->cmsg
->poolp
;
156 /* we assume that we have precomputed digests if there is a list of algorithms, and */
157 /* a chunk of data for each of those algorithms */
158 if (sigd
->digestAlgorithms
!= NULL
&& sigd
->digests
!= NULL
) {
159 for (i
=0; sigd
->digestAlgorithms
[i
] != NULL
; i
++) {
160 if (sigd
->digests
[i
] == NULL
)
163 if (sigd
->digestAlgorithms
[i
] == NULL
) /* reached the end of the array? */
164 haveDigests
= PR_TRUE
; /* yes: we must have all the digests */
167 version
= NSS_CMS_SIGNED_DATA_VERSION_BASIC
;
169 /* RFC2630 5.1 "version is the syntax version number..." */
170 if (NSS_CMSContentInfo_GetContentTypeTag(&(sigd
->contentInfo
)) != SEC_OID_PKCS7_DATA
)
171 version
= NSS_CMS_SIGNED_DATA_VERSION_EXT
;
173 /* prepare all the SignerInfos (there may be none) */
174 for (i
=0; i
< NSS_CMSSignedData_SignerInfoCount(sigd
); i
++) {
175 signerinfo
= NSS_CMSSignedData_GetSignerInfo(sigd
, i
);
177 /* RFC2630 5.1 "version is the syntax version number..." */
178 if (NSS_CMSSignerInfo_GetVersion(signerinfo
) != NSS_CMS_SIGNER_INFO_VERSION_ISSUERSN
)
179 version
= NSS_CMS_SIGNED_DATA_VERSION_EXT
;
181 /* collect digestAlgorithms from SignerInfos */
182 /* (we need to know which algorithms we have when the content comes in) */
183 /* do not overwrite any existing digestAlgorithms (and digest) */
184 digestalgtag
= NSS_CMSSignerInfo_GetDigestAlgTag(signerinfo
);
185 n
= NSS_CMSAlgArray_GetIndexByAlgTag(sigd
->digestAlgorithms
, digestalgtag
);
186 if (n
< 0 && haveDigests
) {
187 /* oops, there is a digestalg we do not have a digest for */
188 /* but we were supposed to have all the digests already... */
191 /* add the digestAlgorithm & a NULL digest */
192 rv
= NSS_CMSSignedData_AddDigest(poolp
, sigd
, digestalgtag
, NULL
);
193 if (rv
!= SECSuccess
)
196 /* found it, nothing to do */
200 dummy
= SEC_ASN1EncodeInteger(poolp
, &(sigd
->version
), (long)version
);
204 /* this is a SET OF, so we need to sort them guys */
205 rv
= NSS_CMSArray_SortByDER((void **)sigd
->digestAlgorithms
,
206 SEC_ASN1_GET(SECOID_AlgorithmIDTemplate
),
207 (void **)sigd
->digests
);
208 if (rv
!= SECSuccess
)
218 NSS_CMSSignedData_Encode_BeforeData(NSSCMSSignedData
*sigd
)
221 PORT_SetError(SEC_ERROR_INVALID_ARGS
);
224 /* set up the digests */
225 if (sigd
->digests
&& sigd
->digests
[0]) {
226 sigd
->contentInfo
.digcx
= NULL
; /* don't attempt to make new ones. */
227 } else if (sigd
->digestAlgorithms
!= NULL
) {
228 sigd
->contentInfo
.digcx
=
229 NSS_CMSDigestContext_StartMultiple(sigd
->digestAlgorithms
);
230 if (sigd
->contentInfo
.digcx
== NULL
)
237 * NSS_CMSSignedData_Encode_AfterData - do all the necessary things to a SignedData
238 * after all the encapsulated data was passed through the encoder.
241 * - create the signatures in all the SignerInfos
243 * Please note that nothing is done to the Certificates and CRLs in the message - this
244 * is entirely the responsibility of our callers.
247 NSS_CMSSignedData_Encode_AfterData(NSSCMSSignedData
*sigd
)
249 NSSCMSSignerInfo
**signerinfos
, *signerinfo
;
250 NSSCMSContentInfo
*cinfo
;
251 SECOidTag digestalgtag
;
252 SECStatus ret
= SECFailure
;
254 SECItem
*contentType
;
256 int i
, ci
, cli
, n
, rci
, si
;
258 CERTCertificateList
*certlist
;
259 extern const SEC_ASN1Template NSSCMSSignerInfoTemplate
[];
262 PORT_SetError(SEC_ERROR_INVALID_ARGS
);
266 poolp
= sigd
->cmsg
->poolp
;
267 cinfo
= &(sigd
->contentInfo
);
269 /* did we have digest calculation going on? */
271 rv
= NSS_CMSDigestContext_FinishMultiple(cinfo
->digcx
, poolp
,
273 /* error has been set by NSS_CMSDigestContext_FinishMultiple */
275 if (rv
!= SECSuccess
)
279 signerinfos
= sigd
->signerInfos
;
282 /* prepare all the SignerInfos (there may be none) */
283 for (i
=0; i
< NSS_CMSSignedData_SignerInfoCount(sigd
); i
++) {
284 signerinfo
= NSS_CMSSignedData_GetSignerInfo(sigd
, i
);
286 /* find correct digest for this signerinfo */
287 digestalgtag
= NSS_CMSSignerInfo_GetDigestAlgTag(signerinfo
);
288 n
= NSS_CMSAlgArray_GetIndexByAlgTag(sigd
->digestAlgorithms
, digestalgtag
);
289 if (n
< 0 || sigd
->digests
== NULL
|| sigd
->digests
[n
] == NULL
) {
290 /* oops - digest not found */
291 PORT_SetError(SEC_ERROR_DIGEST_NOT_FOUND
);
295 /* XXX if our content is anything else but data, we need to force the
296 * presence of signed attributes (RFC2630 5.3 "signedAttributes is a
299 /* pass contentType here as we want a contentType attribute */
300 if ((contentType
= NSS_CMSContentInfo_GetContentTypeOID(cinfo
)) == NULL
)
304 rv
= NSS_CMSSignerInfo_Sign(signerinfo
, sigd
->digests
[n
], contentType
);
305 if (rv
!= SECSuccess
)
308 /* while we're at it, count number of certs in certLists */
309 certlist
= NSS_CMSSignerInfo_GetCertList(signerinfo
);
311 certcount
+= certlist
->len
;
314 /* this is a SET OF, so we need to sort them guys */
315 rv
= NSS_CMSArray_SortByDER((void **)signerinfos
, NSSCMSSignerInfoTemplate
, NULL
);
316 if (rv
!= SECSuccess
)
320 * now prepare certs & crls
323 /* count the rest of the certs */
324 if (sigd
->certs
!= NULL
) {
325 for (ci
= 0; sigd
->certs
[ci
] != NULL
; ci
++)
329 if (sigd
->certLists
!= NULL
) {
330 for (cli
= 0; sigd
->certLists
[cli
] != NULL
; cli
++)
331 certcount
+= sigd
->certLists
[cli
]->len
;
334 if (certcount
== 0) {
335 sigd
->rawCerts
= NULL
;
338 * Combine all of the certs and cert chains into rawcerts.
339 * Note: certcount is an upper bound; we may not need that many slots
340 * but we will allocate anyway to avoid having to do another pass.
341 * (The temporary space saving is not worth it.)
343 * XXX ARGH - this NEEDS to be fixed. need to come up with a decent
344 * SetOfDERcertficates implementation
346 sigd
->rawCerts
= (SECItem
**)PORT_ArenaAlloc(poolp
, (certcount
+ 1) * sizeof(SECItem
*));
347 if (sigd
->rawCerts
== NULL
)
351 * XXX Want to check for duplicates and not add *any* cert that is
352 * already in the set. This will be more important when we start
353 * dealing with larger sets of certs, dual-key certs (signing and
354 * encryption), etc. For the time being we can slide by...
356 * XXX ARGH - this NEEDS to be fixed. need to come up with a decent
357 * SetOfDERcertficates implementation
360 if (signerinfos
!= NULL
) {
361 for (si
= 0; signerinfos
[si
] != NULL
; si
++) {
362 signerinfo
= signerinfos
[si
];
363 for (ci
= 0; ci
< signerinfo
->certList
->len
; ci
++)
364 sigd
->rawCerts
[rci
++] = &(signerinfo
->certList
->certs
[ci
]);
368 if (sigd
->certs
!= NULL
) {
369 for (ci
= 0; sigd
->certs
[ci
] != NULL
; ci
++)
370 sigd
->rawCerts
[rci
++] = &(sigd
->certs
[ci
]->derCert
);
373 if (sigd
->certLists
!= NULL
) {
374 for (cli
= 0; sigd
->certLists
[cli
] != NULL
; cli
++) {
375 for (ci
= 0; ci
< sigd
->certLists
[cli
]->len
; ci
++)
376 sigd
->rawCerts
[rci
++] = &(sigd
->certLists
[cli
]->certs
[ci
]);
380 sigd
->rawCerts
[rci
] = NULL
;
382 /* this is a SET OF, so we need to sort them guys - we have the DER already, though */
383 NSS_CMSArray_Sort((void **)sigd
->rawCerts
, NSS_CMSUtil_DERCompare
, NULL
, NULL
);
393 NSS_CMSSignedData_Decode_BeforeData(NSSCMSSignedData
*sigd
)
396 PORT_SetError(SEC_ERROR_INVALID_ARGS
);
399 /* set up the digests */
400 if (sigd
->digestAlgorithms
!= NULL
&& sigd
->digests
== NULL
) {
401 /* if digests are already there, do nothing */
402 sigd
->contentInfo
.digcx
= NSS_CMSDigestContext_StartMultiple(sigd
->digestAlgorithms
);
403 if (sigd
->contentInfo
.digcx
== NULL
)
410 * NSS_CMSSignedData_Decode_AfterData - do all the necessary things to a
411 * SignedData after all the encapsulated data was passed through the decoder.
414 NSS_CMSSignedData_Decode_AfterData(NSSCMSSignedData
*sigd
)
416 SECStatus rv
= SECSuccess
;
419 PORT_SetError(SEC_ERROR_INVALID_ARGS
);
423 /* did we have digest calculation going on? */
424 if (sigd
->contentInfo
.digcx
) {
425 rv
= NSS_CMSDigestContext_FinishMultiple(sigd
->contentInfo
.digcx
,
426 sigd
->cmsg
->poolp
, &(sigd
->digests
));
427 /* error set by NSS_CMSDigestContext_FinishMultiple */
428 sigd
->contentInfo
.digcx
= NULL
;
434 * NSS_CMSSignedData_Decode_AfterEnd - do all the necessary things to a SignedData
435 * after all decoding is finished.
438 NSS_CMSSignedData_Decode_AfterEnd(NSSCMSSignedData
*sigd
)
440 NSSCMSSignerInfo
**signerinfos
= NULL
;
444 PORT_SetError(SEC_ERROR_INVALID_ARGS
);
448 /* set cmsg for all the signerinfos */
449 signerinfos
= sigd
->signerInfos
;
451 /* set cmsg for all the signerinfos */
453 for (i
= 0; signerinfos
[i
] != NULL
; i
++)
454 signerinfos
[i
]->cmsg
= sigd
->cmsg
;
461 * NSS_CMSSignedData_GetSignerInfos - retrieve the SignedData's signer list
464 NSS_CMSSignedData_GetSignerInfos(NSSCMSSignedData
*sigd
)
467 PORT_SetError(SEC_ERROR_INVALID_ARGS
);
470 return sigd
->signerInfos
;
474 NSS_CMSSignedData_SignerInfoCount(NSSCMSSignedData
*sigd
)
477 PORT_SetError(SEC_ERROR_INVALID_ARGS
);
480 return NSS_CMSArray_Count((void **)sigd
->signerInfos
);
484 NSS_CMSSignedData_GetSignerInfo(NSSCMSSignedData
*sigd
, int i
)
487 PORT_SetError(SEC_ERROR_INVALID_ARGS
);
490 return sigd
->signerInfos
[i
];
494 * NSS_CMSSignedData_GetDigestAlgs - retrieve the SignedData's digest algorithm list
497 NSS_CMSSignedData_GetDigestAlgs(NSSCMSSignedData
*sigd
)
500 PORT_SetError(SEC_ERROR_INVALID_ARGS
);
503 return sigd
->digestAlgorithms
;
507 * NSS_CMSSignedData_GetContentInfo - return pointer to this signedData's contentinfo
510 NSS_CMSSignedData_GetContentInfo(NSSCMSSignedData
*sigd
)
513 PORT_SetError(SEC_ERROR_INVALID_ARGS
);
516 return &(sigd
->contentInfo
);
520 * NSS_CMSSignedData_GetCertificateList - retrieve the SignedData's certificate list
523 NSS_CMSSignedData_GetCertificateList(NSSCMSSignedData
*sigd
)
526 PORT_SetError(SEC_ERROR_INVALID_ARGS
);
529 return sigd
->rawCerts
;
533 NSS_CMSSignedData_ImportCerts(NSSCMSSignedData
*sigd
, CERTCertDBHandle
*certdb
,
534 SECCertUsage certusage
, PRBool keepcerts
)
537 CERTCertificate
**certArray
= NULL
;
538 CERTCertList
*certList
= NULL
;
539 CERTCertListNode
*node
;
546 PORT_SetError(SEC_ERROR_INVALID_ARGS
);
550 certcount
= NSS_CMSArray_Count((void **)sigd
->rawCerts
);
552 /* get the certs in the temp DB */
553 rv
= CERT_ImportCerts(certdb
, certusage
, certcount
, sigd
->rawCerts
,
554 &certArray
, PR_FALSE
, PR_FALSE
, NULL
);
555 if (rv
!= SECSuccess
) {
559 /* save the certs so they don't get destroyed */
560 for (i
=0; i
< certcount
; i
++) {
561 CERTCertificate
*cert
= certArray
[i
];
563 NSS_CMSSignedData_AddTempCertificate(sigd
, cert
);
570 /* build a CertList for filtering */
571 certList
= CERT_NewCertList();
572 if (certList
== NULL
) {
576 for (i
=0; i
< certcount
; i
++) {
577 CERTCertificate
*cert
= certArray
[i
];
579 cert
= CERT_DupCertificate(cert
);
581 CERT_AddCertToListTail(certList
,cert
);
584 /* filter out the certs we don't want */
585 rv
= CERT_FilterCertListByUsage(certList
,certusage
, PR_FALSE
);
586 if (rv
!= SECSuccess
) {
590 /* go down the remaining list of certs and verify that they have
591 * valid chains, then import them.
594 for (node
= CERT_LIST_HEAD(certList
) ; !CERT_LIST_END(node
,certList
);
595 node
= CERT_LIST_NEXT(node
)) {
596 CERTCertificateList
*certChain
;
598 if (CERT_VerifyCert(certdb
, node
->cert
,
599 PR_TRUE
, certusage
, now
, NULL
, NULL
) != SECSuccess
) {
603 certChain
= CERT_CertChainFromCert(node
->cert
, certusage
, PR_FALSE
);
609 * CertChain returns an array of SECItems, import expects an array of
610 * SECItem pointers. Create the SECItem Pointers from the array of
613 rawArray
= (SECItem
**)PORT_Alloc(certChain
->len
*sizeof (SECItem
*));
615 CERT_DestroyCertificateList(certChain
);
618 for (i
=0; i
< certChain
->len
; i
++) {
619 rawArray
[i
] = &certChain
->certs
[i
];
621 (void )CERT_ImportCerts(certdb
, certusage
, certChain
->len
,
622 rawArray
, NULL
, keepcerts
, PR_FALSE
, NULL
);
624 CERT_DestroyCertificateList(certChain
);
629 /* XXX CRL handling */
632 if (sigd
->signerInfos
!= NULL
) {
633 /* fill in all signerinfo's certs */
634 for (i
= 0; sigd
->signerInfos
[i
] != NULL
; i
++)
635 (void)NSS_CMSSignerInfo_GetSigningCertificate(
636 sigd
->signerInfos
[i
], certdb
);
640 /* now free everything */
642 CERT_DestroyCertArray(certArray
,certcount
);
645 CERT_DestroyCertList(certList
);
652 * XXX the digests need to be passed in BETWEEN the decoding and the verification in case
653 * of external signatures!
657 * NSS_CMSSignedData_VerifySignerInfo - check the signatures.
659 * The digests were either calculated during decoding (and are stored in the
660 * signedData itself) or set after decoding using NSS_CMSSignedData_SetDigests.
662 * The verification checks if the signing cert is valid and has a trusted chain
663 * for the purpose specified by "certusage".
666 NSS_CMSSignedData_VerifySignerInfo(NSSCMSSignedData
*sigd
, int i
,
667 CERTCertDBHandle
*certdb
, SECCertUsage certusage
)
669 NSSCMSSignerInfo
*signerinfo
;
670 NSSCMSContentInfo
*cinfo
;
671 SECOidData
*algiddata
;
672 SECItem
*contentType
, *digest
;
677 PORT_SetError(SEC_ERROR_INVALID_ARGS
);
681 cinfo
= &(sigd
->contentInfo
);
683 signerinfo
= sigd
->signerInfos
[i
];
685 /* verify certificate */
686 rv
= NSS_CMSSignerInfo_VerifyCertificate(signerinfo
, certdb
, certusage
);
687 if (rv
!= SECSuccess
)
688 return rv
; /* error is set */
690 /* find digest and contentType for signerinfo */
691 algiddata
= NSS_CMSSignerInfo_GetDigestAlg(signerinfo
);
692 oidTag
= algiddata
? algiddata
->offset
: SEC_OID_UNKNOWN
;
693 digest
= NSS_CMSSignedData_GetDigestValue(sigd
, oidTag
);
694 /* NULL digest is acceptable. */
695 contentType
= NSS_CMSContentInfo_GetContentTypeOID(cinfo
);
696 /* NULL contentType is acceptable. */
698 /* now verify signature */
699 rv
= NSS_CMSSignerInfo_Verify(signerinfo
, digest
, contentType
);
704 * NSS_CMSSignedData_VerifyCertsOnly - verify the certs in a certs-only message
707 NSS_CMSSignedData_VerifyCertsOnly(NSSCMSSignedData
*sigd
,
708 CERTCertDBHandle
*certdb
,
711 CERTCertificate
*cert
;
712 SECStatus rv
= SECSuccess
;
717 if (!sigd
|| !certdb
|| !sigd
->rawCerts
) {
718 PORT_SetError(SEC_ERROR_INVALID_ARGS
);
722 count
= NSS_CMSArray_Count((void**)sigd
->rawCerts
);
724 for (i
=0; i
< count
; i
++) {
725 if (sigd
->certs
&& sigd
->certs
[i
]) {
726 cert
= CERT_DupCertificate(sigd
->certs
[i
]);
728 cert
= CERT_FindCertByDERCert(certdb
, sigd
->rawCerts
[i
]);
734 rv
|= CERT_VerifyCert(certdb
, cert
, PR_TRUE
, usage
, now
,
736 CERT_DestroyCertificate(cert
);
743 * NSS_CMSSignedData_HasDigests - see if we have digests in place
746 NSS_CMSSignedData_HasDigests(NSSCMSSignedData
*sigd
)
749 PORT_SetError(SEC_ERROR_INVALID_ARGS
);
752 return (sigd
->digests
!= NULL
);
756 NSS_CMSSignedData_AddCertList(NSSCMSSignedData
*sigd
, CERTCertificateList
*certlist
)
760 if (!sigd
|| !certlist
) {
761 PORT_SetError(SEC_ERROR_INVALID_ARGS
);
765 /* XXX memory?? a certlist has an arena of its own and is not refcounted!?!? */
766 rv
= NSS_CMSArray_Add(sigd
->cmsg
->poolp
, (void ***)&(sigd
->certLists
), (void *)certlist
);
772 * NSS_CMSSignedData_AddCertChain - add cert and its entire chain to the set of certs
775 NSS_CMSSignedData_AddCertChain(NSSCMSSignedData
*sigd
, CERTCertificate
*cert
)
777 CERTCertificateList
*certlist
;
781 usage
= certUsageEmailSigner
;
783 if (!sigd
|| !cert
) {
784 PORT_SetError(SEC_ERROR_INVALID_ARGS
);
788 /* do not include root */
789 certlist
= CERT_CertChainFromCert(cert
, usage
, PR_FALSE
);
790 if (certlist
== NULL
)
793 rv
= NSS_CMSSignedData_AddCertList(sigd
, certlist
);
799 NSS_CMSSignedData_AddTempCertificate(NSSCMSSignedData
*sigd
, CERTCertificate
*cert
)
804 if (!sigd
|| !cert
) {
805 PORT_SetError(SEC_ERROR_INVALID_ARGS
);
809 c
= CERT_DupCertificate(cert
);
810 rv
= NSS_CMSArray_Add(sigd
->cmsg
->poolp
, (void ***)&(sigd
->tempCerts
), (void *)c
);
815 NSS_CMSSignedData_AddCertificate(NSSCMSSignedData
*sigd
, CERTCertificate
*cert
)
820 if (!sigd
|| !cert
) {
821 PORT_SetError(SEC_ERROR_INVALID_ARGS
);
825 c
= CERT_DupCertificate(cert
);
826 rv
= NSS_CMSArray_Add(sigd
->cmsg
->poolp
, (void ***)&(sigd
->certs
), (void *)c
);
831 NSS_CMSSignedData_ContainsCertsOrCrls(NSSCMSSignedData
*sigd
)
834 PORT_SetError(SEC_ERROR_INVALID_ARGS
);
837 if (sigd
->rawCerts
!= NULL
&& sigd
->rawCerts
[0] != NULL
)
839 else if (sigd
->crls
!= NULL
&& sigd
->crls
[0] != NULL
)
846 NSS_CMSSignedData_AddSignerInfo(NSSCMSSignedData
*sigd
,
847 NSSCMSSignerInfo
*signerinfo
)
851 SECOidTag digestalgtag
;
854 if (!sigd
|| !signerinfo
) {
855 PORT_SetError(SEC_ERROR_INVALID_ARGS
);
859 poolp
= sigd
->cmsg
->poolp
;
861 mark
= PORT_ArenaMark(poolp
);
864 rv
= NSS_CMSArray_Add(poolp
, (void ***)&(sigd
->signerInfos
), (void *)signerinfo
);
865 if (rv
!= SECSuccess
)
870 * Empty because we don't have it yet. Either it gets created during encoding
871 * (if the data is present) or has to be set externally.
872 * XXX maybe pass it in optionally?
874 digestalgtag
= NSS_CMSSignerInfo_GetDigestAlgTag(signerinfo
);
875 rv
= NSS_CMSSignedData_SetDigestValue(sigd
, digestalgtag
, NULL
);
876 if (rv
!= SECSuccess
)
880 * The last thing to get consistency would be adding the digest.
883 PORT_ArenaUnmark(poolp
, mark
);
887 PORT_ArenaRelease (poolp
, mark
);
892 * NSS_CMSSignedData_SetDigests - set a signedData's digests member
894 * "digestalgs" - array of digest algorithm IDs
895 * "digests" - array of digests corresponding to the digest algorithms
898 NSS_CMSSignedData_SetDigests(NSSCMSSignedData
*sigd
,
899 SECAlgorithmID
**digestalgs
,
904 if (!sigd
|| !digestalgs
|| !digests
) {
905 PORT_SetError(SEC_ERROR_INVALID_ARGS
);
909 if (sigd
->digestAlgorithms
== NULL
) {
910 PORT_SetError(SEC_ERROR_INVALID_ARGS
);
914 /* we assume that the digests array is just not there yet */
915 PORT_Assert(sigd
->digests
== NULL
);
916 if (sigd
->digests
!= NULL
) {
917 PORT_SetError(SEC_ERROR_LIBRARY_FAILURE
);
921 /* now allocate one (same size as digestAlgorithms) */
922 cnt
= NSS_CMSArray_Count((void **)sigd
->digestAlgorithms
);
923 sigd
->digests
= PORT_ArenaZAlloc(sigd
->cmsg
->poolp
, (cnt
+ 1) * sizeof(SECItem
*));
924 if (sigd
->digests
== NULL
) {
925 PORT_SetError(SEC_ERROR_NO_MEMORY
);
929 for (i
= 0; sigd
->digestAlgorithms
[i
] != NULL
; i
++) {
930 /* try to find the sigd's i'th digest algorithm in the array we passed in */
931 idx
= NSS_CMSAlgArray_GetIndexByAlgID(digestalgs
, sigd
->digestAlgorithms
[i
]);
933 PORT_SetError(SEC_ERROR_DIGEST_NOT_FOUND
);
937 /* We have no digest for this algorithm, probably because it is
938 ** unrecognized or unsupported. We'll ignore this here. If this
939 ** digest is needed later, an error will be be generated then.
944 /* found it - now set it */
945 if ((sigd
->digests
[i
] = SECITEM_AllocItem(sigd
->cmsg
->poolp
, NULL
, 0)) == NULL
||
946 SECITEM_CopyItem(sigd
->cmsg
->poolp
, sigd
->digests
[i
], digests
[idx
]) != SECSuccess
)
948 PORT_SetError(SEC_ERROR_NO_MEMORY
);
956 NSS_CMSSignedData_SetDigestValue(NSSCMSSignedData
*sigd
,
957 SECOidTag digestalgtag
,
960 SECItem
*digest
= NULL
;
966 PORT_SetError(SEC_ERROR_INVALID_ARGS
);
970 poolp
= sigd
->cmsg
->poolp
;
972 mark
= PORT_ArenaMark(poolp
);
976 digest
= (SECItem
*) PORT_ArenaZAlloc(poolp
,sizeof(SECItem
));
978 /* copy digestdata item to arena (in case we have it and are not only making room) */
979 if (SECITEM_CopyItem(poolp
, digest
, digestdata
) != SECSuccess
)
983 /* now allocate one (same size as digestAlgorithms) */
984 if (sigd
->digests
== NULL
) {
985 cnt
= NSS_CMSArray_Count((void **)sigd
->digestAlgorithms
);
986 sigd
->digests
= PORT_ArenaZAlloc(sigd
->cmsg
->poolp
, (cnt
+ 1) * sizeof(SECItem
*));
987 if (sigd
->digests
== NULL
) {
988 PORT_SetError(SEC_ERROR_NO_MEMORY
);
994 if (sigd
->digestAlgorithms
!= NULL
)
995 n
= NSS_CMSAlgArray_GetIndexByAlgTag(sigd
->digestAlgorithms
, digestalgtag
);
997 /* if not found, add a digest */
999 if (NSS_CMSSignedData_AddDigest(poolp
, sigd
, digestalgtag
, digest
) != SECSuccess
)
1002 /* replace NULL pointer with digest item (and leak previous value) */
1003 sigd
->digests
[n
] = digest
;
1006 PORT_ArenaUnmark(poolp
, mark
);
1010 PORT_ArenaRelease(poolp
, mark
);
1015 NSS_CMSSignedData_AddDigest(PRArenaPool
*poolp
,
1016 NSSCMSSignedData
*sigd
,
1017 SECOidTag digestalgtag
,
1020 SECAlgorithmID
*digestalg
;
1023 if (!sigd
|| !poolp
) {
1024 PORT_SetError(SEC_ERROR_INVALID_ARGS
);
1028 mark
= PORT_ArenaMark(poolp
);
1030 digestalg
= PORT_ArenaZAlloc(poolp
, sizeof(SECAlgorithmID
));
1031 if (digestalg
== NULL
)
1034 if (SECOID_SetAlgorithmID (poolp
, digestalg
, digestalgtag
, NULL
) != SECSuccess
) /* no params */
1037 if (NSS_CMSArray_Add(poolp
, (void ***)&(sigd
->digestAlgorithms
), (void *)digestalg
) != SECSuccess
||
1038 /* even if digest is NULL, add dummy to have same-size array */
1039 NSS_CMSArray_Add(poolp
, (void ***)&(sigd
->digests
), (void *)digest
) != SECSuccess
)
1044 PORT_ArenaUnmark(poolp
, mark
);
1048 PORT_ArenaRelease(poolp
, mark
);
1052 /* XXX This function doesn't set the error code on failure. */
1054 NSS_CMSSignedData_GetDigestValue(NSSCMSSignedData
*sigd
, SECOidTag digestalgtag
)
1059 PORT_SetError(SEC_ERROR_INVALID_ARGS
);
1063 if (sigd
->digestAlgorithms
== NULL
|| sigd
->digests
== NULL
) {
1064 PORT_SetError(SEC_ERROR_DIGEST_NOT_FOUND
);
1068 n
= NSS_CMSAlgArray_GetIndexByAlgTag(sigd
->digestAlgorithms
, digestalgtag
);
1070 return (n
< 0) ? NULL
: sigd
->digests
[n
];
1073 /* =============================================================================
1074 * Misc. utility functions
1078 * NSS_CMSSignedData_CreateCertsOnly - create a certs-only SignedData.
1080 * cert - base certificates that will be included
1081 * include_chain - if true, include the complete cert chain for cert
1083 * More certs and chains can be added via AddCertificate and AddCertChain.
1085 * An error results in a return value of NULL and an error set.
1090 NSS_CMSSignedData_CreateCertsOnly(NSSCMSMessage
*cmsg
, CERTCertificate
*cert
, PRBool include_chain
)
1092 NSSCMSSignedData
*sigd
;
1097 if (!cmsg
|| !cert
) {
1098 PORT_SetError(SEC_ERROR_INVALID_ARGS
);
1102 poolp
= cmsg
->poolp
;
1103 mark
= PORT_ArenaMark(poolp
);
1105 sigd
= NSS_CMSSignedData_Create(cmsg
);
1109 /* no signerinfos, thus no digestAlgorithms */
1112 if (include_chain
) {
1113 rv
= NSS_CMSSignedData_AddCertChain(sigd
, cert
);
1115 rv
= NSS_CMSSignedData_AddCertificate(sigd
, cert
);
1117 if (rv
!= SECSuccess
)
1121 * In the degenerate case where there are no signers, the
1122 * EncapsulatedContentInfo value being "signed" is irrelevant. In this
1123 * case, the content type within the EncapsulatedContentInfo value being
1124 * "signed" should be id-data (as defined in section 4), and the content
1125 * field of the EncapsulatedContentInfo value should be omitted.
1127 rv
= NSS_CMSContentInfo_SetContent_Data(cmsg
, &(sigd
->contentInfo
), NULL
, PR_TRUE
);
1128 if (rv
!= SECSuccess
)
1131 PORT_ArenaUnmark(poolp
, mark
);
1136 NSS_CMSSignedData_Destroy(sigd
);
1137 PORT_ArenaRelease(poolp
, mark
);
1142 * NSS_CMSSignerInfo_GetReceiptRequest()
1143 * NSS_CMSSignedData_HasReceiptRequest()
1144 * easy way to iterate over signers