2  * Copyright (c) 2006-2016 Apple Inc. All Rights Reserved. 
   4  * @APPLE_LICENSE_HEADER_START@ 
   6  * This file contains Original Code and/or Modifications of Original Code 
   7  * as defined in and that are subject to the Apple Public Source License 
   8  * Version 2.0 (the 'License'). You may not use this file except in 
   9  * compliance with the License. Please obtain a copy of the License at 
  10  * http://www.opensource.apple.com/apsl/ and read it before using this 
  13  * The Original Code and all software distributed under the License are 
  14  * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 
  15  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 
  16  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 
  17  * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 
  18  * Please see the License for the specific language governing rights and 
  19  * limitations under the License. 
  21  * @APPLE_LICENSE_HEADER_END@ 
  25  * CMSEncoder.c - encode, sign, and/or encrypt CMS messages. 
  28 #include "CMSEncoder.h" 
  30 #include <Security/SecBase.h> 
  31 #include <Security/SecCmsEncoder.h> 
  32 #include <Security/SecCmsEnvelopedData.h> 
  33 #include <Security/SecCmsMessage.h> 
  34 #include <Security/SecCmsRecipientInfo.h> 
  35 #include <Security/SecCmsSignedData.h> 
  36 #include <Security/SecCmsSignerInfo.h> 
  37 #include <Security/SecCmsContentInfo.h> 
  38 #include <Security/SecCertificate.h> 
  39 #include <Security/SecIdentity.h> 
  40 #include <Security/SecSMIME.h> 
  41 #include <Security/oidsattr.h> 
  42 #include <Security/SecAsn1Coder.h> 
  43 #include <Security/SecAsn1Types.h> 
  44 #include <Security/SecAsn1Templates.h> 
  45 #include <CoreFoundation/CFRuntime.h> 
  47 #include <utilities/SecCFRelease.h> 
  49 #include <security_smime/cmspriv.h> 
  51 #if TIMESTAMPING_SUPPORTED 
  52 #include <security_smime/tsaSupport.h> 
  55 #pragma mark --- Private types and definitions --- 
  61     ES_Init
,            /* between CMSEncoderCreate and earlier of CMSEncoderUpdateContent 
  62                      *   and CMSEncodeGetCmsMessage */ 
  63     ES_Msg
,                     /* created cmsMsg in CMSEncodeGetCmsMessage, but no encoder yet */ 
  64     ES_Updating
,        /* between first CMSEncoderUpdateContent and CMSEncoderCopyEncodedContent */ 
  65     ES_Final            
/* CMSEncoderCopyEncodedContent has been called */ 
  69  * High-level operation: what are we doing? 
  78  * Caller's CMSEncoderRef points to one of these. 
  82     CMSEncoderState             encState
; 
  84     Boolean                             detachedContent
; 
  85     SecAsn1Oid          eContentType
; 
  86     CFMutableArrayRef   signers
; 
  87     CFMutableArrayRef   recipients
; 
  88     CFMutableArrayRef   otherCerts
; 
  89     CMSSignedAttributes signedAttributes
; 
  90     CFAbsoluteTime              signingTime
; 
  91     SecCmsMessageRef    cmsMsg
;                         /* the encoder's arena */ 
  92     SecCmsEncoderRef    encoder
; 
  93     CFMutableDataRef    encoderOut
;                             /* output goes here... */ 
  94     bool                                customCoder
;                    /* unless this is set by 
  95                                                  *    CMSEncoderSetEncoder */ 
  96     SECOidTag           digestalgtag
; 
  98     CMSCertificateChainMode chainMode
; 
  99     CFDataRef           hashAgilityAttrValue
; 
 102 static void cmsEncoderInit(CFTypeRef enc
); 
 103 static void cmsEncoderFinalize(CFTypeRef enc
); 
 105 static CFRuntimeClass cmsEncoderRuntimeClass 
= 
 112     NULL
,               /* equal - just use pointer equality */ 
 113     NULL
,               /* hash, ditto */ 
 114     NULL
,               /* copyFormattingDesc */ 
 115     NULL                
/* copyDebugDesc */ 
 118 #if TIMESTAMPING_SUPPORTED 
 119 void CmsMessageSetTSACallback(CMSEncoderRef cmsEncoder
, SecCmsTSACallback tsaCallback
); 
 122 #pragma mark --- Private routines --- 
 125  * Decode a CFStringRef representation of an integer 
 127 static int cfStringToNumber( 
 132     if (!inStr 
|| !CFStringGetCString(inStr
, buf
, max
-1, kCFStringEncodingASCII
)) 
 138  * Encode an integer component of an OID, return resulting number of bytes; 
 139  * actual bytes are mallocd and returned in *encodeArray. 
 141 static unsigned encodeNumber( 
 143                              unsigned char **encodeArray
)               // mallocd and RETURNED 
 145     unsigned char *result
; 
 147     unsigned numDigits 
= 0; 
 150     /* trival case - 0 maps to 0 */ 
 152         *encodeArray 
= (unsigned char *)malloc(1); 
 157     /* first calculate the number of digits in num, base 128 */ 
 158     scratch 
= (unsigned)num
; 
 159     while(scratch 
!= 0) { 
 164     result 
= (unsigned char *)malloc(numDigits
); 
 165     scratch 
= (unsigned)num
; 
 166     for(dex
=0; dex
<numDigits
; dex
++) { 
 167         result
[numDigits 
- dex 
- 1] = scratch 
& 0x7f; 
 171     /* all digits except the last one have m.s. bit set */ 
 172     for(dex
=0; dex
<(numDigits 
- 1); dex
++) { 
 176     *encodeArray 
= result
; 
 181  * Given an OID in dotted-decimal string representation, convert to binary 
 182  * DER format. Returns a pointer in outOid which the caller must free(), 
 183  * as well as the length of the data in outLen. 
 184  * Function returns 0 if successful, non-zero otherwise. 
 186 static int encodeOid( 
 187                      const unsigned char *inStr
, 
 188                      unsigned char **outOid
, 
 189                      unsigned int *outLen
) 
 191     unsigned char **digits 
= NULL
;              /* array of char * from encodeNumber */ 
 192     unsigned *numDigits 
= NULL
;                 /* array of unsigned from encodeNumber */ 
 194     unsigned numDigitBytes
;                             /* total #of output chars */ 
 195     unsigned char firstByte
; 
 197     CFIndex numsToProcess
; 
 198     CFStringRef oidStr 
= NULL
; 
 199     CFArrayRef argvRef 
= NULL
; 
 203     /* parse input string into array of substrings */ 
 204     if (!inStr 
|| !outOid 
|| !outLen
) goto cleanExit
; 
 205     oidStr 
= CFStringCreateWithCString(NULL
, (const char *)inStr
, kCFStringEncodingASCII
); 
 206     if (!oidStr
) goto cleanExit
; 
 207     argvRef 
= CFStringCreateArrayBySeparatingStrings(NULL
, oidStr
, CFSTR(".")); 
 208     if (!argvRef
) goto cleanExit
; 
 209     argc 
= CFArrayGetCount(argvRef
); 
 210     if (argc 
< 3) goto cleanExit
; 
 212     /* first two numbers in OID munge together */ 
 213     num 
= cfStringToNumber((CFStringRef
)CFArrayGetValueAtIndex(argvRef
, 0)); 
 214     if (num 
< 0) goto cleanExit
; 
 215     firstByte 
= (40 * num
); 
 216     num 
= cfStringToNumber((CFStringRef
)CFArrayGetValueAtIndex(argvRef
, 1)); 
 217     if (num 
< 0) goto cleanExit
; 
 221     numsToProcess 
= argc 
- 2; 
 222     if(numsToProcess 
> 0) { 
 223         /* skip this loop in the unlikely event that input is only two numbers */ 
 224         digits 
= (unsigned char **) malloc(numsToProcess 
* sizeof(unsigned char *)); 
 225         numDigits 
= (unsigned *) malloc(numsToProcess 
* sizeof(unsigned)); 
 226         for(digit
=0; digit
<numsToProcess
; digit
++) { 
 227             num 
= cfStringToNumber((CFStringRef
)CFArrayGetValueAtIndex(argvRef
, digit
+2)); 
 228             if (num 
< 0) goto cleanExit
; 
 229             numDigits
[digit
] = encodeNumber(num
, &digits
[digit
]); 
 230             numDigitBytes 
+= numDigits
[digit
]; 
 233     *outLen 
= (2 + numDigitBytes
); 
 234     *outOid 
= outP 
= (unsigned char *) malloc(*outLen
); 
 236     *outP
++ = numDigitBytes
; 
 238     for(digit
=0; digit
<numsToProcess
; digit
++) { 
 239         unsigned int byteDex
; 
 240         for(byteDex
=0; byteDex
<numDigits
[digit
]; byteDex
++) { 
 241             *outP
++ = digits
[digit
][byteDex
]; 
 245         for(digit
=0; digit
<numsToProcess
; digit
++) { 
 252     if (digits
) free(digits
); 
 253     if (numDigits
) free(numDigits
); 
 254     if (oidStr
) CFRelease(oidStr
); 
 255     if (argvRef
) CFRelease(argvRef
); 
 261  * Given a CF object reference describing an OID, convert to binary DER format 
 262  * and fill out the CSSM_OID structure provided by the caller. Caller is 
 263  * responsible for freeing the data pointer in outOid->Data. 
 265  * Function returns 0 if successful, non-zero otherwise. 
 268 static int convertOid( 
 272     if (!inRef 
|| !outOid
) 
 275     unsigned char *oidData 
= NULL
; 
 276     unsigned int oidLen 
= 0; 
 278     if (CFGetTypeID(inRef
) == CFStringGetTypeID()) { 
 279         // CFStringRef: OID representation is a dotted-decimal string 
 280         CFStringRef inStr 
= (CFStringRef
)inRef
; 
 281         CFIndex max 
= CFStringGetLength(inStr
) * 3; 
 283         if (!CFStringGetCString(inStr
, buf
, max
-1, kCFStringEncodingASCII
)) 
 286         if(encodeOid((unsigned char *)buf
, &oidData
, &oidLen
) != 0) 
 289     else if (CFGetTypeID(inRef
) == CFDataGetTypeID()) { 
 290         // CFDataRef: OID representation is in binary DER format 
 291         CFDataRef inData 
= (CFDataRef
)inRef
; 
 292         oidLen 
= (unsigned int) CFDataGetLength(inData
); 
 293         oidData 
= (unsigned char *) malloc(oidLen
); 
 294         memcpy(oidData
, CFDataGetBytePtr(inData
), oidLen
); 
 297         // Not in a format we understand 
 300     outOid
->Length 
= oidLen
; 
 301     outOid
->Data 
= (uint8_t *)oidData
; 
 305 static CFTypeID cmsEncoderTypeID 
= _kCFRuntimeNotATypeID
; 
 307 /* one time only class init, called via pthread_once() in CMSEncoderGetTypeID() */ 
 308 static void cmsEncoderClassInitialize(void) 
 311     _CFRuntimeRegisterClass((const CFRuntimeClass 
* const)&cmsEncoderRuntimeClass
); 
 314 /* init called out from _CFRuntimeCreateInstance() */ 
 315 static void cmsEncoderInit(CFTypeRef enc
) 
 317     char *start 
= ((char *)enc
) + sizeof(CFRuntimeBase
); 
 318     memset(start
, 0, sizeof(struct _CMSEncoder
) - sizeof(CFRuntimeBase
)); 
 322  * Dispose of a CMSEncoder. Called out from CFRelease(). 
 324 static void cmsEncoderFinalize( 
 327     CMSEncoderRef cmsEncoder 
= (CMSEncoderRef
)enc
; 
 328     if(cmsEncoder 
== NULL
) { 
 331     if(cmsEncoder
->eContentType
.Data 
!= NULL
) { 
 332         free(cmsEncoder
->eContentType
.Data
); 
 334     CFRELEASE(cmsEncoder
->signers
); 
 335     CFRELEASE(cmsEncoder
->recipients
); 
 336     CFRELEASE(cmsEncoder
->otherCerts
); 
 337     if(cmsEncoder
->cmsMsg 
!= NULL
) { 
 338         SecCmsMessageDestroy(cmsEncoder
->cmsMsg
); 
 339         cmsEncoder
->cmsMsg 
= NULL
; 
 341     if(cmsEncoder
->encoder 
!= NULL
) { 
 343          * Normally this gets freed in SecCmsEncoderFinish - this is 
 346         SecCmsEncoderDestroy(cmsEncoder
->encoder
); 
 350 static OSStatus 
cmsSetupEncoder( 
 351                                 CMSEncoderRef           cmsEncoder
) 
 355     ASSERT(cmsEncoder
->arena 
== NULL
); 
 356     ASSERT(cmsEncoder
->encoder 
== NULL
); 
 358     cmsEncoder
->encoderOut 
= CFDataCreateMutable(NULL
, 0); 
 359     if (!cmsEncoder
->encoderOut
) { 
 360         return errSecAllocate
; 
 363     ortn 
= SecCmsEncoderCreate(cmsEncoder
->cmsMsg
, 
 364                                NULL
, NULL
,                                      // no callback 
 365                                cmsEncoder
->encoderOut
,      // data goes here 
 366                                NULL
, NULL
,                                      // no password callback (right?) 
 367                                NULL
, NULL
,                                      // decrypt key callback 
 368                                &cmsEncoder
->encoder
); 
 370         return cmsRtnToOSStatus(ortn
); 
 372     return errSecSuccess
; 
 376  * Set up a SecCmsMessageRef for a SignedData creation. 
 378 static OSStatus 
cmsSetupForSignedData( 
 379                                       CMSEncoderRef             cmsEncoder
) 
 381     ASSERT((cmsEncoder
->signers 
!= NULL
) || (cmsEncoder
->otherCerts 
!= NULL
)); 
 383     SecCmsContentInfoRef contentInfo 
= NULL
; 
 384     SecCmsSignedDataRef signedData 
= NULL
; 
 387     /* build chain of objects: message->signedData->data */ 
 388     if(cmsEncoder
->cmsMsg 
!= NULL
) { 
 389         SecCmsMessageDestroy(cmsEncoder
->cmsMsg
); 
 391     cmsEncoder
->cmsMsg 
= SecCmsMessageCreate(); 
 392     if(cmsEncoder
->cmsMsg 
== NULL
) { 
 393         return errSecInternalComponent
; 
 396     signedData 
= SecCmsSignedDataCreate(cmsEncoder
->cmsMsg
); 
 397     if(signedData 
== NULL
) { 
 398         return errSecInternalComponent
; 
 400     contentInfo 
= SecCmsMessageGetContentInfo(cmsEncoder
->cmsMsg
); 
 401     ortn 
= SecCmsContentInfoSetContentSignedData(contentInfo
,signedData
); 
 403         return cmsRtnToOSStatus(ortn
); 
 405     contentInfo 
= SecCmsSignedDataGetContentInfo(signedData
); 
 406     if(cmsEncoder
->eContentType
.Data 
!= NULL
) { 
 407         /* Override the default eContentType of id-data */ 
 408         ortn 
= SecCmsContentInfoSetContentOther(contentInfo
, 
 409                                                 NULL
,           /* data - provided to encoder, not here */ 
 410                                                 cmsEncoder
->detachedContent
, 
 411                                                 &cmsEncoder
->eContentType
); 
 414         ortn 
= SecCmsContentInfoSetContentData(contentInfo
, 
 415                                                NULL
, /* data - provided to encoder, not here */ 
 416                                                cmsEncoder
->detachedContent
); 
 419         ortn 
= cmsRtnToOSStatus(ortn
); 
 420         CSSM_PERROR("SecCmsContentInfoSetContent*", ortn
); 
 424     /* optional 'global' (per-SignedData) certs */ 
 425     if(cmsEncoder
->otherCerts 
!= NULL
) { 
 426         ortn 
= SecCmsSignedDataAddCertList(signedData
, cmsEncoder
->otherCerts
); 
 428             ortn 
= cmsRtnToOSStatus(ortn
); 
 429             CSSM_PERROR("SecCmsSignedDataAddCertList", ortn
); 
 434     /* SignerInfos, one per signer */ 
 435     CFIndex numSigners 
= 0; 
 436     if(cmsEncoder
->signers 
!= NULL
) { 
 437         /* this is optional...in case we're just creating a cert bundle */ 
 438         numSigners 
= CFArrayGetCount(cmsEncoder
->signers
); 
 441     SecCertificateRef ourCert 
= NULL
; 
 442     SecCmsCertChainMode chainMode 
= SecCmsCMCertChain
; 
 444     switch(cmsEncoder
->chainMode
) { 
 445         case kCMSCertificateNone
: 
 446             chainMode 
= SecCmsCMNone
; 
 448         case kCMSCertificateSignerOnly
: 
 449             chainMode 
= SecCmsCMCertOnly
; 
 451         case kCMSCertificateChainWithRoot
: 
 452             chainMode 
= SecCmsCMCertChainWithRoot
; 
 457     for(dex
=0; dex
<numSigners
; dex
++) { 
 458         SecCmsSignerInfoRef signerInfo
; 
 460         SecIdentityRef ourId 
= 
 461         (SecIdentityRef
)CFArrayGetValueAtIndex(cmsEncoder
->signers
, dex
); 
 462         ortn 
= SecIdentityCopyCertificate(ourId
, &ourCert
); 
 464             CSSM_PERROR("SecIdentityCopyCertificate", ortn
); 
 467         /* this creates the signerInfo and adds it to the signedData object */ 
 468         signerInfo 
= SecCmsSignerInfoCreate(signedData
, ourId
, cmsEncoder
->digestalgtag
); 
 469         if (signerInfo 
== NULL
) { 
 470             ortn 
= errSecInternalComponent
; 
 474         /* we want the cert chain included for this one */ 
 475         /* NOTE the usage parameter is currently unused by the SMIME lib */ 
 476         ortn 
= SecCmsSignerInfoIncludeCerts(signerInfo
, chainMode
, 
 477                                             certUsageEmailSigner
); 
 479             ortn 
= cmsRtnToOSStatus(ortn
); 
 480             CSSM_PERROR("SecCmsSignerInfoIncludeCerts", ortn
); 
 485         if(cmsEncoder
->signedAttributes 
& kCMSAttrSmimeCapabilities
) { 
 486             ortn 
= SecCmsSignerInfoAddSMIMECaps(signerInfo
); 
 488                 ortn 
= cmsRtnToOSStatus(ortn
); 
 489                 CSSM_PERROR("SecCmsSignerInfoAddSMIMEEncKeyPrefs", ortn
); 
 493         if(cmsEncoder
->signedAttributes 
& kCMSAttrSmimeEncryptionKeyPrefs
) { 
 494             ortn 
= SecCmsSignerInfoAddSMIMEEncKeyPrefs(signerInfo
, ourCert
, NULL
); 
 496                 ortn 
= cmsRtnToOSStatus(ortn
); 
 497                 CSSM_PERROR("SecCmsSignerInfoAddSMIMEEncKeyPrefs", ortn
); 
 501         if(cmsEncoder
->signedAttributes 
& kCMSAttrSmimeMSEncryptionKeyPrefs
) { 
 502             ortn 
= SecCmsSignerInfoAddMSSMIMEEncKeyPrefs(signerInfo
, ourCert
, NULL
); 
 504                 ortn 
= cmsRtnToOSStatus(ortn
); 
 505                 CSSM_PERROR("SecCmsSignerInfoAddMSSMIMEEncKeyPrefs", ortn
); 
 509         if(cmsEncoder
->signedAttributes 
& kCMSAttrSigningTime
) { 
 510             if (cmsEncoder
->signingTime 
== 0) 
 511                 cmsEncoder
->signingTime 
= CFAbsoluteTimeGetCurrent(); 
 512             ortn 
= SecCmsSignerInfoAddSigningTime(signerInfo
, cmsEncoder
->signingTime
); 
 514                 ortn 
= cmsRtnToOSStatus(ortn
); 
 515                 CSSM_PERROR("SecCmsSignerInfoAddSigningTime", ortn
); 
 519         if(cmsEncoder
->signedAttributes 
& kCMSAttrAppleCodesigningHashAgility
) { 
 520             ortn 
= SecCmsSignerInfoAddAppleCodesigningHashAgility(signerInfo
, cmsEncoder
->hashAgilityAttrValue
); 
 521             /* libsecurity_smime made a copy of the attribute value. We don't need it anymore. */ 
 522             CFReleaseNull(cmsEncoder
->hashAgilityAttrValue
); 
 524                 ortn 
= cmsRtnToOSStatus(ortn
); 
 525                 CSSM_PERROR("SecCmsSignerInfoAddAppleCodesigningHashAgility", ortn
); 
 540  * Set up a SecCmsMessageRef for a EnvelopedData creation. 
 542 static OSStatus 
cmsSetupForEnvelopedData( 
 543                                          CMSEncoderRef          cmsEncoder
) 
 545     ASSERT(cmsEncoder
->op 
== EO_Encrypt
); 
 546     ASSERT(cmsEncoder
->recipients 
!= NULL
); 
 548     SecCmsContentInfoRef contentInfo 
= NULL
; 
 549     SecCmsEnvelopedDataRef envelopedData 
= NULL
; 
 550     SECOidTag algorithmTag
; 
 555      * Find encryption algorithm...unfortunately we need a NULL-terminated array 
 556      * of SecCertificateRefs for this. 
 558     CFIndex numCerts 
= CFArrayGetCount(cmsEncoder
->recipients
); 
 560     SecCertificateRef 
*certArray 
= (SecCertificateRef 
*)malloc( 
 561                                                                (numCerts
+1) * sizeof(SecCertificateRef
)); 
 563     for(dex
=0; dex
<numCerts
; dex
++) { 
 564         certArray
[dex
] = (SecCertificateRef
)CFArrayGetValueAtIndex( 
 565                                                                    cmsEncoder
->recipients
, dex
); 
 567     certArray
[numCerts
] = NULL
; 
 568     ortn 
= SecSMIMEFindBulkAlgForRecipients(certArray
, &algorithmTag
, &keySize
); 
 571         CSSM_PERROR("SecSMIMEFindBulkAlgForRecipients", ortn
); 
 575     /* build chain of objects: message->envelopedData->data */ 
 576     if(cmsEncoder
->cmsMsg 
!= NULL
) { 
 577         SecCmsMessageDestroy(cmsEncoder
->cmsMsg
); 
 579     cmsEncoder
->cmsMsg 
= SecCmsMessageCreate(); 
 580     if(cmsEncoder
->cmsMsg 
== NULL
) { 
 581         return errSecInternalComponent
; 
 583     envelopedData 
= SecCmsEnvelopedDataCreate(cmsEncoder
->cmsMsg
, 
 584                                               algorithmTag
, keySize
); 
 585     if(envelopedData 
== NULL
) { 
 586         return errSecInternalComponent
; 
 588     contentInfo 
= SecCmsMessageGetContentInfo(cmsEncoder
->cmsMsg
); 
 589     ortn 
= SecCmsContentInfoSetContentEnvelopedData(contentInfo
, envelopedData
); 
 591         ortn 
= cmsRtnToOSStatus(ortn
); 
 592         CSSM_PERROR("SecCmsContentInfoSetContentEnvelopedData", ortn
); 
 595     contentInfo 
= SecCmsEnvelopedDataGetContentInfo(envelopedData
); 
 596     if(cmsEncoder
->eContentType
.Data 
!= NULL
) { 
 597         /* Override the default ContentType of id-data */ 
 598         ortn 
= SecCmsContentInfoSetContentOther(contentInfo
, 
 599                                                 NULL
,           /* data - provided to encoder, not here */ 
 600                                                 FALSE
,          /* detachedContent */ 
 601                                                 &cmsEncoder
->eContentType
); 
 604         ortn 
= SecCmsContentInfoSetContentData(contentInfo
, 
 605                                                NULL 
/* data - provided to encoder, not here */, 
 606                                                cmsEncoder
->detachedContent
); 
 609         ortn 
= cmsRtnToOSStatus(ortn
); 
 610         CSSM_PERROR("SecCmsContentInfoSetContentData*", ortn
); 
 615      * create & attach recipient information, one for each recipient 
 617     for(dex
=0; dex
<numCerts
; dex
++) { 
 618         SecCmsRecipientInfoRef recipientInfo 
= NULL
; 
 620         SecCertificateRef thisRecip 
= (SecCertificateRef
)CFArrayGetValueAtIndex( 
 621                                                                                 cmsEncoder
->recipients
, dex
); 
 622         recipientInfo 
= SecCmsRecipientInfoCreate(envelopedData
, thisRecip
); 
 623         ortn 
= SecCmsEnvelopedDataAddRecipient(envelopedData
, recipientInfo
); 
 625             ortn 
= cmsRtnToOSStatus(ortn
); 
 626             CSSM_PERROR("SecCmsEnvelopedDataAddRecipient", ortn
); 
 630     return errSecSuccess
; 
 634  * Set up cmsMsg. Called from either the first call to CMSEncoderUpdateContent, or 
 635  * from CMSEncodeGetCmsMessage(). 
 637 static OSStatus 
cmsSetupCmsMsg( 
 638                                CMSEncoderRef            cmsEncoder
) 
 640     ASSERT(cmsEncoder 
!= NULL
); 
 641     ASSERT(cmsEncoder
->encState 
== ES_Init
); 
 643     /* figure out what high-level operation we're doing */ 
 644     if((cmsEncoder
->signers 
!= NULL
) || (cmsEncoder
->otherCerts 
!= NULL
)) { 
 645         if(cmsEncoder
->recipients 
!= NULL
) { 
 646             cmsEncoder
->op 
= EO_SignEncrypt
; 
 649             cmsEncoder
->op 
= EO_Sign
; 
 652     else if(cmsEncoder
->recipients 
!= NULL
) { 
 653         cmsEncoder
->op 
= EO_Encrypt
; 
 656         dprintf("CMSEncoderUpdateContent: nothing to do\n"); 
 660     OSStatus ortn 
= errSecSuccess
; 
 662     switch(cmsEncoder
->op
) { 
 665             /* If we're signing & encrypting, do the signing first */ 
 666             ortn 
= cmsSetupForSignedData(cmsEncoder
); 
 669             ortn 
= cmsSetupForEnvelopedData(cmsEncoder
); 
 672     cmsEncoder
->encState 
= ES_Msg
; 
 677  * ASN.1 template for decoding a ContentInfo. 
 680     SecAsn1Oid  contentType
; 
 684 static const SecAsn1Template cmsSimpleContentInfoTemplate
[] = { 
 685     { SEC_ASN1_SEQUENCE
, 0, NULL
, sizeof(SimpleContentInfo
) }, 
 686     { SEC_ASN1_OBJECT_ID
, offsetof(SimpleContentInfo
, contentType
) }, 
 687     { SEC_ASN1_EXPLICIT 
| SEC_ASN1_CONSTRUCTED 
| SEC_ASN1_CONTEXT_SPECIFIC 
| 0, 
 688         offsetof(SimpleContentInfo
, content
), 
 689         kSecAsn1AnyTemplate 
}, 
 694  * Obtain the content of a contentInfo, This basically strips off the contentType OID 
 695  * and returns its ASN_ANY content, allocated the provided coder's memory space. 
 697 static OSStatus 
cmsContentInfoContent( 
 698                                       SecAsn1CoderRef asn1Coder
, 
 699                                       const SecAsn1Item 
*contentInfo
, 
 700                                       SecAsn1Item 
*content
)                             /* RETURNED */ 
 703     SimpleContentInfo decodedInfo
; 
 705     memset(&decodedInfo
, 0, sizeof(decodedInfo
)); 
 706     ortn 
= SecAsn1DecodeData(asn1Coder
, contentInfo
, 
 707                              cmsSimpleContentInfoTemplate
, &decodedInfo
); 
 711     if(decodedInfo
.content
.Data 
== NULL
) { 
 712         dprintf("***Error decoding contentInfo: no content\n"); 
 713         return errSecInternalComponent
; 
 715     *content 
= decodedInfo
.content
; 
 716     return errSecSuccess
; 
 719 #pragma mark --- Start of Public API --- 
 721 CFTypeID 
CMSEncoderGetTypeID(void) 
 723     static pthread_once_t once 
= PTHREAD_ONCE_INIT
; 
 725     if(cmsEncoderTypeID 
== _kCFRuntimeNotATypeID
) { 
 726         pthread_once(&once
, &cmsEncoderClassInitialize
); 
 728     return cmsEncoderTypeID
; 
 732  * Create a CMSEncoder. Result must eventually be freed via CFRelease(). 
 734 OSStatus 
CMSEncoderCreate( 
 735                           CMSEncoderRef         
*cmsEncoderOut
) /* RETURNED */ 
 737     CMSEncoderRef cmsEncoder 
= NULL
; 
 739     uint32_t extra 
= sizeof(*cmsEncoder
) - sizeof(cmsEncoder
->base
); 
 740     cmsEncoder 
= (CMSEncoderRef
)_CFRuntimeCreateInstance(NULL
, CMSEncoderGetTypeID(), 
 742     if(cmsEncoder 
== NULL
) { 
 743         return errSecAllocate
; 
 745     cmsEncoder
->encState 
= ES_Init
; 
 746     cmsEncoder
->chainMode 
= kCMSCertificateChain
; 
 747     cmsEncoder
->digestalgtag 
= SEC_OID_SHA1
; 
 748     *cmsEncoderOut 
= cmsEncoder
; 
 749     return errSecSuccess
; 
 752 #pragma mark --- Getters & Setters --- 
 754 const CFStringRef __nonnull kCMSEncoderDigestAlgorithmSHA1 
= CFSTR("sha1"); 
 755 const CFStringRef __nonnull kCMSEncoderDigestAlgorithmSHA256 
= CFSTR("sha256"); 
 758 OSStatus 
CMSEncoderSetSignerAlgorithm( 
 759                                       CMSEncoderRef             cmsEncoder
, 
 760                                       CFStringRef               digestAlgorithm
) 
 762     if (CFEqual(digestAlgorithm
, kCMSEncoderDigestAlgorithmSHA1
)) { 
 763         cmsEncoder
->digestalgtag 
= SEC_OID_SHA1
; 
 764     } else if (CFEqual(digestAlgorithm
, kCMSEncoderDigestAlgorithmSHA256
)) { 
 765         cmsEncoder
->digestalgtag 
= SEC_OID_SHA256
; 
 770     return errSecSuccess
; 
 774  * Specify signers of the CMS message; implies that the message will be signed. 
 776 OSStatus 
CMSEncoderAddSigners( 
 777                               CMSEncoderRef             cmsEncoder
, 
 778                               CFTypeRef                 signerOrArray
) 
 780     if(cmsEncoder 
== NULL
) { 
 783     if(cmsEncoder
->encState 
!= ES_Init
) { 
 786     return cmsAppendToArray(signerOrArray
, &cmsEncoder
->signers
, SecIdentityGetTypeID()); 
 790  * Obtain an array of signers as specified in CMSEncoderSetSigners(). 
 792 OSStatus 
CMSEncoderCopySigners( 
 793                                CMSEncoderRef            cmsEncoder
, 
 796     if((cmsEncoder 
== NULL
) || (signers 
== NULL
)) { 
 799     if(cmsEncoder
->signers 
!= NULL
) { 
 800         CFRetain(cmsEncoder
->signers
); 
 802     *signers 
= cmsEncoder
->signers
; 
 803     return errSecSuccess
; 
 807  * Specify recipients of the message. Implies that the message will be encrypted. 
 809 OSStatus 
CMSEncoderAddRecipients( 
 810                                  CMSEncoderRef          cmsEncoder
, 
 811                                  CFTypeRef                      recipientOrArray
) 
 813     if(cmsEncoder 
== NULL
) { 
 816     if(cmsEncoder
->encState 
!= ES_Init
) { 
 819     return cmsAppendToArray(recipientOrArray
, &cmsEncoder
->recipients
, 
 820                             SecCertificateGetTypeID()); 
 824  * Obtain an array of recipients as specified in CMSEncoderSetRecipients(). 
 826 OSStatus 
CMSEncoderCopyRecipients( 
 827                                   CMSEncoderRef         cmsEncoder
, 
 828                                   CFArrayRef                    
*recipients
) 
 830     if((cmsEncoder 
== NULL
) || (recipients 
== NULL
)) { 
 833     if(cmsEncoder
->recipients 
!= NULL
) { 
 834         CFRetain(cmsEncoder
->recipients
); 
 836     *recipients 
= cmsEncoder
->recipients
; 
 837     return errSecSuccess
; 
 841  * Specify additional certs to include in a signed message. 
 843 OSStatus 
CMSEncoderAddSupportingCerts( 
 844                                       CMSEncoderRef             cmsEncoder
, 
 845                                       CFTypeRef                 certOrArray
) 
 847     if(cmsEncoder 
== NULL
) { 
 850     if(cmsEncoder
->encState 
!= ES_Init
) { 
 853     return cmsAppendToArray(certOrArray
, &cmsEncoder
->otherCerts
, 
 854                             SecCertificateGetTypeID()); 
 858  * Obtain the SecCertificates provided in CMSEncoderAddSupportingCerts(). 
 860 OSStatus 
CMSEncoderCopySupportingCerts( 
 861                                        CMSEncoderRef            cmsEncoder
, 
 862                                        CFArrayRef                       
*certs
)                 /* RETURNED */ 
 864     if((cmsEncoder 
== NULL
) || (certs 
== NULL
)) { 
 867     if(cmsEncoder
->otherCerts 
!= NULL
) { 
 868         CFRetain(cmsEncoder
->otherCerts
); 
 870     *certs 
= cmsEncoder
->otherCerts
; 
 871     return errSecSuccess
; 
 874 OSStatus 
CMSEncoderSetHasDetachedContent( 
 875                                          CMSEncoderRef          cmsEncoder
, 
 876                                          Boolean                                detachedContent
) 
 878     if(cmsEncoder 
== NULL
) { 
 881     if(cmsEncoder
->encState 
!= ES_Init
) { 
 884     cmsEncoder
->detachedContent 
= detachedContent
; 
 885     return errSecSuccess
; 
 888 OSStatus 
CMSEncoderGetHasDetachedContent( 
 889                                          CMSEncoderRef          cmsEncoder
, 
 890                                          Boolean                                
*detachedContent
)       /* RETURNED */ 
 892     if((cmsEncoder 
== NULL
) || (detachedContent 
== NULL
)) { 
 895     *detachedContent 
= cmsEncoder
->detachedContent
; 
 896     return errSecSuccess
; 
 900  * Optionally specify an eContentType OID for the inner EncapsulatedData for 
 901  * a signed message. The default eContentType, used of this function is not 
 902  * called, is id-data. 
 904 static OSStatus 
CMSEncoderSetEncapsulatedContentType( 
 905                                               CMSEncoderRef             cmsEncoder
, 
 906                                               const SecAsn1Oid  
*eContentType
) 
 908     if((cmsEncoder 
== NULL
) || (eContentType 
== NULL
)) { 
 911     if(cmsEncoder
->encState 
!= ES_Init
) { 
 915     SecAsn1Oid 
*ecOid 
= &cmsEncoder
->eContentType
; 
 916     if(ecOid
->Data 
!= NULL
) { 
 919     cmsCopyCmsData(eContentType
, ecOid
); 
 920     return errSecSuccess
; 
 923 OSStatus 
CMSEncoderSetEncapsulatedContentTypeOID( 
 924                                                  CMSEncoderRef          cmsEncoder
, 
 925                                                  CFTypeRef                      eContentTypeOID
) 
 927     // convert eContentTypeOID to a CSSM_OID 
 928     SecAsn1Oid contentType 
= { 0, NULL 
}; 
 929     if (!eContentTypeOID 
|| convertOid(eContentTypeOID
, &contentType
) != 0) 
 931     OSStatus result 
= CMSEncoderSetEncapsulatedContentType(cmsEncoder
, &contentType
); 
 932     if (contentType
.Data
) 
 933         free(contentType
.Data
); 
 938  * Obtain the eContentType OID specified in CMSEncoderSetEncapsulatedContentType(). 
 940 OSStatus 
CMSEncoderCopyEncapsulatedContentType( 
 941                                                CMSEncoderRef            cmsEncoder
, 
 942                                                CFDataRef                        
*eContentType
) 
 944     if((cmsEncoder 
== NULL
) || (eContentType 
== NULL
)) { 
 948     SecAsn1Oid 
*ecOid 
= &cmsEncoder
->eContentType
; 
 949     if(ecOid
->Data 
== NULL
) { 
 950         *eContentType 
= NULL
; 
 953         *eContentType 
= CFDataCreate(NULL
, ecOid
->Data
, ecOid
->Length
); 
 955     return errSecSuccess
; 
 959  * Optionally specify signed attributes. Only meaningful when creating a 
 960  * signed message. If this is called, it must be called before 
 961  * CMSEncoderUpdateContent(). 
 963 OSStatus 
CMSEncoderAddSignedAttributes( 
 964                                        CMSEncoderRef            cmsEncoder
, 
 965                                        CMSSignedAttributes      signedAttributes
) 
 967     if(cmsEncoder 
== NULL
) { 
 970     if(cmsEncoder
->encState 
!= ES_Init
) { 
 973     cmsEncoder
->signedAttributes 
|= signedAttributes
; 
 974     return errSecSuccess
; 
 978  * Set the signing time for a CMSEncoder. 
 979  * This is only used if the kCMSAttrSigningTime attribute is included. 
 981 OSStatus 
CMSEncoderSetSigningTime( 
 982                                   CMSEncoderRef         cmsEncoder
, 
 985     if(cmsEncoder 
== NULL
) { 
 988     if(cmsEncoder
->encState 
!= ES_Init
) { 
 991     cmsEncoder
->signingTime 
= time
; 
 992     return errSecSuccess
; 
 996  * Set the hash agility attribute for a CMSEncoder. 
 997  * This is only used if the kCMSAttrAppleCodesigningHashAgility attribute 
1000 OSStatus 
CMSEncoderSetAppleCodesigningHashAgility( 
1001                                                   CMSEncoderRef   cmsEncoder
, 
1002                                                   CFDataRef       hashAgilityAttrValue
) 
1004     if (cmsEncoder 
== NULL 
|| cmsEncoder
->encState 
!= ES_Init
) { 
1007     cmsEncoder
->hashAgilityAttrValue 
= CFRetainSafe(hashAgilityAttrValue
); 
1008     return errSecSuccess
; 
1011 OSStatus 
CMSEncoderSetCertificateChainMode( 
1012                                            CMSEncoderRef                        cmsEncoder
, 
1013                                            CMSCertificateChainMode      chainMode
) 
1015     if(cmsEncoder 
== NULL
) { 
1018     if(cmsEncoder
->encState 
!= ES_Init
) { 
1022         case kCMSCertificateNone
: 
1023         case kCMSCertificateSignerOnly
: 
1024         case kCMSCertificateChain
: 
1025         case kCMSCertificateChainWithRoot
: 
1030     cmsEncoder
->chainMode 
= chainMode
; 
1031     return errSecSuccess
; 
1034 OSStatus 
CMSEncoderGetCertificateChainMode( 
1035                                            CMSEncoderRef                        cmsEncoder
, 
1036                                            CMSCertificateChainMode      
*chainModeOut
) 
1038     if(cmsEncoder 
== NULL
) { 
1041     *chainModeOut 
= cmsEncoder
->chainMode
; 
1042     return errSecSuccess
; 
1045 #if TIMESTAMPING_SUPPORTED 
1047 CmsMessageSetTSACallback(CMSEncoderRef cmsEncoder
, SecCmsTSACallback tsaCallback
) 
1049     if (cmsEncoder
->cmsMsg
) 
1050         SecCmsMessageSetTSACallback(cmsEncoder
->cmsMsg
, tsaCallback
); 
1054 CmsMessageSetTSAContext(CMSEncoderRef cmsEncoder
, CFTypeRef tsaContext
) 
1056     if (cmsEncoder
->cmsMsg
) 
1057         SecCmsMessageSetTSAContext(cmsEncoder
->cmsMsg
, tsaContext
); 
1061 #pragma mark --- Action --- 
1064  * Feed content bytes into the encoder. 
1065  * Can be called multiple times. 
1066  * No 'setter' routines can be called after this function has been called. 
1068 OSStatus 
CMSEncoderUpdateContent( 
1069                                  CMSEncoderRef          cmsEncoder
, 
1070                                  const void                     *content
, 
1073     if(cmsEncoder 
== NULL
) { 
1077     OSStatus ortn 
= errSecSuccess
; 
1078     switch(cmsEncoder
->encState
) { 
1081              * First time thru: do the CmsMsg setup. 
1083             ortn 
= cmsSetupCmsMsg(cmsEncoder
); 
1087             /* fall thru to set up the encoder */ 
1090             /* We have a cmsMsg but no encoder; create one */ 
1091             ASSERT(cmsEncoder
->cmsMsg 
!= NULL
); 
1092             ASSERT(cmsEncoder
->encoder 
== NULL
); 
1093             ortn 
= cmsSetupEncoder(cmsEncoder
); 
1097             /* only legal calls now are update and finalize */ 
1098             cmsEncoder
->encState 
= ES_Updating
; 
1102             ASSERT(cmsEncoder
->encoder 
!= NULL
); 
1106             /* Too late for another update */ 
1110             return errSecInternalComponent
; 
1113     /* FIXME - CFIndex same size as size_t on 64bit? */ 
1114     ortn 
= SecCmsEncoderUpdate(cmsEncoder
->encoder
, content
, (CFIndex
)contentLen
); 
1116         ortn 
= cmsRtnToOSStatus(ortn
); 
1117         CSSM_PERROR("SecCmsEncoderUpdate", ortn
); 
1122 /* forward declaration */ 
1123 static OSStatus 
CMSEncode( 
1125                           CFTypeRef                     recipients
, 
1126                           const SecAsn1Oid              
*eContentType
, 
1127                           Boolean                               detachedContent
, 
1128                           CMSSignedAttributes   signedAttributes
, 
1129                           const void                    *content
, 
1131                           CFDataRef                     
*encodedContent
); 
1134  * Finish encoding the message and obtain the encoded result. 
1135  * Caller must CFRelease the result. 
1137 OSStatus 
CMSEncoderCopyEncodedContent( 
1138                                       CMSEncoderRef             cmsEncoder
, 
1139                                       CFDataRef                 
*encodedContent
) 
1141     if((cmsEncoder 
== NULL
) || (encodedContent 
== NULL
)) { 
1147     switch(cmsEncoder
->encState
) { 
1149             /* normal termination */ 
1152             /* already been called */ 
1157              * The only time these are legal is when we're doing a SignedData 
1158              * with certificates only (no signers, no content). 
1160             if((cmsEncoder
->signers 
!= NULL
) || 
1161                (cmsEncoder
->recipients 
!= NULL
) || 
1162                (cmsEncoder
->otherCerts 
== NULL
)) { 
1166             /* Set up for certs only */ 
1167             ortn 
= cmsSetupForSignedData(cmsEncoder
); 
1171             /* and an encoder */ 
1172             ortn 
= cmsSetupEncoder(cmsEncoder
); 
1180     ASSERT(cmsEncoder
->encoder 
!= NULL
); 
1181     ortn 
= SecCmsEncoderFinish(cmsEncoder
->encoder
); 
1182     /* regardless of the outcome, the encoder itself has been freed */ 
1183     cmsEncoder
->encoder 
= NULL
; 
1185         return cmsRtnToOSStatus(ortn
); 
1187     cmsEncoder
->encState 
= ES_Final
; 
1189     if((cmsEncoder
->encoderOut 
== NULL
) && !cmsEncoder
->customCoder
) { 
1190         /* not sure how this could happen... */ 
1191         dprintf("Successful encode, but no data\n"); 
1192         return errSecInternalComponent
; 
1194     if(cmsEncoder
->customCoder
) { 
1196         *encodedContent 
= NULL
; 
1197         return errSecSuccess
; 
1200     /* in two out of three cases, we're done */ 
1201     switch(cmsEncoder
->op
) { 
1204             *encodedContent 
= CFDataCreateCopy(NULL
, cmsEncoder
->encoderOut
); 
1205             return errSecSuccess
; 
1206         case EO_SignEncrypt
: 
1207             /* proceed, more work to do */ 
1212      * Signing & encrypting. 
1213      * Due to bugs in the libsecurity_smime encoder, it can't encode nested 
1214      * ContentInfos in one shot. So we do another pass, specifying the SignedData 
1215      * inside of the ContentInfo we just created as the data to encrypt. 
1217     SecAsn1CoderRef asn1Coder 
= NULL
; 
1218     SecAsn1Item signedData 
= {0, NULL
}; 
1220     ortn 
= SecAsn1CoderCreate(&asn1Coder
); 
1224     SecAsn1Item encoderOut 
= { CFDataGetLength(cmsEncoder
->encoderOut
), 
1225                                CFDataGetMutableBytePtr(cmsEncoder
->encoderOut
)}; 
1226     ortn 
= cmsContentInfoContent(asn1Coder
, &encoderOut
, &signedData
); 
1231     /* now just encrypt that, one-shot */ 
1232     ortn 
= CMSEncode(NULL
,                      /* no signers this time */ 
1233                      cmsEncoder
->recipients
, 
1234                      &CSSMOID_PKCS7_SignedData
, /* fake out encoder so it doesn't try to actually 
1235                                                  *   encode the signedData - this asserts the 
1236                                                  *   SEC_OID_OTHER OID tag in the EnvelopedData's 
1238                      FALSE
,                                             /* detachedContent */ 
1239                      kCMSAttrNone
,                              /* signedAttributes - none this time */ 
1240                      signedData
.Data
, signedData
.Length
, 
1245         SecAsn1CoderRelease(asn1Coder
); 
1250 #pragma mark --- High-level API --- 
1253  * High-level, one-shot encoder function. 
1255 static OSStatus 
CMSEncode( 
1257                    CFTypeRef                    recipients
, 
1258                    const SecAsn1Oid             
*eContentType
, 
1259                    Boolean                              detachedContent
, 
1260                    CMSSignedAttributes  signedAttributes
, 
1261                    const void                   *content
, 
1263                    CFDataRef                    
*encodedContent
)        /* RETURNED */ 
1265     if((signers 
== NULL
) && (recipients 
== NULL
)) { 
1268     if(encodedContent 
== NULL
) { 
1272     CMSEncoderRef cmsEncoder
; 
1275     /* set up the encoder */ 
1276     ortn 
= CMSEncoderCreate(&cmsEncoder
); 
1281     /* subsequent errors to errOut: */ 
1283         ortn 
= CMSEncoderAddSigners(cmsEncoder
, signers
); 
1289         ortn 
= CMSEncoderAddRecipients(cmsEncoder
, recipients
); 
1295         ortn 
= CMSEncoderSetEncapsulatedContentType(cmsEncoder
, eContentType
); 
1300     if(detachedContent
) { 
1301         ortn 
= CMSEncoderSetHasDetachedContent(cmsEncoder
, detachedContent
); 
1306     if(signedAttributes
) { 
1307         ortn 
= CMSEncoderAddSignedAttributes(cmsEncoder
, signedAttributes
); 
1313     ortn 
= CMSEncoderUpdateContent(cmsEncoder
, content
, contentLen
); 
1317     ortn 
= CMSEncoderCopyEncodedContent(cmsEncoder
, encodedContent
); 
1320     CFRelease(cmsEncoder
); 
1324 OSStatus 
CMSEncodeContent( 
1326                           CFTypeRef                     recipients
, 
1327                           CFTypeRef                     eContentTypeOID
, 
1328                           Boolean                               detachedContent
, 
1329                           CMSSignedAttributes   signedAttributes
, 
1330                           const void                    *content
, 
1332                           CFDataRef                     
*encodedContentOut
)     /* RETURNED */ 
1334     // convert eContentTypeOID to a CSSM_OID 
1335     SecAsn1Oid contentType 
= { 0, NULL 
}; 
1336     if (eContentTypeOID 
&& convertOid(eContentTypeOID
, &contentType
) != 0) 
1338     const SecAsn1Oid 
*contentTypePtr 
= (eContentTypeOID
) ? &contentType 
: NULL
; 
1339     OSStatus result 
= CMSEncode(signers
, recipients
, contentTypePtr
, 
1340                                 detachedContent
, signedAttributes
, 
1341                                 content
, contentLen
, encodedContentOut
); 
1342     if (contentType
.Data
) 
1343         free(contentType
.Data
); 
1347 #pragma mark --- SPI routines declared in CMSPrivate.h --- 
1350  * Obtain the SecCmsMessageRef associated with a CMSEncoderRef.  
1351  * If we don't have a SecCmsMessageRef yet, we create one now. 
1352  * This is the only place where we go to state ES_Msg.  
1354 OSStatus 
CMSEncoderGetCmsMessage( 
1355                                  CMSEncoderRef          cmsEncoder
, 
1356                                  SecCmsMessageRef       
*cmsMessage
)            /* RETURNED */ 
1358     if((cmsEncoder 
== NULL
) || (cmsMessage 
== NULL
)) { 
1361     if(cmsEncoder
->cmsMsg 
!= NULL
) { 
1362         ASSERT(cmsEncoder
->encState 
!= ES_Init
); 
1363         *cmsMessage 
= cmsEncoder
->cmsMsg
; 
1364         return errSecSuccess
; 
1367     OSStatus ortn 
= cmsSetupCmsMsg(cmsEncoder
); 
1371     *cmsMessage 
= cmsEncoder
->cmsMsg
; 
1373     /* Don't set up encoder yet; caller might do that via CMSEncoderSetEncoder */ 
1374     cmsEncoder
->encState 
= ES_Msg
; 
1375     return errSecSuccess
; 
1379  * Optionally specify a SecCmsEncoderRef to use with a CMSEncoderRef. 
1380  * If this is called, it must be called before the first call to  
1381  * CMSEncoderUpdateContent(). The CMSEncoderRef takes ownership of the 
1382  * incoming SecCmsEncoderRef. 
1384 OSStatus 
CMSEncoderSetEncoder( 
1385                               CMSEncoderRef             cmsEncoder
, 
1386                               SecCmsEncoderRef  encoder
) 
1388     if((cmsEncoder 
== NULL
) || (encoder 
== NULL
)) { 
1394     switch(cmsEncoder
->encState
) { 
1396             /* No message, no encoder */ 
1397             ASSERT(cmsEncoder
->cmsMsg 
== NULL
); 
1398             ASSERT(cmsEncoder
->encoder 
== NULL
); 
1399             ortn 
= cmsSetupCmsMsg(cmsEncoder
); 
1403             /* drop thru to set encoder */ 
1405             /* cmsMsg but no encoder */ 
1406             ASSERT(cmsEncoder
->cmsMsg 
!= NULL
); 
1407             ASSERT(cmsEncoder
->encoder 
== NULL
); 
1408             cmsEncoder
->encoder 
= encoder
; 
1409             cmsEncoder
->encState 
= ES_Updating
; 
1410             cmsEncoder
->customCoder 
= true;                     /* we won't see data */ 
1411             return errSecSuccess
; 
1413             /* no can do, too late */ 
1419  * Obtain the SecCmsEncoderRef associated with a CMSEncoderRef.  
1420  * Returns a NULL SecCmsEncoderRef if neither CMSEncoderSetEncoder nor 
1421  * CMSEncoderUpdateContent() has been called.  
1422  * The CMSEncoderRef retains ownership of the SecCmsEncoderRef. 
1424 OSStatus 
CMSEncoderGetEncoder( 
1425                               CMSEncoderRef             cmsEncoder
, 
1426                               SecCmsEncoderRef  
*encoder
)                       /* RETURNED */ 
1428     if((cmsEncoder 
== NULL
) || (encoder 
== NULL
)) { 
1432     /* any state, whether we have an encoder or not is OK */ 
1433     *encoder 
= cmsEncoder
->encoder
; 
1434     return errSecSuccess
; 
1437 #if TIMESTAMPING_SUPPORTED 
1438 #include <AssertMacros.h> 
1440  * Obtain the timestamp of signer 'signerIndex' of a CMS message, if 
1441  * present. This timestamp is an authenticated timestamp provided by 
1442  * a timestamping authority. 
1444  * Returns errSecParam if the CMS message was not signed or if signerIndex 
1445  * is greater than the number of signers of the message minus one.  
1447  * This cannot be called until after CMSEncoderCopyEncodedContent() is called.  
1449 OSStatus 
CMSEncoderCopySignerTimestamp( 
1450                                        CMSEncoderRef            cmsEncoder
, 
1451                                        size_t                           signerIndex
,        /* usually 0 */ 
1452                                        CFAbsoluteTime      
*timestamp
)                  /* RETURNED */ 
1454     return CMSEncoderCopySignerTimestampWithPolicy( 
1461 OSStatus 
CMSEncoderCopySignerTimestampWithPolicy( 
1462                                                  CMSEncoderRef          cmsEncoder
, 
1463                                                  CFTypeRef            timeStampPolicy
, 
1464                                                  size_t                         signerIndex
,        /* usually 0 */ 
1465                                                  CFAbsoluteTime      
*timestamp
)                        /* RETURNED */ 
1467     OSStatus status 
= errSecParam
; 
1468     SecCmsMessageRef cmsg
; 
1469     SecCmsSignedDataRef signedData 
= NULL
; 
1470     int numContentInfos 
= 0; 
1472     require(cmsEncoder 
&& timestamp
, xit
); 
1473     require_noerr(CMSEncoderGetCmsMessage(cmsEncoder
, &cmsg
), xit
); 
1474     numContentInfos 
= SecCmsMessageContentLevelCount(cmsg
); 
1475     for (int dex 
= 0; !signedData 
&& dex 
< numContentInfos
; dex
++) 
1477         SecCmsContentInfoRef ci 
= SecCmsMessageContentLevel(cmsg
, dex
); 
1478         SECOidTag tag 
= SecCmsContentInfoGetContentTypeTag(ci
); 
1479         if (tag 
== SEC_OID_PKCS7_SIGNED_DATA
) 
1480             if ((signedData 
= (SecCmsSignedDataRef
)SecCmsContentInfoGetContent(ci
))) { 
1481                 SecCmsSignerInfoRef signerInfo 
= SecCmsSignedDataGetSignerInfo(signedData
, (int)signerIndex
); 
1484                     status 
= SecCmsSignerInfoGetTimestampTimeWithPolicy(signerInfo
, timeStampPolicy
, timestamp
);