+++ /dev/null
-/*
- * Copyright (c) 2006-2013 Apple Inc. All Rights Reserved.
- *
- * @APPLE_LICENSE_HEADER_START@
- *
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
- *
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
- * limitations under the License.
- *
- * @APPLE_LICENSE_HEADER_END@
- */
-
-/*
- * CMSEncoder.cpp - encode, sign, and/or encrypt CMS messages.
- */
-
-#include "CMSEncoder.h"
-#include "CMSPrivate.h"
-#include "CMSUtils.h"
-#include <Security/SecBase.h>
-#include <Security/SecCmsEncoder.h>
-#include <Security/SecCmsEnvelopedData.h>
-#include <Security/SecCmsMessage.h>
-#include <Security/SecCmsRecipientInfo.h>
-#include <Security/SecCmsSignedData.h>
-#include <Security/SecCmsSignerInfo.h>
-#include <Security/SecCmsContentInfo.h>
-#include <Security/SecCertificate.h>
-#include <Security/SecIdentity.h>
-#include <Security/SecKeychain.h>
-#include <Security/SecKeychainItem.h>
-#include <Security/SecSMIME.h>
-#include <Security/oidsattr.h>
-#include <Security/SecAsn1Coder.h>
-#include <Security/SecAsn1Types.h>
-#include <Security/SecAsn1Templates.h>
-#include <CoreFoundation/CFRuntime.h>
-#include <pthread.h>
-
-#include <security_smime/tsaSupport.h>
-#include <security_smime/cmspriv.h>
-
-#pragma mark --- Private types and definitions ---
-
-/*
- * Encoder state.
- */
-typedef enum {
- ES_Init, /* between CMSEncoderCreate and earlier of CMSEncoderUpdateContent
- * and CMSEncodeGetCmsMessage */
- ES_Msg, /* created cmsMsg in CMSEncodeGetCmsMessage, but no encoder yet */
- ES_Updating, /* between first CMSEncoderUpdateContent and CMSEncoderCopyEncodedContent */
- ES_Final /* CMSEncoderCopyEncodedContent has been called */
-} CMSEncoderState;
-
-/*
- * High-level operation: what are we doing?
- */
-typedef enum {
- EO_Sign,
- EO_Encrypt,
- EO_SignEncrypt
-} CMSEncoderOp;
-
-/*
- * Caller's CMSEncoderRef points to one of these.
- */
-struct _CMSEncoder {
- CFRuntimeBase base;
- CMSEncoderState encState;
- CMSEncoderOp op;
- Boolean detachedContent;
- CSSM_OID eContentType;
- CFMutableArrayRef signers;
- CFMutableArrayRef recipients;
- CFMutableArrayRef otherCerts;
- CMSSignedAttributes signedAttributes;
- CFAbsoluteTime signingTime;
- SecCmsMessageRef cmsMsg;
- SecArenaPoolRef arena; /* the encoder's arena */
- SecCmsEncoderRef encoder;
- CSSM_DATA encoderOut; /* output goes here... */
- bool customCoder; /* unless this is set by
- * CMSEncoderSetEncoder */
- CMSCertificateChainMode chainMode;
-};
-
-static void cmsEncoderInit(CFTypeRef enc);
-static void cmsEncoderFinalize(CFTypeRef enc);
-
-static CFRuntimeClass cmsEncoderRuntimeClass =
-{
- 0, /* version */
- "CMSEncoder",
- cmsEncoderInit,
- NULL, /* copy */
- cmsEncoderFinalize,
- NULL, /* equal - just use pointer equality */
- NULL, /* hash, ditto */
- NULL, /* copyFormattingDesc */
- NULL /* copyDebugDesc */
-};
-
-void
-CmsMessageSetTSACallback(CMSEncoderRef cmsEncoder, SecCmsTSACallback tsaCallback);
-
-#pragma mark --- Private routines ---
-
-/*
- * Decode a CFStringRef representation of an integer
- */
-static int cfStringToNumber(
- CFStringRef inStr)
-{
- int max = 32;
- char buf[max];
- if (!inStr || !CFStringGetCString(inStr, buf, max-1, kCFStringEncodingASCII))
- return -1;
- return atoi(buf);
-}
-
-/*
- * Encode an integer component of an OID, return resulting number of bytes;
- * actual bytes are mallocd and returned in *encodeArray.
- */
-static unsigned encodeNumber(
- int num,
- unsigned char **encodeArray) // mallocd and RETURNED
-{
- unsigned char *result;
- unsigned dex;
- unsigned numDigits = 0;
- unsigned scratch;
-
- /* trival case - 0 maps to 0 */
- if(num == 0) {
- *encodeArray = (unsigned char *)malloc(1);
- **encodeArray = 0;
- return 1;
- }
-
- /* first calculate the number of digits in num, base 128 */
- scratch = (unsigned)num;
- while(scratch != 0) {
- numDigits++;
- scratch >>= 7;
- }
-
- result = (unsigned char *)malloc(numDigits);
- scratch = (unsigned)num;
- for(dex=0; dex<numDigits; dex++) {
- result[numDigits - dex - 1] = scratch & 0x7f;
- scratch >>= 7;
- }
-
- /* all digits except the last one have m.s. bit set */
- for(dex=0; dex<(numDigits - 1); dex++) {
- result[dex] |= 0x80;
- }
-
- *encodeArray = result;
- return numDigits;
-}
-
-/*
- * Given an OID in dotted-decimal string representation, convert to binary
- * DER format. Returns a pointer in outOid which the caller must free(),
- * as well as the length of the data in outLen.
- * Function returns 0 if successful, non-zero otherwise.
- */
-static int encodeOid(
- const unsigned char *inStr,
- unsigned char **outOid,
- unsigned int *outLen)
-{
- unsigned char **digits = NULL; /* array of char * from encodeNumber */
- unsigned *numDigits = NULL; /* array of unsigned from encodeNumber */
- CFIndex digit;
- unsigned numDigitBytes; /* total #of output chars */
- unsigned char firstByte;
- unsigned char *outP;
- CFIndex numsToProcess;
- CFStringRef oidStr = NULL;
- CFArrayRef argvRef = NULL;
- int num, result = 1;
- CFIndex argc;
-
- /* parse input string into array of substrings */
- if (!inStr || !outOid || !outLen) goto cleanExit;
- oidStr = CFStringCreateWithCString(NULL, (const char *)inStr, kCFStringEncodingASCII);
- if (!oidStr) goto cleanExit;
- argvRef = CFStringCreateArrayBySeparatingStrings(NULL, oidStr, CFSTR("."));
- if (!argvRef) goto cleanExit;
- argc = CFArrayGetCount(argvRef);
- if (argc < 3) goto cleanExit;
-
- /* first two numbers in OID munge together */
- num = cfStringToNumber((CFStringRef)CFArrayGetValueAtIndex(argvRef, 0));
- if (num < 0) goto cleanExit;
- firstByte = (40 * num);
- num = cfStringToNumber((CFStringRef)CFArrayGetValueAtIndex(argvRef, 1));
- if (num < 0) goto cleanExit;
- firstByte += num;
- numDigitBytes = 1;
-
- numsToProcess = argc - 2;
- if(numsToProcess > 0) {
- /* skip this loop in the unlikely event that input is only two numbers */
- digits = (unsigned char **) malloc(numsToProcess * sizeof(unsigned char *));
- numDigits = (unsigned *) malloc(numsToProcess * sizeof(unsigned));
- for(digit=0; digit<numsToProcess; digit++) {
- num = cfStringToNumber((CFStringRef)CFArrayGetValueAtIndex(argvRef, digit+2));
- if (num < 0) goto cleanExit;
- numDigits[digit] = encodeNumber(num, &digits[digit]);
- numDigitBytes += numDigits[digit];
- }
- }
- *outLen = (2 + numDigitBytes);
- *outOid = outP = (unsigned char *) malloc(*outLen);
- *outP++ = 0x06;
- *outP++ = numDigitBytes;
- *outP++ = firstByte;
- for(digit=0; digit<numsToProcess; digit++) {
- unsigned int byteDex;
- for(byteDex=0; byteDex<numDigits[digit]; byteDex++) {
- *outP++ = digits[digit][byteDex];
- }
- }
- if(digits) {
- for(digit=0; digit<numsToProcess; digit++) {
- free(digits[digit]);
- }
- free(digits);
- free(numDigits);
- }
- result = 0;
-
-cleanExit:
- if (oidStr) CFRelease(oidStr);
- if (argvRef) CFRelease(argvRef);
-
- return result;
-}
-
-/*
- * Given a CF object reference describing an OID, convert to binary DER format
- * and fill out the CSSM_OID structure provided by the caller. Caller is
- * responsible for freeing the data pointer in outOid->Data.
- *
- * Function returns 0 if successful, non-zero otherwise.
- */
-
-static int convertOid(
- CFTypeRef inRef,
- CSSM_OID *outOid)
-{
- if (!inRef || !outOid)
- return errSecParam;
-
- unsigned char *oidData = NULL;
- unsigned int oidLen = 0;
-
- if (CFGetTypeID(inRef) == CFStringGetTypeID()) {
- // CFStringRef: OID representation is a dotted-decimal string
- CFStringRef inStr = (CFStringRef)inRef;
- CFIndex max = CFStringGetLength(inStr) * 3;
- char buf[max];
- if (!CFStringGetCString(inStr, buf, max-1, kCFStringEncodingASCII))
- return errSecParam;
-
- if(encodeOid((unsigned char *)buf, &oidData, &oidLen) != 0)
- return errSecParam;
- }
- else if (CFGetTypeID(inRef) == CFDataGetTypeID()) {
- // CFDataRef: OID representation is in binary DER format
- CFDataRef inData = (CFDataRef)inRef;
- oidLen = (unsigned int) CFDataGetLength(inData);
- oidData = (unsigned char *) malloc(oidLen);
- memcpy(oidData, CFDataGetBytePtr(inData), oidLen);
- }
- else {
- // Not in a format we understand
- return errSecParam;
- }
- outOid->Length = oidLen;
- outOid->Data = (uint8 *)oidData;
- return 0;
-}
-
-static CFTypeID cmsEncoderTypeID = _kCFRuntimeNotATypeID;
-
-/* one time only class init, called via pthread_once() in CMSEncoderGetTypeID() */
-static void cmsEncoderClassInitialize(void)
-{
- cmsEncoderTypeID =
- _CFRuntimeRegisterClass((const CFRuntimeClass * const)&cmsEncoderRuntimeClass);
-}
-
-/* init called out from _CFRuntimeCreateInstance() */
-static void cmsEncoderInit(CFTypeRef enc)
-{
- char *start = ((char *)enc) + sizeof(CFRuntimeBase);
- memset(start, 0, sizeof(struct _CMSEncoder) - sizeof(CFRuntimeBase));
-}
-
-/*
- * Dispose of a CMSEncoder. Called out from CFRelease().
- */
-static void cmsEncoderFinalize(
- CFTypeRef enc)
-{
- CMSEncoderRef cmsEncoder = (CMSEncoderRef)enc;
- if(cmsEncoder == NULL) {
- return;
- }
- if(cmsEncoder->eContentType.Data != NULL) {
- free(cmsEncoder->eContentType.Data);
- }
- CFRELEASE(cmsEncoder->signers);
- CFRELEASE(cmsEncoder->recipients);
- CFRELEASE(cmsEncoder->otherCerts);
- if(cmsEncoder->cmsMsg != NULL) {
- SecCmsMessageDestroy(cmsEncoder->cmsMsg);
- }
- if(cmsEncoder->arena != NULL) {
- SecArenaPoolFree(cmsEncoder->arena, false);
- }
- if(cmsEncoder->encoder != NULL) {
- /*
- * Normally this gets freed in SecCmsEncoderFinish - this is
- * an error case.
- */
- SecCmsEncoderDestroy(cmsEncoder->encoder);
- }
-}
-
-static OSStatus cmsSetupEncoder(
- CMSEncoderRef cmsEncoder)
-{
- OSStatus ortn;
-
- ASSERT(cmsEncoder->arena == NULL);
- ASSERT(cmsEncoder->encoder == NULL);
-
- ortn = SecArenaPoolCreate(1024, &cmsEncoder->arena);
- if(ortn) {
- return cmsRtnToOSStatus(ortn);
- }
- ortn = SecCmsEncoderCreate(cmsEncoder->cmsMsg,
- NULL, NULL, // no callback
- &cmsEncoder->encoderOut, // data goes here
- cmsEncoder->arena,
- NULL, NULL, // no password callback (right?)
- NULL, NULL, // decrypt key callback
- NULL, NULL, // detached digests
- &cmsEncoder->encoder);
- if(ortn) {
- return cmsRtnToOSStatus(ortn);
- }
- return errSecSuccess;
-}
-
-/*
- * Set up a SecCmsMessageRef for a SignedData creation.
- */
-static OSStatus cmsSetupForSignedData(
- CMSEncoderRef cmsEncoder)
-{
- ASSERT((cmsEncoder->signers != NULL) || (cmsEncoder->otherCerts != NULL));
-
- SecCmsContentInfoRef contentInfo = NULL;
- SecCmsSignedDataRef signedData = NULL;
- OSStatus ortn;
-
- /* build chain of objects: message->signedData->data */
- if(cmsEncoder->cmsMsg != NULL) {
- SecCmsMessageDestroy(cmsEncoder->cmsMsg);
- }
- cmsEncoder->cmsMsg = SecCmsMessageCreate(NULL);
- if(cmsEncoder->cmsMsg == NULL) {
- return errSecInternalComponent;
- }
-
- signedData = SecCmsSignedDataCreate(cmsEncoder->cmsMsg);
- if(signedData == NULL) {
- return errSecInternalComponent;
- }
- contentInfo = SecCmsMessageGetContentInfo(cmsEncoder->cmsMsg);
- ortn = SecCmsContentInfoSetContentSignedData(cmsEncoder->cmsMsg, contentInfo,
- signedData);
- if(ortn) {
- return cmsRtnToOSStatus(ortn);
- }
- contentInfo = SecCmsSignedDataGetContentInfo(signedData);
- if(cmsEncoder->eContentType.Data != NULL) {
- /* Override the default eContentType of id-data */
- ortn = SecCmsContentInfoSetContentOther(cmsEncoder->cmsMsg,
- contentInfo,
- NULL, /* data - provided to encoder, not here */
- cmsEncoder->detachedContent,
- &cmsEncoder->eContentType);
- }
- else {
- ortn = SecCmsContentInfoSetContentData(cmsEncoder->cmsMsg,
- contentInfo,
- NULL, /* data - provided to encoder, not here */
- cmsEncoder->detachedContent);
- }
- if(ortn) {
- ortn = cmsRtnToOSStatus(ortn);
- CSSM_PERROR("SecCmsContentInfoSetContent*", ortn);
- return ortn;
- }
-
- /* optional 'global' (per-SignedData) certs */
- if(cmsEncoder->otherCerts != NULL) {
- ortn = SecCmsSignedDataAddCertList(signedData, cmsEncoder->otherCerts);
- if(ortn) {
- ortn = cmsRtnToOSStatus(ortn);
- CSSM_PERROR("SecCmsSignedDataAddCertList", ortn);
- return ortn;
- }
- }
-
- /* SignerInfos, one per signer */
- CFIndex numSigners = 0;
- if(cmsEncoder->signers != NULL) {
- /* this is optional...in case we're just creating a cert bundle */
- numSigners = CFArrayGetCount(cmsEncoder->signers);
- }
- CFIndex dex;
- SecKeychainRef ourKc = NULL;
- SecCertificateRef ourCert = NULL;
- SecCmsCertChainMode chainMode = SecCmsCMCertChain;
-
- switch(cmsEncoder->chainMode) {
- case kCMSCertificateNone:
- chainMode = SecCmsCMNone;
- break;
- case kCMSCertificateSignerOnly:
- chainMode = SecCmsCMCertOnly;
- break;
- case kCMSCertificateChainWithRoot:
- chainMode = SecCmsCMCertChainWithRoot;
- break;
- default:
- break;
- }
- for(dex=0; dex<numSigners; dex++) {
- SecCmsSignerInfoRef signerInfo;
-
- SecIdentityRef ourId =
- (SecIdentityRef)CFArrayGetValueAtIndex(cmsEncoder->signers, dex);
- ortn = SecIdentityCopyCertificate(ourId, &ourCert);
- if(ortn) {
- CSSM_PERROR("SecIdentityCopyCertificate", ortn);
- break;
- }
- ortn = SecKeychainItemCopyKeychain((SecKeychainItemRef)ourCert, &ourKc);
- if(ortn) {
- CSSM_PERROR("SecKeychainItemCopyKeychain", ortn);
- break;
- }
- signerInfo = SecCmsSignerInfoCreate(cmsEncoder->cmsMsg, ourId, SEC_OID_SHA1);
- if (signerInfo == NULL) {
- ortn = errSecInternalComponent;
- break;
- }
-
- /* we want the cert chain included for this one */
- /* NOTE the usage parameter is currently unused by the SMIME lib */
- ortn = SecCmsSignerInfoIncludeCerts(signerInfo, chainMode,
- certUsageEmailSigner);
- if(ortn) {
- ortn = cmsRtnToOSStatus(ortn);
- CSSM_PERROR("SecCmsSignerInfoIncludeCerts", ortn);
- break;
- }
-
- /* other options */
- if(cmsEncoder->signedAttributes & kCMSAttrSmimeCapabilities) {
- ortn = SecCmsSignerInfoAddSMIMECaps(signerInfo);
- if(ortn) {
- ortn = cmsRtnToOSStatus(ortn);
- CSSM_PERROR("SecCmsSignerInfoAddSMIMEEncKeyPrefs", ortn);
- break;
- }
- }
- if(cmsEncoder->signedAttributes & kCMSAttrSmimeEncryptionKeyPrefs) {
- ortn = SecCmsSignerInfoAddSMIMEEncKeyPrefs(signerInfo, ourCert, ourKc);
- if(ortn) {
- ortn = cmsRtnToOSStatus(ortn);
- CSSM_PERROR("SecCmsSignerInfoAddSMIMEEncKeyPrefs", ortn);
- break;
- }
- }
- if(cmsEncoder->signedAttributes & kCMSAttrSmimeMSEncryptionKeyPrefs) {
- ortn = SecCmsSignerInfoAddMSSMIMEEncKeyPrefs(signerInfo, ourCert, ourKc);
- if(ortn) {
- ortn = cmsRtnToOSStatus(ortn);
- CSSM_PERROR("SecCmsSignerInfoAddMSSMIMEEncKeyPrefs", ortn);
- break;
- }
- }
- if(cmsEncoder->signedAttributes & kCMSAttrSigningTime) {
- if (cmsEncoder->signingTime == 0)
- cmsEncoder->signingTime = CFAbsoluteTimeGetCurrent();
- ortn = SecCmsSignerInfoAddSigningTime(signerInfo, cmsEncoder->signingTime);
- if(ortn) {
- ortn = cmsRtnToOSStatus(ortn);
- CSSM_PERROR("SecCmsSignerInfoAddSigningTime", ortn);
- break;
- }
- }
-
- ortn = SecCmsSignedDataAddSignerInfo(signedData, signerInfo);
- if(ortn) {
- ortn = cmsRtnToOSStatus(ortn);
- CSSM_PERROR("SecCmsSignedDataAddSignerInfo", ortn);
- break;
- }
-
- CFRELEASE(ourKc);
- CFRELEASE(ourCert);
- ourKc = NULL;
- ourCert = NULL;
- }
- if(ortn) {
- CFRELEASE(ourKc);
- CFRELEASE(ourCert);
- }
- return ortn;
-}
-
-/*
- * Set up a SecCmsMessageRef for a EnvelopedData creation.
- */
-static OSStatus cmsSetupForEnvelopedData(
- CMSEncoderRef cmsEncoder)
-{
- ASSERT(cmsEncoder->op == EO_Encrypt);
- ASSERT(cmsEncoder->recipients != NULL);
-
- SecCmsContentInfoRef contentInfo = NULL;
- SecCmsEnvelopedDataRef envelopedData = NULL;
- SECOidTag algorithmTag;
- int keySize;
- OSStatus ortn;
-
- /*
- * Find encryption algorithm...unfortunately we need a NULL-terminated array
- * of SecCertificateRefs for this.
- */
- CFIndex numCerts = CFArrayGetCount(cmsEncoder->recipients);
- CFIndex dex;
- SecCertificateRef *certArray = (SecCertificateRef *)malloc(
- (numCerts+1) * sizeof(SecCertificateRef));
-
- for(dex=0; dex<numCerts; dex++) {
- certArray[dex] = (SecCertificateRef)CFArrayGetValueAtIndex(
- cmsEncoder->recipients, dex);
- }
- certArray[numCerts] = NULL;
- ortn = SecSMIMEFindBulkAlgForRecipients(certArray, &algorithmTag, &keySize);
- free(certArray);
- if(ortn) {
- CSSM_PERROR("SecSMIMEFindBulkAlgForRecipients", ortn);
- return ortn;
- }
-
- /* build chain of objects: message->envelopedData->data */
- if(cmsEncoder->cmsMsg != NULL) {
- SecCmsMessageDestroy(cmsEncoder->cmsMsg);
- }
- cmsEncoder->cmsMsg = SecCmsMessageCreate(NULL);
- if(cmsEncoder->cmsMsg == NULL) {
- return errSecInternalComponent;
- }
- envelopedData = SecCmsEnvelopedDataCreate(cmsEncoder->cmsMsg,
- algorithmTag, keySize);
- if(envelopedData == NULL) {
- return errSecInternalComponent;
- }
- contentInfo = SecCmsMessageGetContentInfo(cmsEncoder->cmsMsg);
- ortn = SecCmsContentInfoSetContentEnvelopedData(cmsEncoder->cmsMsg,
- contentInfo, envelopedData);
- if(ortn) {
- ortn = cmsRtnToOSStatus(ortn);
- CSSM_PERROR("SecCmsContentInfoSetContentEnvelopedData", ortn);
- return ortn;
- }
- contentInfo = SecCmsEnvelopedDataGetContentInfo(envelopedData);
- if(cmsEncoder->eContentType.Data != NULL) {
- /* Override the default ContentType of id-data */
- ortn = SecCmsContentInfoSetContentOther(cmsEncoder->cmsMsg,
- contentInfo,
- NULL, /* data - provided to encoder, not here */
- FALSE, /* detachedContent */
- &cmsEncoder->eContentType);
- }
- else {
- ortn = SecCmsContentInfoSetContentData(cmsEncoder->cmsMsg,
- contentInfo,
- NULL /* data - provided to encoder, not here */,
- cmsEncoder->detachedContent);
- }
- if(ortn) {
- ortn = cmsRtnToOSStatus(ortn);
- CSSM_PERROR("SecCmsContentInfoSetContentData*", ortn);
- return ortn;
- }
-
- /*
- * create & attach recipient information, one for each recipient
- */
- for(dex=0; dex<numCerts; dex++) {
- SecCmsRecipientInfoRef recipientInfo = NULL;
-
- SecCertificateRef thisRecip = (SecCertificateRef)CFArrayGetValueAtIndex(
- cmsEncoder->recipients, dex);
- recipientInfo = SecCmsRecipientInfoCreate(cmsEncoder->cmsMsg, thisRecip);
- ortn = SecCmsEnvelopedDataAddRecipient(envelopedData, recipientInfo);
- if(ortn) {
- ortn = cmsRtnToOSStatus(ortn);
- CSSM_PERROR("SecCmsEnvelopedDataAddRecipient", ortn);
- return ortn;
- }
- }
- return errSecSuccess;
-}
-
-/*
- * Set up cmsMsg. Called from either the first call to CMSEncoderUpdateContent, or
- * from CMSEncodeGetCmsMessage().
- */
-static OSStatus cmsSetupCmsMsg(
- CMSEncoderRef cmsEncoder)
-{
- ASSERT(cmsEncoder != NULL);
- ASSERT(cmsEncoder->encState == ES_Init);
-
- /* figure out what high-level operation we're doing */
- if((cmsEncoder->signers != NULL) || (cmsEncoder->otherCerts != NULL)) {
- if(cmsEncoder->recipients != NULL) {
- cmsEncoder->op = EO_SignEncrypt;
- }
- else {
- cmsEncoder->op = EO_Sign;
- }
- }
- else if(cmsEncoder->recipients != NULL) {
- cmsEncoder->op = EO_Encrypt;
- }
- else {
- dprintf("CMSEncoderUpdateContent: nothing to do\n");
- return errSecParam;
- }
-
- OSStatus ortn = errSecSuccess;
-
- switch(cmsEncoder->op) {
- case EO_Sign:
- case EO_SignEncrypt:
- /* If we're signing & encrypting, do the signing first */
- ortn = cmsSetupForSignedData(cmsEncoder);
- break;
- case EO_Encrypt:
- ortn = cmsSetupForEnvelopedData(cmsEncoder);
- break;
- }
- cmsEncoder->encState = ES_Msg;
- return ortn;
-}
-
-/*
- * ASN.1 template for decoding a ContentInfo.
- */
-typedef struct {
- CSSM_OID contentType;
- CSSM_DATA content;
-} SimpleContentInfo;
-
-static const SecAsn1Template cmsSimpleContentInfoTemplate[] = {
- { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(SimpleContentInfo) },
- { SEC_ASN1_OBJECT_ID, offsetof(SimpleContentInfo, contentType) },
- { SEC_ASN1_EXPLICIT | SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC | 0,
- offsetof(SimpleContentInfo, content),
- kSecAsn1AnyTemplate },
- { 0, }
-};
-
-/*
- * Obtain the content of a contentInfo, This basically strips off the contentType OID
- * and returns its ASN_ANY content, allocated the provided coder's memory space.
- */
-static OSStatus cmsContentInfoContent(
- SecAsn1CoderRef asn1Coder,
- const CSSM_DATA *contentInfo,
- CSSM_DATA *content) /* RETURNED */
-{
- OSStatus ortn;
- SimpleContentInfo decodedInfo;
-
- memset(&decodedInfo, 0, sizeof(decodedInfo));
- ortn = SecAsn1DecodeData(asn1Coder, contentInfo,
- cmsSimpleContentInfoTemplate, &decodedInfo);
- if(ortn) {
- return ortn;
- }
- if(decodedInfo.content.Data == NULL) {
- dprintf("***Error decoding contentInfo: no content\n");
- return errSecInternalComponent;
- }
- *content = decodedInfo.content;
- return errSecSuccess;
-}
-
-#pragma mark --- Start of Public API ---
-
-CFTypeID CMSEncoderGetTypeID(void)
-{
- static pthread_once_t once = PTHREAD_ONCE_INIT;
-
- if(cmsEncoderTypeID == _kCFRuntimeNotATypeID) {
- pthread_once(&once, &cmsEncoderClassInitialize);
- }
- return cmsEncoderTypeID;
-}
-
-/*
- * Create a CMSEncoder. Result must eventually be freed via CFRelease().
- */
-OSStatus CMSEncoderCreate(
- CMSEncoderRef *cmsEncoderOut) /* RETURNED */
-{
- CMSEncoderRef cmsEncoder = NULL;
-
- uint32_t extra = sizeof(*cmsEncoder) - sizeof(cmsEncoder->base);
- cmsEncoder = (CMSEncoderRef)_CFRuntimeCreateInstance(NULL, CMSEncoderGetTypeID(),
- extra, NULL);
- if(cmsEncoder == NULL) {
- return errSecAllocate;
- }
- cmsEncoder->encState = ES_Init;
- cmsEncoder->chainMode = kCMSCertificateChain;
- *cmsEncoderOut = cmsEncoder;
- return errSecSuccess;
-}
-
-#pragma mark --- Getters & Setters ---
-
-/*
- * Specify signers of the CMS message; implies that the message will be signed.
- */
-OSStatus CMSEncoderAddSigners(
- CMSEncoderRef cmsEncoder,
- CFTypeRef signerOrArray)
-{
- if(cmsEncoder == NULL) {
- return errSecParam;
- }
- if(cmsEncoder->encState != ES_Init) {
- return errSecParam;
- }
- return cmsAppendToArray(signerOrArray, &cmsEncoder->signers, SecIdentityGetTypeID());
-}
-
-/*
- * Obtain an array of signers as specified in CMSEncoderSetSigners().
- */
-OSStatus CMSEncoderCopySigners(
- CMSEncoderRef cmsEncoder,
- CFArrayRef *signers)
-{
- if((cmsEncoder == NULL) || (signers == NULL)) {
- return errSecParam;
- }
- if(cmsEncoder->signers != NULL) {
- CFRetain(cmsEncoder->signers);
- }
- *signers = cmsEncoder->signers;
- return errSecSuccess;
-}
-
-/*
- * Specify recipients of the message. Implies that the message will be encrypted.
- */
-OSStatus CMSEncoderAddRecipients(
- CMSEncoderRef cmsEncoder,
- CFTypeRef recipientOrArray)
-{
- if(cmsEncoder == NULL) {
- return errSecParam;
- }
- if(cmsEncoder->encState != ES_Init) {
- return errSecParam;
- }
- return cmsAppendToArray(recipientOrArray, &cmsEncoder->recipients,
- SecCertificateGetTypeID());
-}
-
-/*
- * Obtain an array of recipients as specified in CMSEncoderSetRecipients().
- */
-OSStatus CMSEncoderCopyRecipients(
- CMSEncoderRef cmsEncoder,
- CFArrayRef *recipients)
-{
- if((cmsEncoder == NULL) || (recipients == NULL)) {
- return errSecParam;
- }
- if(cmsEncoder->recipients != NULL) {
- CFRetain(cmsEncoder->recipients);
- }
- *recipients = cmsEncoder->recipients;
- return errSecSuccess;
-}
-
-/*
- * Specify additional certs to include in a signed message.
- */
-OSStatus CMSEncoderAddSupportingCerts(
- CMSEncoderRef cmsEncoder,
- CFTypeRef certOrArray)
-{
- if(cmsEncoder == NULL) {
- return errSecParam;
- }
- if(cmsEncoder->encState != ES_Init) {
- return errSecParam;
- }
- return cmsAppendToArray(certOrArray, &cmsEncoder->otherCerts,
- SecCertificateGetTypeID());
-}
-
-/*
- * Obtain the SecCertificates provided in CMSEncoderAddSupportingCerts().
- */
-OSStatus CMSEncoderCopySupportingCerts(
- CMSEncoderRef cmsEncoder,
- CFArrayRef *certs) /* RETURNED */
-{
- if((cmsEncoder == NULL) || (certs == NULL)) {
- return errSecParam;
- }
- if(cmsEncoder->otherCerts != NULL) {
- CFRetain(cmsEncoder->otherCerts);
- }
- *certs = cmsEncoder->otherCerts;
- return errSecSuccess;
-}
-
-OSStatus CMSEncoderSetHasDetachedContent(
- CMSEncoderRef cmsEncoder,
- Boolean detachedContent)
-{
- if(cmsEncoder == NULL) {
- return errSecParam;
- }
- if(cmsEncoder->encState != ES_Init) {
- return errSecParam;
- }
- cmsEncoder->detachedContent = detachedContent;
- return errSecSuccess;
-}
-
-OSStatus CMSEncoderGetHasDetachedContent(
- CMSEncoderRef cmsEncoder,
- Boolean *detachedContent) /* RETURNED */
-{
- if((cmsEncoder == NULL) || (detachedContent == NULL)) {
- return errSecParam;
- }
- *detachedContent = cmsEncoder->detachedContent;
- return errSecSuccess;
-}
-
-/*
- * Optionally specify an eContentType OID for the inner EncapsulatedData for
- * a signed message. The default eContentType, used of this function is not
- * called, is id-data.
- */
-OSStatus CMSEncoderSetEncapsulatedContentType(
- CMSEncoderRef cmsEncoder,
- const CSSM_OID *eContentType)
-{
- if((cmsEncoder == NULL) || (eContentType == NULL)) {
- return errSecParam;
- }
- if(cmsEncoder->encState != ES_Init) {
- return errSecParam;
- }
-
- CSSM_OID *ecOid = &cmsEncoder->eContentType;
- if(ecOid->Data != NULL) {
- free(ecOid->Data);
- }
- cmsCopyCmsData(eContentType, ecOid);
- return errSecSuccess;
-}
-
-OSStatus CMSEncoderSetEncapsulatedContentTypeOID(
- CMSEncoderRef cmsEncoder,
- CFTypeRef eContentTypeOID)
-{
- // convert eContentTypeOID to a CSSM_OID
- CSSM_OID contentType = { 0, NULL };
- if (!eContentTypeOID || convertOid(eContentTypeOID, &contentType) != 0)
- return errSecParam;
- OSStatus result = CMSEncoderSetEncapsulatedContentType(cmsEncoder, &contentType);
- if (contentType.Data)
- free(contentType.Data);
- return result;
-}
-
-/*
- * Obtain the eContentType OID specified in CMSEncoderSetEncapsulatedContentType().
- */
-OSStatus CMSEncoderCopyEncapsulatedContentType(
- CMSEncoderRef cmsEncoder,
- CFDataRef *eContentType)
-{
- if((cmsEncoder == NULL) || (eContentType == NULL)) {
- return errSecParam;
- }
-
- CSSM_OID *ecOid = &cmsEncoder->eContentType;
- if(ecOid->Data == NULL) {
- *eContentType = NULL;
- }
- else {
- *eContentType = CFDataCreate(NULL, ecOid->Data, ecOid->Length);
- }
- return errSecSuccess;
-}
-
-/*
- * Optionally specify signed attributes. Only meaningful when creating a
- * signed message. If this is called, it must be called before
- * CMSEncoderUpdateContent().
- */
-OSStatus CMSEncoderAddSignedAttributes(
- CMSEncoderRef cmsEncoder,
- CMSSignedAttributes signedAttributes)
-{
- if(cmsEncoder == NULL) {
- return errSecParam;
- }
- if(cmsEncoder->encState != ES_Init) {
- return errSecParam;
- }
- cmsEncoder->signedAttributes = signedAttributes;
- return errSecSuccess;
-}
-
-/*
- * Set the signing time for a CMSEncoder.
- * This is only used if the kCMSAttrSigningTime attribute is included.
- */
-OSStatus CMSEncoderSetSigningTime(
- CMSEncoderRef cmsEncoder,
- CFAbsoluteTime time)
-{
- if(cmsEncoder == NULL) {
- return errSecParam;
- }
- if(cmsEncoder->encState != ES_Init) {
- return errSecParam;
- }
- cmsEncoder->signingTime = time;
- return errSecSuccess;
-}
-
-
-OSStatus CMSEncoderSetCertificateChainMode(
- CMSEncoderRef cmsEncoder,
- CMSCertificateChainMode chainMode)
-{
- if(cmsEncoder == NULL) {
- return errSecParam;
- }
- if(cmsEncoder->encState != ES_Init) {
- return errSecParam;
- }
- switch(chainMode) {
- case kCMSCertificateNone:
- case kCMSCertificateSignerOnly:
- case kCMSCertificateChain:
- case kCMSCertificateChainWithRoot:
- break;
- default:
- return errSecParam;
- }
- cmsEncoder->chainMode = chainMode;
- return errSecSuccess;
-}
-
-OSStatus CMSEncoderGetCertificateChainMode(
- CMSEncoderRef cmsEncoder,
- CMSCertificateChainMode *chainModeOut)
-{
- if(cmsEncoder == NULL) {
- return errSecParam;
- }
- *chainModeOut = cmsEncoder->chainMode;
- return errSecSuccess;
-}
-
-void
-CmsMessageSetTSACallback(CMSEncoderRef cmsEncoder, SecCmsTSACallback tsaCallback)
-{
- if (cmsEncoder->cmsMsg)
- SecCmsMessageSetTSACallback(cmsEncoder->cmsMsg, tsaCallback);
-}
-
-void
-CmsMessageSetTSAContext(CMSEncoderRef cmsEncoder, CFTypeRef tsaContext)
-{
- if (cmsEncoder->cmsMsg)
- SecCmsMessageSetTSAContext(cmsEncoder->cmsMsg, tsaContext);
-}
-
-#pragma mark --- Action ---
-
-/*
- * Feed content bytes into the encoder.
- * Can be called multiple times.
- * No 'setter' routines can be called after this function has been called.
- */
-OSStatus CMSEncoderUpdateContent(
- CMSEncoderRef cmsEncoder,
- const void *content,
- size_t contentLen)
-{
- if(cmsEncoder == NULL) {
- return errSecParam;
- }
-
- OSStatus ortn = errSecSuccess;
- switch(cmsEncoder->encState) {
- case ES_Init:
- /*
- * First time thru: do the CmsMsg setup.
- */
- ortn = cmsSetupCmsMsg(cmsEncoder);
- if(ortn) {
- return ortn;
- }
- /* fall thru to set up the encoder */
-
- case ES_Msg:
- /* We have a cmsMsg but no encoder; create one */
- ASSERT(cmsEncoder->cmsMsg != NULL);
- ASSERT(cmsEncoder->encoder == NULL);
- ortn = cmsSetupEncoder(cmsEncoder);
- if(ortn) {
- return ortn;
- }
- /* only legal calls now are update and finalize */
- cmsEncoder->encState = ES_Updating;
- break;
-
- case ES_Updating:
- ASSERT(cmsEncoder->encoder != NULL);
- break;
-
- case ES_Final:
- /* Too late for another update */
- return errSecParam;
-
- default:
- return errSecInternalComponent;
- }
-
- /* FIXME - CFIndex same size as size_t on 64bit? */
- ortn = SecCmsEncoderUpdate(cmsEncoder->encoder, content, (CFIndex)contentLen);
- if(ortn) {
- ortn = cmsRtnToOSStatus(ortn);
- CSSM_PERROR("SecCmsEncoderUpdate", ortn);
- }
- return ortn;
-}
-
-/*
- * Finish encoding the message and obtain the encoded result.
- * Caller must CFRelease the result.
- */
-OSStatus CMSEncoderCopyEncodedContent(
- CMSEncoderRef cmsEncoder,
- CFDataRef *encodedContent)
-{
- if((cmsEncoder == NULL) || (encodedContent == NULL)) {
- return errSecParam;
- }
-
- OSStatus ortn;
-
- switch(cmsEncoder->encState) {
- case ES_Updating:
- /* normal termination */
- break;
- case ES_Final:
- /* already been called */
- return errSecParam;
- case ES_Msg:
- case ES_Init:
- /*
- * The only time these are legal is when we're doing a SignedData
- * with certificates only (no signers, no content).
- */
- if((cmsEncoder->signers != NULL) ||
- (cmsEncoder->recipients != NULL) ||
- (cmsEncoder->otherCerts == NULL)) {
- return errSecParam;
- }
-
- /* Set up for certs only */
- ortn = cmsSetupForSignedData(cmsEncoder);
- if(ortn) {
- return ortn;
- }
- /* and an encoder */
- ortn = cmsSetupEncoder(cmsEncoder);
- if(ortn) {
- return ortn;
- }
- break;
- }
-
-
- ASSERT(cmsEncoder->encoder != NULL);
- ortn = SecCmsEncoderFinish(cmsEncoder->encoder);
- /* regardless of the outcome, the encoder itself has been freed */
- cmsEncoder->encoder = NULL;
- if(ortn) {
- return cmsRtnToOSStatus(ortn);
- }
- cmsEncoder->encState = ES_Final;
-
- if((cmsEncoder->encoderOut.Data == NULL) && !cmsEncoder->customCoder) {
- /* not sure how this could happen... */
- dprintf("Successful encode, but no data\n");
- return errSecInternalComponent;
- }
- if(cmsEncoder->customCoder) {
- /* we're done */
- *encodedContent = NULL;
- return errSecSuccess;
- }
-
- /* in two out of three cases, we're done */
- switch(cmsEncoder->op) {
- case EO_Sign:
- case EO_Encrypt:
- *encodedContent = CFDataCreate(NULL, (const UInt8 *)cmsEncoder->encoderOut.Data,
- cmsEncoder->encoderOut.Length);
- return errSecSuccess;
- case EO_SignEncrypt:
- /* proceed, more work to do */
- break;
- }
-
- /*
- * Signing & encrypting.
- * Due to bugs in the libsecurity_smime encoder, it can't encode nested
- * ContentInfos in one shot. So we do another pass, specifying the SignedData
- * inside of the ContentInfo we just created as the data to encrypt.
- */
- SecAsn1CoderRef asn1Coder = NULL;
- CSSM_DATA signedData = {0, NULL};
-
- ortn = SecAsn1CoderCreate(&asn1Coder);
- if(ortn) {
- return ortn;
- }
- ortn = cmsContentInfoContent(asn1Coder, &cmsEncoder->encoderOut, &signedData);
- if(ortn) {
- goto errOut;
- }
-
- /* now just encrypt that, one-shot */
- ortn = CMSEncode(NULL, /* no signers this time */
- cmsEncoder->recipients,
- &CSSMOID_PKCS7_SignedData, /* fake out encoder so it doesn't try to actually
- * encode the signedData - this asserts the
- * SEC_OID_OTHER OID tag in the EnvelopedData's
- * ContentInfo */
- FALSE, /* detachedContent */
- kCMSAttrNone, /* signedAttributes - none this time */
- signedData.Data, signedData.Length,
- encodedContent);
-
-errOut:
- if(asn1Coder) {
- SecAsn1CoderRelease(asn1Coder);
- }
- return ortn;
-}
-
-#pragma mark --- High-level API ---
-
-/*
- * High-level, one-shot encoder function.
- */
-OSStatus CMSEncode(
- CFTypeRef signers,
- CFTypeRef recipients,
- const CSSM_OID *eContentType,
- Boolean detachedContent,
- CMSSignedAttributes signedAttributes,
- const void *content,
- size_t contentLen,
- CFDataRef *encodedContent) /* RETURNED */
-{
- if((signers == NULL) && (recipients == NULL)) {
- return errSecParam;
- }
- if(encodedContent == NULL) {
- return errSecParam;
- }
-
- CMSEncoderRef cmsEncoder;
- OSStatus ortn;
-
- /* set up the encoder */
- ortn = CMSEncoderCreate(&cmsEncoder);
- if(ortn) {
- return ortn;
- }
-
- /* subsequent errors to errOut: */
- if(signers) {
- ortn = CMSEncoderAddSigners(cmsEncoder, signers);
- if(ortn) {
- goto errOut;
- }
- }
- if(recipients) {
- ortn = CMSEncoderAddRecipients(cmsEncoder, recipients);
- if(ortn) {
- goto errOut;
- }
- }
- if(eContentType) {
- ortn = CMSEncoderSetEncapsulatedContentType(cmsEncoder, eContentType);
- if(ortn) {
- goto errOut;
- }
- }
- if(detachedContent) {
- ortn = CMSEncoderSetHasDetachedContent(cmsEncoder, detachedContent);
- if(ortn) {
- goto errOut;
- }
- }
- if(signedAttributes) {
- ortn = CMSEncoderAddSignedAttributes(cmsEncoder, signedAttributes);
- if(ortn) {
- goto errOut;
- }
- }
- /* GO */
- ortn = CMSEncoderUpdateContent(cmsEncoder, content, contentLen);
- if(ortn) {
- goto errOut;
- }
- ortn = CMSEncoderCopyEncodedContent(cmsEncoder, encodedContent);
-
-errOut:
- CFRelease(cmsEncoder);
- return ortn;
-}
-
-OSStatus CMSEncodeContent(
- CFTypeRef signers,
- CFTypeRef recipients,
- CFTypeRef eContentTypeOID,
- Boolean detachedContent,
- CMSSignedAttributes signedAttributes,
- const void *content,
- size_t contentLen,
- CFDataRef *encodedContentOut) /* RETURNED */
-{
- // convert eContentTypeOID to a CSSM_OID
- CSSM_OID contentType = { 0, NULL };
- if (eContentTypeOID && convertOid(eContentTypeOID, &contentType) != 0)
- return errSecParam;
- const CSSM_OID *contentTypePtr = (eContentTypeOID) ? &contentType : NULL;
- OSStatus result = CMSEncode(signers, recipients, contentTypePtr,
- detachedContent, signedAttributes,
- content, contentLen, encodedContentOut);
- if (contentType.Data)
- free(contentType.Data);
- return result;
-}
-
-#pragma mark --- SPI routines declared in CMSPrivate.h ---
-
-/*
- * Obtain the SecCmsMessageRef associated with a CMSEncoderRef.
- * If we don't have a SecCmsMessageRef yet, we create one now.
- * This is the only place where we go to state ES_Msg.
- */
-OSStatus CMSEncoderGetCmsMessage(
- CMSEncoderRef cmsEncoder,
- SecCmsMessageRef *cmsMessage) /* RETURNED */
-{
- if((cmsEncoder == NULL) || (cmsMessage == NULL)) {
- return errSecParam;
- }
- if(cmsEncoder->cmsMsg != NULL) {
- ASSERT(cmsEncoder->encState != ES_Init);
- *cmsMessage = cmsEncoder->cmsMsg;
- return errSecSuccess;
- }
-
- OSStatus ortn = cmsSetupCmsMsg(cmsEncoder);
- if(ortn) {
- return ortn;
- }
- *cmsMessage = cmsEncoder->cmsMsg;
-
- /* Don't set up encoder yet; caller might do that via CMSEncoderSetEncoder */
- cmsEncoder->encState = ES_Msg;
- return errSecSuccess;
-}
-
-/*
- * Optionally specify a SecCmsEncoderRef to use with a CMSEncoderRef.
- * If this is called, it must be called before the first call to
- * CMSEncoderUpdateContent(). The CMSEncoderRef takes ownership of the
- * incoming SecCmsEncoderRef.
- */
-OSStatus CMSEncoderSetEncoder(
- CMSEncoderRef cmsEncoder,
- SecCmsEncoderRef encoder)
-{
- if((cmsEncoder == NULL) || (encoder == NULL)) {
- return errSecParam;
- }
-
- OSStatus ortn;
-
- switch(cmsEncoder->encState) {
- case ES_Init:
- /* No message, no encoder */
- ASSERT(cmsEncoder->cmsMsg == NULL);
- ASSERT(cmsEncoder->encoder == NULL);
- ortn = cmsSetupCmsMsg(cmsEncoder);
- if(ortn) {
- return ortn;
- }
- /* drop thru to set encoder */
- case ES_Msg:
- /* cmsMsg but no encoder */
- ASSERT(cmsEncoder->cmsMsg != NULL);
- ASSERT(cmsEncoder->encoder == NULL);
- cmsEncoder->encoder = encoder;
- cmsEncoder->encState = ES_Updating;
- cmsEncoder->customCoder = true; /* we won't see data */
- return errSecSuccess;
- default:
- /* no can do, too late */
- return errSecParam;
- }
-}
-
-/*
- * Obtain the SecCmsEncoderRef associated with a CMSEncoderRef.
- * Returns a NULL SecCmsEncoderRef if neither CMSEncoderSetEncoder nor
- * CMSEncoderUpdateContent() has been called.
- * The CMSEncoderRef retains ownership of the SecCmsEncoderRef.
- */
-OSStatus CMSEncoderGetEncoder(
- CMSEncoderRef cmsEncoder,
- SecCmsEncoderRef *encoder) /* RETURNED */
-{
- if((cmsEncoder == NULL) || (encoder == NULL)) {
- return errSecParam;
- }
-
- /* any state, whether we have an encoder or not is OK */
- *encoder = cmsEncoder->encoder;
- return errSecSuccess;
-}
-
-#include <AssertMacros.h>
-
-/*
- * Obtain the timestamp of signer 'signerIndex' of a CMS message, if
- * present. This timestamp is an authenticated timestamp provided by
- * a timestamping authority.
- *
- * Returns errSecParam if the CMS message was not signed or if signerIndex
- * is greater than the number of signers of the message minus one.
- *
- * This cannot be called until after CMSEncoderCopyEncodedContent() is called.
- */
-OSStatus CMSEncoderCopySignerTimestamp(
- CMSEncoderRef cmsEncoder,
- size_t signerIndex, /* usually 0 */
- CFAbsoluteTime *timestamp) /* RETURNED */
-{
- return CMSEncoderCopySignerTimestampWithPolicy(
- cmsEncoder,
- NULL,
- signerIndex,
- timestamp);
-}
-
-OSStatus CMSEncoderCopySignerTimestampWithPolicy(
- CMSEncoderRef cmsEncoder,
- CFTypeRef timeStampPolicy,
- size_t signerIndex, /* usually 0 */
- CFAbsoluteTime *timestamp) /* RETURNED */
-{
- OSStatus status = errSecParam;
- SecCmsMessageRef cmsg;
- SecCmsSignedDataRef signedData = NULL;
- int numContentInfos = 0;
-
- require(cmsEncoder && timestamp, xit);
- require_noerr(CMSEncoderGetCmsMessage(cmsEncoder, &cmsg), xit);
- numContentInfos = SecCmsMessageContentLevelCount(cmsg);
- for (int dex = 0; !signedData && dex < numContentInfos; dex++)
- {
- SecCmsContentInfoRef ci = SecCmsMessageContentLevel(cmsg, dex);
- SECOidTag tag = SecCmsContentInfoGetContentTypeTag(ci);
- if (tag == SEC_OID_PKCS7_SIGNED_DATA)
- if ((signedData = SecCmsSignedDataRef(SecCmsContentInfoGetContent(ci))))
- if (SecCmsSignerInfoRef signerInfo = SecCmsSignedDataGetSignerInfo(signedData, (int)signerIndex))
- {
- status = SecCmsSignerInfoGetTimestampTimeWithPolicy(signerInfo, timeStampPolicy, timestamp);
- break;
- }
- }
-
-xit:
- return status;
-}