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 <Security/CMSEncoder.h> 
  29 #include <Security/CMSPrivate.h> 
  31 #include <Security/SecBase.h> 
  32 #include <Security/SecCmsEncoder.h> 
  33 #include <Security/SecCmsEnvelopedData.h> 
  34 #include <Security/SecCmsMessage.h> 
  35 #include <Security/SecCmsRecipientInfo.h> 
  36 #include <Security/SecCmsSignedData.h> 
  37 #include <Security/SecCmsSignerInfo.h> 
  38 #include <Security/SecCmsContentInfo.h> 
  39 #include <Security/SecCertificate.h> 
  40 #include <Security/SecIdentity.h> 
  41 #include <Security/SecSMIME.h> 
  42 #include <Security/oidsattr.h> 
  43 #include <Security/SecAsn1Coder.h> 
  44 #include <Security/SecAsn1Types.h> 
  45 #include <Security/SecAsn1Templates.h> 
  46 #include <CoreFoundation/CFRuntime.h> 
  48 #include <utilities/SecCFRelease.h> 
  50 #include <security_smime/cmspriv.h> 
  52 #if TIMESTAMPING_SUPPORTED 
  53 #include <security_smime/tsaSupport.h> 
  56 #pragma mark --- Private types and definitions --- 
  62     ES_Init
,            /* between CMSEncoderCreate and earlier of CMSEncoderUpdateContent 
  63                      *   and CMSEncodeGetCmsMessage */ 
  64     ES_Msg
,                     /* created cmsMsg in CMSEncodeGetCmsMessage, but no encoder yet */ 
  65     ES_Updating
,        /* between first CMSEncoderUpdateContent and CMSEncoderCopyEncodedContent */ 
  66     ES_Final            
/* CMSEncoderCopyEncodedContent has been called */ 
  70  * High-level operation: what are we doing? 
  79  * Caller's CMSEncoderRef points to one of these. 
  83     CMSEncoderState             encState
; 
  85     Boolean                             detachedContent
; 
  86     SecAsn1Oid          eContentType
; 
  87     CFMutableArrayRef   signers
; 
  88     CFMutableArrayRef   recipients
; 
  89     CFMutableArrayRef   otherCerts
; 
  90     CMSSignedAttributes signedAttributes
; 
  91     CFAbsoluteTime              signingTime
; 
  92     SecCmsMessageRef    cmsMsg
;                         /* the encoder's arena */ 
  93     SecCmsEncoderRef    encoder
; 
  94     CFMutableDataRef    encoderOut
;                             /* output goes here... */ 
  95     bool                                customCoder
;                    /* unless this is set by 
  96                                                  *    CMSEncoderSetEncoder */ 
  97     SECOidTag           digestalgtag
; 
  99     CMSCertificateChainMode chainMode
; 
 100     CFDataRef           hashAgilityAttrValue
; 
 101     CFDictionaryRef     hashAgilityV2AttrValues
; 
 102     CFAbsoluteTime      expirationTime
; 
 105 static void cmsEncoderInit(CFTypeRef enc
); 
 106 static void cmsEncoderFinalize(CFTypeRef enc
); 
 108 static CFRuntimeClass cmsEncoderRuntimeClass 
= 
 115     NULL
,               /* equal - just use pointer equality */ 
 116     NULL
,               /* hash, ditto */ 
 117     NULL
,               /* copyFormattingDesc */ 
 118     NULL                
/* copyDebugDesc */ 
 121 #if TIMESTAMPING_SUPPORTED 
 122 void CmsMessageSetTSACallback(CMSEncoderRef cmsEncoder
, SecCmsTSACallback tsaCallback
); 
 125 #pragma mark --- Private routines --- 
 128  * Decode a CFStringRef representation of an integer 
 130 static int cfStringToNumber( 
 135     if (!inStr 
|| !CFStringGetCString(inStr
, buf
, max
-1, kCFStringEncodingASCII
)) 
 141  * Encode an integer component of an OID, return resulting number of bytes; 
 142  * actual bytes are mallocd and returned in *encodeArray. 
 144 static unsigned encodeNumber( 
 146                              unsigned char **encodeArray
)               // mallocd and RETURNED 
 148     unsigned char *result
; 
 150     unsigned numDigits 
= 0; 
 153     /* trival case - 0 maps to 0 */ 
 155         *encodeArray 
= (unsigned char *)malloc(1); 
 160     /* first calculate the number of digits in num, base 128 */ 
 161     scratch 
= (unsigned)num
; 
 162     while(scratch 
!= 0) { 
 167     result 
= (unsigned char *)malloc(numDigits
); 
 168     scratch 
= (unsigned)num
; 
 169     for(dex
=0; dex
<numDigits
; dex
++) { 
 170         result
[numDigits 
- dex 
- 1] = scratch 
& 0x7f; 
 174     /* all digits except the last one have m.s. bit set */ 
 175     for(dex
=0; dex
<(numDigits 
- 1); dex
++) { 
 179     *encodeArray 
= result
; 
 184  * Given an OID in dotted-decimal string representation, convert to binary 
 185  * DER format. Returns a pointer in outOid which the caller must free(), 
 186  * as well as the length of the data in outLen. 
 187  * Function returns 0 if successful, non-zero otherwise. 
 189 static int encodeOid( 
 190                      const unsigned char *inStr
, 
 191                      unsigned char **outOid
, 
 192                      unsigned int *outLen
) 
 194     unsigned char **digits 
= NULL
;              /* array of char * from encodeNumber */ 
 195     unsigned *numDigits 
= NULL
;                 /* array of unsigned from encodeNumber */ 
 197     unsigned numDigitBytes
;                             /* total #of output chars */ 
 198     unsigned char firstByte
; 
 200     CFIndex numsToProcess
; 
 201     CFStringRef oidStr 
= NULL
; 
 202     CFArrayRef argvRef 
= NULL
; 
 206     /* parse input string into array of substrings */ 
 207     if (!inStr 
|| !outOid 
|| !outLen
) goto cleanExit
; 
 208     oidStr 
= CFStringCreateWithCString(NULL
, (const char *)inStr
, kCFStringEncodingASCII
); 
 209     if (!oidStr
) goto cleanExit
; 
 210     argvRef 
= CFStringCreateArrayBySeparatingStrings(NULL
, oidStr
, CFSTR(".")); 
 211     if (!argvRef
) goto cleanExit
; 
 212     argc 
= CFArrayGetCount(argvRef
); 
 213     if (argc 
< 3) goto cleanExit
; 
 215     /* first two numbers in OID munge together */ 
 216     num 
= cfStringToNumber((CFStringRef
)CFArrayGetValueAtIndex(argvRef
, 0)); 
 217     if (num 
< 0) goto cleanExit
; 
 218     firstByte 
= (40 * num
); 
 219     num 
= cfStringToNumber((CFStringRef
)CFArrayGetValueAtIndex(argvRef
, 1)); 
 220     if (num 
< 0) goto cleanExit
; 
 224     numsToProcess 
= argc 
- 2; 
 225     if(numsToProcess 
> 0) { 
 226         /* skip this loop in the unlikely event that input is only two numbers */ 
 227         digits 
= (unsigned char **) malloc(numsToProcess 
* sizeof(unsigned char *)); 
 228         numDigits 
= (unsigned *) malloc(numsToProcess 
* sizeof(unsigned)); 
 229         for(digit
=0; digit
<numsToProcess
; digit
++) { 
 230             num 
= cfStringToNumber((CFStringRef
)CFArrayGetValueAtIndex(argvRef
, digit
+2)); 
 231             if (num 
< 0) goto cleanExit
; 
 232             numDigits
[digit
] = encodeNumber(num
, &digits
[digit
]); 
 233             numDigitBytes 
+= numDigits
[digit
]; 
 236     *outLen 
= (2 + numDigitBytes
); 
 237     *outOid 
= outP 
= (unsigned char *) malloc(*outLen
); 
 239     *outP
++ = numDigitBytes
; 
 241     for(digit
=0; digit
<numsToProcess
; digit
++) { 
 242         unsigned int byteDex
; 
 243         for(byteDex
=0; byteDex
<numDigits
[digit
]; byteDex
++) { 
 244             *outP
++ = digits
[digit
][byteDex
]; 
 248         for(digit
=0; digit
<numsToProcess
; digit
++) { 
 255     if (digits
) free(digits
); 
 256     if (numDigits
) free(numDigits
); 
 257     if (oidStr
) CFRelease(oidStr
); 
 258     if (argvRef
) CFRelease(argvRef
); 
 264  * Given a CF object reference describing an OID, convert to binary DER format 
 265  * and fill out the CSSM_OID structure provided by the caller. Caller is 
 266  * responsible for freeing the data pointer in outOid->Data. 
 268  * Function returns 0 if successful, non-zero otherwise. 
 271 static int convertOid( 
 275     if (!inRef 
|| !outOid
) 
 278     unsigned char *oidData 
= NULL
; 
 279     unsigned int oidLen 
= 0; 
 281     if (CFGetTypeID(inRef
) == CFStringGetTypeID()) { 
 282         // CFStringRef: OID representation is a dotted-decimal string 
 283         CFStringRef inStr 
= (CFStringRef
)inRef
; 
 284         CFIndex max 
= CFStringGetLength(inStr
) * 3; 
 285         char *buf 
= (char *)malloc(max
); 
 287             return errSecMemoryError
; 
 289         if (!CFStringGetCString(inStr
, buf
, max
-1, kCFStringEncodingASCII
)) { 
 294         if (encodeOid((unsigned char *)buf
, &oidData
, &oidLen
) != 0) { 
 300     else if (CFGetTypeID(inRef
) == CFDataGetTypeID()) { 
 301         // CFDataRef: OID representation is in binary DER format 
 302         CFDataRef inData 
= (CFDataRef
)inRef
; 
 303         oidLen 
= (unsigned int) CFDataGetLength(inData
); 
 304         oidData 
= (unsigned char *) malloc(oidLen
); 
 305         memcpy(oidData
, CFDataGetBytePtr(inData
), oidLen
); 
 308         // Not in a format we understand 
 311     outOid
->Length 
= oidLen
; 
 312     outOid
->Data 
= (uint8_t *)oidData
; 
 316 static CFTypeID cmsEncoderTypeID 
= _kCFRuntimeNotATypeID
; 
 318 /* one time only class init, called via pthread_once() in CMSEncoderGetTypeID() */ 
 319 static void cmsEncoderClassInitialize(void) 
 322     _CFRuntimeRegisterClass((const CFRuntimeClass 
* const)&cmsEncoderRuntimeClass
); 
 325 /* init called out from _CFRuntimeCreateInstance() */ 
 326 static void cmsEncoderInit(CFTypeRef enc
) 
 328     char *start 
= ((char *)enc
) + sizeof(CFRuntimeBase
); 
 329     memset(start
, 0, sizeof(struct _CMSEncoder
) - sizeof(CFRuntimeBase
)); 
 333  * Dispose of a CMSEncoder. Called out from CFRelease(). 
 335 static void cmsEncoderFinalize( 
 338     CMSEncoderRef cmsEncoder 
= (CMSEncoderRef
)enc
; 
 339     if(cmsEncoder 
== NULL
) { 
 342     if(cmsEncoder
->eContentType
.Data 
!= NULL
) { 
 343         free(cmsEncoder
->eContentType
.Data
); 
 345     CFRELEASE(cmsEncoder
->signers
); 
 346     CFRELEASE(cmsEncoder
->recipients
); 
 347     CFRELEASE(cmsEncoder
->otherCerts
); 
 348     if(cmsEncoder
->cmsMsg 
!= NULL
) { 
 349         SecCmsMessageDestroy(cmsEncoder
->cmsMsg
); 
 350         cmsEncoder
->cmsMsg 
= NULL
; 
 352     if(cmsEncoder
->encoder 
!= NULL
) { 
 354          * Normally this gets freed in SecCmsEncoderFinish - this is 
 357         SecCmsEncoderDestroy(cmsEncoder
->encoder
); 
 361 static OSStatus 
cmsSetupEncoder( 
 362                                 CMSEncoderRef           cmsEncoder
) 
 366     ASSERT(cmsEncoder
->cmsMsg 
!= NULL
); 
 367     ASSERT(cmsEncoder
->encoder 
== NULL
); 
 369     cmsEncoder
->encoderOut 
= CFDataCreateMutable(NULL
, 0); 
 370     if (!cmsEncoder
->encoderOut
) { 
 371         return errSecAllocate
; 
 374     ortn 
= SecCmsEncoderCreate(cmsEncoder
->cmsMsg
, 
 375                                NULL
, NULL
,                                      // no callback 
 376                                cmsEncoder
->encoderOut
,      // data goes here 
 377                                NULL
, NULL
,                                      // no password callback (right?) 
 378                                NULL
, NULL
,                                      // decrypt key callback 
 379                                &cmsEncoder
->encoder
); 
 381         return cmsRtnToOSStatus(ortn
); 
 383     return errSecSuccess
; 
 387  * Set up a SecCmsMessageRef for a SignedData creation. 
 389 static OSStatus 
cmsSetupForSignedData( 
 390                                       CMSEncoderRef             cmsEncoder
) 
 392     ASSERT((cmsEncoder
->signers 
!= NULL
) || (cmsEncoder
->otherCerts 
!= NULL
)); 
 394     SecCmsContentInfoRef contentInfo 
= NULL
; 
 395     SecCmsSignedDataRef signedData 
= NULL
; 
 398     /* build chain of objects: message->signedData->data */ 
 399     if(cmsEncoder
->cmsMsg 
!= NULL
) { 
 400         SecCmsMessageDestroy(cmsEncoder
->cmsMsg
); 
 402     cmsEncoder
->cmsMsg 
= SecCmsMessageCreate(); 
 403     if(cmsEncoder
->cmsMsg 
== NULL
) { 
 404         return errSecInternalComponent
; 
 407     signedData 
= SecCmsSignedDataCreate(cmsEncoder
->cmsMsg
); 
 408     if(signedData 
== NULL
) { 
 409         return errSecInternalComponent
; 
 411     contentInfo 
= SecCmsMessageGetContentInfo(cmsEncoder
->cmsMsg
); 
 412     ortn 
= SecCmsContentInfoSetContentSignedData(contentInfo
,signedData
); 
 414         return cmsRtnToOSStatus(ortn
); 
 416     contentInfo 
= SecCmsSignedDataGetContentInfo(signedData
); 
 417     if(cmsEncoder
->eContentType
.Data 
!= NULL
) { 
 418         /* Override the default eContentType of id-data */ 
 419         ortn 
= SecCmsContentInfoSetContentOther(contentInfo
, 
 420                                                 NULL
,           /* data - provided to encoder, not here */ 
 421                                                 cmsEncoder
->detachedContent
, 
 422                                                 &cmsEncoder
->eContentType
); 
 425         ortn 
= SecCmsContentInfoSetContentData(contentInfo
, 
 426                                                NULL
, /* data - provided to encoder, not here */ 
 427                                                cmsEncoder
->detachedContent
); 
 430         ortn 
= cmsRtnToOSStatus(ortn
); 
 431         CSSM_PERROR("SecCmsContentInfoSetContent*", ortn
); 
 435     /* optional 'global' (per-SignedData) certs */ 
 436     if(cmsEncoder
->otherCerts 
!= NULL
) { 
 437         ortn 
= SecCmsSignedDataAddCertList(signedData
, cmsEncoder
->otherCerts
); 
 439             ortn 
= cmsRtnToOSStatus(ortn
); 
 440             CSSM_PERROR("SecCmsSignedDataAddCertList", ortn
); 
 445     /* SignerInfos, one per signer */ 
 446     CFIndex numSigners 
= 0; 
 447     if(cmsEncoder
->signers 
!= NULL
) { 
 448         /* this is optional...in case we're just creating a cert bundle */ 
 449         numSigners 
= CFArrayGetCount(cmsEncoder
->signers
); 
 452     SecCertificateRef ourCert 
= NULL
; 
 453     SecCmsCertChainMode chainMode 
= SecCmsCMCertChain
; 
 455     switch(cmsEncoder
->chainMode
) { 
 456         case kCMSCertificateNone
: 
 457             chainMode 
= SecCmsCMNone
; 
 459         case kCMSCertificateSignerOnly
: 
 460             chainMode 
= SecCmsCMCertOnly
; 
 462         case kCMSCertificateChainWithRoot
: 
 463             chainMode 
= SecCmsCMCertChainWithRoot
; 
 465         case kCMSCertificateChainWithRootOrFail
: 
 466             chainMode 
= SecCmsCMCertChainWithRootOrFail
; 
 471     for(dex
=0; dex
<numSigners
; dex
++) { 
 472         SecCmsSignerInfoRef signerInfo
; 
 474         SecIdentityRef ourId 
= 
 475         (SecIdentityRef
)CFArrayGetValueAtIndex(cmsEncoder
->signers
, dex
); 
 476         ortn 
= SecIdentityCopyCertificate(ourId
, &ourCert
); 
 478             CSSM_PERROR("SecIdentityCopyCertificate", ortn
); 
 481         /* this creates the signerInfo and adds it to the signedData object */ 
 482         signerInfo 
= SecCmsSignerInfoCreate(signedData
, ourId
, cmsEncoder
->digestalgtag
); 
 483         if (signerInfo 
== NULL
) { 
 484             ortn 
= errSecInternalComponent
; 
 488         /* we want the cert chain included for this one */ 
 489         /* NOTE the usage parameter is currently unused by the SMIME lib */ 
 490         ortn 
= SecCmsSignerInfoIncludeCerts(signerInfo
, chainMode
, 
 491                                             certUsageEmailSigner
); 
 493             ortn 
= cmsRtnToOSStatus(ortn
); 
 494             CSSM_PERROR("SecCmsSignerInfoIncludeCerts", ortn
); 
 499         if(cmsEncoder
->signedAttributes 
& kCMSAttrSmimeCapabilities
) { 
 500             ortn 
= SecCmsSignerInfoAddSMIMECaps(signerInfo
); 
 502                 ortn 
= cmsRtnToOSStatus(ortn
); 
 503                 CSSM_PERROR("SecCmsSignerInfoAddSMIMEEncKeyPrefs", ortn
); 
 507         if(cmsEncoder
->signedAttributes 
& kCMSAttrSmimeEncryptionKeyPrefs
) { 
 508             ortn 
= SecCmsSignerInfoAddSMIMEEncKeyPrefs(signerInfo
, ourCert
, NULL
); 
 510                 ortn 
= cmsRtnToOSStatus(ortn
); 
 511                 CSSM_PERROR("SecCmsSignerInfoAddSMIMEEncKeyPrefs", ortn
); 
 515         if(cmsEncoder
->signedAttributes 
& kCMSAttrSmimeMSEncryptionKeyPrefs
) { 
 516             ortn 
= SecCmsSignerInfoAddMSSMIMEEncKeyPrefs(signerInfo
, ourCert
, NULL
); 
 518                 ortn 
= cmsRtnToOSStatus(ortn
); 
 519                 CSSM_PERROR("SecCmsSignerInfoAddMSSMIMEEncKeyPrefs", ortn
); 
 523         if(cmsEncoder
->signedAttributes 
& kCMSAttrSigningTime
) { 
 524             if (cmsEncoder
->signingTime 
== 0) 
 525                 cmsEncoder
->signingTime 
= CFAbsoluteTimeGetCurrent(); 
 526             ortn 
= SecCmsSignerInfoAddSigningTime(signerInfo
, cmsEncoder
->signingTime
); 
 528                 ortn 
= cmsRtnToOSStatus(ortn
); 
 529                 CSSM_PERROR("SecCmsSignerInfoAddSigningTime", ortn
); 
 533         if(cmsEncoder
->signedAttributes 
& kCMSAttrAppleCodesigningHashAgility
) { 
 534             ortn 
= SecCmsSignerInfoAddAppleCodesigningHashAgility(signerInfo
, cmsEncoder
->hashAgilityAttrValue
); 
 535             /* libsecurity_smime made a copy of the attribute value. We don't need it anymore. */ 
 536             CFReleaseNull(cmsEncoder
->hashAgilityAttrValue
); 
 538                 ortn 
= cmsRtnToOSStatus(ortn
); 
 539                 CSSM_PERROR("SecCmsSignerInfoAddAppleCodesigningHashAgility", ortn
); 
 543         if(cmsEncoder
->signedAttributes 
& kCMSAttrAppleCodesigningHashAgilityV2
) { 
 544             ortn 
= SecCmsSignerInfoAddAppleCodesigningHashAgilityV2(signerInfo
, cmsEncoder
->hashAgilityV2AttrValues
); 
 545             /* libsecurity_smime made a copy of the attribute value. We don't need it anymore. */ 
 546             CFReleaseNull(cmsEncoder
->hashAgilityV2AttrValues
); 
 548                 ortn 
= cmsRtnToOSStatus(ortn
); 
 549                 CSSM_PERROR("SecCmsSignerInfoAddAppleCodesigningHashAgilityV2", ortn
); 
 553         if (cmsEncoder
->signedAttributes 
& kCMSAttrAppleExpirationTime
) { 
 554             ortn 
= SecCmsSignerInfoAddAppleExpirationTime(signerInfo
, cmsEncoder
->expirationTime
); 
 556                 ortn 
= cmsRtnToOSStatus(ortn
); 
 557                 CSSM_PERROR("SecCmsSignerInfoAddAppleExpirationTime", ortn
); 
 572  * Set up a SecCmsMessageRef for a EnvelopedData creation. 
 574 static OSStatus 
cmsSetupForEnvelopedData( 
 575                                          CMSEncoderRef          cmsEncoder
) 
 577     ASSERT(cmsEncoder
->op 
== EO_Encrypt
); 
 578     ASSERT(cmsEncoder
->recipients 
!= NULL
); 
 580     SecCmsContentInfoRef contentInfo 
= NULL
; 
 581     SecCmsEnvelopedDataRef envelopedData 
= NULL
; 
 582     SECOidTag algorithmTag
; 
 587      * Find encryption algorithm...unfortunately we need a NULL-terminated array 
 588      * of SecCertificateRefs for this. 
 590     CFIndex numCerts 
= CFArrayGetCount(cmsEncoder
->recipients
); 
 592     SecCertificateRef 
*certArray 
= (SecCertificateRef 
*)malloc( 
 593                                                                (numCerts
+1) * sizeof(SecCertificateRef
)); 
 595     for(dex
=0; dex
<numCerts
; dex
++) { 
 596         certArray
[dex
] = (SecCertificateRef
)CFArrayGetValueAtIndex( 
 597                                                                    cmsEncoder
->recipients
, dex
); 
 599     certArray
[numCerts
] = NULL
; 
 600     ortn 
= SecSMIMEFindBulkAlgForRecipients(certArray
, &algorithmTag
, &keySize
); 
 603         CSSM_PERROR("SecSMIMEFindBulkAlgForRecipients", ortn
); 
 607     /* build chain of objects: message->envelopedData->data */ 
 608     if(cmsEncoder
->cmsMsg 
!= NULL
) { 
 609         SecCmsMessageDestroy(cmsEncoder
->cmsMsg
); 
 611     cmsEncoder
->cmsMsg 
= SecCmsMessageCreate(); 
 612     if(cmsEncoder
->cmsMsg 
== NULL
) { 
 613         return errSecInternalComponent
; 
 615     envelopedData 
= SecCmsEnvelopedDataCreate(cmsEncoder
->cmsMsg
, 
 616                                               algorithmTag
, keySize
); 
 617     if(envelopedData 
== NULL
) { 
 618         return errSecInternalComponent
; 
 620     contentInfo 
= SecCmsMessageGetContentInfo(cmsEncoder
->cmsMsg
); 
 621     ortn 
= SecCmsContentInfoSetContentEnvelopedData(contentInfo
, envelopedData
); 
 623         ortn 
= cmsRtnToOSStatus(ortn
); 
 624         CSSM_PERROR("SecCmsContentInfoSetContentEnvelopedData", ortn
); 
 627     contentInfo 
= SecCmsEnvelopedDataGetContentInfo(envelopedData
); 
 628     if(cmsEncoder
->eContentType
.Data 
!= NULL
) { 
 629         /* Override the default ContentType of id-data */ 
 630         ortn 
= SecCmsContentInfoSetContentOther(contentInfo
, 
 631                                                 NULL
,           /* data - provided to encoder, not here */ 
 632                                                 FALSE
,          /* detachedContent */ 
 633                                                 &cmsEncoder
->eContentType
); 
 636         ortn 
= SecCmsContentInfoSetContentData(contentInfo
, 
 637                                                NULL 
/* data - provided to encoder, not here */, 
 638                                                cmsEncoder
->detachedContent
); 
 641         ortn 
= cmsRtnToOSStatus(ortn
); 
 642         CSSM_PERROR("SecCmsContentInfoSetContentData*", ortn
); 
 647      * create & attach recipient information, one for each recipient 
 649     for(dex
=0; dex
<numCerts
; dex
++) { 
 650         SecCmsRecipientInfoRef recipientInfo 
= NULL
; 
 652         SecCertificateRef thisRecip 
= (SecCertificateRef
)CFArrayGetValueAtIndex( 
 653                                                                                 cmsEncoder
->recipients
, dex
); 
 654         recipientInfo 
= SecCmsRecipientInfoCreate(envelopedData
, thisRecip
); 
 655         ortn 
= SecCmsEnvelopedDataAddRecipient(envelopedData
, recipientInfo
); 
 657             ortn 
= cmsRtnToOSStatus(ortn
); 
 658             CSSM_PERROR("SecCmsEnvelopedDataAddRecipient", ortn
); 
 662     return errSecSuccess
; 
 666  * Set up cmsMsg. Called from either the first call to CMSEncoderUpdateContent, or 
 667  * from CMSEncodeGetCmsMessage(). 
 669 static OSStatus 
cmsSetupCmsMsg( 
 670                                CMSEncoderRef            cmsEncoder
) 
 672     ASSERT(cmsEncoder 
!= NULL
); 
 673     ASSERT(cmsEncoder
->encState 
== ES_Init
); 
 675     /* figure out what high-level operation we're doing */ 
 676     if((cmsEncoder
->signers 
!= NULL
) || (cmsEncoder
->otherCerts 
!= NULL
)) { 
 677         if(cmsEncoder
->recipients 
!= NULL
) { 
 678             cmsEncoder
->op 
= EO_SignEncrypt
; 
 681             cmsEncoder
->op 
= EO_Sign
; 
 684     else if(cmsEncoder
->recipients 
!= NULL
) { 
 685         cmsEncoder
->op 
= EO_Encrypt
; 
 688         dprintf("CMSEncoderUpdateContent: nothing to do\n"); 
 692     OSStatus ortn 
= errSecSuccess
; 
 694     switch(cmsEncoder
->op
) { 
 697             /* If we're signing & encrypting, do the signing first */ 
 698             ortn 
= cmsSetupForSignedData(cmsEncoder
); 
 701             ortn 
= cmsSetupForEnvelopedData(cmsEncoder
); 
 704     cmsEncoder
->encState 
= ES_Msg
; 
 709  * ASN.1 template for decoding a ContentInfo. 
 712     SecAsn1Oid  contentType
; 
 716 static const SecAsn1Template cmsSimpleContentInfoTemplate
[] = { 
 717     { SEC_ASN1_SEQUENCE
, 0, NULL
, sizeof(SimpleContentInfo
) }, 
 718     { SEC_ASN1_OBJECT_ID
, offsetof(SimpleContentInfo
, contentType
) }, 
 719     { SEC_ASN1_EXPLICIT 
| SEC_ASN1_CONSTRUCTED 
| SEC_ASN1_CONTEXT_SPECIFIC 
| 0, 
 720         offsetof(SimpleContentInfo
, content
), 
 721         kSecAsn1AnyTemplate 
}, 
 726  * Obtain the content of a contentInfo, This basically strips off the contentType OID 
 727  * and returns its ASN_ANY content, allocated the provided coder's memory space. 
 729 static OSStatus 
cmsContentInfoContent( 
 730                                       SecAsn1CoderRef asn1Coder
, 
 731                                       const SecAsn1Item 
*contentInfo
, 
 732                                       SecAsn1Item 
*content
)                             /* RETURNED */ 
 735     SimpleContentInfo decodedInfo
; 
 737     memset(&decodedInfo
, 0, sizeof(decodedInfo
)); 
 738     ortn 
= SecAsn1DecodeData(asn1Coder
, contentInfo
, 
 739                              cmsSimpleContentInfoTemplate
, &decodedInfo
); 
 743     if(decodedInfo
.content
.Data 
== NULL
) { 
 744         dprintf("***Error decoding contentInfo: no content\n"); 
 745         return errSecInternalComponent
; 
 747     *content 
= decodedInfo
.content
; 
 748     return errSecSuccess
; 
 751 #pragma mark --- Start of Public API --- 
 753 CFTypeID 
CMSEncoderGetTypeID(void) 
 755     static pthread_once_t once 
= PTHREAD_ONCE_INIT
; 
 757     if(cmsEncoderTypeID 
== _kCFRuntimeNotATypeID
) { 
 758         pthread_once(&once
, &cmsEncoderClassInitialize
); 
 760     return cmsEncoderTypeID
; 
 764  * Create a CMSEncoder. Result must eventually be freed via CFRelease(). 
 766 OSStatus 
CMSEncoderCreate( 
 767                           CMSEncoderRef         
*cmsEncoderOut
) /* RETURNED */ 
 769     CMSEncoderRef cmsEncoder 
= NULL
; 
 771     uint32_t extra 
= sizeof(*cmsEncoder
) - sizeof(cmsEncoder
->base
); 
 772     cmsEncoder 
= (CMSEncoderRef
)_CFRuntimeCreateInstance(NULL
, CMSEncoderGetTypeID(), 
 774     if(cmsEncoder 
== NULL
) { 
 775         return errSecAllocate
; 
 777     cmsEncoder
->encState 
= ES_Init
; 
 778     cmsEncoder
->chainMode 
= kCMSCertificateChain
; 
 779     cmsEncoder
->digestalgtag 
= SEC_OID_SHA1
; 
 780     *cmsEncoderOut 
= cmsEncoder
; 
 781     return errSecSuccess
; 
 784 #pragma mark --- Getters & Setters --- 
 786 const CFStringRef __nonnull kCMSEncoderDigestAlgorithmSHA1 
= CFSTR("sha1"); 
 787 const CFStringRef __nonnull kCMSEncoderDigestAlgorithmSHA256 
= CFSTR("sha256"); 
 790 OSStatus 
CMSEncoderSetSignerAlgorithm( 
 791                                       CMSEncoderRef             cmsEncoder
, 
 792                                       CFStringRef               digestAlgorithm
) 
 794     if (CFEqual(digestAlgorithm
, kCMSEncoderDigestAlgorithmSHA1
)) { 
 795         cmsEncoder
->digestalgtag 
= SEC_OID_SHA1
; 
 796     } else if (CFEqual(digestAlgorithm
, kCMSEncoderDigestAlgorithmSHA256
)) { 
 797         cmsEncoder
->digestalgtag 
= SEC_OID_SHA256
; 
 802     return errSecSuccess
; 
 806  * Specify signers of the CMS message; implies that the message will be signed. 
 808 OSStatus 
CMSEncoderAddSigners( 
 809                               CMSEncoderRef             cmsEncoder
, 
 810                               CFTypeRef                 signerOrArray
) 
 812     if(cmsEncoder 
== NULL
) { 
 815     if(cmsEncoder
->encState 
!= ES_Init
) { 
 818     return cmsAppendToArray(signerOrArray
, &cmsEncoder
->signers
, SecIdentityGetTypeID()); 
 822  * Obtain an array of signers as specified in CMSEncoderSetSigners(). 
 824 OSStatus 
CMSEncoderCopySigners( 
 825                                CMSEncoderRef            cmsEncoder
, 
 828     if((cmsEncoder 
== NULL
) || (signers 
== NULL
)) { 
 831     if(cmsEncoder
->signers 
!= NULL
) { 
 832         CFRetain(cmsEncoder
->signers
); 
 834     *signers 
= cmsEncoder
->signers
; 
 835     return errSecSuccess
; 
 839  * Specify recipients of the message. Implies that the message will be encrypted. 
 841 OSStatus 
CMSEncoderAddRecipients( 
 842                                  CMSEncoderRef          cmsEncoder
, 
 843                                  CFTypeRef                      recipientOrArray
) 
 845     if(cmsEncoder 
== NULL
) { 
 848     if(cmsEncoder
->encState 
!= ES_Init
) { 
 851     return cmsAppendToArray(recipientOrArray
, &cmsEncoder
->recipients
, 
 852                             SecCertificateGetTypeID()); 
 856  * Obtain an array of recipients as specified in CMSEncoderSetRecipients(). 
 858 OSStatus 
CMSEncoderCopyRecipients( 
 859                                   CMSEncoderRef         cmsEncoder
, 
 860                                   CFArrayRef                    
*recipients
) 
 862     if((cmsEncoder 
== NULL
) || (recipients 
== NULL
)) { 
 865     if(cmsEncoder
->recipients 
!= NULL
) { 
 866         CFRetain(cmsEncoder
->recipients
); 
 868     *recipients 
= cmsEncoder
->recipients
; 
 869     return errSecSuccess
; 
 873  * Specify additional certs to include in a signed message. 
 875 OSStatus 
CMSEncoderAddSupportingCerts( 
 876                                       CMSEncoderRef             cmsEncoder
, 
 877                                       CFTypeRef                 certOrArray
) 
 879     if(cmsEncoder 
== NULL
) { 
 882     if(cmsEncoder
->encState 
!= ES_Init
) { 
 885     return cmsAppendToArray(certOrArray
, &cmsEncoder
->otherCerts
, 
 886                             SecCertificateGetTypeID()); 
 890  * Obtain the SecCertificates provided in CMSEncoderAddSupportingCerts(). 
 892 OSStatus 
CMSEncoderCopySupportingCerts( 
 893                                        CMSEncoderRef            cmsEncoder
, 
 894                                        CFArrayRef                       
*certs
)                 /* RETURNED */ 
 896     if((cmsEncoder 
== NULL
) || (certs 
== NULL
)) { 
 899     if(cmsEncoder
->otherCerts 
!= NULL
) { 
 900         CFRetain(cmsEncoder
->otherCerts
); 
 902     *certs 
= cmsEncoder
->otherCerts
; 
 903     return errSecSuccess
; 
 906 OSStatus 
CMSEncoderSetHasDetachedContent( 
 907                                          CMSEncoderRef          cmsEncoder
, 
 908                                          Boolean                                detachedContent
) 
 910     if(cmsEncoder 
== NULL
) { 
 913     if(cmsEncoder
->encState 
!= ES_Init
) { 
 916     cmsEncoder
->detachedContent 
= detachedContent
; 
 917     return errSecSuccess
; 
 920 OSStatus 
CMSEncoderGetHasDetachedContent( 
 921                                          CMSEncoderRef          cmsEncoder
, 
 922                                          Boolean                                
*detachedContent
)       /* RETURNED */ 
 924     if((cmsEncoder 
== NULL
) || (detachedContent 
== NULL
)) { 
 927     *detachedContent 
= cmsEncoder
->detachedContent
; 
 928     return errSecSuccess
; 
 932  * Optionally specify an eContentType OID for the inner EncapsulatedData for 
 933  * a signed message. The default eContentType, used of this function is not 
 934  * called, is id-data. 
 936 static OSStatus 
CMSEncoderSetEncapsulatedContentType( 
 937                                               CMSEncoderRef             cmsEncoder
, 
 938                                               const SecAsn1Oid  
*eContentType
) 
 940     if((cmsEncoder 
== NULL
) || (eContentType 
== NULL
)) { 
 943     if(cmsEncoder
->encState 
!= ES_Init
) { 
 947     SecAsn1Oid 
*ecOid 
= &cmsEncoder
->eContentType
; 
 948     if(ecOid
->Data 
!= NULL
) { 
 951     cmsCopyCmsData(eContentType
, ecOid
); 
 952     return errSecSuccess
; 
 955 OSStatus 
CMSEncoderSetEncapsulatedContentTypeOID( 
 956                                                  CMSEncoderRef          cmsEncoder
, 
 957                                                  CFTypeRef                      eContentTypeOID
) 
 959     // convert eContentTypeOID to a CSSM_OID 
 960     SecAsn1Oid contentType 
= { 0, NULL 
}; 
 961     if (!eContentTypeOID 
|| convertOid(eContentTypeOID
, &contentType
) != 0) 
 963     OSStatus result 
= CMSEncoderSetEncapsulatedContentType(cmsEncoder
, &contentType
); 
 964     if (contentType
.Data
) 
 965         free(contentType
.Data
); 
 970  * Obtain the eContentType OID specified in CMSEncoderSetEncapsulatedContentType(). 
 972 OSStatus 
CMSEncoderCopyEncapsulatedContentType( 
 973                                                CMSEncoderRef            cmsEncoder
, 
 974                                                CFDataRef                        
*eContentType
) 
 976     if((cmsEncoder 
== NULL
) || (eContentType 
== NULL
)) { 
 980     SecAsn1Oid 
*ecOid 
= &cmsEncoder
->eContentType
; 
 981     if(ecOid
->Data 
== NULL
) { 
 982         *eContentType 
= NULL
; 
 985         *eContentType 
= CFDataCreate(NULL
, ecOid
->Data
, ecOid
->Length
); 
 987     return errSecSuccess
; 
 991  * Optionally specify signed attributes. Only meaningful when creating a 
 992  * signed message. If this is called, it must be called before 
 993  * CMSEncoderUpdateContent(). 
 995 OSStatus 
CMSEncoderAddSignedAttributes( 
 996                                        CMSEncoderRef            cmsEncoder
, 
 997                                        CMSSignedAttributes      signedAttributes
) 
 999     if(cmsEncoder 
== NULL
) { 
1002     if(cmsEncoder
->encState 
!= ES_Init
) { 
1005     cmsEncoder
->signedAttributes 
|= signedAttributes
; 
1006     return errSecSuccess
; 
1010  * Set the signing time for a CMSEncoder. 
1011  * This is only used if the kCMSAttrSigningTime attribute is included. 
1013 OSStatus 
CMSEncoderSetSigningTime( 
1014                                   CMSEncoderRef         cmsEncoder
, 
1015                                   CFAbsoluteTime                time
) 
1017     if(cmsEncoder 
== NULL
) { 
1020     if(cmsEncoder
->encState 
!= ES_Init
) { 
1023     cmsEncoder
->signingTime 
= time
; 
1024     return errSecSuccess
; 
1028  * Set the hash agility attribute for a CMSEncoder. 
1029  * This is only used if the kCMSAttrAppleCodesigningHashAgility attribute 
1032 OSStatus 
CMSEncoderSetAppleCodesigningHashAgility( 
1033                                                   CMSEncoderRef   cmsEncoder
, 
1034                                                   CFDataRef       hashAgilityAttrValue
) 
1036     if (cmsEncoder 
== NULL 
|| cmsEncoder
->encState 
!= ES_Init
) { 
1039     cmsEncoder
->hashAgilityAttrValue 
= CFRetainSafe(hashAgilityAttrValue
); 
1040     return errSecSuccess
; 
1044  * Set the hash agility attribute for a CMSEncoder. 
1045  * This is only used if the kCMSAttrAppleCodesigningHashAgilityV2 attribute 
1048 OSStatus 
CMSEncoderSetAppleCodesigningHashAgilityV2( 
1049                                                   CMSEncoderRef   cmsEncoder
, 
1050                                                   CFDictionaryRef  hashAgilityV2AttrValues
) 
1052     if (cmsEncoder 
== NULL 
|| cmsEncoder
->encState 
!= ES_Init
) { 
1055     cmsEncoder
->hashAgilityV2AttrValues 
= CFRetainSafe(hashAgilityV2AttrValues
); 
1056     return errSecSuccess
; 
1060  * Set the expiration time for a CMSEncoder. 
1061  * This is only used if the kCMSAttrAppleExpirationTime attribute is included. 
1063 OSStatus 
CMSEncoderSetAppleExpirationTime( 
1064                                           CMSEncoderRef cmsEncoder
, 
1065                                           CFAbsoluteTime time
) 
1067     if(cmsEncoder 
== NULL
) { 
1070     if(cmsEncoder
->encState 
!= ES_Init
) { 
1073     cmsEncoder
->expirationTime 
= time
; 
1074     return errSecSuccess
; 
1077 OSStatus 
CMSEncoderSetCertificateChainMode( 
1078                                            CMSEncoderRef                        cmsEncoder
, 
1079                                            CMSCertificateChainMode      chainMode
) 
1081     if(cmsEncoder 
== NULL
) { 
1084     if(cmsEncoder
->encState 
!= ES_Init
) { 
1088         case kCMSCertificateNone
: 
1089         case kCMSCertificateSignerOnly
: 
1090         case kCMSCertificateChain
: 
1091         case kCMSCertificateChainWithRoot
: 
1092         case kCMSCertificateChainWithRootOrFail
: 
1097     cmsEncoder
->chainMode 
= chainMode
; 
1098     return errSecSuccess
; 
1101 OSStatus 
CMSEncoderGetCertificateChainMode( 
1102                                            CMSEncoderRef                        cmsEncoder
, 
1103                                            CMSCertificateChainMode      
*chainModeOut
) 
1105     if(cmsEncoder 
== NULL
) { 
1108     *chainModeOut 
= cmsEncoder
->chainMode
; 
1109     return errSecSuccess
; 
1112 #if TIMESTAMPING_SUPPORTED 
1114 CmsMessageSetTSACallback(CMSEncoderRef cmsEncoder
, SecCmsTSACallback tsaCallback
) 
1116     if (cmsEncoder
->cmsMsg
) 
1117         SecCmsMessageSetTSACallback(cmsEncoder
->cmsMsg
, tsaCallback
); 
1121 CmsMessageSetTSAContext(CMSEncoderRef cmsEncoder
, CFTypeRef tsaContext
) 
1123     if (cmsEncoder
->cmsMsg
) 
1124         SecCmsMessageSetTSAContext(cmsEncoder
->cmsMsg
, tsaContext
); 
1128 #pragma mark --- Action --- 
1131  * Feed content bytes into the encoder. 
1132  * Can be called multiple times. 
1133  * No 'setter' routines can be called after this function has been called. 
1135 OSStatus 
CMSEncoderUpdateContent( 
1136                                  CMSEncoderRef          cmsEncoder
, 
1137                                  const void                     *content
, 
1140     if(cmsEncoder 
== NULL
) { 
1144     OSStatus ortn 
= errSecSuccess
; 
1145     switch(cmsEncoder
->encState
) { 
1148              * First time thru: do the CmsMsg setup. 
1150             ortn 
= cmsSetupCmsMsg(cmsEncoder
); 
1154             /* fall thru to set up the encoder */ 
1157             /* We have a cmsMsg but no encoder; create one */ 
1158             ASSERT(cmsEncoder
->cmsMsg 
!= NULL
); 
1159             ASSERT(cmsEncoder
->encoder 
== NULL
); 
1160             ortn 
= cmsSetupEncoder(cmsEncoder
); 
1164             /* only legal calls now are update and finalize */ 
1165             cmsEncoder
->encState 
= ES_Updating
; 
1169             ASSERT(cmsEncoder
->encoder 
!= NULL
); 
1173             /* Too late for another update */ 
1177             return errSecInternalComponent
; 
1180     /* FIXME - CFIndex same size as size_t on 64bit? */ 
1181     ortn 
= SecCmsEncoderUpdate(cmsEncoder
->encoder
, content
, (CFIndex
)contentLen
); 
1183         ortn 
= cmsRtnToOSStatus(ortn
); 
1184         CSSM_PERROR("SecCmsEncoderUpdate", ortn
); 
1189 /* forward declaration */ 
1190 static OSStatus 
CMSEncode( 
1192                           CFTypeRef                     recipients
, 
1193                           const SecAsn1Oid              
*eContentType
, 
1194                           Boolean                               detachedContent
, 
1195                           CMSSignedAttributes   signedAttributes
, 
1196                           const void                    *content
, 
1198                           CFDataRef                     
*encodedContent
); 
1201  * Finish encoding the message and obtain the encoded result. 
1202  * Caller must CFRelease the result. 
1204 OSStatus 
CMSEncoderCopyEncodedContent( 
1205                                       CMSEncoderRef             cmsEncoder
, 
1206                                       CFDataRef                 
*encodedContent
) 
1208     if((cmsEncoder 
== NULL
) || (encodedContent 
== NULL
)) { 
1214     switch(cmsEncoder
->encState
) { 
1216             /* normal termination */ 
1219             /* already been called */ 
1224              * The only time these are legal is when we're doing a SignedData 
1225              * with certificates only (no signers, no content). 
1227             if((cmsEncoder
->signers 
!= NULL
) || 
1228                (cmsEncoder
->recipients 
!= NULL
) || 
1229                (cmsEncoder
->otherCerts 
== NULL
)) { 
1233             /* Set up for certs only */ 
1234             ortn 
= cmsSetupForSignedData(cmsEncoder
); 
1238             /* and an encoder */ 
1239             ortn 
= cmsSetupEncoder(cmsEncoder
); 
1247     ASSERT(cmsEncoder
->encoder 
!= NULL
); 
1248     ortn 
= SecCmsEncoderFinish(cmsEncoder
->encoder
); 
1249     /* regardless of the outcome, the encoder itself has been freed */ 
1250     cmsEncoder
->encoder 
= NULL
; 
1252         return cmsRtnToOSStatus(ortn
); 
1254     cmsEncoder
->encState 
= ES_Final
; 
1256     if((cmsEncoder
->encoderOut 
== NULL
) && !cmsEncoder
->customCoder
) { 
1257         /* not sure how this could happen... */ 
1258         dprintf("Successful encode, but no data\n"); 
1259         return errSecInternalComponent
; 
1261     if(cmsEncoder
->customCoder
) { 
1263         *encodedContent 
= NULL
; 
1264         return errSecSuccess
; 
1267     /* in two out of three cases, we're done */ 
1268     switch(cmsEncoder
->op
) { 
1271             *encodedContent 
= CFDataCreateCopy(NULL
, cmsEncoder
->encoderOut
); 
1272             return errSecSuccess
; 
1273         case EO_SignEncrypt
: 
1274             /* proceed, more work to do */ 
1279      * Signing & encrypting. 
1280      * Due to bugs in the libsecurity_smime encoder, it can't encode nested 
1281      * ContentInfos in one shot. So we do another pass, specifying the SignedData 
1282      * inside of the ContentInfo we just created as the data to encrypt. 
1284     SecAsn1CoderRef asn1Coder 
= NULL
; 
1285     SecAsn1Item signedData 
= {0, NULL
}; 
1287     ortn 
= SecAsn1CoderCreate(&asn1Coder
); 
1291     SecAsn1Item encoderOut 
= { CFDataGetLength(cmsEncoder
->encoderOut
), 
1292                                CFDataGetMutableBytePtr(cmsEncoder
->encoderOut
)}; 
1293     ortn 
= cmsContentInfoContent(asn1Coder
, &encoderOut
, &signedData
); 
1298     /* now just encrypt that, one-shot */ 
1299     ortn 
= CMSEncode(NULL
,                      /* no signers this time */ 
1300                      cmsEncoder
->recipients
, 
1301                      &CSSMOID_PKCS7_SignedData
, /* fake out encoder so it doesn't try to actually 
1302                                                  *   encode the signedData - this asserts the 
1303                                                  *   SEC_OID_OTHER OID tag in the EnvelopedData's 
1305                      FALSE
,                                             /* detachedContent */ 
1306                      kCMSAttrNone
,                              /* signedAttributes - none this time */ 
1307                      signedData
.Data
, signedData
.Length
, 
1312         SecAsn1CoderRelease(asn1Coder
); 
1317 #pragma mark --- High-level API --- 
1320  * High-level, one-shot encoder function. 
1322 static OSStatus 
CMSEncode( 
1324                    CFTypeRef                    recipients
, 
1325                    const SecAsn1Oid             
*eContentType
, 
1326                    Boolean                              detachedContent
, 
1327                    CMSSignedAttributes  signedAttributes
, 
1328                    const void                   *content
, 
1330                    CFDataRef                    
*encodedContent
)        /* RETURNED */ 
1332     if((signers 
== NULL
) && (recipients 
== NULL
)) { 
1335     if(encodedContent 
== NULL
) { 
1339     CMSEncoderRef cmsEncoder
; 
1342     /* set up the encoder */ 
1343     ortn 
= CMSEncoderCreate(&cmsEncoder
); 
1348     /* subsequent errors to errOut: */ 
1350         ortn 
= CMSEncoderAddSigners(cmsEncoder
, signers
); 
1356         ortn 
= CMSEncoderAddRecipients(cmsEncoder
, recipients
); 
1362         ortn 
= CMSEncoderSetEncapsulatedContentType(cmsEncoder
, eContentType
); 
1367     if(detachedContent
) { 
1368         ortn 
= CMSEncoderSetHasDetachedContent(cmsEncoder
, detachedContent
); 
1373     if(signedAttributes
) { 
1374         ortn 
= CMSEncoderAddSignedAttributes(cmsEncoder
, signedAttributes
); 
1380     ortn 
= CMSEncoderUpdateContent(cmsEncoder
, content
, contentLen
); 
1384     ortn 
= CMSEncoderCopyEncodedContent(cmsEncoder
, encodedContent
); 
1387     CFRelease(cmsEncoder
); 
1391 OSStatus 
CMSEncodeContent( 
1393                           CFTypeRef                     recipients
, 
1394                           CFTypeRef                     eContentTypeOID
, 
1395                           Boolean                               detachedContent
, 
1396                           CMSSignedAttributes   signedAttributes
, 
1397                           const void                    *content
, 
1399                           CFDataRef                     
*encodedContentOut
)     /* RETURNED */ 
1401     // convert eContentTypeOID to a CSSM_OID 
1402     SecAsn1Oid contentType 
= { 0, NULL 
}; 
1403     if (eContentTypeOID 
&& convertOid(eContentTypeOID
, &contentType
) != 0) 
1405     const SecAsn1Oid 
*contentTypePtr 
= (eContentTypeOID
) ? &contentType 
: NULL
; 
1406     OSStatus result 
= CMSEncode(signers
, recipients
, contentTypePtr
, 
1407                                 detachedContent
, signedAttributes
, 
1408                                 content
, contentLen
, encodedContentOut
); 
1409     if (contentType
.Data
) 
1410         free(contentType
.Data
); 
1414 #pragma mark --- SPI routines declared in CMSPrivate.h --- 
1417  * Obtain the SecCmsMessageRef associated with a CMSEncoderRef.  
1418  * If we don't have a SecCmsMessageRef yet, we create one now. 
1419  * This is the only place where we go to state ES_Msg.  
1421 OSStatus 
CMSEncoderGetCmsMessage( 
1422                                  CMSEncoderRef          cmsEncoder
, 
1423                                  SecCmsMessageRef       
*cmsMessage
)            /* RETURNED */ 
1425     if((cmsEncoder 
== NULL
) || (cmsMessage 
== NULL
)) { 
1428     if(cmsEncoder
->cmsMsg 
!= NULL
) { 
1429         ASSERT(cmsEncoder
->encState 
!= ES_Init
); 
1430         *cmsMessage 
= cmsEncoder
->cmsMsg
; 
1431         return errSecSuccess
; 
1434     OSStatus ortn 
= cmsSetupCmsMsg(cmsEncoder
); 
1438     *cmsMessage 
= cmsEncoder
->cmsMsg
; 
1440     /* Don't set up encoder yet; caller might do that via CMSEncoderSetEncoder */ 
1441     cmsEncoder
->encState 
= ES_Msg
; 
1442     return errSecSuccess
; 
1446  * Optionally specify a SecCmsEncoderRef to use with a CMSEncoderRef. 
1447  * If this is called, it must be called before the first call to  
1448  * CMSEncoderUpdateContent(). The CMSEncoderRef takes ownership of the 
1449  * incoming SecCmsEncoderRef. 
1451 OSStatus 
CMSEncoderSetEncoder( 
1452                               CMSEncoderRef             cmsEncoder
, 
1453                               SecCmsEncoderRef  encoder
) 
1455     if((cmsEncoder 
== NULL
) || (encoder 
== NULL
)) { 
1461     switch(cmsEncoder
->encState
) { 
1463             /* No message, no encoder */ 
1464             ASSERT(cmsEncoder
->cmsMsg 
== NULL
); 
1465             ASSERT(cmsEncoder
->encoder 
== NULL
); 
1466             ortn 
= cmsSetupCmsMsg(cmsEncoder
); 
1470             /* drop thru to set encoder */ 
1472             /* cmsMsg but no encoder */ 
1473             ASSERT(cmsEncoder
->cmsMsg 
!= NULL
); 
1474             ASSERT(cmsEncoder
->encoder 
== NULL
); 
1475             cmsEncoder
->encoder 
= encoder
; 
1476             cmsEncoder
->encState 
= ES_Updating
; 
1477             cmsEncoder
->customCoder 
= true;                     /* we won't see data */ 
1478             return errSecSuccess
; 
1480             /* no can do, too late */ 
1486  * Obtain the SecCmsEncoderRef associated with a CMSEncoderRef.  
1487  * Returns a NULL SecCmsEncoderRef if neither CMSEncoderSetEncoder nor 
1488  * CMSEncoderUpdateContent() has been called.  
1489  * The CMSEncoderRef retains ownership of the SecCmsEncoderRef. 
1491 OSStatus 
CMSEncoderGetEncoder( 
1492                               CMSEncoderRef             cmsEncoder
, 
1493                               SecCmsEncoderRef  
*encoder
)                       /* RETURNED */ 
1495     if((cmsEncoder 
== NULL
) || (encoder 
== NULL
)) { 
1499     /* any state, whether we have an encoder or not is OK */ 
1500     *encoder 
= cmsEncoder
->encoder
; 
1501     return errSecSuccess
; 
1504 #if TIMESTAMPING_SUPPORTED 
1505 #include <AssertMacros.h> 
1507  * Obtain the timestamp of signer 'signerIndex' of a CMS message, if 
1508  * present. This timestamp is an authenticated timestamp provided by 
1509  * a timestamping authority. 
1511  * Returns errSecParam if the CMS message was not signed or if signerIndex 
1512  * is greater than the number of signers of the message minus one.  
1514  * This cannot be called until after CMSEncoderCopyEncodedContent() is called.  
1516 OSStatus 
CMSEncoderCopySignerTimestamp( 
1517                                        CMSEncoderRef            cmsEncoder
, 
1518                                        size_t                           signerIndex
,        /* usually 0 */ 
1519                                        CFAbsoluteTime      
*timestamp
)                  /* RETURNED */ 
1521     return CMSEncoderCopySignerTimestampWithPolicy( 
1528 OSStatus 
CMSEncoderCopySignerTimestampWithPolicy( 
1529                                                  CMSEncoderRef          cmsEncoder
, 
1530                                                  CFTypeRef            timeStampPolicy
, 
1531                                                  size_t                         signerIndex
,        /* usually 0 */ 
1532                                                  CFAbsoluteTime      
*timestamp
)                        /* RETURNED */ 
1534     OSStatus status 
= errSecParam
; 
1535     SecCmsMessageRef cmsg
; 
1536     SecCmsSignedDataRef signedData 
= NULL
; 
1537     int numContentInfos 
= 0; 
1539     require(cmsEncoder 
&& timestamp
, xit
); 
1540     require_noerr(CMSEncoderGetCmsMessage(cmsEncoder
, &cmsg
), xit
); 
1541     numContentInfos 
= SecCmsMessageContentLevelCount(cmsg
); 
1542     for (int dex 
= 0; !signedData 
&& dex 
< numContentInfos
; dex
++) 
1544         SecCmsContentInfoRef ci 
= SecCmsMessageContentLevel(cmsg
, dex
); 
1545         SECOidTag tag 
= SecCmsContentInfoGetContentTypeTag(ci
); 
1546         if (tag 
== SEC_OID_PKCS7_SIGNED_DATA
) 
1547             if ((signedData 
= (SecCmsSignedDataRef
)SecCmsContentInfoGetContent(ci
))) { 
1548                 SecCmsSignerInfoRef signerInfo 
= SecCmsSignedDataGetSignerInfo(signedData
, (int)signerIndex
); 
1551                     status 
= SecCmsSignerInfoGetTimestampTimeWithPolicy(signerInfo
, timeStampPolicy
, timestamp
);