]> git.saurik.com Git - apple/security.git/blobdiff - Security/libsecurity_cms/lib/CMSEncoder.cpp
Security-57336.1.9.tar.gz
[apple/security.git] / Security / libsecurity_cms / lib / CMSEncoder.cpp
diff --git a/Security/libsecurity_cms/lib/CMSEncoder.cpp b/Security/libsecurity_cms/lib/CMSEncoder.cpp
deleted file mode 100644 (file)
index 12829f5..0000000
+++ /dev/null
@@ -1,1451 +0,0 @@
-/*
- * 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;
-}