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>
55 #include <Security/SecCertificatePriv.h>
59 SecCmsSignedDataCreate(SecCmsMessageRef cmsg
)
62 SecCmsSignedDataRef sigd
;
67 mark
= PORT_ArenaMark(poolp
);
69 sigd
= (SecCmsSignedDataRef
)PORT_ArenaZAlloc (poolp
, sizeof(SecCmsSignedData
));
73 sigd
->contentInfo
.cmsg
= cmsg
;
75 /* signerInfos, certs, certlists, crls are all empty */
76 /* version is set in SecCmsSignedDataFinalize() */
78 PORT_ArenaUnmark(poolp
, mark
);
82 PORT_ArenaRelease(poolp
, mark
);
87 SecCmsSignedDataDestroy(SecCmsSignedDataRef sigd
)
89 SecCmsSignerInfoRef
*signerinfos
, si
;
94 if (sigd
->certs
!= NULL
)
95 CFRelease(sigd
->certs
);
97 signerinfos
= sigd
->signerInfos
;
98 if (signerinfos
!= NULL
) {
99 while ((si
= *signerinfos
++) != NULL
)
100 SecCmsSignerInfoDestroy(si
);
103 /* everything's in a pool, so don't worry about the storage */
104 SecCmsContentInfoDestroy(&(sigd
->contentInfo
));
108 * SecCmsSignedDataEncodeBeforeStart - do all the necessary things to a SignedData
109 * before start of encoding.
112 * - find out about the right value to put into sigd->version
113 * - come up with a list of digestAlgorithms (which should be the union of the algorithms
114 * in the signerinfos).
115 * If we happen to have a pre-set list of algorithms (and digest values!), we
116 * check if we have all the signerinfos' algorithms. If not, this is an error.
119 SecCmsSignedDataEncodeBeforeStart(SecCmsSignedDataRef sigd
)
121 SecCmsSignerInfoRef signerinfo
;
122 SECOidTag digestalgtag
;
126 Boolean haveDigests
= PR_FALSE
;
130 poolp
= sigd
->contentInfo
.cmsg
->poolp
;
132 /* we assume that we have precomputed digests if there is a list of algorithms, and */
133 /* a chunk of data for each of those algorithms */
134 if (sigd
->digestAlgorithms
!= NULL
&& sigd
->digests
!= NULL
) {
135 for (i
=0; sigd
->digestAlgorithms
[i
] != NULL
; i
++) {
136 if (sigd
->digests
[i
] == NULL
)
139 if (sigd
->digestAlgorithms
[i
] == NULL
) /* reached the end of the array? */
140 haveDigests
= PR_TRUE
; /* yes: we must have all the digests */
143 version
= SEC_CMS_SIGNED_DATA_VERSION_BASIC
;
145 /* RFC2630 5.1 "version is the syntax version number..." */
146 if (SecCmsContentInfoGetContentTypeTag(&(sigd
->contentInfo
)) != SEC_OID_PKCS7_DATA
)
147 version
= SEC_CMS_SIGNED_DATA_VERSION_EXT
;
149 /* prepare all the SignerInfos (there may be none) */
150 for (i
=0; i
< SecCmsSignedDataSignerInfoCount(sigd
); i
++) {
151 signerinfo
= SecCmsSignedDataGetSignerInfo(sigd
, i
);
153 /* RFC2630 5.1 "version is the syntax version number..." */
154 if (SecCmsSignerInfoGetVersion(signerinfo
) != SEC_CMS_SIGNER_INFO_VERSION_ISSUERSN
)
155 version
= SEC_CMS_SIGNED_DATA_VERSION_EXT
;
157 /* collect digestAlgorithms from SignerInfos */
158 /* (we need to know which algorithms we have when the content comes in) */
159 /* do not overwrite any existing digestAlgorithms (and digest) */
160 digestalgtag
= SecCmsSignerInfoGetDigestAlgTag(signerinfo
);
161 n
= SecCmsAlgArrayGetIndexByAlgTag(sigd
->digestAlgorithms
, digestalgtag
);
162 if (n
< 0 && haveDigests
) {
163 /* oops, there is a digestalg we do not have a digest for */
164 /* but we were supposed to have all the digests already... */
167 /* add the digestAlgorithm & a NULL digest */
168 rv
= SecCmsSignedDataAddDigest(poolp
, sigd
, digestalgtag
, NULL
);
169 if (rv
!= SECSuccess
)
172 /* found it, nothing to do */
176 dummy
= SEC_ASN1EncodeInteger(poolp
, &(sigd
->version
), (long)version
);
180 /* this is a SET OF, so we need to sort them guys */
181 rv
= SecCmsArraySortByDER((void **)sigd
->digestAlgorithms
,
182 SEC_ASN1_GET(SECOID_AlgorithmIDTemplate
),
183 (void **)sigd
->digests
);
184 if (rv
!= SECSuccess
)
194 SecCmsSignedDataEncodeBeforeData(SecCmsSignedDataRef sigd
)
196 /* set up the digests */
197 if (sigd
->digestAlgorithms
!= NULL
) {
198 sigd
->contentInfo
.digcx
= SecCmsDigestContextStartMultiple(sigd
->digestAlgorithms
);
199 if (sigd
->contentInfo
.digcx
== NULL
)
206 * SecCmsSignedDataEncodeAfterData - do all the necessary things to a SignedData
207 * after all the encapsulated data was passed through the encoder.
210 * - create the signatures in all the SignerInfos
212 * Please note that nothing is done to the Certificates and CRLs in the message - this
213 * is entirely the responsibility of our callers.
216 SecCmsSignedDataEncodeAfterData(SecCmsSignedDataRef sigd
)
218 SecCmsSignerInfoRef
*signerinfos
, signerinfo
;
219 SecCmsContentInfoRef cinfo
;
220 SECOidTag digestalgtag
;
221 OSStatus ret
= SECFailure
;
223 SecAsn1Item
* contentType
;
225 int i
, ci
, n
, rci
, si
;
228 extern const SecAsn1Template SecCmsSignerInfoTemplate
[];
230 cinfo
= &(sigd
->contentInfo
);
231 poolp
= cinfo
->cmsg
->poolp
;
233 /* did we have digest calculation going on? */
235 SecAsn1Item
**digests
= NULL
;
236 SECAlgorithmID
**digestalgs
= NULL
;
237 rv
= SecCmsDigestContextFinishMultiple(cinfo
->digcx
, &digestalgs
, &digests
);
238 if (rv
!= SECSuccess
)
239 goto loser
; /* error has been set by SecCmsDigestContextFinishMultiple */
240 if (digestalgs
&& digests
) {
241 rv
= SecCmsSignedDataSetDigests(sigd
, digestalgs
, digests
);
242 if (rv
!= SECSuccess
)
243 goto loser
; /* error has been set by SecCmsSignedDataSetDigests */
245 SecCmsDigestContextDestroy(cinfo
->digcx
);
249 signerinfos
= sigd
->signerInfos
;
252 /* prepare all the SignerInfos (there may be none) */
253 for (i
=0; i
< SecCmsSignedDataSignerInfoCount(sigd
); i
++) {
254 signerinfo
= SecCmsSignedDataGetSignerInfo(sigd
, i
);
256 /* find correct digest for this signerinfo */
257 digestalgtag
= SecCmsSignerInfoGetDigestAlgTag(signerinfo
);
258 n
= SecCmsAlgArrayGetIndexByAlgTag(sigd
->digestAlgorithms
, digestalgtag
);
259 if (n
< 0 || sigd
->digests
== NULL
|| sigd
->digests
[n
] == NULL
) {
260 /* oops - digest not found */
261 PORT_SetError(SEC_ERROR_DIGEST_NOT_FOUND
);
265 /* XXX if our content is anything else but data, we need to force the
266 * presence of signed attributes (RFC2630 5.3 "signedAttributes is a
269 /* pass contentType here as we want a contentType attribute */
270 if ((contentType
= SecCmsContentInfoGetContentTypeOID(cinfo
)) == NULL
)
274 rv
= SecCmsSignerInfoSign(signerinfo
, sigd
->digests
[n
], contentType
);
275 if (rv
!= SECSuccess
)
278 /* while we're at it, count number of certs in certLists */
279 certlist
= SecCmsSignerInfoGetCertList(signerinfo
);
281 certcount
+= CFArrayGetCount(certlist
);
284 /* this is a SET OF, so we need to sort them guys */
285 rv
= SecCmsArraySortByDER((void **)signerinfos
, SecCmsSignerInfoTemplate
, NULL
);
286 if (rv
!= SECSuccess
)
290 * now prepare certs & crls
293 /* count the rest of the certs */
294 if (sigd
->certs
!= NULL
)
295 certcount
+= CFArrayGetCount(sigd
->certs
);
297 if (certcount
== 0) {
298 sigd
->rawCerts
= NULL
;
301 * Combine all of the certs and cert chains into rawcerts.
302 * Note: certcount is an upper bound; we may not need that many slots
303 * but we will allocate anyway to avoid having to do another pass.
304 * (The temporary space saving is not worth it.)
306 * XXX ARGH - this NEEDS to be fixed. need to come up with a decent
307 * SetOfDERcertficates implementation
309 sigd
->rawCerts
= (SecAsn1Item
* *)PORT_ArenaAlloc(poolp
, (certcount
+ 1) * sizeof(SecAsn1Item
*));
310 if (sigd
->rawCerts
== NULL
)
314 * XXX Want to check for duplicates and not add *any* cert that is
315 * already in the set. This will be more important when we start
316 * dealing with larger sets of certs, dual-key certs (signing and
317 * encryption), etc. For the time being we can slide by...
319 * XXX ARGH - this NEEDS to be fixed. need to come up with a decent
320 * SetOfDERcertficates implementation
323 if (signerinfos
!= NULL
) {
324 for (si
= 0; signerinfos
[si
] != NULL
; si
++) {
325 signerinfo
= signerinfos
[si
];
326 for (ci
= 0; ci
< CFArrayGetCount(signerinfo
->certList
); ci
++) {
327 sigd
->rawCerts
[rci
] = PORT_ArenaZAlloc(poolp
, sizeof(SecAsn1Item
));
328 SecCertificateRef cert
= (SecCertificateRef
)CFArrayGetValueAtIndex(signerinfo
->certList
, ci
);
330 SecCertificateGetData(cert
, sigd
->rawCerts
[rci
++]);
332 SecAsn1Item cert_data
= { SecCertificateGetLength(cert
),
333 (uint8_t *)SecCertificateGetBytePtr(cert
) };
334 *(sigd
->rawCerts
[rci
++]) = cert_data
;
340 if (sigd
->certs
!= NULL
) {
341 for (ci
= 0; ci
< CFArrayGetCount(sigd
->certs
); ci
++) {
342 sigd
->rawCerts
[rci
] = PORT_ArenaZAlloc(poolp
, sizeof(SecAsn1Item
));
343 SecCertificateRef cert
= (SecCertificateRef
)CFArrayGetValueAtIndex(sigd
->certs
, ci
);
345 SecCertificateGetData(cert
, sigd
->rawCerts
[rci
++]);
347 SecAsn1Item cert_data
= { SecCertificateGetLength(cert
),
348 (uint8_t *)SecCertificateGetBytePtr(cert
) };
349 *(sigd
->rawCerts
[rci
++]) = cert_data
;
354 sigd
->rawCerts
[rci
] = NULL
;
356 /* this is a SET OF, so we need to sort them guys - we have the DER already, though */
357 SecCmsArraySort((void **)sigd
->rawCerts
, SecCmsUtilDERCompare
, NULL
, NULL
);
367 SecCmsSignedDataDecodeBeforeData(SecCmsSignedDataRef sigd
)
369 /* set up the digests, if we have digest algorithms, no digests yet, and content is attached */
370 if (sigd
->digestAlgorithms
!= NULL
&& sigd
->digests
== NULL
/* && sigd->contentInfo.content.pointer != NULL*/) {
371 /* if digests are already there, do nothing */
372 sigd
->contentInfo
.digcx
= SecCmsDigestContextStartMultiple(sigd
->digestAlgorithms
);
373 if (sigd
->contentInfo
.digcx
== NULL
)
380 * SecCmsSignedDataDecodeAfterData - do all the necessary things to a SignedData
381 * after all the encapsulated data was passed through the decoder.
384 SecCmsSignedDataDecodeAfterData(SecCmsSignedDataRef sigd
)
386 OSStatus rv
= SECSuccess
;
388 /* did we have digest calculation going on? */
389 if (sigd
->contentInfo
.digcx
) {
390 /* @@@ we should see if data was absent vs. zero length */
391 if (sigd
->contentInfo
.content
.data
&& sigd
->contentInfo
.content
.data
->Length
) {
392 SecAsn1Item
* *digests
= NULL
;
393 SECAlgorithmID
**digestalgs
= NULL
;
394 rv
= SecCmsDigestContextFinishMultiple(sigd
->contentInfo
.digcx
, &digestalgs
, &digests
);
395 if (rv
!= SECSuccess
)
396 goto loser
; /* error has been set by SecCmsDigestContextFinishMultiple */
397 rv
= SecCmsSignedDataSetDigests(sigd
, digestalgs
, digests
);
398 if (rv
!= SECSuccess
)
399 goto loser
; /* error has been set by SecCmsSignedDataSetDigests */
401 SecCmsDigestContextDestroy(sigd
->contentInfo
.digcx
);
402 sigd
->contentInfo
.digcx
= NULL
;
410 * SecCmsSignedDataDecodeAfterEnd - do all the necessary things to a SignedData
411 * after all decoding is finished.
414 SecCmsSignedDataDecodeAfterEnd(SecCmsSignedDataRef sigd
)
416 SecCmsSignerInfoRef
*signerinfos
;
423 /* set cmsg for all the signerinfos */
424 signerinfos
= sigd
->signerInfos
;
426 /* set signedData for all the signerinfos */
428 for (i
= 0; signerinfos
[i
] != NULL
; i
++)
429 signerinfos
[i
]->signedData
= sigd
;
436 * SecCmsSignedDataGetSignerInfos - retrieve the SignedData's signer list
438 SecCmsSignerInfoRef
*
439 SecCmsSignedDataGetSignerInfos(SecCmsSignedDataRef sigd
)
441 return sigd
->signerInfos
;
445 SecCmsSignedDataSignerInfoCount(SecCmsSignedDataRef sigd
)
447 return SecCmsArrayCount((void **)sigd
->signerInfos
);
451 SecCmsSignedDataGetSignerInfo(SecCmsSignedDataRef sigd
, int i
)
453 return sigd
->signerInfos
[i
];
457 * SecCmsSignedDataGetDigestAlgs - retrieve the SignedData's digest algorithm list
460 SecCmsSignedDataGetDigestAlgs(SecCmsSignedDataRef sigd
)
462 return sigd
->digestAlgorithms
;
466 * SecCmsSignedDataGetContentInfo - return pointer to this signedData's contentinfo
469 SecCmsSignedDataGetContentInfo(SecCmsSignedDataRef sigd
)
471 return &(sigd
->contentInfo
);
475 * SecCmsSignedDataGetCertificateList - retrieve the SignedData's certificate list
478 SecCmsSignedDataGetCertificateList(SecCmsSignedDataRef sigd
)
480 return sigd
->rawCerts
;
484 SecCmsSignedDataImportCerts(SecCmsSignedDataRef sigd
, SecKeychainRef keychain
,
485 SECCertUsage certusage
, Boolean keepcerts
)
490 int ix
, certcount
= SecCmsArrayCount((void **)sigd
->rawCerts
);
491 rv
= CERT_ImportCerts(keychain
, certusage
, certcount
, sigd
->rawCerts
, NULL
,
492 keepcerts
, PR_FALSE
, NULL
);
493 /* XXX CRL handling */
495 if (sigd
->signerInfos
!= NULL
) {
496 /* fill in all signerinfo's certs */
497 for (ix
= 0; sigd
->signerInfos
[ix
] != NULL
; i
++)
498 (void)SecCmsSignerInfoGetSigningCertificate(sigd
->signerInfos
[ix
], keychain
);
501 // XXX we should only ever import certs for a cert only data blob
508 * XXX the digests need to be passed in BETWEEN the decoding and the verification in case
509 * of external signatures!
514 * SecCmsSignedDataVerifySignerInfo - check the signatures.
516 * The digests were either calculated during decoding (and are stored in the
517 * signedData itself) or set after decoding using SecCmsSignedDataSetDigests.
519 * The verification checks if the signing cert is valid and has a trusted chain
520 * for the purpose specified by "policies".
522 * If trustRef is NULL the cert chain is verified and the VerificationStatus is set accordingly.
523 * Otherwise a SecTrust object is returned for the caller to evaluate using SecTrustEvaluate().
526 SecCmsSignedDataVerifySignerInfo(SecCmsSignedDataRef sigd
, int i
,
527 SecKeychainRef keychainOrArray
, CFTypeRef policies
, SecTrustRef
*trustRef
)
529 SecCmsSignerInfoRef signerinfo
;
530 SecCmsContentInfoRef cinfo
;
531 SECOidData
*algiddata
;
532 SecAsn1Item
*contentType
, *digest
;
535 if (sigd
== NULL
|| sigd
->signerInfos
== NULL
|| i
>= SecCmsSignedDataSignerInfoCount(sigd
)) {
539 cinfo
= &(sigd
->contentInfo
);
540 signerinfo
= sigd
->signerInfos
[i
];
542 /* Signature or digest level verificationStatus errors should supercede
543 certificate level errors, so check the digest and signature first. */
545 /* Find digest and contentType for signerinfo */
546 algiddata
= SecCmsSignerInfoGetDigestAlg(signerinfo
);
547 if (algiddata
== NULL
) {
548 return errSecInvalidDigestAlgorithm
;
551 if (!sigd
->digests
) {
552 SECAlgorithmID
**digestalgs
= SecCmsSignedDataGetDigestAlgs(sigd
);
553 SecCmsDigestContextRef digcx
= SecCmsDigestContextStartMultiple(digestalgs
);
554 SecCmsSignedDataSetDigestContext(sigd
, digcx
);
555 SecCmsDigestContextDestroy(digcx
);
558 digest
= SecCmsSignedDataGetDigestByAlgTag(sigd
, algiddata
->offset
);
559 if (digest
== NULL
) {
560 return errSecDataNotAvailable
;
563 contentType
= SecCmsContentInfoGetContentTypeOID(cinfo
);
565 /* verify signature */
566 status
= SecCmsSignerInfoVerify(signerinfo
, digest
, contentType
);
567 #if SECTRUST_VERBOSE_DEBUG
568 syslog(LOG_ERR
, "SecCmsSignedDataVerifySignerInfo: SecCmsSignerInfoVerify returned %d, will %sverify cert",
569 (int)status
, (status
) ? "NOT " : "");
575 /* Now verify the certificate. We only do this when the signature verification succeeds. Note that this
576 behavior is different than the macOS code. */
577 status
= SecCmsSignerInfoVerifyCertificate(signerinfo
, keychainOrArray
, policies
, trustRef
);
578 #if SECTRUST_VERBOSE_DEBUG
579 syslog(LOG_ERR
, "SecCmsSignedDataVerifySignerInfo: SecCmsSignerInfoVerifyCertificate returned %d", (int)status
);
588 * SecCmsSignedDataVerifyCertsOnly - verify the certs in a certs-only message
591 SecCmsSignedDataVerifyCertsOnly(SecCmsSignedDataRef sigd
,
592 SecKeychainRef keychainOrArray
,
595 SecCertificateRef cert
;
596 OSStatus rv
= SECSuccess
;
600 if (!sigd
|| !keychainOrArray
|| !sigd
->rawCerts
) {
601 PORT_SetError(SEC_ERROR_INVALID_ARGS
);
605 count
= SecCmsArrayCount((void**)sigd
->rawCerts
);
606 for (i
=0; i
< count
; i
++) {
607 if (sigd
->certs
&& CFArrayGetCount(sigd
->certs
) > i
) {
608 cert
= (SecCertificateRef
)CFArrayGetValueAtIndex(sigd
->certs
, i
);
611 cert
= CERT_FindCertByDERCert(keychainOrArray
, sigd
->rawCerts
[i
]);
617 rv
|= CERT_VerifyCert(keychainOrArray
, cert
, policies
, CFAbsoluteTimeGetCurrent(), NULL
);
625 SecCmsSignedDataVerifyCertsOnly(SecCmsSignedDataRef sigd
,
626 SecKeychainRef keychainOrArray
,
629 OSStatus rv
= SECSuccess
;
631 if (!sigd
|| !keychainOrArray
|| !sigd
->rawCerts
) {
632 PORT_SetError(SEC_ERROR_INVALID_ARGS
);
636 SecAsn1Item
**cert_datas
= sigd
->rawCerts
;
637 SecAsn1Item
*cert_data
;
638 while ((cert_data
= *cert_datas
++) != NULL
) {
639 SecCertificateRef cert
= SecCertificateCreateWithBytes(NULL
, cert_data
->Data
, cert_data
->Length
);
641 CFArrayRef certs
= CFArrayCreate(kCFAllocatorDefault
, (const void **)&cert
, 1, NULL
);
642 rv
|= CERT_VerifyCert(keychainOrArray
, certs
, policies
, CFAbsoluteTimeGetCurrent(), NULL
);
655 * SecCmsSignedDataHasDigests - see if we have digests in place
658 SecCmsSignedDataHasDigests(SecCmsSignedDataRef sigd
)
660 return (sigd
->digests
!= NULL
);
664 SecCmsSignedDataAddCertList(SecCmsSignedDataRef sigd
, CFArrayRef certlist
)
666 PORT_Assert(certlist
!= NULL
);
668 if (certlist
== NULL
)
672 sigd
->certs
= CFArrayCreateMutableCopy(NULL
, 0, certlist
);
675 CFRange certlistRange
= { 0, CFArrayGetCount(certlist
) };
676 CFArrayAppendArray(sigd
->certs
, certlist
, certlistRange
);
683 * SecCmsSignedDataAddCertChain - add cert and its entire chain to the set of certs
686 SecCmsSignedDataAddCertChain(SecCmsSignedDataRef sigd
, SecCertificateRef cert
)
692 usage
= certUsageEmailSigner
;
694 /* do not include root */
695 certlist
= CERT_CertChainFromCert(cert
, usage
, PR_FALSE
);
696 if (certlist
== NULL
)
699 rv
= SecCmsSignedDataAddCertList(sigd
, certlist
);
706 SecCmsSignedDataAddCertificate(SecCmsSignedDataRef sigd
, SecCertificateRef cert
)
708 PORT_Assert(cert
!= NULL
);
714 sigd
->certs
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
716 CFArrayAppendValue(sigd
->certs
, cert
);
722 SecCmsSignedDataContainsCertsOrCrls(SecCmsSignedDataRef sigd
)
724 if (sigd
->rawCerts
!= NULL
&& sigd
->rawCerts
[0] != NULL
)
726 else if (sigd
->rawCrls
!= NULL
&& sigd
->rawCrls
[0] != NULL
)
733 SecCmsSignedDataAddSignerInfo(SecCmsSignedDataRef sigd
,
734 SecCmsSignerInfoRef signerinfo
)
738 SECOidTag digestalgtag
;
741 poolp
= sigd
->contentInfo
.cmsg
->poolp
;
743 mark
= PORT_ArenaMark(poolp
);
746 rv
= SecCmsArrayAdd(poolp
, (void ***)&(sigd
->signerInfos
), (void *)signerinfo
);
747 if (rv
!= SECSuccess
)
752 * Empty because we don't have it yet. Either it gets created during encoding
753 * (if the data is present) or has to be set externally.
754 * XXX maybe pass it in optionally?
756 digestalgtag
= SecCmsSignerInfoGetDigestAlgTag(signerinfo
);
757 rv
= SecCmsSignedDataSetDigestValue(sigd
, digestalgtag
, NULL
);
758 if (rv
!= SECSuccess
)
762 * The last thing to get consistency would be adding the digest.
765 PORT_ArenaUnmark(poolp
, mark
);
769 PORT_ArenaRelease (poolp
, mark
);
774 SecCmsSignedDataGetDigestByAlgTag(SecCmsSignedDataRef sigd
, SECOidTag algtag
)
778 if(sigd
== NULL
|| sigd
->digests
== NULL
) {
781 idx
= SecCmsAlgArrayGetIndexByAlgTag(sigd
->digestAlgorithms
, algtag
);
782 return (idx
>= 0)?(sigd
->digests
)[idx
]:NULL
;
786 SecCmsSignedDataSetDigestContext(SecCmsSignedDataRef sigd
,
787 SecCmsDigestContextRef digestContext
)
789 SECAlgorithmID
**digestalgs
;
790 SecAsn1Item
* *digests
;
792 if (SecCmsDigestContextFinishMultiple(digestContext
, &digestalgs
, &digests
) != SECSuccess
)
794 if (SecCmsSignedDataSetDigests(sigd
, digestalgs
, digests
) != SECSuccess
)
799 return PORT_GetError();
803 * SecCmsSignedDataSetDigests - set a signedData's digests member
805 * "digestalgs" - array of digest algorithm IDs
806 * "digests" - array of digests corresponding to the digest algorithms
809 SecCmsSignedDataSetDigests(SecCmsSignedDataRef sigd
,
810 SECAlgorithmID
**digestalgs
,
811 SecAsn1Item
* *digests
)
815 /* Check input structure and items in structure */
816 if (sigd
== NULL
|| sigd
->digestAlgorithms
== NULL
|| sigd
->contentInfo
.cmsg
== NULL
||
817 sigd
->contentInfo
.cmsg
->poolp
== NULL
) {
818 PORT_SetError(SEC_ERROR_INVALID_ARGS
);
822 /* Since we'll generate a empty digest for content-less messages
823 whether or not they're detached, we have to avoid overwriting
824 externally set digest for detached content => return early */
825 if (sigd
->digests
&& sigd
->digests
[0])
828 /* we assume that the digests array is just not there yet */
830 PORT_Assert(sigd->digests == NULL);
831 if (sigd->digests != NULL) {
832 PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
836 /* now allocate one (same size as digestAlgorithms) */
837 if (sigd
->digests
== NULL
) {
838 cnt
= SecCmsArrayCount((void **)sigd
->digestAlgorithms
);
839 sigd
->digests
= PORT_ArenaZAlloc(sigd
->contentInfo
.cmsg
->poolp
, (cnt
+ 1) * sizeof(SecAsn1Item
*));
840 if (sigd
->digests
== NULL
) {
841 PORT_SetError(SEC_ERROR_NO_MEMORY
);
846 for (i
= 0; sigd
->digestAlgorithms
[i
] != NULL
; i
++) {
847 /* try to find the sigd's i'th digest algorithm in the array we passed in */
848 idx
= SecCmsAlgArrayGetIndexByAlgID(digestalgs
, sigd
->digestAlgorithms
[i
]);
850 PORT_SetError(SEC_ERROR_DIGEST_NOT_FOUND
);
854 /* found it - now set it */
855 if ((sigd
->digests
[i
] = SECITEM_AllocItem(sigd
->contentInfo
.cmsg
->poolp
, NULL
, 0)) == NULL
||
856 SECITEM_CopyItem(sigd
->contentInfo
.cmsg
->poolp
, sigd
->digests
[i
], digests
[idx
]) != SECSuccess
)
858 PORT_SetError(SEC_ERROR_NO_MEMORY
);
866 SecCmsSignedDataSetDigestValue(SecCmsSignedDataRef sigd
,
867 SECOidTag digestalgtag
,
868 SecAsn1Item
* digestdata
)
870 SecAsn1Item
* digest
= NULL
;
875 poolp
= sigd
->contentInfo
.cmsg
->poolp
;
877 mark
= PORT_ArenaMark(poolp
);
881 digest
= (SecAsn1Item
*) PORT_ArenaZAlloc(poolp
,sizeof(SecAsn1Item
));
883 /* copy digestdata item to arena (in case we have it and are not only making room) */
884 if (SECITEM_CopyItem(poolp
, digest
, digestdata
) != SECSuccess
)
888 /* now allocate one (same size as digestAlgorithms) */
889 if (sigd
->digests
== NULL
) {
890 cnt
= SecCmsArrayCount((void **)sigd
->digestAlgorithms
);
891 sigd
->digests
= PORT_ArenaZAlloc(sigd
->contentInfo
.cmsg
->poolp
, (cnt
+ 1) * sizeof(SecAsn1Item
*));
892 if (sigd
->digests
== NULL
) {
893 PORT_SetError(SEC_ERROR_NO_MEMORY
);
899 if (sigd
->digestAlgorithms
!= NULL
)
900 n
= SecCmsAlgArrayGetIndexByAlgTag(sigd
->digestAlgorithms
, digestalgtag
);
902 /* if not found, add a digest */
904 if (SecCmsSignedDataAddDigest(poolp
, sigd
, digestalgtag
, digest
) != SECSuccess
)
907 /* replace NULL pointer with digest item (and leak previous value) */
908 sigd
->digests
[n
] = digest
;
911 PORT_ArenaUnmark(poolp
, mark
);
915 PORT_ArenaRelease(poolp
, mark
);
920 SecCmsSignedDataAddDigest(PRArenaPool
*poolp
,
921 SecCmsSignedDataRef sigd
,
922 SECOidTag digestalgtag
,
923 SecAsn1Item
* digest
)
925 SECAlgorithmID
*digestalg
;
928 mark
= PORT_ArenaMark(poolp
);
930 digestalg
= PORT_ArenaZAlloc(poolp
, sizeof(SECAlgorithmID
));
931 if (digestalg
== NULL
)
934 if (SECOID_SetAlgorithmID (poolp
, digestalg
, digestalgtag
, NULL
) != SECSuccess
) /* no params */
937 if (SecCmsArrayAdd(poolp
, (void ***)&(sigd
->digestAlgorithms
), (void *)digestalg
) != SECSuccess
||
938 /* even if digest is NULL, add dummy to have same-size array */
939 SecCmsArrayAdd(poolp
, (void ***)&(sigd
->digests
), (void *)digest
) != SECSuccess
)
944 PORT_ArenaUnmark(poolp
, mark
);
948 PORT_ArenaRelease(poolp
, mark
);
953 SecCmsSignedDataGetDigestValue(SecCmsSignedDataRef sigd
, SECOidTag digestalgtag
)
957 if (sigd
->digestAlgorithms
== NULL
)
960 n
= SecCmsAlgArrayGetIndexByAlgTag(sigd
->digestAlgorithms
, digestalgtag
);
962 return (n
< 0) ? NULL
: sigd
->digests
[n
];
965 /* =============================================================================
966 * Misc. utility functions
970 * SecCmsSignedDataCreateCertsOnly - create a certs-only SignedData.
972 * cert - base certificates that will be included
973 * include_chain - if true, include the complete cert chain for cert
975 * More certs and chains can be added via AddCertificate and AddCertChain.
977 * An error results in a return value of NULL and an error set.
982 SecCmsSignedDataCreateCertsOnly(SecCmsMessageRef cmsg
, SecCertificateRef cert
, Boolean include_chain
)
984 SecCmsSignedDataRef sigd
;
990 mark
= PORT_ArenaMark(poolp
);
992 sigd
= SecCmsSignedDataCreate(cmsg
);
996 /* no signerinfos, thus no digestAlgorithms */
1000 rv
= SecCmsSignedDataAddCertChain(sigd
, cert
);
1002 rv
= SecCmsSignedDataAddCertificate(sigd
, cert
);
1004 if (rv
!= SECSuccess
)
1008 * In the degenerate case where there are no signers, the
1009 * EncapsulatedContentInfo value being "signed" is irrelevant. In this
1010 * case, the content type within the EncapsulatedContentInfo value being
1011 * "signed" should be id-data (as defined in section 4), and the content
1012 * field of the EncapsulatedContentInfo value should be omitted.
1014 rv
= SecCmsContentInfoSetContentData(&(sigd
->contentInfo
), NULL
, PR_TRUE
);
1015 if (rv
!= SECSuccess
)
1018 PORT_ArenaUnmark(poolp
, mark
);
1023 SecCmsSignedDataDestroy(sigd
);
1024 PORT_ArenaRelease(poolp
, mark
);
1029 * SecCmsSignerInfoGetReceiptRequest()
1030 * SecCmsSignedDataHasReceiptRequest()
1031 * easy way to iterate over signers