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 }