/ OSX / libsecurity_cms / lib / CMSEncoder.cpp
CMSEncoder.cpp
   1  /*
   2   * Copyright (c) 2006-2013 Apple Inc. All Rights Reserved.
   3   * 
   4   * @APPLE_LICENSE_HEADER_START@
   5   * 
   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
  11   * file.
  12   * 
  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.
  20   * 
  21   * @APPLE_LICENSE_HEADER_END@
  22   */
  23  
  24  /*
  25   * CMSEncoder.cpp - encode, sign, and/or encrypt CMS messages. 
  26   */
  27   
  28  #include <Security/CMSEncoder.h>
  29  #include <Security/CMSPrivate.h>
  30  #include "CMSUtils.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/SecKeychain.h>
  42  #include <Security/SecKeychainItem.h>
  43  #include <Security/SecSMIME.h>
  44  #include <Security/oidsattr.h>
  45  #include <Security/SecAsn1Coder.h>
  46  #include <Security/SecAsn1Types.h>
  47  #include <Security/SecAsn1Templates.h>
  48  #include <CoreFoundation/CFRuntime.h>
  49  #include <pthread.h>
  50  #include <utilities/SecCFRelease.h>
  51  
  52  #include <security_smime/tsaSupport.h>
  53  #include <security_smime/cmspriv.h>
  54  
  55  #pragma mark --- Private types and definitions ---
  56  
  57  /*
  58   * Encoder state.
  59   */
  60  typedef enum {
  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 */
  66  } CMSEncoderState;
  67  
  68  /* 
  69   * High-level operation: what are we doing? 
  70   */
  71  typedef enum {
  72  	EO_Sign,
  73  	EO_Encrypt,
  74  	EO_SignEncrypt
  75  } CMSEncoderOp;
  76  
  77  /*
  78   * Caller's CMSEncoderRef points to one of these.
  79   */
  80  struct _CMSEncoder {
  81  	CFRuntimeBase		base;
  82  	CMSEncoderState		encState;
  83  	CMSEncoderOp		op;
  84  	Boolean				detachedContent;
  85  	CSSM_OID			eContentType;
  86  	CFMutableArrayRef	signers;
  87  	CFMutableArrayRef	recipients;
  88  	CFMutableArrayRef	otherCerts;
  89  	CMSSignedAttributes	signedAttributes;
  90  	CFAbsoluteTime		signingTime;
  91  	SecCmsMessageRef	cmsMsg;
  92  	SecArenaPoolRef		arena;					/* the encoder's arena */
  93  	SecCmsEncoderRef	encoder;
  94  	CSSM_DATA			encoderOut;				/* output goes here... */
  95  	bool				customCoder;			/* unless this is set by 
  96  												 *    CMSEncoderSetEncoder */
  97  	SECOidTag		digestalgtag;
  98  
  99  	CMSCertificateChainMode chainMode;
 100      CFDataRef           hashAgilityAttrValue;
 101      CFDictionaryRef     hashAgilityV2AttrValues;
 102      CFAbsoluteTime      expirationTime;
 103  };
 104  
 105  static void cmsEncoderInit(CFTypeRef enc);
 106  static void cmsEncoderFinalize(CFTypeRef enc);
 107      
 108  static CFRuntimeClass cmsEncoderRuntimeClass = 
 109  {
 110  	0,			/* version */
 111  	"CMSEncoder",
 112  	cmsEncoderInit,
 113  	NULL,		/* copy */
 114  	cmsEncoderFinalize,
 115  	NULL,		/* equal - just use pointer equality */
 116  	NULL,		/* hash, ditto */
 117  	NULL,		/* copyFormattingDesc */
 118  	NULL		/* copyDebugDesc */
 119  };
 120  
 121  void
 122  CmsMessageSetTSACallback(CMSEncoderRef cmsEncoder, SecCmsTSACallback tsaCallback);
 123  
 124  #pragma mark --- Private routines ---
 125  
 126  /*
 127   * Decode a CFStringRef representation of an integer
 128   */
 129  static int cfStringToNumber(
 130  	CFStringRef inStr)
 131  {
 132  	int max = 32;
 133  	char buf[max];
 134  	if (!inStr || !CFStringGetCString(inStr, buf, max-1, kCFStringEncodingASCII))
 135  		return -1;
 136  	return atoi(buf);
 137  }
 138  	
 139  /*
 140   * Encode an integer component of an OID, return resulting number of bytes;
 141   * actual bytes are mallocd and returned in *encodeArray.
 142   */
 143  static unsigned encodeNumber(
 144  	int num,
 145  	unsigned char **encodeArray)		// mallocd and RETURNED 
 146  {
 147  	unsigned char *result;
 148  	unsigned dex;
 149  	unsigned numDigits = 0;
 150  	unsigned scratch;
 151  	
 152  	/* trival case - 0 maps to 0 */
 153  	if(num == 0) {
 154  		*encodeArray = (unsigned char *)malloc(1);
 155  		**encodeArray = 0;
 156  		return 1;
 157  	}
 158  	
 159  	/* first calculate the number of digits in num, base 128 */
 160  	scratch = (unsigned)num;
 161  	while(scratch != 0) {
 162  		numDigits++;
 163  		scratch >>= 7;
 164  	}
 165  	
 166  	result = (unsigned char *)malloc(numDigits);
 167  	scratch = (unsigned)num;
 168  	for(dex=0; dex<numDigits; dex++) { 
 169  		result[numDigits - dex - 1] = scratch & 0x7f;
 170  		scratch >>= 7;
 171  	}
 172  	
 173  	/* all digits except the last one have m.s. bit set */
 174  	for(dex=0; dex<(numDigits - 1); dex++) {
 175  		result[dex] |= 0x80;
 176  	}
 177  	
 178  	*encodeArray = result;
 179  	return numDigits;
 180  }
 181  
 182  /*
 183   * Given an OID in dotted-decimal string representation, convert to binary
 184   * DER format. Returns a pointer in outOid which the caller must free(),
 185   * as well as the length of the data in outLen.
 186   * Function returns 0 if successful, non-zero otherwise.
 187   */
 188  static int encodeOid(
 189  	const unsigned char *inStr,
 190  	unsigned char **outOid,
 191  	unsigned int *outLen)
 192  {
 193  	unsigned char **digits = NULL;		/* array of char * from encodeNumber */
 194  	unsigned *numDigits = NULL;			/* array of unsigned from encodeNumber */
 195  	CFIndex digit;
 196  	unsigned numDigitBytes;				/* total #of output chars */
 197  	unsigned char firstByte;
 198  	unsigned char *outP;
 199  	CFIndex numsToProcess;
 200  	CFStringRef oidStr = NULL;
 201  	CFArrayRef argvRef = NULL;
 202  	int num, result = 1;
 203          CFIndex argc;
 204  	
 205  	/* parse input string into array of substrings */
 206  	if (!inStr || !outOid || !outLen) goto cleanExit;
 207  	oidStr = CFStringCreateWithCString(NULL, (const char *)inStr, kCFStringEncodingASCII);
 208  	if (!oidStr) goto cleanExit;
 209  	argvRef = CFStringCreateArrayBySeparatingStrings(NULL, oidStr, CFSTR("."));
 210  	if (!argvRef) goto cleanExit;
 211  	argc = CFArrayGetCount(argvRef);
 212  	if (argc < 3) goto cleanExit;
 213  	
 214  	/* first two numbers in OID munge together */
 215  	num = cfStringToNumber((CFStringRef)CFArrayGetValueAtIndex(argvRef, 0));
 216  	if (num < 0) goto cleanExit;
 217  	firstByte = (40 * num);
 218  	num = cfStringToNumber((CFStringRef)CFArrayGetValueAtIndex(argvRef, 1));
 219  	if (num < 0) goto cleanExit;
 220  	firstByte += num;
 221  	numDigitBytes = 1;
 222  
 223  	numsToProcess = argc - 2;
 224  	if(numsToProcess > 0) {
 225  		/* skip this loop in the unlikely event that input is only two numbers */
 226  		digits = (unsigned char **) malloc(numsToProcess * sizeof(unsigned char *));
 227  		numDigits = (unsigned *) malloc(numsToProcess * sizeof(unsigned));
 228  		for(digit=0; digit<numsToProcess; digit++) {
 229  			num = cfStringToNumber((CFStringRef)CFArrayGetValueAtIndex(argvRef, digit+2));
 230  			if (num < 0) goto cleanExit;
 231  			numDigits[digit] = encodeNumber(num, &digits[digit]);
 232  			numDigitBytes += numDigits[digit];
 233  		}
 234  	}
 235  	*outLen = (2 + numDigitBytes);
 236  	*outOid = outP = (unsigned char *) malloc(*outLen);
 237  	*outP++ = 0x06;
 238  	*outP++ = numDigitBytes;
 239  	*outP++ = firstByte;
 240  	for(digit=0; digit<numsToProcess; digit++) {
 241  		unsigned int byteDex;
 242  		for(byteDex=0; byteDex<numDigits[digit]; byteDex++) {
 243  			*outP++ = digits[digit][byteDex];
 244  		}
 245  	}	
 246  	if(digits) {
 247  		for(digit=0; digit<numsToProcess; digit++) {
 248  			free(digits[digit]);
 249  		}
 250  	}
 251  	result = 0;
 252  
 253  cleanExit:
 254      if (digits) free(digits);
 255      if (numDigits) free(numDigits);
 256  	if (oidStr) CFRelease(oidStr);
 257  	if (argvRef) CFRelease(argvRef);
 258  
 259  	return result;
 260  }
 261  
 262  /*
 263   * Given a CF object reference describing an OID, convert to binary DER format
 264   * and fill out the CSSM_OID structure provided by the caller. Caller is
 265   * responsible for freeing the data pointer in outOid->Data.
 266   *
 267   * Function returns 0 if successful, non-zero otherwise.
 268   */
 269  
 270  static int convertOid(
 271  	CFTypeRef inRef,
 272  	CSSM_OID *outOid)
 273  {
 274  	if (!inRef || !outOid)
 275  		return errSecParam;
 276  	
 277  	unsigned char *oidData = NULL;
 278  	unsigned int oidLen = 0;
 279  
 280  	if (CFGetTypeID(inRef) == CFStringGetTypeID()) {
 281  		// CFStringRef: OID representation is a dotted-decimal string
 282  		CFStringRef inStr = (CFStringRef)inRef;
 283  		CFIndex max = CFStringGetLength(inStr) * 3;
 284  		char *buf = (char *)malloc(max);
 285  		if (!buf) {
 286  			return errSecMemoryError;
 287  		}
 288  		if (!CFStringGetCString(inStr, buf, max-1, kCFStringEncodingASCII)) {
 289  			free(buf);
 290  			return errSecParam;
 291  		}
 292  
 293  		if (encodeOid((unsigned char *)buf, &oidData, &oidLen) != 0) {
 294  			free(buf);
 295  			return errSecParam;
 296  		}
 297  		free(buf);
 298  	}
 299  	else if (CFGetTypeID(inRef) == CFDataGetTypeID()) {
 300  		// CFDataRef: OID representation is in binary DER format
 301  		CFDataRef inData = (CFDataRef)inRef;
 302  		oidLen = (unsigned int) CFDataGetLength(inData);
 303  		oidData = (unsigned char *) malloc(oidLen);
 304  		memcpy(oidData, CFDataGetBytePtr(inData), oidLen);
 305  	}
 306  	else {
 307  		// Not in a format we understand
 308  		return errSecParam;
 309  	}
 310  	outOid->Length = oidLen;
 311  	outOid->Data = (uint8 *)oidData;
 312  	return 0;
 313  }
 314  
 315  static CFTypeID cmsEncoderTypeID = _kCFRuntimeNotATypeID;
 316  
 317  /* one time only class init, called via pthread_once() in CMSEncoderGetTypeID() */
 318  static void cmsEncoderClassInitialize(void)
 319  {
 320  	cmsEncoderTypeID = 
 321  		_CFRuntimeRegisterClass((const CFRuntimeClass * const)&cmsEncoderRuntimeClass);
 322  }
 323  
 324  /* init called out from _CFRuntimeCreateInstance() */
 325  static void cmsEncoderInit(CFTypeRef enc)
 326  {
 327  	char *start = ((char *)enc) + sizeof(CFRuntimeBase);
 328  	memset(start, 0, sizeof(struct _CMSEncoder) - sizeof(CFRuntimeBase));
 329  }
 330  
 331  /*
 332   * Dispose of a CMSEncoder. Called out from CFRelease().
 333   */
 334  static void cmsEncoderFinalize(
 335  	CFTypeRef		enc)
 336  {
 337  	CMSEncoderRef cmsEncoder = (CMSEncoderRef)enc;
 338  	if(cmsEncoder == NULL) {
 339  		return;
 340  	}
 341  	if(cmsEncoder->eContentType.Data != NULL) {
 342  		free(cmsEncoder->eContentType.Data);
 343  	}
 344  	CFRELEASE(cmsEncoder->signers);
 345  	CFRELEASE(cmsEncoder->recipients);
 346  	CFRELEASE(cmsEncoder->otherCerts);
 347  	if(cmsEncoder->cmsMsg != NULL) {
 348  		SecCmsMessageDestroy(cmsEncoder->cmsMsg);
 349  		cmsEncoder->cmsMsg = NULL;
 350  	}
 351  	if(cmsEncoder->arena != NULL) {
 352  		SecArenaPoolFree(cmsEncoder->arena, false);
 353  	}
 354  	if(cmsEncoder->encoder != NULL) {
 355  		/* 
 356  		 * Normally this gets freed in SecCmsEncoderFinish - this is 
 357  		 * an error case.
 358  		 */
 359  		SecCmsEncoderDestroy(cmsEncoder->encoder);
 360  	}
 361  }
 362  
 363  static OSStatus cmsSetupEncoder(
 364  	CMSEncoderRef		cmsEncoder)
 365  {
 366  	OSStatus ortn;
 367  	
 368  	ASSERT(cmsEncoder->arena == NULL);
 369  	ASSERT(cmsEncoder->encoder == NULL);
 370  	
 371  	ortn = SecArenaPoolCreate(1024, &cmsEncoder->arena);
 372  	if(ortn) {
 373  		return cmsRtnToOSStatus(ortn);
 374  	}
 375  	ortn = SecCmsEncoderCreate(cmsEncoder->cmsMsg, 
 376  		NULL, NULL,					// no callback 
 377  		&cmsEncoder->encoderOut,	// data goes here
 378  		cmsEncoder->arena,	
 379  		NULL, NULL,					// no password callback (right?) 
 380  		NULL, NULL,					// decrypt key callback
 381  		NULL, NULL,					// detached digests
 382  		&cmsEncoder->encoder);
 383  	if(ortn) {
 384  		return cmsRtnToOSStatus(ortn);
 385  	}
 386  	return errSecSuccess;
 387  }
 388  
 389  /* 
 390   * Set up a SecCmsMessageRef for a SignedData creation.
 391   */
 392  static OSStatus cmsSetupForSignedData(
 393  	CMSEncoderRef		cmsEncoder)
 394  {
 395  	ASSERT((cmsEncoder->signers != NULL) || (cmsEncoder->otherCerts != NULL));
 396  	
 397      SecCmsContentInfoRef contentInfo = NULL;
 398      SecCmsSignedDataRef signedData = NULL;
 399  	OSStatus ortn;
 400  
 401      /* build chain of objects: message->signedData->data */
 402  	if(cmsEncoder->cmsMsg != NULL) {
 403  		SecCmsMessageDestroy(cmsEncoder->cmsMsg);
 404  	}
 405  	cmsEncoder->cmsMsg = SecCmsMessageCreate(NULL);
 406  	if(cmsEncoder->cmsMsg == NULL) {
 407  		return errSecInternalComponent;
 408  	}
 409  
 410  	signedData = SecCmsSignedDataCreate(cmsEncoder->cmsMsg);
 411  	if(signedData == NULL) {
 412  		return errSecInternalComponent;
 413  	}
 414  	contentInfo = SecCmsMessageGetContentInfo(cmsEncoder->cmsMsg);
 415  	ortn = SecCmsContentInfoSetContentSignedData(cmsEncoder->cmsMsg, contentInfo, 
 416  			signedData);
 417  	if(ortn) {
 418  		return cmsRtnToOSStatus(ortn);
 419  	}
 420      contentInfo = SecCmsSignedDataGetContentInfo(signedData);
 421  	if(cmsEncoder->eContentType.Data != NULL) {
 422  		/* Override the default eContentType of id-data */
 423  		ortn = SecCmsContentInfoSetContentOther(cmsEncoder->cmsMsg, 
 424  			contentInfo, 
 425  			NULL,		/* data - provided to encoder, not here */
 426  			cmsEncoder->detachedContent,
 427  			&cmsEncoder->eContentType);
 428  	}
 429  	else {
 430  		ortn = SecCmsContentInfoSetContentData(cmsEncoder->cmsMsg, 
 431  			contentInfo, 
 432  			NULL, /* data - provided to encoder, not here */
 433  			cmsEncoder->detachedContent);
 434  	}
 435  	if(ortn) {
 436  		ortn = cmsRtnToOSStatus(ortn);
 437  		CSSM_PERROR("SecCmsContentInfoSetContent*", ortn);
 438  		return ortn;
 439  	}
 440  
 441  	/* optional 'global' (per-SignedData) certs */
 442  	if(cmsEncoder->otherCerts != NULL) {
 443  		ortn = SecCmsSignedDataAddCertList(signedData, cmsEncoder->otherCerts);
 444  		if(ortn) {
 445  			ortn = cmsRtnToOSStatus(ortn);
 446  			CSSM_PERROR("SecCmsSignedDataAddCertList", ortn);
 447  			return ortn;
 448  		}
 449  	}
 450  	
 451  	/* SignerInfos, one per signer */
 452  	CFIndex numSigners = 0;
 453  	if(cmsEncoder->signers != NULL) {
 454  		/* this is optional...in case we're just creating a cert bundle */
 455  		numSigners = CFArrayGetCount(cmsEncoder->signers);
 456  	}
 457  	CFIndex dex;
 458  	SecCertificateRef ourCert = NULL;
 459  	SecCmsCertChainMode chainMode = SecCmsCMCertChain;
 460  
 461  	switch(cmsEncoder->chainMode) {
 462  		case kCMSCertificateNone:
 463  			chainMode = SecCmsCMNone;
 464  			break;
 465  		case kCMSCertificateSignerOnly:
 466  			chainMode = SecCmsCMCertOnly;
 467  			break;
 468  		case kCMSCertificateChainWithRoot:
 469  			chainMode = SecCmsCMCertChainWithRoot;
 470  			break;
 471  		case kCMSCertificateChainWithRootOrFail:
 472  			chainMode = SecCmsCMCertChainWithRootOrFail;
 473  			break;
 474  		default:
 475  			break;
 476  	}
 477  	for(dex=0; dex<numSigners; dex++) {
 478  		SecCmsSignerInfoRef signerInfo;
 479  		
 480  		SecIdentityRef ourId = 
 481  			(SecIdentityRef)CFArrayGetValueAtIndex(cmsEncoder->signers, dex);
 482  		ortn = SecIdentityCopyCertificate(ourId, &ourCert);
 483  		if(ortn) {
 484  			CSSM_PERROR("SecIdentityCopyCertificate", ortn);
 485  			break;
 486  		}
 487  		signerInfo = SecCmsSignerInfoCreate(cmsEncoder->cmsMsg, ourId, cmsEncoder->digestalgtag);
 488  		if (signerInfo == NULL) {
 489  			ortn = errSecInternalComponent;
 490  			break;
 491  		}
 492  
 493  		/* we want the cert chain included for this one */
 494  		/* NOTE the usage parameter is currently unused by the SMIME lib */
 495  		ortn = SecCmsSignerInfoIncludeCerts(signerInfo, chainMode, 
 496  			certUsageEmailSigner);
 497  		if(ortn) {
 498  			ortn = cmsRtnToOSStatus(ortn);
 499  			CSSM_PERROR("SecCmsSignerInfoIncludeCerts", ortn);
 500  			break;
 501  		}
 502  		
 503  		/* other options */
 504  		if(cmsEncoder->signedAttributes & kCMSAttrSmimeCapabilities) {
 505  			ortn = SecCmsSignerInfoAddSMIMECaps(signerInfo);
 506  			if(ortn) {
 507  				ortn = cmsRtnToOSStatus(ortn);
 508  				CSSM_PERROR("SecCmsSignerInfoAddSMIMEEncKeyPrefs", ortn);
 509  				break;
 510  			}
 511  		}
 512  		if(cmsEncoder->signedAttributes & kCMSAttrSmimeEncryptionKeyPrefs) {
 513  			ortn = SecCmsSignerInfoAddSMIMEEncKeyPrefs(signerInfo, ourCert, NULL);
 514  			if(ortn) {
 515  				ortn = cmsRtnToOSStatus(ortn);
 516  				CSSM_PERROR("SecCmsSignerInfoAddSMIMEEncKeyPrefs", ortn);
 517  				break;
 518  			}
 519  		}
 520  		if(cmsEncoder->signedAttributes & kCMSAttrSmimeMSEncryptionKeyPrefs) {
 521  			ortn = SecCmsSignerInfoAddMSSMIMEEncKeyPrefs(signerInfo, ourCert, NULL);
 522  			if(ortn) {
 523  				ortn = cmsRtnToOSStatus(ortn);
 524  				CSSM_PERROR("SecCmsSignerInfoAddMSSMIMEEncKeyPrefs", ortn);
 525  				break;
 526  			}
 527  		}
 528  		if(cmsEncoder->signedAttributes & kCMSAttrSigningTime) {
 529  			if (cmsEncoder->signingTime == 0)
 530  				cmsEncoder->signingTime = CFAbsoluteTimeGetCurrent();
 531  			ortn = SecCmsSignerInfoAddSigningTime(signerInfo, cmsEncoder->signingTime);
 532  			if(ortn) {
 533  				ortn = cmsRtnToOSStatus(ortn);
 534  				CSSM_PERROR("SecCmsSignerInfoAddSigningTime", ortn);
 535  				break;
 536  			}
 537  		}
 538          if(cmsEncoder->signedAttributes & kCMSAttrAppleCodesigningHashAgility) {
 539              ortn = SecCmsSignerInfoAddAppleCodesigningHashAgility(signerInfo, cmsEncoder->hashAgilityAttrValue);
 540              /* libsecurity_smime made a copy of the attribute value. We don't need it anymore. */
 541              CFReleaseNull(cmsEncoder->hashAgilityAttrValue);
 542              if(ortn) {
 543                  ortn = cmsRtnToOSStatus(ortn);
 544                  CSSM_PERROR("SecCmsSignerInfoAddAppleCodesigningHashAgility", ortn);
 545                  break;
 546              }
 547          }
 548          if(cmsEncoder->signedAttributes & kCMSAttrAppleCodesigningHashAgilityV2) {
 549              ortn = SecCmsSignerInfoAddAppleCodesigningHashAgilityV2(signerInfo, cmsEncoder->hashAgilityV2AttrValues);
 550              /* libsecurity_smime made a copy of the attribute value. We don't need it anymore. */
 551              CFReleaseNull(cmsEncoder->hashAgilityV2AttrValues);
 552              if(ortn) {
 553                  ortn = cmsRtnToOSStatus(ortn);
 554                  CSSM_PERROR("SecCmsSignerInfoAddAppleCodesigningHashAgilityV2", ortn);
 555                  break;
 556              }
 557          }
 558          if (cmsEncoder->signedAttributes & kCMSAttrAppleExpirationTime) {
 559              ortn = SecCmsSignerInfoAddAppleExpirationTime(signerInfo, cmsEncoder->expirationTime);
 560              if(ortn) {
 561                  ortn = cmsRtnToOSStatus(ortn);
 562                  CSSM_PERROR("SecCmsSignerInfoAddAppleExpirationTime", ortn);
 563                  break;
 564              }
 565          }
 566  		
 567  		ortn = SecCmsSignedDataAddSignerInfo(signedData, signerInfo);
 568  		if(ortn) {
 569  			ortn = cmsRtnToOSStatus(ortn);
 570  			CSSM_PERROR("SecCmsSignedDataAddSignerInfo", ortn);
 571  			break;
 572  		}
 573  
 574  		CFRELEASE(ourCert);
 575  		ourCert = NULL;
 576  	}
 577  	if(ortn) {
 578  		CFRELEASE(ourCert);
 579  	}
 580  	return ortn;
 581  }
 582  
 583  /* 
 584   * Set up a SecCmsMessageRef for a EnvelopedData creation.
 585   */
 586  static OSStatus cmsSetupForEnvelopedData(
 587  	CMSEncoderRef		cmsEncoder)
 588  {
 589  	ASSERT(cmsEncoder->op == EO_Encrypt);
 590  	ASSERT(cmsEncoder->recipients != NULL);
 591  	
 592      SecCmsContentInfoRef contentInfo = NULL;
 593      SecCmsEnvelopedDataRef envelopedData = NULL;
 594  	SECOidTag algorithmTag;
 595      int keySize;
 596  	OSStatus ortn;
 597  
 598  	/*
 599  	 * Find encryption algorithm...unfortunately we need a NULL-terminated array
 600  	 * of SecCertificateRefs for this.
 601  	 */
 602  	CFIndex numCerts = CFArrayGetCount(cmsEncoder->recipients);
 603  	CFIndex dex;
 604  	SecCertificateRef *certArray = (SecCertificateRef *)malloc(
 605  		(numCerts+1) * sizeof(SecCertificateRef));
 606  
 607  	for(dex=0; dex<numCerts; dex++) {
 608  		certArray[dex] = (SecCertificateRef)CFArrayGetValueAtIndex(
 609  			cmsEncoder->recipients, dex);
 610  	}
 611  	certArray[numCerts] = NULL;
 612  	ortn = SecSMIMEFindBulkAlgForRecipients(certArray, &algorithmTag, &keySize);
 613  	free(certArray);
 614  	if(ortn) {
 615  		CSSM_PERROR("SecSMIMEFindBulkAlgForRecipients", ortn);
 616  		return ortn;
 617  	}
 618  	
 619      /* build chain of objects: message->envelopedData->data */
 620  	if(cmsEncoder->cmsMsg != NULL) {
 621  		SecCmsMessageDestroy(cmsEncoder->cmsMsg);
 622  	}
 623  	cmsEncoder->cmsMsg = SecCmsMessageCreate(NULL);
 624  	if(cmsEncoder->cmsMsg == NULL) {
 625  		return errSecInternalComponent;
 626  	}
 627  	envelopedData = SecCmsEnvelopedDataCreate(cmsEncoder->cmsMsg, 
 628  		algorithmTag, keySize);
 629  	if(envelopedData == NULL) {
 630  		return errSecInternalComponent;
 631  	}
 632  	contentInfo = SecCmsMessageGetContentInfo(cmsEncoder->cmsMsg);
 633  	ortn = SecCmsContentInfoSetContentEnvelopedData(cmsEncoder->cmsMsg, 
 634  		contentInfo, envelopedData);
 635  	if(ortn) {
 636  		ortn = cmsRtnToOSStatus(ortn);
 637  		CSSM_PERROR("SecCmsContentInfoSetContentEnvelopedData", ortn);
 638  		return ortn;
 639  	}
 640      contentInfo = SecCmsEnvelopedDataGetContentInfo(envelopedData);
 641  	if(cmsEncoder->eContentType.Data != NULL) {
 642  		/* Override the default ContentType of id-data */
 643  		ortn = SecCmsContentInfoSetContentOther(cmsEncoder->cmsMsg, 
 644  			contentInfo, 
 645  			NULL,		/* data - provided to encoder, not here */
 646  			FALSE,		/* detachedContent */
 647  			&cmsEncoder->eContentType);
 648  	}
 649  	else {
 650  		ortn = SecCmsContentInfoSetContentData(cmsEncoder->cmsMsg, 
 651  			contentInfo, 
 652  			NULL /* data - provided to encoder, not here */, 
 653  			cmsEncoder->detachedContent);
 654  	}
 655  	if(ortn) {
 656  		ortn = cmsRtnToOSStatus(ortn);
 657  		CSSM_PERROR("SecCmsContentInfoSetContentData*", ortn);
 658  		return ortn;
 659  	}
 660  
 661      /* 
 662       * create & attach recipient information, one for each recipient
 663       */
 664  	for(dex=0; dex<numCerts; dex++) {
 665  		SecCmsRecipientInfoRef recipientInfo = NULL;
 666  		
 667  		SecCertificateRef thisRecip = (SecCertificateRef)CFArrayGetValueAtIndex(
 668  			cmsEncoder->recipients, dex);
 669  		recipientInfo = SecCmsRecipientInfoCreate(cmsEncoder->cmsMsg, thisRecip);
 670  		ortn = SecCmsEnvelopedDataAddRecipient(envelopedData, recipientInfo);
 671  		if(ortn) {
 672  			ortn = cmsRtnToOSStatus(ortn);
 673  			CSSM_PERROR("SecCmsEnvelopedDataAddRecipient", ortn);
 674  			return ortn;
 675  		}
 676  	}
 677  	return errSecSuccess;
 678  }
 679  
 680  /* 
 681   * Set up cmsMsg. Called from either the first call to CMSEncoderUpdateContent, or
 682   * from CMSEncodeGetCmsMessage().
 683   */
 684  static OSStatus cmsSetupCmsMsg(
 685  	CMSEncoderRef		cmsEncoder)
 686  {
 687  	ASSERT(cmsEncoder != NULL);
 688  	ASSERT(cmsEncoder->encState == ES_Init);
 689  	
 690  	/* figure out what high-level operation we're doing */
 691  	if((cmsEncoder->signers != NULL) || (cmsEncoder->otherCerts != NULL)) {
 692  		if(cmsEncoder->recipients != NULL) {
 693  			cmsEncoder->op = EO_SignEncrypt;
 694  		}
 695  		else {
 696  			cmsEncoder->op = EO_Sign;
 697  		}
 698  	}
 699  	else if(cmsEncoder->recipients != NULL) {
 700  		cmsEncoder->op = EO_Encrypt;
 701  	}
 702  	else {
 703  		dprintf("CMSEncoderUpdateContent: nothing to do\n");
 704  		return errSecParam;
 705  	}
 706  	
 707  	OSStatus ortn = errSecSuccess;
 708  	
 709  	switch(cmsEncoder->op) {
 710  		case EO_Sign:
 711  		case EO_SignEncrypt:
 712  			/* If we're signing & encrypting, do the signing first */
 713  			ortn = cmsSetupForSignedData(cmsEncoder);
 714  			break;
 715  		case EO_Encrypt:
 716  			ortn = cmsSetupForEnvelopedData(cmsEncoder);
 717  			break;
 718  	}
 719  	cmsEncoder->encState = ES_Msg;
 720  	return ortn;
 721  }
 722  
 723  /* 
 724   * ASN.1 template for decoding a ContentInfo.
 725   */
 726  typedef struct {
 727      CSSM_OID	contentType;
 728      CSSM_DATA	content;    
 729  } SimpleContentInfo;
 730  
 731  static const SecAsn1Template cmsSimpleContentInfoTemplate[] = {
 732      { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(SimpleContentInfo) },
 733      { SEC_ASN1_OBJECT_ID, offsetof(SimpleContentInfo, contentType) },
 734      { SEC_ASN1_EXPLICIT | SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC | 0, 
 735  	  offsetof(SimpleContentInfo, content),
 736  	  kSecAsn1AnyTemplate },
 737      { 0, }
 738  };
 739  
 740  /*
 741   * Obtain the content of a contentInfo, This basically strips off the contentType OID
 742   * and returns its ASN_ANY content, allocated the provided coder's memory space. 
 743   */
 744  static OSStatus cmsContentInfoContent(
 745  	SecAsn1CoderRef asn1Coder,
 746  	const CSSM_DATA *contentInfo,
 747  	CSSM_DATA *content)				/* RETURNED */
 748  {
 749      OSStatus ortn;
 750      SimpleContentInfo decodedInfo;
 751      
 752      memset(&decodedInfo, 0, sizeof(decodedInfo));
 753      ortn = SecAsn1DecodeData(asn1Coder, contentInfo, 
 754  		cmsSimpleContentInfoTemplate, &decodedInfo);
 755      if(ortn) {
 756  		return ortn;
 757      }
 758      if(decodedInfo.content.Data == NULL) {
 759  		dprintf("***Error decoding contentInfo: no content\n");
 760  		return errSecInternalComponent;
 761      }
 762      *content = decodedInfo.content;
 763  	return errSecSuccess;
 764  }
 765  
 766  #pragma mark --- Start of Public API ---
 767  
 768  CFTypeID CMSEncoderGetTypeID(void)
 769  {
 770  	static pthread_once_t once = PTHREAD_ONCE_INIT;
 771  	
 772  	if(cmsEncoderTypeID == _kCFRuntimeNotATypeID) {
 773  		pthread_once(&once, &cmsEncoderClassInitialize);
 774  	}
 775  	return cmsEncoderTypeID;
 776  }
 777  
 778  /*
 779   * Create a CMSEncoder. Result must eventually be freed via CFRelease().
 780   */
 781  OSStatus CMSEncoderCreate(
 782  	CMSEncoderRef		*cmsEncoderOut)	/* RETURNED */
 783  {
 784  	CMSEncoderRef cmsEncoder = NULL;
 785  	
 786  	uint32_t extra = sizeof(*cmsEncoder) - sizeof(cmsEncoder->base);
 787  	cmsEncoder = (CMSEncoderRef)_CFRuntimeCreateInstance(NULL, CMSEncoderGetTypeID(),
 788  		extra, NULL);
 789  	if(cmsEncoder == NULL) {
 790  		return errSecAllocate;
 791  	}
 792  	cmsEncoder->encState = ES_Init;
 793  	cmsEncoder->chainMode = kCMSCertificateChain;
 794  	cmsEncoder->digestalgtag = SEC_OID_SHA1;
 795  	*cmsEncoderOut = cmsEncoder;
 796  	return errSecSuccess;
 797  }
 798  	
 799  #pragma mark --- Getters & Setters ---
 800  
 801  const CFStringRef __nonnull kCMSEncoderDigestAlgorithmSHA1 = CFSTR("sha1");
 802  const CFStringRef __nonnull kCMSEncoderDigestAlgorithmSHA256 = CFSTR("sha256");
 803  
 804  
 805  OSStatus CMSEncoderSetSignerAlgorithm(
 806  	CMSEncoderRef		cmsEncoder,
 807  	CFStringRef		digestAlgorithm)
 808  {
 809      if (CFEqual(digestAlgorithm, kCMSEncoderDigestAlgorithmSHA1)) {
 810  	cmsEncoder->digestalgtag = SEC_OID_SHA1;
 811      } else if (CFEqual(digestAlgorithm, kCMSEncoderDigestAlgorithmSHA256)) {
 812  	cmsEncoder->digestalgtag = SEC_OID_SHA256;
 813      } else {
 814  	return errSecParam;
 815      }
 816  
 817      return errSecSuccess;
 818  }
 819  
 820  /* 
 821   * Specify signers of the CMS message; implies that the message will be signed. 
 822   */
 823  OSStatus CMSEncoderAddSigners(
 824  	CMSEncoderRef		cmsEncoder,
 825  	CFTypeRef			signerOrArray)
 826  {
 827  	if(cmsEncoder == NULL) {
 828  		return errSecParam;
 829  	}
 830  	if(cmsEncoder->encState != ES_Init) {
 831  		return errSecParam;
 832  	}
 833  	return cmsAppendToArray(signerOrArray, &cmsEncoder->signers, SecIdentityGetTypeID());
 834  }
 835  
 836  /*
 837   * Obtain an array of signers as specified in CMSEncoderSetSigners(). 
 838   */
 839  OSStatus CMSEncoderCopySigners(
 840  	CMSEncoderRef		cmsEncoder,
 841  	CFArrayRef			*signers)
 842  {
 843  	if((cmsEncoder == NULL) || (signers == NULL)) {
 844  		return errSecParam;
 845  	}
 846  	if(cmsEncoder->signers != NULL) {
 847  		CFRetain(cmsEncoder->signers);
 848  	}
 849  	*signers = cmsEncoder->signers;
 850  	return errSecSuccess;
 851  }
 852  
 853  /*
 854   * Specify recipients of the message. Implies that the message will be encrypted. 
 855   */
 856  OSStatus CMSEncoderAddRecipients(
 857  	CMSEncoderRef		cmsEncoder,
 858  	CFTypeRef			recipientOrArray)
 859  {
 860  	if(cmsEncoder == NULL) {
 861  		return errSecParam;
 862  	}
 863  	if(cmsEncoder->encState != ES_Init) {
 864  		return errSecParam;
 865  	}
 866  	return cmsAppendToArray(recipientOrArray, &cmsEncoder->recipients, 
 867  			SecCertificateGetTypeID());
 868  }
 869  
 870  /*
 871   * Obtain an array of recipients as specified in CMSEncoderSetRecipients(). 
 872   */
 873  OSStatus CMSEncoderCopyRecipients(
 874  	CMSEncoderRef		cmsEncoder,
 875  	CFArrayRef			*recipients)
 876  {
 877  	if((cmsEncoder == NULL) || (recipients == NULL)) {
 878  		return errSecParam;
 879  	}
 880  	if(cmsEncoder->recipients != NULL) {
 881  		CFRetain(cmsEncoder->recipients);
 882  	}
 883  	*recipients = cmsEncoder->recipients;
 884  	return errSecSuccess;
 885  }
 886  
 887  /* 
 888   * Specify additional certs to include in a signed message. 
 889   */
 890  OSStatus CMSEncoderAddSupportingCerts(
 891  	CMSEncoderRef		cmsEncoder,
 892  	CFTypeRef			certOrArray)
 893  {
 894  	if(cmsEncoder == NULL) {
 895  		return errSecParam;
 896  	}
 897  	if(cmsEncoder->encState != ES_Init) {
 898  		return errSecParam;
 899  	}
 900  	return cmsAppendToArray(certOrArray, &cmsEncoder->otherCerts, 
 901  			SecCertificateGetTypeID());
 902  }
 903  	
 904  /*
 905   * Obtain the SecCertificates provided in CMSEncoderAddSupportingCerts(). 
 906   */
 907  OSStatus CMSEncoderCopySupportingCerts(
 908  	CMSEncoderRef		cmsEncoder,
 909  	CFArrayRef			*certs)			/* RETURNED */
 910  {
 911  	if((cmsEncoder == NULL) || (certs == NULL)) {
 912  		return errSecParam;
 913  	}
 914  	if(cmsEncoder->otherCerts != NULL) {
 915  		CFRetain(cmsEncoder->otherCerts);
 916  	}
 917  	*certs = cmsEncoder->otherCerts;
 918  	return errSecSuccess;
 919  }
 920  
 921  OSStatus CMSEncoderSetHasDetachedContent(
 922  	CMSEncoderRef		cmsEncoder,
 923  	Boolean				detachedContent)
 924  {
 925  	if(cmsEncoder == NULL) {
 926  		return errSecParam;
 927  	}
 928  	if(cmsEncoder->encState != ES_Init) {
 929  		return errSecParam;
 930  	}
 931  	cmsEncoder->detachedContent = detachedContent;
 932  	return errSecSuccess;
 933  }
 934  
 935  OSStatus CMSEncoderGetHasDetachedContent(
 936  	CMSEncoderRef		cmsEncoder,
 937  	Boolean				*detachedContent)	/* RETURNED */
 938  {
 939  	if((cmsEncoder == NULL) || (detachedContent == NULL)) {
 940  		return errSecParam;
 941  	}
 942  	*detachedContent = cmsEncoder->detachedContent;
 943  	return errSecSuccess;
 944  }
 945  
 946  /*
 947   * Optionally specify an eContentType OID for the inner EncapsulatedData for
 948   * a signed message. The default eContentType, used of this function is not
 949   * called, is id-data. 
 950   */
 951  OSStatus CMSEncoderSetEncapsulatedContentType(
 952  	CMSEncoderRef		cmsEncoder,
 953  	const CSSM_OID	*eContentType)
 954  {
 955  	if((cmsEncoder == NULL) || (eContentType == NULL)) {
 956  		return errSecParam;
 957  	}
 958  	if(cmsEncoder->encState != ES_Init) {
 959  		return errSecParam;
 960  	}
 961  	
 962  	CSSM_OID *ecOid = &cmsEncoder->eContentType;
 963  	if(ecOid->Data != NULL) {
 964  		free(ecOid->Data);
 965  	}
 966  	cmsCopyCmsData(eContentType, ecOid);
 967  	return errSecSuccess;
 968  }
 969  
 970  OSStatus CMSEncoderSetEncapsulatedContentTypeOID(
 971  	CMSEncoderRef		cmsEncoder,
 972  	CFTypeRef			eContentTypeOID)
 973  {
 974  	// convert eContentTypeOID to a CSSM_OID
 975  	CSSM_OID contentType = { 0, NULL };
 976  	if (!eContentTypeOID || convertOid(eContentTypeOID, &contentType) != 0)
 977  		return errSecParam;
 978  	OSStatus result = CMSEncoderSetEncapsulatedContentType(cmsEncoder, &contentType);
 979  	if (contentType.Data)
 980  		free(contentType.Data);
 981  	return result;
 982  }
 983  
 984  /*
 985   * Obtain the eContentType OID specified in CMSEncoderSetEncapsulatedContentType().
 986   */
 987  OSStatus CMSEncoderCopyEncapsulatedContentType(
 988  	CMSEncoderRef		cmsEncoder,
 989  	CFDataRef			*eContentType)
 990  {
 991  	if((cmsEncoder == NULL) || (eContentType == NULL)) {
 992  		return errSecParam;
 993  	}
 994  	
 995  	CSSM_OID *ecOid = &cmsEncoder->eContentType;
 996  	if(ecOid->Data == NULL) {
 997  		*eContentType = NULL;
 998  	}
 999  	else {
1000  		*eContentType = CFDataCreate(NULL, ecOid->Data, ecOid->Length);
1001  	}
1002  	return errSecSuccess;
1003  }
1004  
1005  /*
1006   * Optionally specify signed attributes. Only meaningful when creating a 
1007   * signed message. If this is called, it must be called before
1008   * CMSEncoderUpdateContent().
1009   */
1010  OSStatus CMSEncoderAddSignedAttributes(
1011  	CMSEncoderRef		cmsEncoder,
1012  	CMSSignedAttributes	signedAttributes)
1013  {
1014  	if(cmsEncoder == NULL) {
1015  		return errSecParam;
1016  	}
1017  	if(cmsEncoder->encState != ES_Init) {
1018  		return errSecParam;
1019  	}
1020  	cmsEncoder->signedAttributes |= signedAttributes;
1021  	return errSecSuccess;
1022  }
1023  
1024  /*
1025   * Set the signing time for a CMSEncoder.
1026   * This is only used if the kCMSAttrSigningTime attribute is included.
1027   */
1028  OSStatus CMSEncoderSetSigningTime(
1029  	CMSEncoderRef		cmsEncoder,
1030  	CFAbsoluteTime		time)
1031  {
1032  	if(cmsEncoder == NULL) {
1033  		return errSecParam;
1034  	}
1035  	if(cmsEncoder->encState != ES_Init) {
1036  		return errSecParam;
1037  	}
1038  	cmsEncoder->signingTime = time;
1039  	return errSecSuccess;
1040  }
1041  
1042  /*
1043   * Set the hash agility attribute for a CMSEncoder.
1044   * This is only used if the kCMSAttrAppleCodesigningHashAgility attribute
1045   * is included.
1046   */
1047  OSStatus CMSEncoderSetAppleCodesigningHashAgility(
1048      CMSEncoderRef   cmsEncoder,
1049      CFDataRef       hashAgilityAttrValue)
1050  {
1051      if (cmsEncoder == NULL || cmsEncoder->encState != ES_Init) {
1052          return errSecParam;
1053      }
1054      cmsEncoder->hashAgilityAttrValue = CFRetainSafe(hashAgilityAttrValue);
1055      return errSecSuccess;
1056  }
1057  
1058  /*
1059   * Set the hash agility attribute for a CMSEncoder.
1060   * This is only used if the kCMSAttrAppleCodesigningHashAgilityV2 attribute
1061   * is included.
1062   */
1063  OSStatus CMSEncoderSetAppleCodesigningHashAgilityV2(
1064      CMSEncoderRef   cmsEncoder,
1065      CFDictionaryRef       hashAgilityV2AttrValues)
1066  {
1067      if (cmsEncoder == NULL || cmsEncoder->encState != ES_Init) {
1068          return errSecParam;
1069      }
1070      cmsEncoder->hashAgilityV2AttrValues = CFRetainSafe(hashAgilityV2AttrValues);
1071      return errSecSuccess;
1072  }
1073  
1074  /*
1075   * Set the expiration time for a CMSEncoder.
1076   * This is only used if the kCMSAttrAppleExpirationTime attribute is included.
1077   */
1078  OSStatus CMSEncoderSetAppleExpirationTime(
1079      CMSEncoderRef        cmsEncoder,
1080      CFAbsoluteTime        time)
1081  {
1082      if(cmsEncoder == NULL) {
1083          return errSecParam;
1084      }
1085      if(cmsEncoder->encState != ES_Init) {
1086          return errSecParam;
1087      }
1088      cmsEncoder->expirationTime = time;
1089      return errSecSuccess;
1090  }
1091  
1092  OSStatus CMSEncoderSetCertificateChainMode(
1093  	CMSEncoderRef			cmsEncoder,
1094  	CMSCertificateChainMode	chainMode)
1095  {
1096  	if(cmsEncoder == NULL) {
1097  		return errSecParam;
1098  	}
1099  	if(cmsEncoder->encState != ES_Init) {
1100  		return errSecParam;
1101  	}
1102  	switch(chainMode) {
1103  		case kCMSCertificateNone:
1104  		case kCMSCertificateSignerOnly:
1105  		case kCMSCertificateChain:
1106  		case kCMSCertificateChainWithRoot:
1107  		case kCMSCertificateChainWithRootOrFail:
1108  			break;
1109  		default:
1110  			return errSecParam;
1111  	}
1112  	cmsEncoder->chainMode = chainMode;
1113  	return errSecSuccess;
1114  }
1115  
1116  OSStatus CMSEncoderGetCertificateChainMode(
1117  	CMSEncoderRef			cmsEncoder,
1118  	CMSCertificateChainMode	*chainModeOut)
1119  {
1120  	if(cmsEncoder == NULL) {
1121  		return errSecParam;
1122  	}
1123  	*chainModeOut = cmsEncoder->chainMode;
1124  	return errSecSuccess;
1125  }
1126  
1127  void
1128  CmsMessageSetTSACallback(CMSEncoderRef cmsEncoder, SecCmsTSACallback tsaCallback)
1129  {
1130      if (cmsEncoder->cmsMsg)
1131          SecCmsMessageSetTSACallback(cmsEncoder->cmsMsg, tsaCallback);
1132  }
1133  
1134  void
1135  CmsMessageSetTSAContext(CMSEncoderRef cmsEncoder, CFTypeRef tsaContext)
1136  {
1137      if (cmsEncoder->cmsMsg)
1138          SecCmsMessageSetTSAContext(cmsEncoder->cmsMsg, tsaContext);
1139  }
1140  
1141  #pragma mark --- Action ---
1142  
1143  /*
1144   * Feed content bytes into the encoder. 
1145   * Can be called multiple times. 
1146   * No 'setter' routines can be called after this function has been called. 
1147   */ 
1148  OSStatus CMSEncoderUpdateContent(
1149  	CMSEncoderRef		cmsEncoder,
1150  	const void			*content,
1151  	size_t				contentLen)
1152  {
1153  	if(cmsEncoder == NULL) {
1154  		return errSecParam;
1155  	}
1156  	
1157  	OSStatus ortn = errSecSuccess;
1158  	switch(cmsEncoder->encState) {
1159  		case ES_Init:
1160  			/* 
1161  			 * First time thru: do the CmsMsg setup.
1162  			 */
1163  			ortn = cmsSetupCmsMsg(cmsEncoder);
1164  			if(ortn) {
1165  				return ortn;
1166  			}
1167  			/* fall thru to set up the encoder */
1168  			
1169  		case ES_Msg:
1170  			/* We have a cmsMsg but no encoder; create one */
1171  			ASSERT(cmsEncoder->cmsMsg != NULL);
1172  			ASSERT(cmsEncoder->encoder == NULL);
1173  			ortn = cmsSetupEncoder(cmsEncoder);
1174  			if(ortn) {
1175  				return ortn;
1176  			}
1177  			/* only legal calls now are update and finalize */
1178  			cmsEncoder->encState = ES_Updating;
1179  			break;
1180  			
1181  		case ES_Updating:
1182  			ASSERT(cmsEncoder->encoder != NULL);
1183  			break;
1184  
1185  		case ES_Final:
1186  			/* Too late for another update */
1187  			return errSecParam;
1188  			
1189  		default:
1190  			return errSecInternalComponent;
1191  	}
1192  	
1193  	/* FIXME - CFIndex same size as size_t on 64bit? */
1194  	ortn = SecCmsEncoderUpdate(cmsEncoder->encoder, content, (CFIndex)contentLen);
1195  	if(ortn) {
1196  		ortn = cmsRtnToOSStatus(ortn);
1197  		CSSM_PERROR("SecCmsEncoderUpdate", ortn);
1198  	}
1199  	return ortn;
1200  }
1201  	
1202  /*
1203   * Finish encoding the message and obtain the encoded result.
1204   * Caller must CFRelease the result. 
1205   */
1206  OSStatus CMSEncoderCopyEncodedContent(
1207  	CMSEncoderRef		cmsEncoder,
1208  	CFDataRef			*encodedContent)
1209  {
1210  	if((cmsEncoder == NULL) || (encodedContent == NULL)) {
1211  		return errSecParam;
1212  	}
1213  
1214  	OSStatus ortn;
1215  
1216  	switch(cmsEncoder->encState) {
1217  		case ES_Updating:
1218  			/* normal termination */
1219  			break;
1220  		case ES_Final:
1221  			/* already been called */
1222  			return errSecParam;
1223  		case ES_Msg:
1224  		case ES_Init:
1225  			/*
1226  			 * The only time these are legal is when we're doing a SignedData
1227  			 * with certificates only (no signers, no content).
1228  			 */
1229  			if((cmsEncoder->signers != NULL) ||
1230  			   (cmsEncoder->recipients != NULL) ||
1231  			   (cmsEncoder->otherCerts == NULL)) {
1232  				return errSecParam;
1233  			}
1234  			
1235  			/* Set up for certs only */
1236  			ortn = cmsSetupForSignedData(cmsEncoder);
1237  			if(ortn) {
1238  				return ortn;
1239  			}
1240  			/* and an encoder */
1241  			ortn = cmsSetupEncoder(cmsEncoder);
1242  			if(ortn) {
1243  				return ortn;
1244  			}
1245  			break;
1246  	}
1247  	
1248  	
1249  	ASSERT(cmsEncoder->encoder != NULL);
1250  	ortn = SecCmsEncoderFinish(cmsEncoder->encoder);
1251  	/* regardless of the outcome, the encoder itself has been freed */
1252  	cmsEncoder->encoder = NULL;
1253  	if(ortn) {
1254  		return cmsRtnToOSStatus(ortn);
1255  	}
1256  	cmsEncoder->encState = ES_Final;
1257  
1258  	if((cmsEncoder->encoderOut.Data == NULL) && !cmsEncoder->customCoder) {
1259  		/* not sure how this could happen... */
1260  		dprintf("Successful encode, but no data\n");
1261  		return errSecInternalComponent;
1262  	}
1263  	if(cmsEncoder->customCoder) {
1264  		/* we're done */
1265  		*encodedContent = NULL;
1266  		return errSecSuccess;
1267  	}
1268  	
1269  	/* in two out of three cases, we're done */
1270  	switch(cmsEncoder->op) {
1271  		case EO_Sign:
1272  		case EO_Encrypt:
1273  			*encodedContent = CFDataCreate(NULL, (const UInt8 *)cmsEncoder->encoderOut.Data,	
1274  				cmsEncoder->encoderOut.Length);
1275  			return errSecSuccess;
1276  		case EO_SignEncrypt:
1277  			/* proceed, more work to do */
1278  			break;
1279  	}
1280  	
1281  	/* 
1282  	 * Signing & encrypting.
1283  	 * Due to bugs in the libsecurity_smime encoder, it can't encode nested 
1284  	 * ContentInfos in one shot. So we do another pass, specifying the SignedData
1285  	 * inside of the ContentInfo we just created as the data to encrypt.
1286  	 */
1287  	SecAsn1CoderRef asn1Coder = NULL;
1288  	CSSM_DATA signedData = {0, NULL};
1289  
1290  	ortn = SecAsn1CoderCreate(&asn1Coder);
1291  	if(ortn) {
1292  		return ortn;
1293  	}
1294  	ortn = cmsContentInfoContent(asn1Coder, &cmsEncoder->encoderOut, &signedData);
1295  	if(ortn) {
1296  		goto errOut;
1297  	}
1298  	
1299  	/* now just encrypt that, one-shot */
1300  	ortn = CMSEncode(NULL,			/* no signers this time */
1301  		cmsEncoder->recipients,
1302  		&CSSMOID_PKCS7_SignedData,	/* fake out encoder so it doesn't try to actually
1303  									 *   encode the signedData - this asserts the
1304  									 *   SEC_OID_OTHER OID tag in the EnvelopedData's
1305  									 *   ContentInfo */
1306  		FALSE,						/* detachedContent */
1307  		kCMSAttrNone,				/* signedAttributes - none this time */
1308  		signedData.Data, signedData.Length,
1309  		encodedContent);
1310  
1311  errOut:
1312  	if(asn1Coder) {
1313  		SecAsn1CoderRelease(asn1Coder);
1314  	}
1315  	return ortn;
1316  }
1317  	
1318  #pragma mark --- High-level API ---
1319  
1320  /*
1321   * High-level, one-shot encoder function.
1322   */
1323  OSStatus CMSEncode(
1324  	CFTypeRef			signers,
1325  	CFTypeRef			recipients,
1326  	const CSSM_OID		*eContentType,
1327  	Boolean				detachedContent,
1328  	CMSSignedAttributes	signedAttributes,
1329  	const void			*content,
1330  	size_t				contentLen,
1331  	CFDataRef			*encodedContent)	/* RETURNED */
1332  {
1333  	if((signers == NULL) && (recipients == NULL)) {
1334  		return errSecParam;
1335  	}
1336  	if(encodedContent == NULL) {
1337  		return errSecParam;
1338  	}
1339  	
1340  	CMSEncoderRef cmsEncoder;
1341  	OSStatus ortn;
1342  	
1343  	/* set up the encoder */
1344  	ortn = CMSEncoderCreate(&cmsEncoder);
1345  	if(ortn) {
1346  		return ortn;
1347  	}
1348  	
1349  	/* subsequent errors to errOut: */
1350  	if(signers) {
1351  		ortn = CMSEncoderAddSigners(cmsEncoder, signers);
1352  		if(ortn) {
1353  			goto errOut;
1354  		}
1355  	}
1356  	if(recipients) {
1357  		ortn = CMSEncoderAddRecipients(cmsEncoder, recipients);
1358  		if(ortn) {
1359  			goto errOut;
1360  		}
1361  	}
1362  	if(eContentType) {
1363  		ortn = CMSEncoderSetEncapsulatedContentType(cmsEncoder, eContentType);
1364  		if(ortn) {
1365  			goto errOut;
1366  		}
1367  	}
1368  	if(detachedContent) {
1369  		ortn = CMSEncoderSetHasDetachedContent(cmsEncoder, detachedContent);
1370  		if(ortn) {
1371  			goto errOut;
1372  		}
1373  	}
1374  	if(signedAttributes) {
1375  		ortn = CMSEncoderAddSignedAttributes(cmsEncoder, signedAttributes);
1376  		if(ortn) {
1377  			goto errOut;
1378  		}
1379  	}
1380  	/* GO */
1381  	ortn = CMSEncoderUpdateContent(cmsEncoder, content, contentLen);
1382  	if(ortn) {
1383  		goto errOut;
1384  	}
1385  	ortn = CMSEncoderCopyEncodedContent(cmsEncoder, encodedContent);
1386  	
1387  errOut:
1388  	CFRelease(cmsEncoder);
1389  	return ortn;
1390  }
1391  
1392  OSStatus CMSEncodeContent(
1393  	CFTypeRef			signers,
1394  	CFTypeRef			recipients,
1395  	CFTypeRef			eContentTypeOID,
1396  	Boolean				detachedContent,
1397  	CMSSignedAttributes	signedAttributes,
1398  	const void			*content,
1399  	size_t				contentLen,
1400  	CFDataRef			*encodedContentOut)	/* RETURNED */
1401  {
1402  	// convert eContentTypeOID to a CSSM_OID
1403  	CSSM_OID contentType = { 0, NULL };
1404  	if (eContentTypeOID && convertOid(eContentTypeOID, &contentType) != 0)
1405  		return errSecParam;
1406  	const CSSM_OID *contentTypePtr = (eContentTypeOID) ? &contentType : NULL;
1407  	OSStatus result = CMSEncode(signers, recipients, contentTypePtr,
1408  									detachedContent, signedAttributes,
1409  									content, contentLen, encodedContentOut);
1410  	if (contentType.Data)
1411  		free(contentType.Data);
1412  	return result;
1413  }
1414  
1415  #pragma mark --- SPI routines declared in CMSPrivate.h ---
1416  
1417  /*
1418   * Obtain the SecCmsMessageRef associated with a CMSEncoderRef. 
1419   * If we don't have a SecCmsMessageRef yet, we create one now.
1420   * This is the only place where we go to state ES_Msg. 
1421   */
1422  OSStatus CMSEncoderGetCmsMessage(
1423  	CMSEncoderRef		cmsEncoder,
1424  	SecCmsMessageRef	*cmsMessage)		/* RETURNED */
1425  {
1426  	if((cmsEncoder == NULL) || (cmsMessage == NULL)) {
1427  		return errSecParam;
1428  	}
1429  	if(cmsEncoder->cmsMsg != NULL) {
1430  		ASSERT(cmsEncoder->encState != ES_Init);
1431  		*cmsMessage = cmsEncoder->cmsMsg;
1432  		return errSecSuccess;
1433  	}
1434  
1435  	OSStatus ortn = cmsSetupCmsMsg(cmsEncoder);
1436  	if(ortn) {
1437  		return ortn;
1438  	}
1439  	*cmsMessage = cmsEncoder->cmsMsg;
1440  	
1441  	/* Don't set up encoder yet; caller might do that via CMSEncoderSetEncoder */
1442  	cmsEncoder->encState = ES_Msg;
1443  	return errSecSuccess;
1444  }
1445  
1446  /* 
1447   * Optionally specify a SecCmsEncoderRef to use with a CMSEncoderRef.
1448   * If this is called, it must be called before the first call to 
1449   * CMSEncoderUpdateContent(). The CMSEncoderRef takes ownership of the
1450   * incoming SecCmsEncoderRef.
1451   */
1452  OSStatus CMSEncoderSetEncoder(
1453  	CMSEncoderRef		cmsEncoder,
1454  	SecCmsEncoderRef	encoder)
1455  {
1456  	if((cmsEncoder == NULL) || (encoder == NULL)) {
1457  		return errSecParam;
1458  	}
1459  	
1460  	OSStatus ortn;
1461  	
1462  	switch(cmsEncoder->encState) {
1463  		case ES_Init:
1464  			/* No message, no encoder */
1465  			ASSERT(cmsEncoder->cmsMsg == NULL);
1466  			ASSERT(cmsEncoder->encoder == NULL);
1467  			ortn = cmsSetupCmsMsg(cmsEncoder);
1468  			if(ortn) {
1469  				return ortn;
1470  			}
1471  			/* drop thru to set encoder */
1472  		case ES_Msg:
1473  			/* cmsMsg but no encoder */
1474  			ASSERT(cmsEncoder->cmsMsg != NULL);
1475  			ASSERT(cmsEncoder->encoder == NULL);
1476  			cmsEncoder->encoder = encoder;
1477  			cmsEncoder->encState = ES_Updating;
1478  			cmsEncoder->customCoder = true;			/* we won't see data */
1479  			return errSecSuccess;
1480  		default:
1481  			/* no can do, too late */
1482  			return errSecParam;
1483  	}
1484  }
1485  	
1486  /* 
1487   * Obtain the SecCmsEncoderRef associated with a CMSEncoderRef. 
1488   * Returns a NULL SecCmsEncoderRef if neither CMSEncoderSetEncoder nor
1489   * CMSEncoderUpdateContent() has been called. 
1490   * The CMSEncoderRef retains ownership of the SecCmsEncoderRef.
1491   */
1492  OSStatus CMSEncoderGetEncoder(
1493  	CMSEncoderRef		cmsEncoder,
1494  	SecCmsEncoderRef	*encoder)			/* RETURNED */
1495  {
1496  	if((cmsEncoder == NULL) || (encoder == NULL)) {
1497  		return errSecParam;
1498  	}
1499  	
1500  	/* any state, whether we have an encoder or not is OK */
1501  	*encoder = cmsEncoder->encoder;
1502  	return errSecSuccess;
1503  }
1504  
1505  #include <AssertMacros.h>
1506  
1507  /*
1508   * Obtain the timestamp of signer 'signerIndex' of a CMS message, if
1509   * present. This timestamp is an authenticated timestamp provided by
1510   * a timestamping authority.
1511   *
1512   * Returns errSecParam if the CMS message was not signed or if signerIndex
1513   * is greater than the number of signers of the message minus one. 
1514   *
1515   * This cannot be called until after CMSEncoderCopyEncodedContent() is called. 
1516   */
1517  OSStatus CMSEncoderCopySignerTimestamp(
1518                                         CMSEncoderRef		cmsEncoder,
1519                                         size_t				signerIndex,        /* usually 0 */
1520                                         CFAbsoluteTime      *timestamp)			/* RETURNED */
1521  {
1522      return CMSEncoderCopySignerTimestampWithPolicy(
1523                                         cmsEncoder,
1524                                         NULL,
1525                                         signerIndex,
1526                                         timestamp);
1527  }
1528  
1529  OSStatus CMSEncoderCopySignerTimestampWithPolicy(
1530  	CMSEncoderRef		cmsEncoder,
1531      CFTypeRef            timeStampPolicy,
1532  	size_t				signerIndex,        /* usually 0 */
1533  	CFAbsoluteTime      *timestamp)			/* RETURNED */
1534  {
1535      OSStatus status = errSecParam;
1536  	SecCmsMessageRef cmsg;
1537  	SecCmsSignedDataRef signedData = NULL;
1538      int numContentInfos = 0;
1539  
1540      require(cmsEncoder && timestamp, xit);
1541  	require_noerr(CMSEncoderGetCmsMessage(cmsEncoder, &cmsg), xit);
1542      numContentInfos = SecCmsMessageContentLevelCount(cmsg);
1543      for (int dex = 0; !signedData && dex < numContentInfos; dex++)
1544      {
1545          SecCmsContentInfoRef ci = SecCmsMessageContentLevel(cmsg, dex);
1546          SECOidTag tag = SecCmsContentInfoGetContentTypeTag(ci);
1547          if (tag == SEC_OID_PKCS7_SIGNED_DATA)
1548              if ((signedData = SecCmsSignedDataRef(SecCmsContentInfoGetContent(ci))))
1549                  if (SecCmsSignerInfoRef signerInfo = SecCmsSignedDataGetSignerInfo(signedData, (int)signerIndex))
1550                  {
1551                      status = SecCmsSignerInfoGetTimestampTimeWithPolicy(signerInfo, timeStampPolicy, timestamp);
1552                      break;
1553                  }
1554      }
1555  
1556  xit:
1557      return status;
1558  }