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