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/
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.
12 * The Original Code is the Netscape security libraries.
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
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
35 * CMS signedData methods.
38 #include <Security/SecCmsSignedData.h>
40 #include <Security/SecCmsContentInfo.h>
41 #include <Security/SecCmsDigestContext.h>
42 #include <Security/SecCmsSignerInfo.h>
47 #include "SecAsn1Item.h"
50 #include <security_asn1/secasn1.h>
51 #include <security_asn1/secerr.h>
52 #include <security_asn1/secport.h>
54 #include <Security/SecCertificatePriv.h>
57 SecCmsSignedDataCreate(SecCmsMessageRef cmsg
)
60 SecCmsSignedDataRef sigd
;
65 mark
= PORT_ArenaMark(poolp
);
67 sigd
= (SecCmsSignedDataRef
)PORT_ArenaZAlloc (poolp
, sizeof(SecCmsSignedData
));
71 sigd
->contentInfo
.cmsg
= cmsg
;
73 /* signerInfos, certs, certlists, crls are all empty */
74 /* version is set in SecCmsSignedDataFinalize() */
76 PORT_ArenaUnmark(poolp
, mark
);
80 PORT_ArenaRelease(poolp
, mark
);
85 SecCmsSignedDataDestroy(SecCmsSignedDataRef sigd
)
87 SecCmsSignerInfoRef
*signerinfos
, si
;
92 if (sigd
->certs
!= NULL
)
93 CFRelease(sigd
->certs
);
95 signerinfos
= sigd
->signerInfos
;
96 if (signerinfos
!= NULL
) {
97 while ((si
= *signerinfos
++) != NULL
)
98 SecCmsSignerInfoDestroy(si
);
101 /* everything's in a pool, so don't worry about the storage */
102 SecCmsContentInfoDestroy(&(sigd
->contentInfo
));
106 * SecCmsSignedDataEncodeBeforeStart - do all the necessary things to a SignedData
107 * before start of encoding.
110 * - find out about the right value to put into sigd->version
111 * - come up with a list of digestAlgorithms (which should be the union of the algorithms
112 * in the signerinfos).
113 * If we happen to have a pre-set list of algorithms (and digest values!), we
114 * check if we have all the signerinfos' algorithms. If not, this is an error.
117 SecCmsSignedDataEncodeBeforeStart(SecCmsSignedDataRef sigd
)
119 SecCmsSignerInfoRef signerinfo
;
120 SECOidTag digestalgtag
;
124 Boolean haveDigests
= PR_FALSE
;
128 poolp
= sigd
->contentInfo
.cmsg
->poolp
;
130 /* we assume that we have precomputed digests if there is a list of algorithms, and */
131 /* a chunk of data for each of those algorithms */
132 if (sigd
->digestAlgorithms
!= NULL
&& sigd
->digests
!= NULL
) {
133 for (i
=0; sigd
->digestAlgorithms
[i
] != NULL
; i
++) {
134 if (sigd
->digests
[i
] == NULL
)
137 if (sigd
->digestAlgorithms
[i
] == NULL
) /* reached the end of the array? */
138 haveDigests
= PR_TRUE
; /* yes: we must have all the digests */
141 version
= SEC_CMS_SIGNED_DATA_VERSION_BASIC
;
143 /* RFC2630 5.1 "version is the syntax version number..." */
144 if (SecCmsContentInfoGetContentTypeTag(&(sigd
->contentInfo
)) != SEC_OID_PKCS7_DATA
)
145 version
= SEC_CMS_SIGNED_DATA_VERSION_EXT
;
147 /* prepare all the SignerInfos (there may be none) */
148 for (i
=0; i
< SecCmsSignedDataSignerInfoCount(sigd
); i
++) {
149 signerinfo
= SecCmsSignedDataGetSignerInfo(sigd
, i
);
151 /* RFC2630 5.1 "version is the syntax version number..." */
152 if (SecCmsSignerInfoGetVersion(signerinfo
) != SEC_CMS_SIGNER_INFO_VERSION_ISSUERSN
)
153 version
= SEC_CMS_SIGNED_DATA_VERSION_EXT
;
155 /* collect digestAlgorithms from SignerInfos */
156 /* (we need to know which algorithms we have when the content comes in) */
157 /* do not overwrite any existing digestAlgorithms (and digest) */
158 digestalgtag
= SecCmsSignerInfoGetDigestAlgTag(signerinfo
);
159 n
= SecCmsAlgArrayGetIndexByAlgTag(sigd
->digestAlgorithms
, digestalgtag
);
160 if (n
< 0 && haveDigests
) {
161 /* oops, there is a digestalg we do not have a digest for */
162 /* but we were supposed to have all the digests already... */
165 /* add the digestAlgorithm & a NULL digest */
166 rv
= SecCmsSignedDataAddDigest(poolp
, sigd
, digestalgtag
, NULL
);
167 if (rv
!= SECSuccess
)
170 /* found it, nothing to do */
174 dummy
= SEC_ASN1EncodeInteger(poolp
, &(sigd
->version
), (long)version
);
178 /* this is a SET OF, so we need to sort them guys */
179 rv
= SecCmsArraySortByDER((void **)sigd
->digestAlgorithms
,
180 SEC_ASN1_GET(SECOID_AlgorithmIDTemplate
),
181 (void **)sigd
->digests
);
182 if (rv
!= SECSuccess
)
192 SecCmsSignedDataEncodeBeforeData(SecCmsSignedDataRef sigd
)
194 /* set up the digests */
195 if (sigd
->digestAlgorithms
!= NULL
) {
196 sigd
->contentInfo
.digcx
= SecCmsDigestContextStartMultiple(sigd
->digestAlgorithms
);
197 if (sigd
->contentInfo
.digcx
== NULL
)
204 * SecCmsSignedDataEncodeAfterData - do all the necessary things to a SignedData
205 * after all the encapsulated data was passed through the encoder.
208 * - create the signatures in all the SignerInfos
210 * Please note that nothing is done to the Certificates and CRLs in the message - this
211 * is entirely the responsibility of our callers.
214 SecCmsSignedDataEncodeAfterData(SecCmsSignedDataRef sigd
)
216 SecCmsSignerInfoRef
*signerinfos
, signerinfo
;
217 SecCmsContentInfoRef cinfo
;
218 SECOidTag digestalgtag
;
219 OSStatus ret
= SECFailure
;
221 SecAsn1Item
* contentType
;
223 int i
, ci
, n
, rci
, si
;
226 extern const SecAsn1Template SecCmsSignerInfoTemplate
[];
228 cinfo
= &(sigd
->contentInfo
);
229 poolp
= cinfo
->cmsg
->poolp
;
231 /* did we have digest calculation going on? */
233 SecAsn1Item
**digests
= NULL
;
234 SECAlgorithmID
**digestalgs
= NULL
;
235 rv
= SecCmsDigestContextFinishMultiple(cinfo
->digcx
, &digestalgs
, &digests
);
236 if (rv
!= SECSuccess
)
237 goto loser
; /* error has been set by SecCmsDigestContextFinishMultiple */
238 if (digestalgs
&& digests
) {
239 rv
= SecCmsSignedDataSetDigests(sigd
, digestalgs
, digests
);
240 if (rv
!= SECSuccess
)
241 goto loser
; /* error has been set by SecCmsSignedDataSetDigests */
243 SecCmsDigestContextDestroy(cinfo
->digcx
);
247 signerinfos
= sigd
->signerInfos
;
250 /* prepare all the SignerInfos (there may be none) */
251 for (i
=0; i
< SecCmsSignedDataSignerInfoCount(sigd
); i
++) {
252 signerinfo
= SecCmsSignedDataGetSignerInfo(sigd
, i
);
254 /* find correct digest for this signerinfo */
255 digestalgtag
= SecCmsSignerInfoGetDigestAlgTag(signerinfo
);
256 n
= SecCmsAlgArrayGetIndexByAlgTag(sigd
->digestAlgorithms
, digestalgtag
);
257 if (n
< 0 || sigd
->digests
== NULL
|| sigd
->digests
[n
] == NULL
) {
258 /* oops - digest not found */
259 PORT_SetError(SEC_ERROR_DIGEST_NOT_FOUND
);
263 /* XXX if our content is anything else but data, we need to force the
264 * presence of signed attributes (RFC2630 5.3 "signedAttributes is a
267 /* pass contentType here as we want a contentType attribute */
268 if ((contentType
= SecCmsContentInfoGetContentTypeOID(cinfo
)) == NULL
)
272 rv
= SecCmsSignerInfoSign(signerinfo
, sigd
->digests
[n
], contentType
);
273 if (rv
!= SECSuccess
)
276 /* while we're at it, count number of certs in certLists */
277 certlist
= SecCmsSignerInfoGetCertList(signerinfo
);
279 certcount
+= CFArrayGetCount(certlist
);
282 /* this is a SET OF, so we need to sort them guys */
283 rv
= SecCmsArraySortByDER((void **)signerinfos
, SecCmsSignerInfoTemplate
, NULL
);
284 if (rv
!= SECSuccess
)
288 * now prepare certs & crls
291 /* count the rest of the certs */
292 if (sigd
->certs
!= NULL
)
293 certcount
+= CFArrayGetCount(sigd
->certs
);
295 if (certcount
== 0) {
296 sigd
->rawCerts
= NULL
;
299 * Combine all of the certs and cert chains into rawcerts.
300 * Note: certcount is an upper bound; we may not need that many slots
301 * but we will allocate anyway to avoid having to do another pass.
302 * (The temporary space saving is not worth it.)
304 * XXX ARGH - this NEEDS to be fixed. need to come up with a decent
305 * SetOfDERcertficates implementation
307 sigd
->rawCerts
= (SecAsn1Item
* *)PORT_ArenaAlloc(poolp
, (certcount
+ 1) * sizeof(SecAsn1Item
*));
308 if (sigd
->rawCerts
== NULL
)
312 * XXX Want to check for duplicates and not add *any* cert that is
313 * already in the set. This will be more important when we start
314 * dealing with larger sets of certs, dual-key certs (signing and
315 * encryption), etc. For the time being we can slide by...
317 * XXX ARGH - this NEEDS to be fixed. need to come up with a decent
318 * SetOfDERcertficates implementation
321 if (signerinfos
!= NULL
) {
322 for (si
= 0; signerinfos
[si
] != NULL
; si
++) {
323 signerinfo
= signerinfos
[si
];
324 for (ci
= 0; ci
< CFArrayGetCount(signerinfo
->certList
); ci
++) {
325 sigd
->rawCerts
[rci
] = PORT_ArenaZAlloc(poolp
, sizeof(SecAsn1Item
));
326 SecCertificateRef cert
= (SecCertificateRef
)CFArrayGetValueAtIndex(signerinfo
->certList
, ci
);
327 SecAsn1Item cert_data
= { SecCertificateGetLength(cert
),
328 (uint8_t *)SecCertificateGetBytePtr(cert
) };
329 *(sigd
->rawCerts
[rci
++]) = cert_data
;
334 if (sigd
->certs
!= NULL
) {
335 for (ci
= 0; ci
< CFArrayGetCount(sigd
->certs
); ci
++) {
336 sigd
->rawCerts
[rci
] = PORT_ArenaZAlloc(poolp
, sizeof(SecAsn1Item
));
337 SecCertificateRef cert
= (SecCertificateRef
)CFArrayGetValueAtIndex(sigd
->certs
, ci
);
338 SecAsn1Item cert_data
= { SecCertificateGetLength(cert
),
339 (uint8_t *)SecCertificateGetBytePtr(cert
) };
340 *(sigd
->rawCerts
[rci
++]) = cert_data
;
344 sigd
->rawCerts
[rci
] = NULL
;
346 /* this is a SET OF, so we need to sort them guys - we have the DER already, though */
347 SecCmsArraySort((void **)sigd
->rawCerts
, SecCmsUtilDERCompare
, NULL
, NULL
);
357 SecCmsSignedDataDecodeBeforeData(SecCmsSignedDataRef sigd
)
359 /* set up the digests, if we have digest algorithms, no digests yet, and content is attached */
360 if (sigd
->digestAlgorithms
!= NULL
&& sigd
->digests
== NULL
/* && sigd->contentInfo.content.pointer != NULL*/) {
361 /* if digests are already there, do nothing */
362 sigd
->contentInfo
.digcx
= SecCmsDigestContextStartMultiple(sigd
->digestAlgorithms
);
363 if (sigd
->contentInfo
.digcx
== NULL
)
370 * SecCmsSignedDataDecodeAfterData - do all the necessary things to a SignedData
371 * after all the encapsulated data was passed through the decoder.
374 SecCmsSignedDataDecodeAfterData(SecCmsSignedDataRef sigd
)
376 OSStatus rv
= SECSuccess
;
378 /* did we have digest calculation going on? */
379 if (sigd
->contentInfo
.digcx
) {
380 /* @@@ we should see if data was absent vs. zero length */
381 if (sigd
->contentInfo
.content
.data
&& sigd
->contentInfo
.content
.data
->Length
) {
382 SecAsn1Item
* *digests
= NULL
;
383 SECAlgorithmID
**digestalgs
= NULL
;
384 rv
= SecCmsDigestContextFinishMultiple(sigd
->contentInfo
.digcx
, &digestalgs
, &digests
);
385 if (rv
!= SECSuccess
)
386 goto loser
; /* error has been set by SecCmsDigestContextFinishMultiple */
387 rv
= SecCmsSignedDataSetDigests(sigd
, digestalgs
, digests
);
388 if (rv
!= SECSuccess
)
389 goto loser
; /* error has been set by SecCmsSignedDataSetDigests */
391 SecCmsDigestContextDestroy(sigd
->contentInfo
.digcx
);
392 sigd
->contentInfo
.digcx
= NULL
;
400 * SecCmsSignedDataDecodeAfterEnd - do all the necessary things to a SignedData
401 * after all decoding is finished.
404 SecCmsSignedDataDecodeAfterEnd(SecCmsSignedDataRef sigd
)
406 SecCmsSignerInfoRef
*signerinfos
;
413 /* set cmsg for all the signerinfos */
414 signerinfos
= sigd
->signerInfos
;
416 /* set signedData for all the signerinfos */
418 for (i
= 0; signerinfos
[i
] != NULL
; i
++)
419 signerinfos
[i
]->signedData
= sigd
;
426 * SecCmsSignedDataGetSignerInfos - retrieve the SignedData's signer list
428 SecCmsSignerInfoRef
*
429 SecCmsSignedDataGetSignerInfos(SecCmsSignedDataRef sigd
)
431 return sigd
->signerInfos
;
435 SecCmsSignedDataSignerInfoCount(SecCmsSignedDataRef sigd
)
437 return SecCmsArrayCount((void **)sigd
->signerInfos
);
441 SecCmsSignedDataGetSignerInfo(SecCmsSignedDataRef sigd
, int i
)
443 return sigd
->signerInfos
[i
];
447 * SecCmsSignedDataGetDigestAlgs - retrieve the SignedData's digest algorithm list
450 SecCmsSignedDataGetDigestAlgs(SecCmsSignedDataRef sigd
)
452 return sigd
->digestAlgorithms
;
456 * SecCmsSignedDataGetContentInfo - return pointer to this signedData's contentinfo
459 SecCmsSignedDataGetContentInfo(SecCmsSignedDataRef sigd
)
461 return &(sigd
->contentInfo
);
465 * SecCmsSignedDataGetCertificateList - retrieve the SignedData's certificate list
468 SecCmsSignedDataGetCertificateList(SecCmsSignedDataRef sigd
)
470 return sigd
->rawCerts
;
474 SecCmsSignedDataImportCerts(SecCmsSignedDataRef sigd
, SecKeychainRef keychain
,
475 SECCertUsage certusage
, Boolean keepcerts
)
482 * XXX the digests need to be passed in BETWEEN the decoding and the verification in case
483 * of external signatures!
488 * SecCmsSignedDataVerifySignerInfo - check the signatures.
490 * The digests were either calculated during decoding (and are stored in the
491 * signedData itself) or set after decoding using SecCmsSignedDataSetDigests.
493 * The verification checks if the signing cert is valid and has a trusted chain
494 * for the purpose specified by "policies".
496 * If trustRef is NULL the cert chain is verified and the VerificationStatus is set accordingly.
497 * Otherwise a SecTrust object is returned for the caller to evaluate using SecTrustEvaluate().
500 SecCmsSignedDataVerifySignerInfo(SecCmsSignedDataRef sigd
, int i
,
501 SecKeychainRef keychainOrArray
, CFTypeRef policies
, SecTrustRef
*trustRef
)
503 SecCmsSignerInfoRef signerinfo
;
504 SecCmsContentInfoRef cinfo
;
505 SECOidData
*algiddata
;
506 SecAsn1Item
*contentType
, *digest
;
509 cinfo
= &(sigd
->contentInfo
);
511 signerinfo
= sigd
->signerInfos
[i
];
513 /* Signature or digest level verificationStatus errors should supercede
514 certificate level errors, so check the digest and signature first. */
516 /* Find digest and contentType for signerinfo */
517 algiddata
= SecCmsSignerInfoGetDigestAlg(signerinfo
);
519 if (!sigd
->digests
) {
520 SECAlgorithmID
**digestalgs
= SecCmsSignedDataGetDigestAlgs(sigd
);
521 SecCmsDigestContextRef digcx
= SecCmsDigestContextStartMultiple(digestalgs
);
522 SecCmsSignedDataSetDigestContext(sigd
, digcx
);
523 SecCmsDigestContextDestroy(digcx
);
526 digest
= SecCmsSignedDataGetDigestByAlgTag(sigd
, algiddata
->offset
);
528 contentType
= SecCmsContentInfoGetContentTypeOID(cinfo
);
530 /* verify signature */
531 status
= SecCmsSignerInfoVerify(signerinfo
, digest
, contentType
);
532 #if SECTRUST_VERBOSE_DEBUG
533 syslog(LOG_ERR
, "SecCmsSignedDataVerifySignerInfo: SecCmsSignerInfoVerify returned %d, will %sverify cert",
534 (int)status
, (status
) ? "NOT " : "");
540 /* Now verify the certificate. We only do this when the signature verification succeeds. Note that this
541 behavior is different than the macOS code. */
542 status
= SecCmsSignerInfoVerifyCertificate(signerinfo
, keychainOrArray
, policies
, trustRef
);
543 #if SECTRUST_VERBOSE_DEBUG
544 syslog(LOG_ERR
, "SecCmsSignedDataVerifySignerInfo: SecCmsSignerInfoVerifyCertificate returned %d", (int)status
);
551 SecCmsSignedDataVerifyCertsOnly(SecCmsSignedDataRef sigd
,
552 SecKeychainRef keychainOrArray
,
555 OSStatus rv
= SECSuccess
;
557 if (!sigd
|| !keychainOrArray
|| !sigd
->rawCerts
) {
558 PORT_SetError(SEC_ERROR_INVALID_ARGS
);
562 SecAsn1Item
**cert_datas
= sigd
->rawCerts
;
563 SecAsn1Item
*cert_data
;
564 while ((cert_data
= *cert_datas
++) != NULL
) {
565 SecCertificateRef cert
= SecCertificateCreateWithBytes(NULL
, cert_data
->Data
, cert_data
->Length
);
567 CFArrayRef certs
= CFArrayCreate(kCFAllocatorDefault
, (const void **)&cert
, 1, NULL
);
568 rv
|= CERT_VerifyCert(keychainOrArray
, certs
, policies
, CFAbsoluteTimeGetCurrent(), NULL
);
580 * SecCmsSignedDataHasDigests - see if we have digests in place
583 SecCmsSignedDataHasDigests(SecCmsSignedDataRef sigd
)
585 return (sigd
->digests
!= NULL
);
589 SecCmsSignedDataAddCertList(SecCmsSignedDataRef sigd
, CFArrayRef certlist
)
591 PORT_Assert(certlist
!= NULL
);
593 if (certlist
== NULL
)
597 sigd
->certs
= CFArrayCreateMutableCopy(NULL
, 0, certlist
);
600 CFRange certlistRange
= { 0, CFArrayGetCount(certlist
) };
601 CFArrayAppendArray(sigd
->certs
, certlist
, certlistRange
);
608 * SecCmsSignedDataAddCertChain - add cert and its entire chain to the set of certs
611 SecCmsSignedDataAddCertChain(SecCmsSignedDataRef sigd
, SecCertificateRef cert
)
617 usage
= certUsageEmailSigner
;
619 /* do not include root */
620 certlist
= CERT_CertChainFromCert(cert
, usage
, PR_FALSE
);
621 if (certlist
== NULL
)
624 rv
= SecCmsSignedDataAddCertList(sigd
, certlist
);
631 SecCmsSignedDataAddCertificate(SecCmsSignedDataRef sigd
, SecCertificateRef cert
)
633 PORT_Assert(cert
!= NULL
);
639 sigd
->certs
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
641 CFArrayAppendValue(sigd
->certs
, cert
);
647 SecCmsSignedDataContainsCertsOrCrls(SecCmsSignedDataRef sigd
)
649 if (sigd
->rawCerts
!= NULL
&& sigd
->rawCerts
[0] != NULL
)
651 else if (sigd
->rawCrls
!= NULL
&& sigd
->rawCrls
[0] != NULL
)
658 SecCmsSignedDataAddSignerInfo(SecCmsSignedDataRef sigd
,
659 SecCmsSignerInfoRef signerinfo
)
663 SECOidTag digestalgtag
;
666 poolp
= sigd
->contentInfo
.cmsg
->poolp
;
668 mark
= PORT_ArenaMark(poolp
);
671 rv
= SecCmsArrayAdd(poolp
, (void ***)&(sigd
->signerInfos
), (void *)signerinfo
);
672 if (rv
!= SECSuccess
)
677 * Empty because we don't have it yet. Either it gets created during encoding
678 * (if the data is present) or has to be set externally.
679 * XXX maybe pass it in optionally?
681 digestalgtag
= SecCmsSignerInfoGetDigestAlgTag(signerinfo
);
682 rv
= SecCmsSignedDataSetDigestValue(sigd
, digestalgtag
, NULL
);
683 if (rv
!= SECSuccess
)
687 * The last thing to get consistency would be adding the digest.
690 PORT_ArenaUnmark(poolp
, mark
);
694 PORT_ArenaRelease (poolp
, mark
);
699 SecCmsSignedDataGetDigestByAlgTag(SecCmsSignedDataRef sigd
, SECOidTag algtag
)
703 if(sigd
== NULL
|| sigd
->digests
== NULL
) {
706 idx
= SecCmsAlgArrayGetIndexByAlgTag(sigd
->digestAlgorithms
, algtag
);
707 return (idx
>= 0)?(sigd
->digests
)[idx
]:NULL
;
711 SecCmsSignedDataSetDigestContext(SecCmsSignedDataRef sigd
,
712 SecCmsDigestContextRef digestContext
)
714 SECAlgorithmID
**digestalgs
;
715 SecAsn1Item
* *digests
;
717 if (SecCmsDigestContextFinishMultiple(digestContext
, &digestalgs
, &digests
) != SECSuccess
)
719 if (SecCmsSignedDataSetDigests(sigd
, digestalgs
, digests
) != SECSuccess
)
724 return PORT_GetError();
728 * SecCmsSignedDataSetDigests - set a signedData's digests member
730 * "digestalgs" - array of digest algorithm IDs
731 * "digests" - array of digests corresponding to the digest algorithms
734 SecCmsSignedDataSetDigests(SecCmsSignedDataRef sigd
,
735 SECAlgorithmID
**digestalgs
,
736 SecAsn1Item
* *digests
)
740 /* Check input structure and items in structure */
741 if (sigd
== NULL
|| sigd
->digestAlgorithms
== NULL
|| sigd
->contentInfo
.cmsg
== NULL
||
742 sigd
->contentInfo
.cmsg
->poolp
== NULL
) {
743 PORT_SetError(SEC_ERROR_INVALID_ARGS
);
747 /* Since we'll generate a empty digest for content-less messages
748 whether or not they're detached, we have to avoid overwriting
749 externally set digest for detached content => return early */
750 if (sigd
->digests
&& sigd
->digests
[0])
753 /* we assume that the digests array is just not there yet */
755 PORT_Assert(sigd->digests == NULL);
756 if (sigd->digests != NULL) {
757 PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
761 /* now allocate one (same size as digestAlgorithms) */
762 if (sigd
->digests
== NULL
) {
763 cnt
= SecCmsArrayCount((void **)sigd
->digestAlgorithms
);
764 sigd
->digests
= PORT_ArenaZAlloc(sigd
->contentInfo
.cmsg
->poolp
, (cnt
+ 1) * sizeof(SecAsn1Item
*));
765 if (sigd
->digests
== NULL
) {
766 PORT_SetError(SEC_ERROR_NO_MEMORY
);
771 for (i
= 0; sigd
->digestAlgorithms
[i
] != NULL
; i
++) {
772 /* try to find the sigd's i'th digest algorithm in the array we passed in */
773 idx
= SecCmsAlgArrayGetIndexByAlgID(digestalgs
, sigd
->digestAlgorithms
[i
]);
775 PORT_SetError(SEC_ERROR_DIGEST_NOT_FOUND
);
779 /* found it - now set it */
780 if ((sigd
->digests
[i
] = SECITEM_AllocItem(sigd
->contentInfo
.cmsg
->poolp
, NULL
, 0)) == NULL
||
781 SECITEM_CopyItem(sigd
->contentInfo
.cmsg
->poolp
, sigd
->digests
[i
], digests
[idx
]) != SECSuccess
)
783 PORT_SetError(SEC_ERROR_NO_MEMORY
);
791 SecCmsSignedDataSetDigestValue(SecCmsSignedDataRef sigd
,
792 SECOidTag digestalgtag
,
793 SecAsn1Item
* digestdata
)
795 SecAsn1Item
* digest
= NULL
;
800 poolp
= sigd
->contentInfo
.cmsg
->poolp
;
802 mark
= PORT_ArenaMark(poolp
);
806 digest
= (SecAsn1Item
*) PORT_ArenaZAlloc(poolp
,sizeof(SecAsn1Item
));
808 /* copy digestdata item to arena (in case we have it and are not only making room) */
809 if (SECITEM_CopyItem(poolp
, digest
, digestdata
) != SECSuccess
)
813 /* now allocate one (same size as digestAlgorithms) */
814 if (sigd
->digests
== NULL
) {
815 cnt
= SecCmsArrayCount((void **)sigd
->digestAlgorithms
);
816 sigd
->digests
= PORT_ArenaZAlloc(sigd
->contentInfo
.cmsg
->poolp
, (cnt
+ 1) * sizeof(SecAsn1Item
*));
817 if (sigd
->digests
== NULL
) {
818 PORT_SetError(SEC_ERROR_NO_MEMORY
);
824 if (sigd
->digestAlgorithms
!= NULL
)
825 n
= SecCmsAlgArrayGetIndexByAlgTag(sigd
->digestAlgorithms
, digestalgtag
);
827 /* if not found, add a digest */
829 if (SecCmsSignedDataAddDigest(poolp
, sigd
, digestalgtag
, digest
) != SECSuccess
)
832 /* replace NULL pointer with digest item (and leak previous value) */
833 sigd
->digests
[n
] = digest
;
836 PORT_ArenaUnmark(poolp
, mark
);
840 PORT_ArenaRelease(poolp
, mark
);
845 SecCmsSignedDataAddDigest(PRArenaPool
*poolp
,
846 SecCmsSignedDataRef sigd
,
847 SECOidTag digestalgtag
,
848 SecAsn1Item
* digest
)
850 SECAlgorithmID
*digestalg
;
853 mark
= PORT_ArenaMark(poolp
);
855 digestalg
= PORT_ArenaZAlloc(poolp
, sizeof(SECAlgorithmID
));
856 if (digestalg
== NULL
)
859 if (SECOID_SetAlgorithmID (poolp
, digestalg
, digestalgtag
, NULL
) != SECSuccess
) /* no params */
862 if (SecCmsArrayAdd(poolp
, (void ***)&(sigd
->digestAlgorithms
), (void *)digestalg
) != SECSuccess
||
863 /* even if digest is NULL, add dummy to have same-size array */
864 SecCmsArrayAdd(poolp
, (void ***)&(sigd
->digests
), (void *)digest
) != SECSuccess
)
869 PORT_ArenaUnmark(poolp
, mark
);
873 PORT_ArenaRelease(poolp
, mark
);
878 SecCmsSignedDataGetDigestValue(SecCmsSignedDataRef sigd
, SECOidTag digestalgtag
)
882 if (sigd
->digestAlgorithms
== NULL
)
885 n
= SecCmsAlgArrayGetIndexByAlgTag(sigd
->digestAlgorithms
, digestalgtag
);
887 return (n
< 0) ? NULL
: sigd
->digests
[n
];
890 /* =============================================================================
891 * Misc. utility functions
895 * SecCmsSignedDataCreateCertsOnly - create a certs-only SignedData.
897 * cert - base certificates that will be included
898 * include_chain - if true, include the complete cert chain for cert
900 * More certs and chains can be added via AddCertificate and AddCertChain.
902 * An error results in a return value of NULL and an error set.
907 SecCmsSignedDataCreateCertsOnly(SecCmsMessageRef cmsg
, SecCertificateRef cert
, Boolean include_chain
)
909 SecCmsSignedDataRef sigd
;
915 mark
= PORT_ArenaMark(poolp
);
917 sigd
= SecCmsSignedDataCreate(cmsg
);
921 /* no signerinfos, thus no digestAlgorithms */
925 rv
= SecCmsSignedDataAddCertChain(sigd
, cert
);
927 rv
= SecCmsSignedDataAddCertificate(sigd
, cert
);
929 if (rv
!= SECSuccess
)
933 * In the degenerate case where there are no signers, the
934 * EncapsulatedContentInfo value being "signed" is irrelevant. In this
935 * case, the content type within the EncapsulatedContentInfo value being
936 * "signed" should be id-data (as defined in section 4), and the content
937 * field of the EncapsulatedContentInfo value should be omitted.
939 rv
= SecCmsContentInfoSetContentData(&(sigd
->contentInfo
), NULL
, PR_TRUE
);
940 if (rv
!= SECSuccess
)
943 PORT_ArenaUnmark(poolp
, mark
);
948 SecCmsSignedDataDestroy(sigd
);
949 PORT_ArenaRelease(poolp
, mark
);
954 * SecCmsSignerInfoGetReceiptRequest()
955 * SecCmsSignedDataHasReceiptRequest()
956 * easy way to iterate over signers