#include <Security/SecCmsSignerInfo.h>
#include "SecSMIMEPriv.h"
#include "cmslocal.h"
#include "cert.h"
#include "secitem.h"
#include "secoid.h"
#include "cryptohi.h"
#include <security_asn1/secasn1.h>
#include <security_asn1/secerr.h>
#include <Security/SecKeychain.h>
#include <Security/SecIdentity.h>
#include <Security/SecCertificatePriv.h>
#include <Security/SecKeyPriv.h>
#include <CoreFoundation/CFTimeZone.h>
#include <utilities/SecCFWrappers.h>
#include <utilities/debugging.h>
#include <AssertMacros.h>
#include <CoreServices/../Frameworks/CarbonCore.framework/Headers/MacErrors.h>
#include <Security/SecPolicyPriv.h>
#include <Security/SecItem.h>
#include <libDER/asn1Types.h>
#include "tsaSupport.h"
#include "tsaSupportPriv.h"
#include <syslog.h>
#define HIDIGIT(v) (((v) / 10) + '0')
#define LODIGIT(v) (((v) % 10) + '0')
#define ISDIGIT(dig) (((dig) >= '0') && ((dig) <= '9'))
#define CAPTURE(var,p,label) \
{ \
if (!ISDIGIT((p)[0]) || !ISDIGIT((p)[1])) goto label; \
(var) = ((p)[0] - '0') * 10 + ((p)[1] - '0'); \
}
#ifndef NDEBUG
#define SIGINFO_DEBUG 1
#endif
#if SIGINFO_DEBUG
#define dprintf(args...) fprintf(stderr, args)
#else
#define dprintf(args...)
#endif
#if RELEASECOUNTDEBUG
#define dprintfRC(args...) dprintf(args)
#else
#define dprintfRC(args...)
#endif
static OSStatus
DER_UTCTimeToCFDate(const CSSM_DATA_PTR utcTime, CFAbsoluteTime *date)
{
CFErrorRef error = NULL;
CFAbsoluteTime result = SecAbsoluteTimeFromDateContentWithError(ASN1_UTC_TIME, utcTime->Data, utcTime->Length, &error);
if (error) {
CFReleaseNull(error);
return SECFailure;
}
if (date) {
*date = result;
}
return SECSuccess;
}
static OSStatus
DER_CFDateToUTCTime(CFAbsoluteTime date, CSSM_DATA_PTR utcTime)
{
unsigned char *d;
utcTime->Length = 13;
utcTime->Data = d = PORT_Alloc(13);
if (!utcTime->Data) {
return SECFailure;
}
__block int year = 0, month = 0, day = 0, hour = 0, minute = 0, second = 0;
__block bool result;
SecCFCalendarDoWithZuluCalendar(^(CFCalendarRef zuluCalendar) {
result = CFCalendarDecomposeAbsoluteTime(zuluCalendar, date, "yMdHms", &year, &month, &day, &hour, &minute, &second);
});
if (!result) {
return SECFailure;
}
if (year < 1950 || year > 2049) {
return SECFailure;
}
year %= 100;
d[0] = HIDIGIT(year);
d[1] = LODIGIT(year);
d[2] = HIDIGIT(month);
d[3] = LODIGIT(month);
d[4] = HIDIGIT(day);
d[5] = LODIGIT(day);
d[6] = HIDIGIT(hour);
d[7] = LODIGIT(hour);
d[8] = HIDIGIT(minute);
d[9] = LODIGIT(minute);
d[10] = HIDIGIT(second);
d[11] = LODIGIT(second);
d[12] = 'Z';
return SECSuccess;
}
SecCmsSignerInfoRef
nss_cmssignerinfo_create(SecCmsMessageRef cmsg, SecCmsSignerIDSelector type, SecCertificateRef cert, CSSM_DATA_PTR subjKeyID, SecPublicKeyRef pubKey, SecPrivateKeyRef signingKey, SECOidTag digestalgtag);
SecCmsSignerInfoRef
SecCmsSignerInfoCreateWithSubjKeyID(SecCmsMessageRef cmsg, CSSM_DATA_PTR subjKeyID, SecPublicKeyRef pubKey, SecPrivateKeyRef signingKey, SECOidTag digestalgtag)
{
return nss_cmssignerinfo_create(cmsg, SecCmsSignerIDSubjectKeyID, NULL, subjKeyID, pubKey, signingKey, digestalgtag);
}
SecCmsSignerInfoRef
SecCmsSignerInfoCreate(SecCmsMessageRef cmsg, SecIdentityRef identity, SECOidTag digestalgtag)
{
SecCmsSignerInfoRef signerInfo = NULL;
SecCertificateRef cert = NULL;
SecPrivateKeyRef signingKey = NULL;
CFDictionaryRef keyAttrs = NULL;
if (SecIdentityCopyCertificate(identity, &cert))
goto loser;
if (SecIdentityCopyPrivateKey(identity, &signingKey))
goto loser;
keyAttrs = SecKeyCopyAttributes(signingKey);
if (!keyAttrs)
goto loser;
CFTypeRef class = CFDictionaryGetValue(keyAttrs, kSecAttrKeyClass);
if (!class || (CFGetTypeID(class) != CFStringGetTypeID()) || !CFEqual(class, kSecAttrKeyClassPrivate))
goto loser;
signerInfo = nss_cmssignerinfo_create(cmsg, SecCmsSignerIDIssuerSN, cert, NULL, NULL, signingKey, digestalgtag);
loser:
if (cert)
CFRelease(cert);
if (signingKey)
CFRelease(signingKey);
if (keyAttrs)
CFRelease(keyAttrs);
return signerInfo;
}
SecCmsSignerInfoRef
nss_cmssignerinfo_create(SecCmsMessageRef cmsg, SecCmsSignerIDSelector type, SecCertificateRef cert, CSSM_DATA_PTR subjKeyID, SecPublicKeyRef pubKey, SecPrivateKeyRef signingKey, SECOidTag digestalgtag)
{
void *mark;
SecCmsSignerInfoRef signerinfo;
int version;
PLArenaPool *poolp;
poolp = cmsg->poolp;
mark = PORT_ArenaMark(poolp);
signerinfo = (SecCmsSignerInfoRef)PORT_ArenaZAlloc(poolp, sizeof(SecCmsSignerInfo));
if (signerinfo == NULL) {
PORT_ArenaRelease(poolp, mark);
return NULL;
}
signerinfo->cmsg = cmsg;
switch(type) {
case SecCmsSignerIDIssuerSN:
signerinfo->signerIdentifier.identifierType = SecCmsSignerIDIssuerSN;
if ((signerinfo->cert = CERT_DupCertificate(cert)) == NULL)
goto loser;
if ((signerinfo->signerIdentifier.id.issuerAndSN = CERT_GetCertIssuerAndSN(poolp, cert)) == NULL)
goto loser;
dprintfRC("nss_cmssignerinfo_create: SecCmsSignerIDIssuerSN: cert.rc %d\n",
(int)CFGetRetainCount(signerinfo->cert));
break;
case SecCmsSignerIDSubjectKeyID:
signerinfo->signerIdentifier.identifierType = SecCmsSignerIDSubjectKeyID;
PORT_Assert(subjKeyID);
if (!subjKeyID)
goto loser;
signerinfo->signerIdentifier.id.subjectKeyID = PORT_ArenaNew(poolp, CSSM_DATA);
if (SECITEM_CopyItem(poolp, signerinfo->signerIdentifier.id.subjectKeyID,
subjKeyID)) {
goto loser;
}
signerinfo->pubKey = SECKEY_CopyPublicKey(pubKey);
if (!signerinfo->pubKey)
goto loser;
break;
default:
goto loser;
}
if (!signingKey)
goto loser;
signerinfo->signingKey = SECKEY_CopyPrivateKey(signingKey);
if (!signerinfo->signingKey)
goto loser;
version = SEC_CMS_SIGNER_INFO_VERSION_ISSUERSN;
if (signerinfo->signerIdentifier.identifierType == SecCmsSignerIDSubjectKeyID)
version = SEC_CMS_SIGNER_INFO_VERSION_SUBJKEY;
(void)SEC_ASN1EncodeInteger(poolp, &(signerinfo->version), (long)version);
if (SECOID_SetAlgorithmID(poolp, &signerinfo->digestAlg, digestalgtag, NULL) != SECSuccess)
goto loser;
PORT_ArenaUnmark(poolp, mark);
return signerinfo;
loser:
PORT_ArenaRelease(poolp, mark);
return NULL;
}
void
SecCmsSignerInfoDestroy(SecCmsSignerInfoRef si)
{
if (si->cert != NULL) {
dprintfRC("SecCmsSignerInfoDestroy top: certp %p cert.rc %d\n",
si->cert, (int)CFGetRetainCount(si->cert));
CERT_DestroyCertificate(si->cert);
}
if (si->certList != NULL) {
dprintfRC("SecCmsSignerInfoDestroy top: certList.rc %d\n",
(int)CFGetRetainCount(si->certList));
CFRelease(si->certList);
}
if (si->timestampCertList != NULL) {
dprintfRC("SecCmsSignerInfoDestroy top: timestampCertList.rc %d\n",
(int)CFGetRetainCount(si->timestampCertList));
CFRelease(si->timestampCertList);
}
if (si->timestampCert != NULL) {
dprintfRC("SecCmsSignerInfoDestroy top: timestampCert.rc %d\n",
(int)CFGetRetainCount(si->timestampCert));
CFRelease(si->timestampCert);
}
if (si->hashAgilityAttrValue != NULL) {
dprintfRC("SecCmsSignerInfoDestroy top: hashAgilityAttrValue.rc %d\n",
(int)CFGetRetainCount(si->hashAgilityAttrValue));
CFRelease(si->hashAgilityAttrValue);
}
if (si->hashAgilityV2AttrValues != NULL) {
dprintfRC("SecCmsSignerInfoDestroy top: hashAgilityV2AttrValues.rc %d\n",
(int)CFGetRetainCount(si->hashAgilityV2AttrValues));
CFRelease(si->hashAgilityV2AttrValues);
}
}
OSStatus
SecCmsSignerInfoSign(SecCmsSignerInfoRef signerinfo, CSSM_DATA_PTR digest, CSSM_DATA_PTR contentType)
{
SecCertificateRef cert;
SecPrivateKeyRef privkey = NULL;
SECOidTag digestalgtag;
SECOidTag pubkAlgTag;
CSSM_DATA signature = { 0 };
OSStatus rv;
PLArenaPool *poolp, *tmppoolp = NULL;
const SECAlgorithmID *algID;
SECAlgorithmID freeAlgID;
PORT_Assert (digest != NULL);
poolp = signerinfo->cmsg->poolp;
switch (signerinfo->signerIdentifier.identifierType) {
case SecCmsSignerIDIssuerSN:
privkey = signerinfo->signingKey;
signerinfo->signingKey = NULL;
cert = signerinfo->cert;
if (SecCertificateGetAlgorithmID(cert,&algID)) {
PORT_SetError(SEC_ERROR_INVALID_ALGORITHM);
goto loser;
}
break;
case SecCmsSignerIDSubjectKeyID:
privkey = signerinfo->signingKey;
signerinfo->signingKey = NULL;
#if 0
spki = SECKEY_CreateSubjectPublicKeyInfo(signerinfo->pubKey);
SECKEY_DestroyPublicKey(signerinfo->pubKey);
signerinfo->pubKey = NULL;
SECOID_CopyAlgorithmID(NULL, &freeAlgID, &spki->algorithm);
SECKEY_DestroySubjectPublicKeyInfo(spki);
algID = &freeAlgID;
#else
#if TARGET_OS_OSX
if (SecKeyGetAlgorithmID(signerinfo->pubKey,&algID)) {
#else
if (true) {
#endif
PORT_SetError(SEC_ERROR_INVALID_ALGORITHM);
goto loser;
}
CFRelease(signerinfo->pubKey);
signerinfo->pubKey = NULL;
#endif
break;
default:
PORT_SetError(SEC_ERROR_UNSUPPORTED_MESSAGE_TYPE);
goto loser;
}
digestalgtag = SecCmsSignerInfoGetDigestAlgTag(signerinfo);
pubkAlgTag = SECOID_GetAlgorithmTag(algID);
if (signerinfo->signerIdentifier.identifierType == SecCmsSignerIDSubjectKeyID) {
SECOID_DestroyAlgorithmID(&freeAlgID, PR_FALSE);
}
#if 0
pubkAlgTag = PK11_FortezzaMapSig(pubkAlgTag);
#endif
if (signerinfo->authAttr != NULL) {
CSSM_DATA encoded_attrs;
rv = SecCmsAttributeArraySetAttr(poolp, &(signerinfo->authAttr),
SEC_OID_PKCS9_MESSAGE_DIGEST, digest, PR_FALSE);
if (rv != SECSuccess)
goto loser;
if (contentType != NULL) {
rv = SecCmsAttributeArraySetAttr(poolp, &(signerinfo->authAttr),
SEC_OID_PKCS9_CONTENT_TYPE, contentType, PR_FALSE);
if (rv != SECSuccess)
goto loser;
}
if ((tmppoolp = PORT_NewArena (1024)) == NULL) {
PORT_SetError(SEC_ERROR_NO_MEMORY);
goto loser;
}
if (SecCmsAttributeArrayReorder(signerinfo->authAttr) != SECSuccess)
goto loser;
encoded_attrs.Data = NULL;
encoded_attrs.Length = 0;
if (SecCmsAttributeArrayEncode(tmppoolp, &(signerinfo->authAttr),
&encoded_attrs) == NULL)
goto loser;
rv = SEC_SignData(&signature, encoded_attrs.Data, (int)encoded_attrs.Length,
privkey, digestalgtag, pubkAlgTag);
PORT_FreeArena(tmppoolp, PR_FALSE);
tmppoolp = 0;
} else {
rv = SGN_Digest(privkey, digestalgtag, pubkAlgTag, &signature, digest);
}
SECKEY_DestroyPrivateKey(privkey);
privkey = NULL;
if (rv != SECSuccess)
goto loser;
if (SECITEM_CopyItem(poolp, &(signerinfo->encDigest), &signature)
!= SECSuccess)
goto loser;
SECITEM_FreeItem(&signature, PR_FALSE);
if(pubkAlgTag == SEC_OID_EC_PUBLIC_KEY) {
if(!SecCmsMsEcdsaCompatMode()) {
pubkAlgTag = SEC_OID_ECDSA_WithSHA1;
}
}
if (SECOID_SetAlgorithmID(poolp, &(signerinfo->digestEncAlg), pubkAlgTag,
NULL) != SECSuccess)
goto loser;
return SECSuccess;
loser:
if (signature.Length != 0)
SECITEM_FreeItem (&signature, PR_FALSE);
if (privkey)
SECKEY_DestroyPrivateKey(privkey);
if (tmppoolp)
PORT_FreeArena(tmppoolp, PR_FALSE);
return SECFailure;
}
OSStatus
SecCmsSignerInfoVerifyCertificate(SecCmsSignerInfoRef signerinfo, SecKeychainRef keychainOrArray,
CFTypeRef policies, SecTrustRef *trustRef)
{
SecCertificateRef cert;
CFAbsoluteTime stime;
OSStatus rv;
CSSM_DATA_PTR *otherCerts;
if ((cert = SecCmsSignerInfoGetSigningCertificate(signerinfo, keychainOrArray)) == NULL) {
dprintf("SecCmsSignerInfoVerifyCertificate: no signing cert\n");
signerinfo->verificationStatus = SecCmsVSSigningCertNotFound;
return SECFailure;
}
CFTypeRef timeStampPolicies=SecPolicyCreateAppleTimeStampingAndRevocationPolicies(policies);
if (SecCmsSignerInfoGetTimestampTimeWithPolicy(signerinfo, timeStampPolicies, &stime) != SECSuccess)
if (SecCmsSignerInfoGetSigningTime(signerinfo, &stime) != SECSuccess)
stime = CFAbsoluteTimeGetCurrent();
CFReleaseSafe(timeStampPolicies);
rv = SecCmsSignedDataRawCerts(signerinfo->sigd, &otherCerts);
if(rv) {
return rv;
}
rv = CERT_VerifyCert(keychainOrArray, cert, otherCerts, policies, stime, trustRef);
dprintfRC("SecCmsSignerInfoVerifyCertificate after vfy: certp %p cert.rc %d\n",
cert, (int)CFGetRetainCount(cert));
if (rv || !trustRef)
{
if (PORT_GetError() == SEC_ERROR_UNTRUSTED_CERT)
{
if (signerinfo->verificationStatus == SecCmsVSGoodSignature)
signerinfo->verificationStatus = SecCmsVSSigningCertNotTrusted;
}
}
dprintf("SecCmsSignerInfoVerifyCertificate: CertVerify rtn %d\n", (int)rv);
return rv;
}
static void debugShowSigningCertificate(SecCmsSignerInfoRef signerinfo)
{
#if SIGINFO_DEBUG
CFStringRef cn = SecCmsSignerInfoGetSignerCommonName(signerinfo);
if (cn)
{
char *ccn = cfStringToChar(cn);
if (ccn)
{
dprintf("SecCmsSignerInfoVerify: cn: %s\n", ccn);
free(ccn);
}
CFRelease(cn);
}
#endif
}
OSStatus
SecCmsSignerInfoVerify(SecCmsSignerInfoRef signerinfo, CSSM_DATA_PTR digest, CSSM_DATA_PTR contentType)
{
return SecCmsSignerInfoVerifyWithPolicy(signerinfo,NULL, digest,contentType);
}
OSStatus
SecCmsSignerInfoVerifyWithPolicy(SecCmsSignerInfoRef signerinfo,CFTypeRef timeStampPolicy, CSSM_DATA_PTR digest, CSSM_DATA_PTR contentType)
{
SecPublicKeyRef publickey = NULL;
SecCmsAttribute *attr = NULL;
CSSM_DATA encoded_attrs;
SecCertificateRef cert = NULL;
SecCmsVerificationStatus vs = SecCmsVSUnverified;
PLArenaPool *poolp = NULL;
SECOidTag digestAlgTag, digestEncAlgTag;
if (signerinfo == NULL)
return SECFailure;
if ((cert = SecCmsSignerInfoGetSigningCertificate(signerinfo, NULL)) == NULL) {
dprintf("SecCmsSignerInfoVerify: no signing cert\n");
vs = SecCmsVSSigningCertNotFound;
goto loser;
}
dprintfRC("SecCmsSignerInfoVerify top: cert %p cert.rc %d\n", cert, (int)CFGetRetainCount(cert));
debugShowSigningCertificate(signerinfo);
if (NULL == (publickey = SecCertificateCopyKey(cert))) {
vs = SecCmsVSProcessingError;
goto loser;
}
digestAlgTag = SECOID_GetAlgorithmTag(&(signerinfo->digestAlg));
digestEncAlgTag = SECOID_GetAlgorithmTag(&(signerinfo->digestEncAlg));
if(digestEncAlgTag == SEC_OID_ECDSA_WithSHA1) {
digestEncAlgTag = SEC_OID_EC_PUBLIC_KEY;
}
if (!SecCmsArrayIsEmpty((void **)signerinfo->authAttr)) {
if (contentType) {
if ((attr = SecCmsAttributeArrayFindAttrByOidTag(signerinfo->authAttr,
SEC_OID_PKCS9_CONTENT_TYPE, PR_TRUE)) == NULL)
{
vs = SecCmsVSMalformedSignature;
goto loser;
}
if (SecCmsAttributeCompareValue(attr, contentType) == PR_FALSE) {
vs = SecCmsVSMalformedSignature;
goto loser;
}
}
if ((attr = SecCmsAttributeArrayFindAttrByOidTag(signerinfo->authAttr, SEC_OID_PKCS9_MESSAGE_DIGEST, PR_TRUE)) == NULL)
{
vs = SecCmsVSMalformedSignature;
goto loser;
}
if (SecCmsAttributeCompareValue(attr, digest) == PR_FALSE) {
vs = SecCmsVSDigestMismatch;
goto loser;
}
if ((poolp = PORT_NewArena (1024)) == NULL) {
vs = SecCmsVSProcessingError;
goto loser;
}
encoded_attrs.Data = NULL;
encoded_attrs.Length = 0;
if (SecCmsAttributeArrayEncode(poolp, &(signerinfo->authAttr), &encoded_attrs) == NULL ||
encoded_attrs.Data == NULL || encoded_attrs.Length == 0)
{
vs = SecCmsVSProcessingError;
goto loser;
}
vs = (VFY_VerifyData (encoded_attrs.Data, (int)encoded_attrs.Length,
publickey, &(signerinfo->encDigest),
digestAlgTag, digestEncAlgTag,
signerinfo->cmsg->pwfn_arg) != SECSuccess) ? SecCmsVSBadSignature : SecCmsVSGoodSignature;
dprintf("VFY_VerifyData (authenticated attributes): %s\n",
(vs == SecCmsVSGoodSignature)?"SecCmsVSGoodSignature":"SecCmsVSBadSignature");
PORT_FreeArena(poolp, PR_FALSE);
} else {
CSSM_DATA_PTR sig;
sig = &(signerinfo->encDigest);
if (sig->Length == 0)
goto loser;
vs = (VFY_VerifyDigest(digest, publickey, sig,
digestAlgTag, digestEncAlgTag,
signerinfo->cmsg->pwfn_arg) != SECSuccess) ? SecCmsVSBadSignature : SecCmsVSGoodSignature;
dprintf("VFY_VerifyData (plain message digest): %s\n",
(vs == SecCmsVSGoodSignature)?"SecCmsVSGoodSignature":"SecCmsVSBadSignature");
}
if (!SecCmsArrayIsEmpty((void **)signerinfo->unAuthAttr))
{
dprintf("found an unAuthAttr\n");
OSStatus rux = SecCmsSignerInfoVerifyUnAuthAttrsWithPolicy(signerinfo,timeStampPolicy);
dprintf("SecCmsSignerInfoVerifyUnAuthAttrs Status: %ld\n", (long)rux);
if (rux) {
goto loser;
}
}
if (vs == SecCmsVSBadSignature) {
if (PORT_GetError() == SEC_ERROR_BAD_SIGNATURE)
PORT_SetError(SEC_ERROR_PKCS7_BAD_SIGNATURE);
}
if (publickey != NULL)
CFRelease(publickey);
signerinfo->verificationStatus = vs;
dprintfRC("SecCmsSignerInfoVerify end: cerp %p cert.rc %d\n",
cert, (int)CFGetRetainCount(cert));
dprintf("verificationStatus: %d\n", vs);
return (vs == SecCmsVSGoodSignature) ? SECSuccess : SECFailure;
loser:
if (publickey != NULL)
SECKEY_DestroyPublicKey (publickey);
dprintf("verificationStatus2: %d\n", vs);
signerinfo->verificationStatus = vs;
PORT_SetError (SEC_ERROR_PKCS7_BAD_SIGNATURE);
return SECFailure;
}
OSStatus
SecCmsSignerInfoVerifyUnAuthAttrs(SecCmsSignerInfoRef signerinfo) {
return SecCmsSignerInfoVerifyUnAuthAttrsWithPolicy(signerinfo, NULL);
}
OSStatus
SecCmsSignerInfoVerifyUnAuthAttrsWithPolicy(SecCmsSignerInfoRef signerinfo,CFTypeRef timeStampPolicy)
{
SecCmsAttribute *attr = NULL;
OSStatus status = SECFailure;
require(signerinfo, xit);
attr = SecCmsAttributeArrayFindAttrByOidTag(signerinfo->unAuthAttr,
SEC_OID_PKCS9_TIMESTAMP_TOKEN, PR_TRUE);
if (attr == NULL)
{
status = errSecTimestampMissing;
goto xit;
}
dprintf("found an id-ct-TSTInfo\n");
status = decodeTimeStampTokenWithPolicy(signerinfo, timeStampPolicy, (attr->values)[0], &signerinfo->encDigest, 0);
if (status != errSecSuccess) {
secerror("timestamp verification failed: %d", (int)status);
}
xit:
return status;
}
CSSM_DATA *
SecCmsSignerInfoGetEncDigest(SecCmsSignerInfoRef signerinfo)
{
return &signerinfo->encDigest;
}
SecCmsVerificationStatus
SecCmsSignerInfoGetVerificationStatus(SecCmsSignerInfoRef signerinfo)
{
return signerinfo->verificationStatus;
}
SECOidData *
SecCmsSignerInfoGetDigestAlg(SecCmsSignerInfoRef signerinfo)
{
return SECOID_FindOID (&(signerinfo->digestAlg.algorithm));
}
SECOidTag
SecCmsSignerInfoGetDigestAlgTag(SecCmsSignerInfoRef signerinfo)
{
SECOidData *algdata;
algdata = SECOID_FindOID (&(signerinfo->digestAlg.algorithm));
if (algdata != NULL)
return algdata->offset;
else
return SEC_OID_UNKNOWN;
}
CFArrayRef
SecCmsSignerInfoGetCertList(SecCmsSignerInfoRef signerinfo)
{
dprintfRC("SecCmsSignerInfoGetCertList: certList.rc %d\n",
(int)CFGetRetainCount(signerinfo->certList));
return signerinfo->certList;
}
CFArrayRef
SecCmsSignerInfoGetTimestampCertList(SecCmsSignerInfoRef signerinfo)
{
dprintfRC("SecCmsSignerInfoGetTimestampCertList: timestampCertList.rc %d\n",
(int)CFGetRetainCount(signerinfo->timestampCertList));
return signerinfo->timestampCertList;
}
SecCertificateRef
SecCmsSignerInfoGetTimestampSigningCert(SecCmsSignerInfoRef signerinfo)
{
dprintfRC("SecCmsSignerInfoGetTimestampSigningCert: timestampCert.rc %d\n",
(int)CFGetRetainCount(signerinfo->timestampCert));
return signerinfo->timestampCert;
}
int
SecCmsSignerInfoGetVersion(SecCmsSignerInfoRef signerinfo)
{
unsigned long version;
if (SEC_ASN1DecodeInteger(&(signerinfo->version), &version) != SECSuccess)
return 0;
else
return (int)version;
}
OSStatus
SecCmsSignerInfoGetSigningTime(SecCmsSignerInfoRef sinfo, CFAbsoluteTime *stime)
{
SecCmsAttribute *attr;
CSSM_DATA_PTR value;
if (sinfo == NULL)
return paramErr;
if (sinfo->signingTime != 0) {
*stime = sinfo->signingTime;
return SECSuccess;
}
attr = SecCmsAttributeArrayFindAttrByOidTag(sinfo->authAttr, SEC_OID_PKCS9_SIGNING_TIME, PR_TRUE);
if (attr == NULL || (value = SecCmsAttributeGetValue(attr)) == NULL)
return errSecSigningTimeMissing;
if (DER_UTCTimeToCFDate(value, stime) != SECSuccess)
return errSecSigningTimeMissing;
sinfo->signingTime = *stime;
return SECSuccess;
}
OSStatus
SecCmsSignerInfoGetTimestampTime(SecCmsSignerInfoRef sinfo, CFAbsoluteTime *stime)
{
return SecCmsSignerInfoGetTimestampTimeWithPolicy(sinfo, NULL, stime);
}
OSStatus
SecCmsSignerInfoGetTimestampTimeWithPolicy(SecCmsSignerInfoRef sinfo, CFTypeRef timeStampPolicy, CFAbsoluteTime *stime)
{
OSStatus status = paramErr;
require(sinfo && stime, xit);
if (sinfo->timestampTime != 0)
{
*stime = sinfo->timestampTime;
return noErr;
}
status = SecCmsSignerInfoVerifyUnAuthAttrsWithPolicy(sinfo,timeStampPolicy);
*stime = sinfo->timestampTime;
xit:
return status;
}
OSStatus
SecCmsSignerInfoGetAppleCodesigningHashAgility(SecCmsSignerInfoRef sinfo, CFDataRef *sdata)
{
SecCmsAttribute *attr;
CSSM_DATA_PTR value;
if (sinfo == NULL || sdata == NULL)
return paramErr;
*sdata = NULL;
if (sinfo->hashAgilityAttrValue != NULL) {
*sdata = sinfo->hashAgilityAttrValue;
return SECSuccess;
}
attr = SecCmsAttributeArrayFindAttrByOidTag(sinfo->authAttr, SEC_OID_APPLE_HASH_AGILITY, PR_TRUE);
if (attr == NULL || (value = SecCmsAttributeGetValue(attr)) == NULL)
return SECSuccess;
sinfo->hashAgilityAttrValue = CFDataCreate(NULL, value->Data, value->Length);
if (sinfo->hashAgilityAttrValue) {
*sdata = sinfo->hashAgilityAttrValue;
return SECSuccess;
}
return errSecAllocate;
}
typedef struct {
SecAsn1Item digestOID;
SecAsn1Item digestValue;
} CMSAppleAgileHash;
static const SecAsn1Template CMSAppleAgileHashTemplate[] = {
{ SEC_ASN1_SEQUENCE,
0, NULL, sizeof(CMSAppleAgileHash) },
{ SEC_ASN1_OBJECT_ID,
offsetof(CMSAppleAgileHash, digestOID), },
{ SEC_ASN1_OCTET_STRING,
offsetof(CMSAppleAgileHash, digestValue), },
{ 0, }
};
static OSStatus CMSAddAgileHashToDictionary(CFMutableDictionaryRef dictionary, SecAsn1Item *DERAgileHash) {
PLArenaPool *tmppoolp = NULL;
OSStatus status = errSecSuccess;
CMSAppleAgileHash agileHash;
CFDataRef digestValue = NULL;
CFNumberRef digestTag = NULL;
tmppoolp = PORT_NewArena(1024);
if (tmppoolp == NULL) {
return errSecAllocate;
}
if ((status = SEC_ASN1DecodeItem(tmppoolp, &agileHash, CMSAppleAgileHashTemplate, DERAgileHash)) != errSecSuccess) {
goto loser;
}
int64_t tag = SECOID_FindOIDTag(&agileHash.digestOID);
digestTag = CFNumberCreate(NULL, kCFNumberSInt64Type, &tag);
digestValue = CFDataCreate(NULL, agileHash.digestValue.Data, agileHash.digestValue.Length);
CFDictionaryAddValue(dictionary, digestTag, digestValue);
loser:
CFReleaseNull(digestValue);
CFReleaseNull(digestTag);
if (tmppoolp) {
PORT_FreeArena(tmppoolp, PR_FALSE);
}
return status;
}
OSStatus
SecCmsSignerInfoGetAppleCodesigningHashAgilityV2(SecCmsSignerInfoRef sinfo, CFDictionaryRef *sdict)
{
SecCmsAttribute *attr;
if (sinfo == NULL || sdict == NULL) {
return errSecParam;
}
*sdict = NULL;
if (sinfo->hashAgilityV2AttrValues != NULL) {
*sdict = sinfo->hashAgilityV2AttrValues;
return SECSuccess;
}
attr = SecCmsAttributeArrayFindAttrByOidTag(sinfo->authAttr, SEC_OID_APPLE_HASH_AGILITY_V2, PR_TRUE);
if (attr == NULL) {
return SECSuccess;
}
CSSM_DATA_PTR *values = attr->values;
if (values == NULL) {
return errSecDecode;
}
CFMutableDictionaryRef agileHashValues = CFDictionaryCreateMutable(NULL, SecCmsArrayCount((void **)values),
&kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks);
while (*values != NULL) {
(void)CMSAddAgileHashToDictionary(agileHashValues, *values++);
}
if (CFDictionaryGetCount(agileHashValues) != SecCmsArrayCount((void **)attr->values)) {
CFReleaseNull(agileHashValues);
return errSecDecode;
}
sinfo->hashAgilityV2AttrValues = agileHashValues;
if (sinfo->hashAgilityV2AttrValues) {
*sdict = sinfo->hashAgilityV2AttrValues;
return SECSuccess;
}
return errSecAllocate;
}
OSStatus
SecCmsSignerInfoGetAppleExpirationTime(SecCmsSignerInfoRef sinfo, CFAbsoluteTime *etime)
{
SecCmsAttribute *attr = NULL;
SecAsn1Item * value = NULL;
if (sinfo == NULL || etime == NULL) {
return SECFailure;
}
if (sinfo->expirationTime != 0) {
*etime = sinfo->expirationTime;
return SECSuccess;
}
attr = SecCmsAttributeArrayFindAttrByOidTag(sinfo->authAttr, SEC_OID_APPLE_EXPIRATION_TIME, PR_TRUE);
if (attr == NULL || (value = SecCmsAttributeGetValue(attr)) == NULL) {
return SECFailure;
}
if (DER_UTCTimeToCFDate(value, etime) != SECSuccess) {
return SECFailure;
}
sinfo->expirationTime = *etime;
return SECSuccess;
}
SecCertificateRef
SecCmsSignerInfoGetSigningCertificate(SecCmsSignerInfoRef signerinfo, SecKeychainRef keychainOrArray)
{
SecCertificateRef cert;
SecCmsSignerIdentifier *sid;
OSStatus ortn;
CSSM_DATA_PTR *rawCerts;
if (signerinfo->cert != NULL) {
dprintfRC("SecCmsSignerInfoGetSigningCertificate top: cert %p cert.rc %d\n",
signerinfo->cert, (int)CFGetRetainCount(signerinfo->cert));
return signerinfo->cert;
}
ortn = SecCmsSignedDataRawCerts(signerinfo->sigd, &rawCerts);
if(ortn) {
return NULL;
}
dprintf("SecCmsSignerInfoGetSigningCertificate: numRawCerts %d\n",
SecCmsArrayCount((void **)rawCerts));
sid = &signerinfo->signerIdentifier;
switch (sid->identifierType) {
case SecCmsSignerIDIssuerSN:
cert = CERT_FindCertByIssuerAndSN(keychainOrArray, rawCerts, signerinfo->sigd->certs, signerinfo->cmsg->poolp,
sid->id.issuerAndSN);
break;
case SecCmsSignerIDSubjectKeyID:
cert = CERT_FindCertBySubjectKeyID(keychainOrArray, rawCerts, signerinfo->sigd->certs, sid->id.subjectKeyID);
break;
default:
cert = NULL;
break;
}
signerinfo->cert = cert;
dprintfRC("SecCmsSignerInfoGetSigningCertificate end: certp %p cert.rc %d\n",
signerinfo->cert, (int)CFGetRetainCount(signerinfo->cert));
return cert;
}
CFStringRef
SecCmsSignerInfoGetSignerCommonName(SecCmsSignerInfoRef sinfo)
{
SecCertificateRef signercert;
CFStringRef commonName = NULL;
if ((signercert = SecCmsSignerInfoGetSigningCertificate(sinfo, NULL)) == NULL)
return NULL;
if (errSecSuccess != SecCertificateCopyCommonName(signercert, &commonName)) {
return NULL;
}
return commonName;
}
CFStringRef
SecCmsSignerInfoGetSignerEmailAddress(SecCmsSignerInfoRef sinfo)
{
SecCertificateRef signercert;
CFStringRef emailAddress = NULL;
if ((signercert = SecCmsSignerInfoGetSigningCertificate(sinfo, NULL)) == NULL)
return NULL;
SecCertificateGetEmailAddress(signercert, &emailAddress);
return CFRetainSafe(emailAddress);
}
OSStatus
SecCmsSignerInfoAddAuthAttr(SecCmsSignerInfoRef signerinfo, SecCmsAttribute *attr)
{
return SecCmsAttributeArrayAddAttr(signerinfo->cmsg->poolp, &(signerinfo->authAttr), attr);
}
OSStatus
SecCmsSignerInfoAddUnauthAttr(SecCmsSignerInfoRef signerinfo, SecCmsAttribute *attr)
{
return SecCmsAttributeArrayAddAttr(signerinfo->cmsg->poolp, &(signerinfo->unAuthAttr), attr);
}
OSStatus
SecCmsSignerInfoAddSigningTime(SecCmsSignerInfoRef signerinfo, CFAbsoluteTime t)
{
SecCmsAttribute *attr;
CSSM_DATA stime;
void *mark;
PLArenaPool *poolp;
poolp = signerinfo->cmsg->poolp;
mark = PORT_ArenaMark(poolp);
if (DER_CFDateToUTCTime(t, &stime) != SECSuccess)
goto loser;
if ((attr = SecCmsAttributeCreate(poolp, SEC_OID_PKCS9_SIGNING_TIME, &stime, PR_FALSE)) == NULL) {
SECITEM_FreeItem (&stime, PR_FALSE);
goto loser;
}
SECITEM_FreeItem (&stime, PR_FALSE);
if (SecCmsSignerInfoAddAuthAttr(signerinfo, attr) != SECSuccess)
goto loser;
PORT_ArenaUnmark (poolp, mark);
return SECSuccess;
loser:
PORT_ArenaRelease (poolp, mark);
return SECFailure;
}
OSStatus
SecCmsSignerInfoAddSMIMECaps(SecCmsSignerInfoRef signerinfo)
{
SecCmsAttribute *attr;
CSSM_DATA_PTR smimecaps = NULL;
void *mark;
PLArenaPool *poolp;
poolp = signerinfo->cmsg->poolp;
mark = PORT_ArenaMark(poolp);
smimecaps = SECITEM_AllocItem(poolp, NULL, 0);
if (smimecaps == NULL)
goto loser;
#if 1
if (SecSMIMECreateSMIMECapabilities((SecArenaPoolRef)poolp, smimecaps, PR_FALSE) != SECSuccess)
#else
if (SecSMIMECreateSMIMECapabilities(poolp, smimecaps,
PK11_FortezzaHasKEA(signerinfo->cert)) != SECSuccess)
#endif
goto loser;
if ((attr = SecCmsAttributeCreate(poolp, SEC_OID_PKCS9_SMIME_CAPABILITIES, smimecaps, PR_TRUE)) == NULL)
goto loser;
if (SecCmsSignerInfoAddAuthAttr(signerinfo, attr) != SECSuccess)
goto loser;
PORT_ArenaUnmark (poolp, mark);
return SECSuccess;
loser:
PORT_ArenaRelease (poolp, mark);
return SECFailure;
}
OSStatus
SecCmsSignerInfoAddSMIMEEncKeyPrefs(SecCmsSignerInfoRef signerinfo, SecCertificateRef cert, SecKeychainRef keychainOrArray)
{
SecCmsAttribute *attr;
CSSM_DATA_PTR smimeekp = NULL;
void *mark;
PLArenaPool *poolp;
#if 0
CFTypeRef policy;
policy = CERT_PolicyForCertUsage(certUsageEmailRecipient);
if (CERT_VerifyCert(keychainOrArray, cert, policy, CFAbsoluteTimeGetCurrent(), NULL) != SECSuccess) {
CFRelease(policy);
return SECFailure;
}
CFRelease(policy);
#endif
poolp = signerinfo->cmsg->poolp;
mark = PORT_ArenaMark(poolp);
smimeekp = SECITEM_AllocItem(poolp, NULL, 0);
if (smimeekp == NULL)
goto loser;
if (SecSMIMECreateSMIMEEncKeyPrefs((SecArenaPoolRef)poolp, smimeekp, cert) != SECSuccess)
goto loser;
if ((attr = SecCmsAttributeCreate(poolp, SEC_OID_SMIME_ENCRYPTION_KEY_PREFERENCE, smimeekp, PR_TRUE)) == NULL)
goto loser;
if (SecCmsSignerInfoAddAuthAttr(signerinfo, attr) != SECSuccess)
goto loser;
PORT_ArenaUnmark (poolp, mark);
return SECSuccess;
loser:
PORT_ArenaRelease (poolp, mark);
return SECFailure;
}
OSStatus
SecCmsSignerInfoAddMSSMIMEEncKeyPrefs(SecCmsSignerInfoRef signerinfo, SecCertificateRef cert, SecKeychainRef keychainOrArray)
{
SecCmsAttribute *attr;
CSSM_DATA_PTR smimeekp = NULL;
void *mark;
PLArenaPool *poolp;
#if 0
CFTypeRef policy;
policy = CERT_PolicyForCertUsage(certUsageEmailRecipient);
if (CERT_VerifyCert(keychainOrArray, cert, policy, CFAbsoluteTimeGetCurrent(), NULL) != SECSuccess) {
CFRelease(policy);
return SECFailure;
}
CFRelease(policy);
#endif
poolp = signerinfo->cmsg->poolp;
mark = PORT_ArenaMark(poolp);
smimeekp = SECITEM_AllocItem(poolp, NULL, 0);
if (smimeekp == NULL)
goto loser;
if (SecSMIMECreateMSSMIMEEncKeyPrefs((SecArenaPoolRef)poolp, smimeekp, cert) != SECSuccess)
goto loser;
if ((attr = SecCmsAttributeCreate(poolp, SEC_OID_MS_SMIME_ENCRYPTION_KEY_PREFERENCE, smimeekp, PR_TRUE)) == NULL)
goto loser;
if (SecCmsSignerInfoAddAuthAttr(signerinfo, attr) != SECSuccess)
goto loser;
PORT_ArenaUnmark (poolp, mark);
return SECSuccess;
loser:
PORT_ArenaRelease (poolp, mark);
return SECFailure;
}
OSStatus
SecCmsSignerInfoAddTimeStamp(SecCmsSignerInfoRef signerinfo, CSSM_DATA *tstoken)
{
SecCmsAttribute *attr;
PLArenaPool *poolp = signerinfo->cmsg->poolp;
void *mark = PORT_ArenaMark(poolp);
if ((attr = SecCmsAttributeCreate(poolp, SEC_OID_PKCS9_TIMESTAMP_TOKEN, tstoken, PR_TRUE)) == NULL)
goto loser;
if (SecCmsSignerInfoAddUnauthAttr(signerinfo, attr) != SECSuccess)
goto loser;
PORT_ArenaUnmark (poolp, mark);
return SECSuccess;
loser:
PORT_ArenaRelease (poolp, mark);
return SECFailure;
}
OSStatus
SecCmsSignerInfoAddCounterSignature(SecCmsSignerInfoRef signerinfo,
SECOidTag digestalg, SecIdentityRef identity)
{
return SECFailure;
}
OSStatus
SecCmsSignerInfoAddAppleCodesigningHashAgility(SecCmsSignerInfoRef signerinfo, CFDataRef attrValue)
{
SecCmsAttribute *attr;
PLArenaPool *poolp = signerinfo->cmsg->poolp;
void *mark = PORT_ArenaMark(poolp);
OSStatus status = SECFailure;
if (!attrValue) {
status = errSecParam;
goto loser;
}
CSSM_DATA value;
value.Length = CFDataGetLength(attrValue);
value.Data = (uint8_t *)CFDataGetBytePtr(attrValue);
if ((attr = SecCmsAttributeCreate(poolp,
SEC_OID_APPLE_HASH_AGILITY,
&value,
PR_FALSE)) == NULL) {
status = errSecAllocate;
goto loser;
}
if (SecCmsSignerInfoAddAuthAttr(signerinfo, attr) != SECSuccess) {
status = errSecInternalError;
goto loser;
}
PORT_ArenaUnmark(poolp, mark);
return SECSuccess;
loser:
PORT_ArenaRelease(poolp, mark);
return status;
}
static OSStatus CMSAddAgileHashToAttribute(PLArenaPool *poolp, SecCmsAttribute *attr, CFNumberRef cftag, CFDataRef value) {
PLArenaPool *tmppoolp = NULL;
int64_t tag;
SECOidData *digestOid = NULL;
CMSAppleAgileHash agileHash;
SecAsn1Item attrValue = { .Data = NULL, .Length = 0 };
OSStatus status = errSecSuccess;
memset(&agileHash, 0, sizeof(agileHash));
if(!CFNumberGetValue(cftag, kCFNumberSInt64Type, &tag)) {
return errSecParam;
}
digestOid = SECOID_FindOIDByTag((SECOidTag)tag);
agileHash.digestValue.Data = (uint8_t *)CFDataGetBytePtr(value);
agileHash.digestValue.Length = CFDataGetLength(value);
agileHash.digestOID.Data = digestOid->oid.Data;
agileHash.digestOID.Length = digestOid->oid.Length;
tmppoolp = PORT_NewArena(1024);
if (tmppoolp == NULL) {
return errSecAllocate;
}
if (SEC_ASN1EncodeItem(tmppoolp, &attrValue, &agileHash, CMSAppleAgileHashTemplate) == NULL) {
status = errSecParam;
goto loser;
}
status = SecCmsAttributeAddValue(poolp, attr, &attrValue);
loser:
if (tmppoolp) {
PORT_FreeArena(tmppoolp, PR_FALSE);
}
return status;
}
OSStatus
SecCmsSignerInfoAddAppleCodesigningHashAgilityV2(SecCmsSignerInfoRef signerinfo, CFDictionaryRef attrValues)
{
__block SecCmsAttribute *attr;
__block PLArenaPool *poolp = signerinfo->cmsg->poolp;
void *mark = PORT_ArenaMark(poolp);
OSStatus status = SECFailure;
if (!attrValues) {
status = errSecParam;
goto loser;
}
if ((attr = SecCmsAttributeCreate(poolp, SEC_OID_APPLE_HASH_AGILITY_V2,
NULL, PR_TRUE)) == NULL) {
status = errSecAllocate;
goto loser;
}
CFDictionaryForEach(attrValues, ^(const void *key, const void *value) {
if (!isNumber(key) || !isData(value)) {
return;
}
(void)CMSAddAgileHashToAttribute(poolp, attr, (CFNumberRef)key, (CFDataRef)value);
});
if (SecCmsSignerInfoAddAuthAttr(signerinfo, attr) != SECSuccess) {
status = errSecInternal;
goto loser;
}
PORT_ArenaUnmark(poolp, mark);
return SECSuccess;
loser:
PORT_ArenaRelease(poolp, mark);
return status;
}
OSStatus
SecCmsSignerInfoAddAppleExpirationTime(SecCmsSignerInfoRef signerinfo, CFAbsoluteTime t)
{
SecCmsAttribute *attr = NULL;
PLArenaPool *poolp = signerinfo->cmsg->poolp;
void *mark = PORT_ArenaMark(poolp);
SecAsn1Item etime;
if (DER_CFDateToUTCTime(t, &etime) != SECSuccess) {
goto loser;
}
if ((attr = SecCmsAttributeCreate(poolp, SEC_OID_APPLE_EXPIRATION_TIME, &etime, PR_FALSE)) == NULL) {
SECITEM_FreeItem (&etime, PR_FALSE);
goto loser;
}
SECITEM_FreeItem(&etime, PR_FALSE);
if (SecCmsSignerInfoAddAuthAttr(signerinfo, attr) != SECSuccess) {
goto loser;
}
PORT_ArenaUnmark(poolp, mark);
return SECSuccess;
loser:
PORT_ArenaRelease(poolp, mark);
return SECFailure;
}
SecCertificateRef SecCmsSignerInfoCopyCertFromEncryptionKeyPreference(SecCmsSignerInfoRef signerinfo) {
SecCertificateRef cert = NULL;
SecCmsAttribute *attr;
CSSM_DATA_PTR ekp;
SecKeychainRef keychainOrArray;
(void)SecKeychainCopyDefault(&keychainOrArray);
if (signerinfo->verificationStatus != SecCmsVSGoodSignature)
return NULL;
CSSM_DATA_PTR *rawCerts = NULL;
if (signerinfo->sigd) {
rawCerts = signerinfo->sigd->rawCerts;
}
if (!SecCmsArrayIsEmpty((void **)signerinfo->authAttr) &&
(attr = SecCmsAttributeArrayFindAttrByOidTag(signerinfo->authAttr,
SEC_OID_SMIME_ENCRYPTION_KEY_PREFERENCE, PR_TRUE)) != NULL)
{
ekp = SecCmsAttributeGetValue(attr);
if (ekp == NULL)
return NULL;
cert = SecSMIMEGetCertFromEncryptionKeyPreference(keychainOrArray, rawCerts, ekp);
}
if(cert) return cert;
if (!SecCmsArrayIsEmpty((void **)signerinfo->authAttr) &&
(attr = SecCmsAttributeArrayFindAttrByOidTag(signerinfo->authAttr,
SEC_OID_MS_SMIME_ENCRYPTION_KEY_PREFERENCE, PR_TRUE)) != NULL)
{
ekp = SecCmsAttributeGetValue(attr);
if (ekp == NULL)
return NULL;
cert = SecSMIMEGetCertFromEncryptionKeyPreference(keychainOrArray, rawCerts, ekp);
}
return cert;
}
OSStatus
SecCmsSignerInfoSaveSMIMEProfile(SecCmsSignerInfoRef signerinfo)
{
SecCertificateRef cert = NULL;
CSSM_DATA_PTR profile = NULL;
SecCmsAttribute *attr;
CSSM_DATA_PTR utc_stime = NULL;
CSSM_DATA_PTR ekp;
int save_error;
OSStatus rv;
Boolean must_free_cert = PR_FALSE;
OSStatus status;
SecKeychainRef keychainOrArray;
status = SecKeychainCopyDefault(&keychainOrArray);
if (signerinfo->verificationStatus != SecCmsVSGoodSignature)
return SECFailure;
if (!SecCmsArrayIsEmpty((void **)signerinfo->authAttr) &&
(attr = SecCmsAttributeArrayFindAttrByOidTag(signerinfo->authAttr,
SEC_OID_SMIME_ENCRYPTION_KEY_PREFERENCE, PR_TRUE)) != NULL)
{
ekp = SecCmsAttributeGetValue(attr);
if (ekp == NULL)
return SECFailure;
cert = SecSMIMEGetCertFromEncryptionKeyPreference(keychainOrArray, NULL, ekp);
if (cert == NULL)
return SECFailure;
must_free_cert = PR_TRUE;
}
if (cert == NULL) {
CFStringRef emailAddress=NULL;
cert = SecCmsSignerInfoGetSigningCertificate(signerinfo, keychainOrArray);
if (cert == NULL)
return SECFailure;
if (SecCertificateGetEmailAddress(cert,&emailAddress))
return SECFailure;
}
#ifdef notdef
if (CERT_VerifyCert(keychainOrArray, cert, certUsageEmailRecipient, CFAbsoluteTimeGetCurrent(), NULL) != SECSuccess) {
if (must_free_cert)
CERT_DestroyCertificate(cert);
return SECFailure;
}
#endif
save_error = PORT_GetError();
if (!SecCmsArrayIsEmpty((void **)signerinfo->authAttr)) {
attr = SecCmsAttributeArrayFindAttrByOidTag(signerinfo->authAttr,
SEC_OID_PKCS9_SMIME_CAPABILITIES,
PR_TRUE);
profile = SecCmsAttributeGetValue(attr);
attr = SecCmsAttributeArrayFindAttrByOidTag(signerinfo->authAttr,
SEC_OID_PKCS9_SIGNING_TIME,
PR_TRUE);
utc_stime = SecCmsAttributeGetValue(attr);
}
rv = CERT_SaveSMimeProfile (cert, profile, utc_stime);
if (must_free_cert)
CERT_DestroyCertificate(cert);
PORT_SetError (save_error);
return rv;
}
OSStatus
SecCmsSignerInfoIncludeCerts(SecCmsSignerInfoRef signerinfo, SecCmsCertChainMode cm, SECCertUsage usage)
{
if (signerinfo->cert == NULL) {
return SECFailure;
}
if (signerinfo->certList != NULL) {
CFRelease(signerinfo->certList);
signerinfo->certList = NULL;
}
switch (cm) {
case SecCmsCMNone:
signerinfo->certList = NULL;
break;
case SecCmsCMCertOnly:
signerinfo->certList = CERT_CertListFromCert(signerinfo->cert);
break;
case SecCmsCMCertChain:
signerinfo->certList = CERT_CertChainFromCert(signerinfo->cert, usage, PR_FALSE, PR_FALSE);
break;
case SecCmsCMCertChainWithRoot:
signerinfo->certList = CERT_CertChainFromCert(signerinfo->cert, usage, PR_TRUE, PR_FALSE);
break;
case SecCmsCMCertChainWithRootOrFail:
signerinfo->certList = CERT_CertChainFromCert(signerinfo->cert, usage, PR_TRUE, PR_TRUE);
}
if (cm != SecCmsCMNone && signerinfo->certList == NULL) {
return SECFailure;
}
return SECSuccess;
}