#include <Security/SecCmsSignedData.h>
#include <Security/SecCmsContentInfo.h>
#include <Security/SecCmsDigestContext.h>
#include <Security/SecCmsSignerInfo.h>
#include "cmslocal.h"
#include "cert.h"
#include "secitem.h"
#include "secoid.h"
#include "tsaTemplates.h"
#include <security_asn1/secasn1.h>
#include <security_asn1/secerr.h>
#include <Security/SecBase.h>
#include <CommonCrypto/CommonRandomSPI.h>
#include <Security/SecPolicy.h>
#include <Security/SecPolicyPriv.h>
#include <utilities/SecCFWrappers.h>
#include <syslog.h>
#ifndef NDEBUG
#define SIGDATA_DEBUG 1
#endif
#if SIGDATA_DEBUG
#define dprintf(args...) fprintf(stderr, args)
#else
#define dprintf(args...)
#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->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;
CSSM_DATA_PTR dummy;
int version;
OSStatus rv;
Boolean haveDigests = PR_FALSE;
int n, i;
PLArenaPool *poolp;
poolp = sigd->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((SecArenaPoolRef)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;
}
#include <AssertMacros.h>
#include "tsaSupport.h"
#include "tsaSupportPriv.h"
#include "tsaTemplates.h"
#include <security_keychain/tsaDERUtilities.h>
extern const SecAsn1Template kSecAsn1TSATSTInfoTemplate;
OSStatus createTSAMessageImprint(SecCmsSignedDataRef signedData, CSSM_DATA_PTR encDigest,
SecAsn1TSAMessageImprint *messageImprint)
{
OSStatus status = SECFailure;
require(signedData && messageImprint, xit);
SECAlgorithmID **digestAlgorithms = SecCmsSignedDataGetDigestAlgs(signedData);
require(digestAlgorithms, xit);
SecCmsDigestContextRef digcx = SecCmsDigestContextStartMultiple(digestAlgorithms);
require(digcx, xit);
require(encDigest, xit);
SecCmsSignerInfoRef signerinfo = SecCmsSignedDataGetSignerInfo(signedData, 0); messageImprint->hashAlgorithm = signerinfo->digestAlg;
SecCmsDigestContextUpdate(digcx, encDigest->Data, encDigest->Length);
require_noerr(SecCmsDigestContextFinishSingle(digcx, (SecArenaPoolRef)signedData->cmsg->poolp,
&messageImprint->hashedMessage), xit);
status = SECSuccess;
xit:
return status;
}
#include <Security/SecAsn1Templates.h>
#ifndef NDEBUG
static OSStatus decodeDERUTF8String(const CSSM_DATA_PTR content, char *statusstr, size_t strsz)
{
OSStatus status = SECFailure;
SecAsn1CoderRef coder = NULL;
CSSM_DATA statusString;
size_t len = 0;
require(content && statusstr, xit);
require_noerr(SecAsn1CoderCreate(&coder), xit);
require_noerr(SecAsn1Decode(coder, content->Data, content->Length, kSecAsn1UTF8StringTemplate, &statusString), xit);
status = 0;
len = (statusString.Length < strsz)?(int)statusString.Length:strsz;
if (statusstr && statusString.Data)
strncpy(statusstr, (const char *)statusString.Data, len);
xit:
if (coder)
SecAsn1CoderRelease(coder);
return status;
}
#endif
static OSStatus validateTSAResponseAndAddTimeStamp(SecCmsSignerInfoRef signerinfo, CSSM_DATA_PTR tsaResponse,
uint64_t expectedNonce)
{
OSStatus status = SECFailure;
SecAsn1CoderRef coder = NULL;
SecAsn1TimeStampRespDER respDER = {{{0}},};
SecAsn1TSAPKIStatusInfo *tsastatus = NULL;
int respstatus = -1;
#ifndef NDEBUG
int failinfo = -1;
#endif
require_action(tsaResponse && tsaResponse->Data && tsaResponse->Length, xit, status = errSecTimestampMissing);
require_noerr(SecAsn1CoderCreate(&coder), xit);
require_noerr(SecTSAResponseCopyDEREncoding(coder, tsaResponse, &respDER), xit);
#ifndef NDEBUG
tsaWriteFileX("/tmp/tsa-timeStampToken.der", respDER.timeStampTokenDER.Data, respDER.timeStampTokenDER.Length);
#endif
tsastatus = (SecAsn1TSAPKIStatusInfo *)&respDER.status;
require_action(tsastatus->status.Data, xit, status = errSecTimestampBadDataFormat);
respstatus = (int)tsaDER_ToInt(&tsastatus->status);
#ifndef NDEBUG
char buf[80]={0,};
if (tsastatus->failInfo.Data) failinfo = (int)tsaDER_ToInt(&tsastatus->failInfo);
if (tsastatus->statusString.Data && tsastatus->statusString.Length)
{
OSStatus strrx = decodeDERUTF8String(&tsastatus->statusString, buf, sizeof(buf));
dprintf("decodeDERUTF8String status: %d\n", (int)strrx);
}
dprintf("validateTSAResponse: status: %d, failinfo: %d, %s\n", respstatus, failinfo, buf);
#endif
switch (respstatus)
{
case PKIS_Granted:
case PKIS_GrantedWithMods: status = noErr;
break;
case PKIS_Rejection:
status = errSecTimestampRejection;
break;
case PKIS_Waiting:
status = errSecTimestampWaiting;
break;
case PKIS_RevocationWarning:
status = errSecTimestampRevocationWarning;
break;
case PKIS_RevocationNotification:
status = errSecTimestampRevocationNotification;
break;
default:
status = errSecTimestampSystemFailure;
break;
}
require_noerr(status, xit);
require_action(respDER.timeStampTokenDER.Data && respDER.timeStampTokenDER.Length, xit, status = errSecTimestampBadDataFormat);
dprintf("timestamp full expected nonce: %lld\n", expectedNonce);
require_noerr(status = decodeTimeStampToken(signerinfo, &respDER.timeStampTokenDER, NULL, expectedNonce), xit);
status = SecCmsSignerInfoAddTimeStamp(signerinfo, &respDER.timeStampTokenDER);
xit:
if (coder)
SecAsn1CoderRelease(coder);
return status;
}
static OSStatus getRandomNonce(uint64_t *nonce)
{
return nonce ? CCRandomCopyBytes(kCCRandomDevRandom, (void *)nonce, sizeof(*nonce)) : SECFailure;
}
static OSStatus remapTimestampError(OSStatus inStatus)
{
switch (inStatus)
{
case errSecTimestampMissing:
case errSecTimestampInvalid:
case errSecTimestampNotTrusted:
case errSecTimestampServiceNotAvailable:
case errSecTimestampBadAlg:
case errSecTimestampBadRequest:
case errSecTimestampBadDataFormat:
case errSecTimestampTimeNotAvailable:
case errSecTimestampUnacceptedPolicy:
case errSecTimestampUnacceptedExtension:
case errSecTimestampAddInfoNotAvailable:
case errSecTimestampSystemFailure:
case errSecSigningTimeMissing:
case errSecTimestampRejection:
case errSecTimestampWaiting:
case errSecTimestampRevocationWarning:
case errSecTimestampRevocationNotification:
return inStatus;
default:
return errSecTimestampServiceNotAvailable;
}
return errSecTimestampServiceNotAvailable;
}
OSStatus
SecCmsSignedDataEncodeAfterData(SecCmsSignedDataRef sigd)
{
SecCmsSignerInfoRef *signerinfos, signerinfo;
SecCmsContentInfoRef cinfo;
SECOidTag digestalgtag;
OSStatus ret = SECFailure;
OSStatus rv;
CSSM_DATA_PTR contentType;
int certcount;
int i, ci, n, rci, si;
PLArenaPool *poolp;
CFArrayRef certlist;
extern const SecAsn1Template SecCmsSignerInfoTemplate[];
poolp = sigd->cmsg->poolp;
cinfo = &(sigd->contentInfo);
if (cinfo->digcx) {
rv = SecCmsDigestContextFinishMultiple(cinfo->digcx, (SecArenaPoolRef)poolp, &(sigd->digests));
if (rv != SECSuccess)
goto loser;
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);
}
if (!sigd->cmsg->tsaCallback)
SecCmsMessageSetTSACallback(sigd->cmsg, (SecCmsTSACallback)SecCmsTSADefaultCallback);
if (sigd->cmsg->tsaCallback && sigd->cmsg->tsaContext)
{
CSSM_DATA tsaResponse = {0,};
SecAsn1TSAMessageImprint messageImprint = {{{0},},{0,}};
uint64_t nonce = 0;
require_noerr(getRandomNonce(&nonce), tsxit);
dprintf("SecCmsSignedDataSignerInfoCount: %d\n", SecCmsSignedDataSignerInfoCount(sigd));
SecCmsSignerInfoRef signerinfo = SecCmsSignedDataGetSignerInfo(sigd, 0); CSSM_DATA *encDigest = SecCmsSignerInfoGetEncDigest(signerinfo);
require_noerr(createTSAMessageImprint(sigd, encDigest, &messageImprint), tsxit);
require_noerr(rv =(*sigd->cmsg->tsaCallback)(sigd->cmsg->tsaContext, &messageImprint,
nonce, &tsaResponse), tsxit);
require_noerr(rv = validateTSAResponseAndAddTimeStamp(signerinfo, &tsaResponse, nonce), tsxit);
tsxit:
if (rv)
{
dprintf("Original timestamp error: %d\n", (int)rv);
rv = remapTimestampError(rv);
PORT_SetError(rv);
goto loser;
}
}
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 = (CSSM_DATA_PTR *)PORT_ArenaAlloc(poolp, (certcount + 1) * sizeof(CSSM_DATA_PTR));
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(CSSM_DATA));
SecCertificateRef cert = (SecCertificateRef)CFArrayGetValueAtIndex(signerinfo->certList, ci);
SecCertificateGetData(cert, sigd->rawCerts[rci++]);
}
}
}
if (sigd->certs != NULL) {
for (ci = 0; ci < CFArrayGetCount(sigd->certs); ci++) {
sigd->rawCerts[rci] = PORT_ArenaZAlloc(poolp, sizeof(CSSM_DATA));
SecCertificateRef cert = (SecCertificateRef)CFArrayGetValueAtIndex(sigd->certs, ci);
SecCertificateGetData(cert, sigd->rawCerts[rci++]);
}
}
sigd->rawCerts[rci] = NULL;
SecCmsArraySort((void **)sigd->rawCerts, SecCmsUtilDERCompare, NULL, NULL);
}
ret = SECSuccess;
loser:
dprintf("SecCmsSignedDataEncodeAfterData: ret: %ld, rv: %ld\n", (long)ret, (long)rv);
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)
{
if (sigd->contentInfo.digcx) {
if (SecCmsDigestContextFinishMultiple(sigd->contentInfo.digcx, (SecArenaPoolRef)sigd->cmsg->poolp, &(sigd->digests)) != SECSuccess)
return SECFailure;
sigd->contentInfo.digcx = NULL;
}
return SECSuccess;
}
OSStatus
SecCmsSignedDataDecodeAfterEnd(SecCmsSignedDataRef sigd)
{
SecCmsSignerInfoRef *signerinfos;
int i;
signerinfos = sigd->signerInfos;
if (signerinfos) {
for (i = 0; signerinfos[i] != NULL; i++) {
signerinfos[i]->cmsg = sigd->cmsg;
signerinfos[i]->sigd = 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);
}
CSSM_DATA_PTR *
SecCmsSignedDataGetCertificateList(SecCmsSignedDataRef sigd)
{
return sigd->rawCerts;
}
OSStatus
SecCmsSignedDataImportCerts(SecCmsSignedDataRef sigd, SecKeychainRef keychain,
SECCertUsage certusage, Boolean keepcerts)
{
int certcount;
OSStatus rv;
int i;
certcount = SecCmsArrayCount((void **)sigd->rawCerts);
rv = CERT_ImportCerts(keychain, certusage, certcount, sigd->rawCerts, NULL,
keepcerts, PR_FALSE, NULL);
if (sigd->signerInfos != NULL) {
for (i = 0; sigd->signerInfos[i] != NULL; i++)
(void)SecCmsSignerInfoGetSigningCertificate(sigd->signerInfos[i], keychain);
}
return rv;
}
OSStatus
SecCmsSignedDataVerifySignerInfo(SecCmsSignedDataRef sigd, int i,
SecKeychainRef keychainOrArray, CFTypeRef policies, SecTrustRef *trustRef)
{
SecCmsSignerInfoRef signerinfo;
SecCmsContentInfoRef cinfo;
SECOidData *algiddata;
CSSM_DATA_PTR contentType, digest;
OSStatus status, status2;
cinfo = &(sigd->contentInfo);
signerinfo = sigd->signerInfos[i];
algiddata = SecCmsSignerInfoGetDigestAlg(signerinfo);
if (algiddata == NULL) {
return errSecInternalError; }
digest = SecCmsSignedDataGetDigestByAlgTag(sigd, algiddata->offset);
if(digest == NULL) {
return errSecDataNotAvailable;
}
contentType = SecCmsContentInfoGetContentTypeOID(cinfo);
#if SECTRUST_OSX
#warning STU: <rdar://21328501>
#if !NDEBUG
syslog(LOG_ERR, "SecCmsSignedDataVerifySignerInfo: using codesign policy without timestamp verification");
#endif
CFTypeRef timeStampPolicies=SecPolicyCreateWithProperties(kSecPolicyAppleCodeSigning, NULL);
#else
CFTypeRef timeStampPolicies=SecPolicyCreateAppleTimeStampingAndRevocationPolicies(policies);
#endif
status = SecCmsSignerInfoVerifyWithPolicy(signerinfo, timeStampPolicies, digest, contentType);
CFReleaseSafe(timeStampPolicies);
status2 = SecCmsSignerInfoVerifyCertificate(signerinfo, keychainOrArray,
policies, trustRef);
dprintf("SecCmsSignedDataVerifySignerInfo: status %d status2 %d\n", (int) status, (int)status2);
if (status)
return status;
return status2;
}
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, sigd->rawCerts,
policies, CFAbsoluteTimeGetCurrent(), NULL);
CFRelease(cert);
}
return rv;
}
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);
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->cmsg->poolp;
mark = PORT_ArenaMark(poolp);
rv = SecCmsArrayAdd(poolp, (void ***)&(sigd->signerInfos), (void *)signerinfo);
if (rv != SECSuccess)
goto loser;
signerinfo->sigd = sigd;
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;
}
CSSM_DATA_PTR
SecCmsSignedDataGetDigestByAlgTag(SecCmsSignedDataRef sigd, SECOidTag algtag)
{
int idx;
if(sigd->digests == NULL) {
return NULL;
}
idx = SecCmsAlgArrayGetIndexByAlgTag(sigd->digestAlgorithms, algtag);
return sigd->digests[idx];
}
OSStatus
SecCmsSignedDataSetDigests(SecCmsSignedDataRef sigd,
SECAlgorithmID **digestalgs,
CSSM_DATA_PTR *digests)
{
int cnt, i, idx;
if (sigd->digestAlgorithms == NULL) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return SECFailure;
}
PORT_Assert(sigd->digests == NULL);
if (sigd->digests != NULL) {
PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
return SECFailure;
}
cnt = SecCmsArrayCount((void **)sigd->digestAlgorithms);
sigd->digests = PORT_ArenaZAlloc(sigd->cmsg->poolp, (cnt + 1) * sizeof(CSSM_DATA_PTR));
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->cmsg->poolp, NULL, 0)) == NULL ||
SECITEM_CopyItem(sigd->cmsg->poolp, sigd->digests[i], digests[idx]) != SECSuccess)
{
PORT_SetError(SEC_ERROR_NO_MEMORY);
return SECFailure;
}
}
return SECSuccess;
}
OSStatus
SecCmsSignedDataSetDigestValue(SecCmsSignedDataRef sigd,
SECOidTag digestalgtag,
CSSM_DATA_PTR digestdata)
{
CSSM_DATA_PTR digest = NULL;
PLArenaPool *poolp;
void *mark;
int n, cnt;
poolp = sigd->cmsg->poolp;
mark = PORT_ArenaMark(poolp);
if (digestdata) {
digest = (CSSM_DATA_PTR) PORT_ArenaZAlloc(poolp,sizeof(CSSM_DATA));
if (SECITEM_CopyItem(poolp, digest, digestdata) != SECSuccess)
goto loser;
}
if (sigd->digests == NULL) {
cnt = SecCmsArrayCount((void **)sigd->digestAlgorithms);
sigd->digests = PORT_ArenaZAlloc(sigd->cmsg->poolp, (cnt + 1) * sizeof(CSSM_DATA_PTR));
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((SecArenaPoolRef)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(SecArenaPoolRef pool,
SecCmsSignedDataRef sigd,
SECOidTag digestalgtag,
CSSM_DATA_PTR digest)
{
PRArenaPool *poolp = (PRArenaPool *)pool;
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;
}
CSSM_DATA_PTR
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(cmsg, &(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;
}
extern OSStatus SecCmsSignedDataRawCerts(SecCmsSignedDataRef sigd,
CSSM_DATA_PTR **rawCerts)
{
*rawCerts = sigd->rawCerts;
return noErr;
}