#include <Security/SecCmsSignedData.h>
#include <Security/SecCmsContentInfo.h>
#include <Security/SecCmsDigestContext.h>
#include <Security/SecCmsSignerInfo.h>
#include "cmslocal.h"
#include "cert.h"
#include "SecAsn1Item.h"
#include "secoid.h"
#include <security_asn1/secasn1.h>
#include <security_asn1/secerr.h>
#include <security_asn1/secport.h>
#if !USE_CDSA_CRYPTO
#include <Security/SecCertificatePriv.h>
#endif
SecCmsSignedDataRef
SecCmsSignedDataCreate(SecCmsMessageRef cmsg)
{
void *mark;
SecCmsSignedDataRef sigd;
PLArenaPool *poolp;
poolp = cmsg->poolp;
mark = PORT_ArenaMark(poolp);
sigd = (SecCmsSignedDataRef)PORT_ArenaZAlloc (poolp, sizeof(SecCmsSignedData));
if (sigd == NULL)
goto loser;
sigd->contentInfo.cmsg = cmsg;
PORT_ArenaUnmark(poolp, mark);
return sigd;
loser:
PORT_ArenaRelease(poolp, mark);
return NULL;
}
void
SecCmsSignedDataDestroy(SecCmsSignedDataRef sigd)
{
SecCmsSignerInfoRef *signerinfos, si;
if (sigd == NULL)
return;
if (sigd->certs != NULL)
CFRelease(sigd->certs);
signerinfos = sigd->signerInfos;
if (signerinfos != NULL) {
while ((si = *signerinfos++) != NULL)
SecCmsSignerInfoDestroy(si);
}
SecCmsContentInfoDestroy(&(sigd->contentInfo));
}
OSStatus
SecCmsSignedDataEncodeBeforeStart(SecCmsSignedDataRef sigd)
{
SecCmsSignerInfoRef signerinfo;
SECOidTag digestalgtag;
SecAsn1Item * dummy;
int version;
OSStatus rv;
Boolean haveDigests = PR_FALSE;
int n, i;
PLArenaPool *poolp;
poolp = sigd->contentInfo.cmsg->poolp;
if (sigd->digestAlgorithms != NULL && sigd->digests != NULL) {
for (i=0; sigd->digestAlgorithms[i] != NULL; i++) {
if (sigd->digests[i] == NULL)
break;
}
if (sigd->digestAlgorithms[i] == NULL)
haveDigests = PR_TRUE;
}
version = SEC_CMS_SIGNED_DATA_VERSION_BASIC;
if (SecCmsContentInfoGetContentTypeTag(&(sigd->contentInfo)) != SEC_OID_PKCS7_DATA)
version = SEC_CMS_SIGNED_DATA_VERSION_EXT;
for (i=0; i < SecCmsSignedDataSignerInfoCount(sigd); i++) {
signerinfo = SecCmsSignedDataGetSignerInfo(sigd, i);
if (SecCmsSignerInfoGetVersion(signerinfo) != SEC_CMS_SIGNER_INFO_VERSION_ISSUERSN)
version = SEC_CMS_SIGNED_DATA_VERSION_EXT;
digestalgtag = SecCmsSignerInfoGetDigestAlgTag(signerinfo);
n = SecCmsAlgArrayGetIndexByAlgTag(sigd->digestAlgorithms, digestalgtag);
if (n < 0 && haveDigests) {
goto loser;
} else if (n < 0) {
rv = SecCmsSignedDataAddDigest(poolp, sigd, digestalgtag, NULL);
if (rv != SECSuccess)
goto loser;
} else {
}
}
dummy = SEC_ASN1EncodeInteger(poolp, &(sigd->version), (long)version);
if (dummy == NULL)
return SECFailure;
rv = SecCmsArraySortByDER((void **)sigd->digestAlgorithms,
SEC_ASN1_GET(SECOID_AlgorithmIDTemplate),
(void **)sigd->digests);
if (rv != SECSuccess)
return SECFailure;
return SECSuccess;
loser:
return SECFailure;
}
OSStatus
SecCmsSignedDataEncodeBeforeData(SecCmsSignedDataRef sigd)
{
if (sigd->digestAlgorithms != NULL) {
sigd->contentInfo.digcx = SecCmsDigestContextStartMultiple(sigd->digestAlgorithms);
if (sigd->contentInfo.digcx == NULL)
return SECFailure;
}
return SECSuccess;
}
OSStatus
SecCmsSignedDataEncodeAfterData(SecCmsSignedDataRef sigd)
{
SecCmsSignerInfoRef *signerinfos, signerinfo;
SecCmsContentInfoRef cinfo;
SECOidTag digestalgtag;
OSStatus ret = SECFailure;
OSStatus rv;
SecAsn1Item * contentType;
CFIndex certcount;
int i, ci, n, rci, si;
PLArenaPool *poolp;
CFArrayRef certlist;
extern const SecAsn1Template SecCmsSignerInfoTemplate[];
cinfo = &(sigd->contentInfo);
poolp = cinfo->cmsg->poolp;
if (cinfo->digcx) {
SecAsn1Item **digests = NULL;
SECAlgorithmID **digestalgs = NULL;
rv = SecCmsDigestContextFinishMultiple(cinfo->digcx, &digestalgs, &digests);
if (rv != SECSuccess)
goto loser;
if (digestalgs && digests) {
rv = SecCmsSignedDataSetDigests(sigd, digestalgs, digests);
if (rv != SECSuccess)
goto loser;
}
SecCmsDigestContextDestroy(cinfo->digcx);
cinfo->digcx = NULL;
}
signerinfos = sigd->signerInfos;
certcount = 0;
for (i=0; i < SecCmsSignedDataSignerInfoCount(sigd); i++) {
signerinfo = SecCmsSignedDataGetSignerInfo(sigd, i);
digestalgtag = SecCmsSignerInfoGetDigestAlgTag(signerinfo);
n = SecCmsAlgArrayGetIndexByAlgTag(sigd->digestAlgorithms, digestalgtag);
if (n < 0 || sigd->digests == NULL || sigd->digests[n] == NULL) {
PORT_SetError(SEC_ERROR_DIGEST_NOT_FOUND);
goto loser;
}
if ((contentType = SecCmsContentInfoGetContentTypeOID(cinfo)) == NULL)
goto loser;
rv = SecCmsSignerInfoSign(signerinfo, sigd->digests[n], contentType);
if (rv != SECSuccess)
goto loser;
certlist = SecCmsSignerInfoGetCertList(signerinfo);
if (certlist)
certcount += CFArrayGetCount(certlist);
}
rv = SecCmsArraySortByDER((void **)signerinfos, SecCmsSignerInfoTemplate, NULL);
if (rv != SECSuccess)
goto loser;
if (sigd->certs != NULL)
certcount += CFArrayGetCount(sigd->certs);
if (certcount == 0) {
sigd->rawCerts = NULL;
} else {
sigd->rawCerts = (SecAsn1Item * *)PORT_ArenaAlloc(poolp, (certcount + 1) * sizeof(SecAsn1Item *));
if (sigd->rawCerts == NULL)
return SECFailure;
rci = 0;
if (signerinfos != NULL) {
for (si = 0; signerinfos[si] != NULL; si++) {
signerinfo = signerinfos[si];
for (ci = 0; ci < CFArrayGetCount(signerinfo->certList); ci++) {
sigd->rawCerts[rci] = PORT_ArenaZAlloc(poolp, sizeof(SecAsn1Item));
SecCertificateRef cert = (SecCertificateRef)CFArrayGetValueAtIndex(signerinfo->certList, ci);
#if USE_CDSA_CRYPTO
SecCertificateGetData(cert, sigd->rawCerts[rci++]);
#else
SecAsn1Item cert_data = { SecCertificateGetLength(cert),
(uint8_t *)SecCertificateGetBytePtr(cert) };
*(sigd->rawCerts[rci++]) = cert_data;
#endif
}
}
}
if (sigd->certs != NULL) {
for (ci = 0; ci < CFArrayGetCount(sigd->certs); ci++) {
sigd->rawCerts[rci] = PORT_ArenaZAlloc(poolp, sizeof(SecAsn1Item));
SecCertificateRef cert = (SecCertificateRef)CFArrayGetValueAtIndex(sigd->certs, ci);
#if USE_CDSA_CRYPTO
SecCertificateGetData(cert, sigd->rawCerts[rci++]);
#else
SecAsn1Item cert_data = { SecCertificateGetLength(cert),
(uint8_t *)SecCertificateGetBytePtr(cert) };
*(sigd->rawCerts[rci++]) = cert_data;
#endif
}
}
sigd->rawCerts[rci] = NULL;
SecCmsArraySort((void **)sigd->rawCerts, SecCmsUtilDERCompare, NULL, NULL);
}
ret = SECSuccess;
loser:
return ret;
}
OSStatus
SecCmsSignedDataDecodeBeforeData(SecCmsSignedDataRef sigd)
{
if (sigd->digestAlgorithms != NULL && sigd->digests == NULL ) {
sigd->contentInfo.digcx = SecCmsDigestContextStartMultiple(sigd->digestAlgorithms);
if (sigd->contentInfo.digcx == NULL)
return SECFailure;
}
return SECSuccess;
}
OSStatus
SecCmsSignedDataDecodeAfterData(SecCmsSignedDataRef sigd)
{
OSStatus rv = SECSuccess;
if (sigd->contentInfo.digcx) {
if (sigd->contentInfo.content.data && sigd->contentInfo.content.data->Length) {
SecAsn1Item * *digests = NULL;
SECAlgorithmID **digestalgs = NULL;
rv = SecCmsDigestContextFinishMultiple(sigd->contentInfo.digcx, &digestalgs, &digests);
if (rv != SECSuccess)
goto loser;
rv = SecCmsSignedDataSetDigests(sigd, digestalgs, digests);
if (rv != SECSuccess)
goto loser;
}
SecCmsDigestContextDestroy(sigd->contentInfo.digcx);
sigd->contentInfo.digcx = NULL;
}
loser:
return rv;
}
OSStatus
SecCmsSignedDataDecodeAfterEnd(SecCmsSignedDataRef sigd)
{
SecCmsSignerInfoRef *signerinfos;
int i;
if (!sigd) {
return SECFailure;
}
signerinfos = sigd->signerInfos;
if (signerinfos) {
for (i = 0; signerinfos[i] != NULL; i++)
signerinfos[i]->signedData = sigd;
}
return SECSuccess;
}
SecCmsSignerInfoRef *
SecCmsSignedDataGetSignerInfos(SecCmsSignedDataRef sigd)
{
return sigd->signerInfos;
}
int
SecCmsSignedDataSignerInfoCount(SecCmsSignedDataRef sigd)
{
return SecCmsArrayCount((void **)sigd->signerInfos);
}
SecCmsSignerInfoRef
SecCmsSignedDataGetSignerInfo(SecCmsSignedDataRef sigd, int i)
{
return sigd->signerInfos[i];
}
SECAlgorithmID **
SecCmsSignedDataGetDigestAlgs(SecCmsSignedDataRef sigd)
{
return sigd->digestAlgorithms;
}
SecCmsContentInfoRef
SecCmsSignedDataGetContentInfo(SecCmsSignedDataRef sigd)
{
return &(sigd->contentInfo);
}
SecAsn1Item * *
SecCmsSignedDataGetCertificateList(SecCmsSignedDataRef sigd)
{
return sigd->rawCerts;
}
OSStatus
SecCmsSignedDataImportCerts(SecCmsSignedDataRef sigd, SecKeychainRef keychain,
SECCertUsage certusage, Boolean keepcerts)
{
OSStatus rv = -1;
#if USE_CDSA_CRYPTO
int ix, certcount = SecCmsArrayCount((void **)sigd->rawCerts);
rv = CERT_ImportCerts(keychain, certusage, certcount, sigd->rawCerts, NULL,
keepcerts, PR_FALSE, NULL);
if (sigd->signerInfos != NULL) {
for (ix = 0; sigd->signerInfos[ix] != NULL; i++)
(void)SecCmsSignerInfoGetSigningCertificate(sigd->signerInfos[ix], keychain);
}
#else
#endif
return rv;
}
OSStatus
SecCmsSignedDataVerifySignerInfo(SecCmsSignedDataRef sigd, int i,
SecKeychainRef keychainOrArray, CFTypeRef policies, SecTrustRef *trustRef)
{
SecCmsSignerInfoRef signerinfo;
SecCmsContentInfoRef cinfo;
SECOidData *algiddata;
SecAsn1Item *contentType, *digest;
OSStatus status;
if (sigd == NULL || sigd->signerInfos == NULL || i >= SecCmsSignedDataSignerInfoCount(sigd)) {
return errSecParam;
}
cinfo = &(sigd->contentInfo);
signerinfo = sigd->signerInfos[i];
algiddata = SecCmsSignerInfoGetDigestAlg(signerinfo);
if (algiddata == NULL) {
return errSecInvalidDigestAlgorithm;
}
if (!sigd->digests) {
SECAlgorithmID **digestalgs = SecCmsSignedDataGetDigestAlgs(sigd);
SecCmsDigestContextRef digcx = SecCmsDigestContextStartMultiple(digestalgs);
SecCmsSignedDataSetDigestContext(sigd, digcx);
SecCmsDigestContextDestroy(digcx);
}
digest = SecCmsSignedDataGetDigestByAlgTag(sigd, algiddata->offset);
if (digest == NULL) {
return errSecDataNotAvailable;
}
contentType = SecCmsContentInfoGetContentTypeOID(cinfo);
status = SecCmsSignerInfoVerify(signerinfo, digest, contentType);
#if SECTRUST_VERBOSE_DEBUG
syslog(LOG_ERR, "SecCmsSignedDataVerifySignerInfo: SecCmsSignerInfoVerify returned %d, will %sverify cert",
(int)status, (status) ? "NOT " : "");
#endif
if (status) {
return status;
}
status = SecCmsSignerInfoVerifyCertificate(signerinfo, keychainOrArray, policies, trustRef);
#if SECTRUST_VERBOSE_DEBUG
syslog(LOG_ERR, "SecCmsSignedDataVerifySignerInfo: SecCmsSignerInfoVerifyCertificate returned %d", (int)status);
#endif
return status;
}
#if USE_CDSA_CRYPTO
OSStatus
SecCmsSignedDataVerifyCertsOnly(SecCmsSignedDataRef sigd,
SecKeychainRef keychainOrArray,
CFTypeRef policies)
{
SecCertificateRef cert;
OSStatus rv = SECSuccess;
int i;
int count;
if (!sigd || !keychainOrArray || !sigd->rawCerts) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return SECFailure;
}
count = SecCmsArrayCount((void**)sigd->rawCerts);
for (i=0; i < count; i++) {
if (sigd->certs && CFArrayGetCount(sigd->certs) > i) {
cert = (SecCertificateRef)CFArrayGetValueAtIndex(sigd->certs, i);
CFRetain(cert);
} else {
cert = CERT_FindCertByDERCert(keychainOrArray, sigd->rawCerts[i]);
if (!cert) {
rv = SECFailure;
break;
}
}
rv |= CERT_VerifyCert(keychainOrArray, cert, policies, CFAbsoluteTimeGetCurrent(), NULL);
CFRelease(cert);
}
return rv;
}
#else
OSStatus
SecCmsSignedDataVerifyCertsOnly(SecCmsSignedDataRef sigd,
SecKeychainRef keychainOrArray,
CFTypeRef policies)
{
OSStatus rv = SECSuccess;
if (!sigd || !keychainOrArray || !sigd->rawCerts) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return SECFailure;
}
SecAsn1Item **cert_datas = sigd->rawCerts;
SecAsn1Item *cert_data;
while ((cert_data = *cert_datas++) != NULL) {
SecCertificateRef cert = SecCertificateCreateWithBytes(NULL, cert_data->Data, cert_data->Length);
if (cert) {
CFArrayRef certs = CFArrayCreate(kCFAllocatorDefault, (const void **)&cert, 1, NULL);
rv |= CERT_VerifyCert(keychainOrArray, certs, policies, CFAbsoluteTimeGetCurrent(), NULL);
CFRelease(certs);
CFRelease(cert);
}
else
rv |= SECFailure;
}
return rv;
}
#endif
Boolean
SecCmsSignedDataHasDigests(SecCmsSignedDataRef sigd)
{
return (sigd->digests != NULL);
}
OSStatus
SecCmsSignedDataAddCertList(SecCmsSignedDataRef sigd, CFArrayRef certlist)
{
PORT_Assert(certlist != NULL);
if (certlist == NULL)
return SECFailure;
if (!sigd->certs)
sigd->certs = CFArrayCreateMutableCopy(NULL, 0, certlist);
else
{
CFRange certlistRange = { 0, CFArrayGetCount(certlist) };
CFArrayAppendArray(sigd->certs, certlist, certlistRange);
}
return SECSuccess;
}
OSStatus
SecCmsSignedDataAddCertChain(SecCmsSignedDataRef sigd, SecCertificateRef cert)
{
CFArrayRef certlist;
SECCertUsage usage;
OSStatus rv;
usage = certUsageEmailSigner;
certlist = CERT_CertChainFromCert(cert, usage, PR_FALSE, PR_FALSE);
if (certlist == NULL)
return SECFailure;
rv = SecCmsSignedDataAddCertList(sigd, certlist);
CFRelease(certlist);
return rv;
}
OSStatus
SecCmsSignedDataAddCertificate(SecCmsSignedDataRef sigd, SecCertificateRef cert)
{
PORT_Assert(cert != NULL);
if (cert == NULL)
return SECFailure;
if (!sigd->certs)
sigd->certs = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
CFArrayAppendValue(sigd->certs, cert);
return SECSuccess;
}
Boolean
SecCmsSignedDataContainsCertsOrCrls(SecCmsSignedDataRef sigd)
{
if (sigd->rawCerts != NULL && sigd->rawCerts[0] != NULL)
return PR_TRUE;
else if (sigd->rawCrls != NULL && sigd->rawCrls[0] != NULL)
return PR_TRUE;
else
return PR_FALSE;
}
OSStatus
SecCmsSignedDataAddSignerInfo(SecCmsSignedDataRef sigd,
SecCmsSignerInfoRef signerinfo)
{
void *mark;
OSStatus rv;
SECOidTag digestalgtag;
PLArenaPool *poolp;
poolp = sigd->contentInfo.cmsg->poolp;
mark = PORT_ArenaMark(poolp);
rv = SecCmsArrayAdd(poolp, (void ***)&(sigd->signerInfos), (void *)signerinfo);
if (rv != SECSuccess)
goto loser;
digestalgtag = SecCmsSignerInfoGetDigestAlgTag(signerinfo);
rv = SecCmsSignedDataSetDigestValue(sigd, digestalgtag, NULL);
if (rv != SECSuccess)
goto loser;
PORT_ArenaUnmark(poolp, mark);
return SECSuccess;
loser:
PORT_ArenaRelease (poolp, mark);
return SECFailure;
}
SecAsn1Item *
SecCmsSignedDataGetDigestByAlgTag(SecCmsSignedDataRef sigd, SECOidTag algtag)
{
int idx;
if(sigd == NULL || sigd->digests == NULL) {
return NULL;
}
idx = SecCmsAlgArrayGetIndexByAlgTag(sigd->digestAlgorithms, algtag);
return (idx >= 0)?(sigd->digests)[idx]:NULL;
}
OSStatus
SecCmsSignedDataSetDigestContext(SecCmsSignedDataRef sigd,
SecCmsDigestContextRef digestContext)
{
SECAlgorithmID **digestalgs;
SecAsn1Item * *digests;
if (SecCmsDigestContextFinishMultiple(digestContext, &digestalgs, &digests) != SECSuccess)
goto loser;
if (SecCmsSignedDataSetDigests(sigd, digestalgs, digests) != SECSuccess)
goto loser;
return 0;
loser:
return PORT_GetError();
}
OSStatus
SecCmsSignedDataSetDigests(SecCmsSignedDataRef sigd,
SECAlgorithmID **digestalgs,
SecAsn1Item * *digests)
{
int cnt, i, idx;
if (sigd == NULL || sigd->digestAlgorithms == NULL || sigd->contentInfo.cmsg == NULL ||
sigd->contentInfo.cmsg->poolp == NULL) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return SECFailure;
}
if (sigd->digests && sigd->digests[0])
return 0;
if (sigd->digests == NULL) {
cnt = SecCmsArrayCount((void **)sigd->digestAlgorithms);
sigd->digests = PORT_ArenaZAlloc(sigd->contentInfo.cmsg->poolp, (cnt + 1) * sizeof(SecAsn1Item *));
if (sigd->digests == NULL) {
PORT_SetError(SEC_ERROR_NO_MEMORY);
return SECFailure;
}
}
for (i = 0; sigd->digestAlgorithms[i] != NULL; i++) {
idx = SecCmsAlgArrayGetIndexByAlgID(digestalgs, sigd->digestAlgorithms[i]);
if (idx < 0) {
PORT_SetError(SEC_ERROR_DIGEST_NOT_FOUND);
return SECFailure;
}
if ((sigd->digests[i] = SECITEM_AllocItem(sigd->contentInfo.cmsg->poolp, NULL, 0)) == NULL ||
SECITEM_CopyItem(sigd->contentInfo.cmsg->poolp, sigd->digests[i], digests[idx]) != SECSuccess)
{
PORT_SetError(SEC_ERROR_NO_MEMORY);
return SECFailure;
}
}
return SECSuccess;
}
OSStatus
SecCmsSignedDataSetDigestValue(SecCmsSignedDataRef sigd,
SECOidTag digestalgtag,
SecAsn1Item * digestdata)
{
SecAsn1Item * digest = NULL;
PLArenaPool *poolp;
void *mark;
int n, cnt;
poolp = sigd->contentInfo.cmsg->poolp;
mark = PORT_ArenaMark(poolp);
if (digestdata) {
digest = (SecAsn1Item *) PORT_ArenaZAlloc(poolp,sizeof(SecAsn1Item));
if (SECITEM_CopyItem(poolp, digest, digestdata) != SECSuccess)
goto loser;
}
if (sigd->digests == NULL) {
cnt = SecCmsArrayCount((void **)sigd->digestAlgorithms);
sigd->digests = PORT_ArenaZAlloc(sigd->contentInfo.cmsg->poolp, (cnt + 1) * sizeof(SecAsn1Item *));
if (sigd->digests == NULL) {
PORT_SetError(SEC_ERROR_NO_MEMORY);
return SECFailure;
}
}
n = -1;
if (sigd->digestAlgorithms != NULL)
n = SecCmsAlgArrayGetIndexByAlgTag(sigd->digestAlgorithms, digestalgtag);
if (n < 0) {
if (SecCmsSignedDataAddDigest(poolp, sigd, digestalgtag, digest) != SECSuccess)
goto loser;
} else {
sigd->digests[n] = digest;
}
PORT_ArenaUnmark(poolp, mark);
return SECSuccess;
loser:
PORT_ArenaRelease(poolp, mark);
return SECFailure;
}
OSStatus
SecCmsSignedDataAddDigest(PRArenaPool *poolp,
SecCmsSignedDataRef sigd,
SECOidTag digestalgtag,
SecAsn1Item * digest)
{
SECAlgorithmID *digestalg;
void *mark;
mark = PORT_ArenaMark(poolp);
digestalg = PORT_ArenaZAlloc(poolp, sizeof(SECAlgorithmID));
if (digestalg == NULL)
goto loser;
if (SECOID_SetAlgorithmID (poolp, digestalg, digestalgtag, NULL) != SECSuccess)
goto loser;
if (SecCmsArrayAdd(poolp, (void ***)&(sigd->digestAlgorithms), (void *)digestalg) != SECSuccess ||
SecCmsArrayAdd(poolp, (void ***)&(sigd->digests), (void *)digest) != SECSuccess)
{
goto loser;
}
PORT_ArenaUnmark(poolp, mark);
return SECSuccess;
loser:
PORT_ArenaRelease(poolp, mark);
return SECFailure;
}
SecAsn1Item *
SecCmsSignedDataGetDigestValue(SecCmsSignedDataRef sigd, SECOidTag digestalgtag)
{
int n;
if (sigd->digestAlgorithms == NULL)
return NULL;
n = SecCmsAlgArrayGetIndexByAlgTag(sigd->digestAlgorithms, digestalgtag);
return (n < 0) ? NULL : sigd->digests[n];
}
SecCmsSignedDataRef
SecCmsSignedDataCreateCertsOnly(SecCmsMessageRef cmsg, SecCertificateRef cert, Boolean include_chain)
{
SecCmsSignedDataRef sigd;
void *mark;
PLArenaPool *poolp;
OSStatus rv;
poolp = cmsg->poolp;
mark = PORT_ArenaMark(poolp);
sigd = SecCmsSignedDataCreate(cmsg);
if (sigd == NULL)
goto loser;
if (include_chain) {
rv = SecCmsSignedDataAddCertChain(sigd, cert);
} else {
rv = SecCmsSignedDataAddCertificate(sigd, cert);
}
if (rv != SECSuccess)
goto loser;
rv = SecCmsContentInfoSetContentData(&(sigd->contentInfo), NULL, PR_TRUE);
if (rv != SECSuccess)
goto loser;
PORT_ArenaUnmark(poolp, mark);
return sigd;
loser:
if (sigd)
SecCmsSignedDataDestroy(sigd);
PORT_ArenaRelease(poolp, mark);
return NULL;
}