1/* 2 * Copyright (c) 2008-2010,2012-2014 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/* 26 * signed_data.c 27 * Security 28 * 29 * 30 */ 31#include <AssertMacros.h> 32 33#include <TargetConditionals.h> 34#if (TARGET_OS_MAC && !(TARGET_OS_EMBEDDED || TARGET_OS_IPHONE)) 35#define ENABLE_CMS 0 36#else 37#define ENABLE_CMS 1 38#endif 39 40#if ENABLE_CMS 41#include <Security/SecBase.h> 42#include <Security/SecCmsMessage.h> 43#include <Security/SecCmsSignedData.h> 44#include <Security/SecCmsEnvelopedData.h> 45#include <Security/SecCmsContentInfo.h> 46#include <Security/SecCmsSignerInfo.h> 47#include <Security/SecCmsRecipientInfo.h> 48#include <Security/SecCmsEncoder.h> 49#include <Security/SecCmsDecoder.h> 50#include <Security/SecCmsDigestContext.h> 51#include <Security/cmstpriv.h> 52 53#include <CoreFoundation/CFData.h> 54 55#include <Security/SecInternal.h> 56#include <Security/SecBasePriv.h> 57#include <Security/SecCertificatePriv.h> 58 59#include "SecCMS.h" 60#include <Security/SecTrustPriv.h> 61 62 63#include <security_asn1/secasn1.h> 64#include <security_asn1/secerr.h> 65#include <security_asn1/secport.h> 66#include <Security/SecAsn1Item.h> 67#include <security_smime/secoid.h> 68#include <security_smime/cmslocal.h> 69 70CFTypeRef kSecCMSBulkEncryptionAlgorithm = CFSTR("kSecCMSBulkEncryptionAlgorithm"); 71CFTypeRef kSecCMSSignDigest = CFSTR("kSecCMSSignDigest"); 72CFTypeRef kSecCMSSignDetached = CFSTR("kSecCMSSignDetached"); 73CFTypeRef kSecCMSSignHashAlgorithm = CFSTR("kSecCMSSignHashAlgorithm"); 74CFTypeRef kSecCMSEncryptionAlgorithmDESCBC = CFSTR("kSecCMSEncryptionAlgorithmDESCBC"); 75CFTypeRef kSecCMSEncryptionAlgorithmAESCBC = CFSTR("kSecCMSEncryptionAlgorithmAESCBC"); 76CFTypeRef kSecCMSHashingAlgorithmMD5 = CFSTR("kSecCMSHashingAlgorithmMD5"); 77CFTypeRef kSecCMSCertChainMode = CFSTR("kSecCMSCertChainMode"); 78CFTypeRef kSecCMSCertChainModeNone = CFSTR("0"); 79CFTypeRef kSecCMSAdditionalCerts = CFSTR("kSecCMSAdditionalCerts"); 80CFTypeRef kSecCMSSignedAttributes = CFSTR("kSecCMSSignedAttributes"); 81CFTypeRef kSecCMSSignDate = CFSTR("kSecCMSSignDate"); 82CFTypeRef kSecCMSAllCerts = CFSTR("kSecCMSAllCerts"); 83 84OSStatus SecCMSCreateEnvelopedData(CFTypeRef recipient_or_cfarray_thereof, 85 CFDictionaryRef params, CFDataRef data, CFMutableDataRef enveloped_data) 86{ 87 SecCmsMessageRef cmsg = NULL; 88 SecCmsContentInfoRef cinfo; 89 SecCmsEnvelopedDataRef envd = NULL; 90 SECOidTag algorithmTag = SEC_OID_DES_EDE3_CBC; 91 int keySize = 192; 92 OSStatus status = errSecParam; 93 94 if (params) { 95 CFStringRef algorithm_name = CFDictionaryGetValue(params, kSecCMSBulkEncryptionAlgorithm); 96 if (algorithm_name) { 97 if (CFEqual(kSecCMSEncryptionAlgorithmDESCBC, algorithm_name)) { 98 algorithmTag = SEC_OID_DES_CBC; 99 keySize = 64; 100 } else if (CFEqual(kSecCMSEncryptionAlgorithmAESCBC, algorithm_name)) { 101 algorithmTag = SEC_OID_AES_128_CBC; 102 keySize = 128; 103 } 104 } 105 } 106 107 require(cmsg = SecCmsMessageCreate(), out); 108 require(envd = SecCmsEnvelopedDataCreate(cmsg, algorithmTag, keySize), out); 109 require(cinfo = SecCmsMessageGetContentInfo(cmsg), out); 110 require_noerr(SecCmsContentInfoSetContentEnvelopedData(cinfo, envd), out); 111 require(cinfo = SecCmsEnvelopedDataGetContentInfo(envd), out); 112 require_noerr(SecCmsContentInfoSetContentData(cinfo, NULL, false), out); 113 // == wrapper of: require(SECSuccess == SecCmsContentInfoSetContent(cinfo, SEC_OID_PKCS7_DATA, NULL), out); 114 115 if (CFGetTypeID(recipient_or_cfarray_thereof) == CFArrayGetTypeID()) { 116 CFIndex dex, numCerts = CFArrayGetCount(recipient_or_cfarray_thereof); 117 for(dex=0; dex<numCerts; dex++) { 118 SecCertificateRef recip = 119 (SecCertificateRef)CFArrayGetValueAtIndex(recipient_or_cfarray_thereof, dex); 120 SecCmsRecipientInfoRef rinfo; 121 require(rinfo = SecCmsRecipientInfoCreate(envd, recip), out); 122 } 123 } else if (CFGetTypeID(recipient_or_cfarray_thereof) == SecCertificateGetTypeID()) { 124 require(SecCmsRecipientInfoCreate(envd, (SecCertificateRef)recipient_or_cfarray_thereof), out); 125 } else 126 goto out; 127 128 SecAsn1Item input = {}; 129 if (data) { 130 input.Length = CFDataGetLength(data); 131 input.Data = (uint8_t*)CFDataGetBytePtr(data); 132 } 133 require_noerr(SecCmsMessageEncode(cmsg, (data && input.Length) ? &input : NULL, enveloped_data), out); 134 135 status = errSecSuccess; 136out: 137 if (cmsg) SecCmsMessageDestroy(cmsg); 138 return status; 139} 140 141OSStatus SecCMSDecryptEnvelopedData(CFDataRef message, 142 CFMutableDataRef data, SecCertificateRef *recipient) 143{ 144 SecCmsMessageRef cmsg = NULL; 145 SecCmsContentInfoRef cinfo; 146 SecCmsEnvelopedDataRef envd = NULL; 147 SecCertificateRef used_recipient = NULL; 148 OSStatus status = errSecParam; 149 150 SecAsn1Item encoded_message = { CFDataGetLength(message), (uint8_t*)CFDataGetBytePtr(message) }; 151 require_noerr_action_quiet(SecCmsMessageDecode(&encoded_message, NULL, NULL, NULL, NULL, NULL, NULL, &cmsg), 152 out, status = errSecDecode); 153 require_quiet(cinfo = SecCmsMessageContentLevel(cmsg, 0), out); 154 require_quiet(SecCmsContentInfoGetContentTypeTag(cinfo) == SEC_OID_PKCS7_ENVELOPED_DATA, out); 155 require_quiet(envd = (SecCmsEnvelopedDataRef)SecCmsContentInfoGetContent(cinfo), out); 156 SecCmsRecipientInfoRef *rinfo = envd->recipientInfos; 157 while (!used_recipient && *rinfo) { 158 used_recipient = (*rinfo)->cert; 159 rinfo++; 160 } 161 require_quiet(2 == SecCmsMessageContentLevelCount(cmsg), out); 162 require_quiet(cinfo = SecCmsMessageContentLevel(cmsg, 1), out); 163 require_quiet(SecCmsContentInfoGetContentTypeTag(cinfo) == SEC_OID_PKCS7_DATA, out); 164 const SecAsn1Item *content = SecCmsMessageGetContent(cmsg); 165 if (content) 166 CFDataAppendBytes(data, content->Data, content->Length); 167 if (recipient) { 168 CFRetainSafe(used_recipient); 169 *recipient = used_recipient; 170 } 171 status = errSecSuccess; 172out: 173 if (cmsg) SecCmsMessageDestroy(cmsg); 174 return status; 175} 176 177static SecCmsAttribute * 178make_attr(PLArenaPool *poolp, SecAsn1Item *type, SecAsn1Item *value, bool encoded) 179{ 180 SecAsn1Item * copiedvalue; 181 SecCmsAttribute *attr = (SecCmsAttribute *)PORT_ArenaZAlloc(poolp, sizeof(SecCmsAttribute)); 182 if (attr == NULL) 183 goto loser; 184 185 if (SECITEM_CopyItem(poolp, &(attr->type), type) != SECSuccess) 186 goto loser; 187 188 if (value != NULL) { 189 if ((copiedvalue = SECITEM_AllocItem(poolp, NULL, value->Length)) == NULL) 190 goto loser; 191 192 if (SECITEM_CopyItem(poolp, copiedvalue, value) != SECSuccess) 193 goto loser; 194 195 SecCmsArrayAdd(poolp, (void ***)&(attr->values), (void *)copiedvalue); 196 } 197 198 attr->encoded = encoded; 199 200loser: 201 return attr; 202} 203 204static void 205signerinfo_add_auth_attr(SecCmsSignerInfoRef signerinfo, /*SECOidTag oidtag*/ 206 SecAsn1Item *oid, SecAsn1Item *value, bool encoded) 207{ 208 PLArenaPool *poolp = signerinfo->signedData->contentInfo.cmsg->poolp; 209 PORT_Assert (poolp != NULL); 210 void *mark = PORT_ArenaMark (poolp); 211 212 SecCmsAttribute *attr = make_attr(poolp, oid, value, encoded); 213 if (!attr || SecCmsAttributeArrayAddAttr(poolp, &(signerinfo->authAttr), attr) != SECSuccess) 214 goto loser; 215 216 PORT_ArenaUnmark (poolp, mark); 217 return; 218 219loser: 220 PORT_Assert (mark != NULL); 221 PORT_ArenaRelease (poolp, mark); 222 return; 223} 224 225static void sign_all_attributes(const void *key, const void *value, void *context) 226{ 227 SecAsn1Item oid = { CFDataGetLength(key), (uint8_t*)CFDataGetBytePtr(key) }, 228 oid_value = { CFDataGetLength(value), (uint8_t*)CFDataGetBytePtr(value) }; 229 230 signerinfo_add_auth_attr((SecCmsSignerInfoRef)context, &oid, &oid_value, true); 231} 232 233#if 0 234static void enveloped_data_add_unprotected_attr(SecCmsEnvelopedDataRef envd, 235 SecAsn1Item *oid, SecAsn1Item *value, bool encoded) 236{ 237 PLArenaPool *poolp = envd->contentInfo.cmsg->poolp; 238 PORT_Assert (poolp != NULL); 239 void *mark = PORT_ArenaMark (poolp); 240 SecCmsAttribute *attr = make_attr(poolp, oid, value, encoded); 241 242 if (!attr || SecCmsAttributeArrayAddAttr( 243 poolp, 244 &(envd->unprotectedAttr), attr) != SECSuccess) 245 goto loser; 246 247 PORT_ArenaUnmark (poolp, mark); 248 return; 249 250loser: 251 PORT_Assert (mark != NULL); 252 PORT_ArenaRelease (poolp, mark); 253 return; 254 255} 256#endif 257 258static OSStatus SecCMSSignDataOrDigestAndAttributes(SecIdentityRef identity, 259 CFDataRef data, bool detached, bool data_is_digest, SECOidTag sign_algorithm, 260 CFMutableDataRef signed_data, CFDictionaryRef signed_attributes, SecCmsCertChainMode chainMode, CFArrayRef additional_certs) 261{ 262 SecCmsMessageRef cmsg = NULL; 263 SecCmsContentInfoRef cinfo; 264 SecCmsSignedDataRef sigd = NULL; 265 SecCmsSignerInfoRef signerinfo; 266 OSStatus status = errSecParam; 267 268 require(!data_is_digest || detached /* if digest, must be detached */, out); 269 270 require(cmsg = SecCmsMessageCreate(), out); 271 require(sigd = SecCmsSignedDataCreate(cmsg), out); 272 require(cinfo = SecCmsMessageGetContentInfo(cmsg), out); 273 require_noerr(SecCmsContentInfoSetContentSignedData(cinfo, sigd), out); 274 require(cinfo = SecCmsSignedDataGetContentInfo(sigd), out); 275 require_noerr(SecCmsContentInfoSetContentData(cinfo, NULL, detached), out); 276 require(signerinfo = SecCmsSignerInfoCreate(sigd, identity, sign_algorithm), out); 277 if (additional_certs) 278 require_noerr(SecCmsSignedDataAddCertList(sigd, additional_certs), out); 279 require_noerr(SecCmsSignerInfoIncludeCerts(signerinfo, chainMode, certUsageAnyCA), out); 280 require_noerr(SecCmsSignerInfoAddSigningTime(signerinfo, CFAbsoluteTimeGetCurrent()), out); 281 282 if (signed_attributes) 283 CFDictionaryApplyFunction(signed_attributes, sign_all_attributes, signerinfo); 284 285 SecAsn1Item input = {}; 286 if (data) { 287 input.Length = CFDataGetLength(data); 288 input.Data = (uint8_t*)CFDataGetBytePtr(data); 289 } 290 if (data_is_digest) { 291 require_noerr(SecCmsSignedDataSetDigestValue(sigd, sign_algorithm, &input), out); 292 require_noerr(SecCmsMessageEncode(cmsg, NULL, signed_data), out); 293 } 294 else 295 require_noerr(SecCmsMessageEncode(cmsg, (data && input.Length) ? &input : NULL, signed_data), out); 296 297 status = errSecSuccess; 298out: 299 if (cmsg) SecCmsMessageDestroy(cmsg); 300 return status; 301} 302 303OSStatus SecCMSSignDataAndAttributes(SecIdentityRef identity, CFDataRef data, bool detached, 304 CFMutableDataRef signed_data, CFDictionaryRef signed_attributes) 305{ 306 return SecCMSSignDataOrDigestAndAttributes(identity, data, detached, false, SEC_OID_SHA1, 307 signed_data, signed_attributes, SecCmsCMCertChain, NULL); 308} 309 310OSStatus SecCMSSignDigestAndAttributes(SecIdentityRef identity, CFDataRef digest, 311 CFMutableDataRef signed_data, CFDictionaryRef signed_attributes) 312{ 313 return SecCMSSignDataOrDigestAndAttributes(identity, digest, true, true, SEC_OID_SHA1, 314 signed_data, signed_attributes, SecCmsCMCertChain, NULL); 315} 316 317 318OSStatus SecCMSCreateSignedData(SecIdentityRef identity, CFDataRef data, 319 CFDictionaryRef parameters, CFDictionaryRef signed_attributes, 320 CFMutableDataRef signed_data) 321{ 322 bool is_digest = false, is_detached = false; 323 CFStringRef algorithm_name = NULL; 324 SecCmsCertChainMode chain_mode = SecCmsCMCertChain; 325 CFArrayRef additional_certs = NULL; 326 327 if (parameters) { 328 is_digest = CFDictionaryGetValueIfPresent(parameters, 329 kSecCMSSignDigest, NULL); 330 is_detached = CFDictionaryGetValueIfPresent(parameters, 331 kSecCMSSignDetached, NULL); 332 algorithm_name = CFDictionaryGetValue(parameters, 333 kSecCMSSignHashAlgorithm); 334 335 CFTypeRef chain_mode_param = CFDictionaryGetValue(parameters, kSecCMSCertChainMode); 336 if (chain_mode_param && (CFGetTypeID(chain_mode_param) == CFStringGetTypeID())) 337 chain_mode = CFStringGetIntValue(chain_mode_param); 338 339 CFTypeRef additional_certs_param = CFDictionaryGetValue(parameters, kSecCMSAdditionalCerts); 340 if (additional_certs_param && (CFGetTypeID(additional_certs_param) == CFArrayGetTypeID())) 341 additional_certs = (CFArrayRef)additional_certs_param; 342 } 343 344 SECOidTag algorithm = SEC_OID_SHA1; 345 if (algorithm_name) { 346 if (CFEqual(kSecCMSHashingAlgorithmMD5, algorithm_name)) { 347 algorithm = SEC_OID_MD5; 348 } else { 349 algorithm = SEC_OID_UNKNOWN; 350 } 351 352 } 353 354 return SecCMSSignDataOrDigestAndAttributes(identity, data, 355 is_detached, is_digest, algorithm, 356 signed_data, signed_attributes, chain_mode, additional_certs); 357} 358 359 360static CFMutableArrayRef copy_signed_attribute_values(SecCmsAttribute *attr) 361{ 362 CFMutableArrayRef array = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks); 363 SecAsn1Item **item = attr->values; 364 if (item) while (*item) { 365 CFDataRef asn1data = CFDataCreate(kCFAllocatorDefault, (*item)->Data, (*item)->Length); 366 if (asn1data) { 367 CFArrayAppendValue(array, asn1data); 368 CFRelease(asn1data); 369 } 370 item++; 371 } 372 return array; 373} 374 375static OSStatus SecCMSVerifySignedData_internal(CFDataRef message, CFDataRef detached_contents, 376 CFTypeRef policy, SecTrustRef *trustref, CFArrayRef additional_certs, 377 CFDataRef *attached_contents, CFDictionaryRef *signed_attributes) 378{ 379 SecCmsMessageRef cmsg = NULL; 380 SecCmsContentInfoRef cinfo; 381 SecCmsSignedDataRef sigd = NULL; 382 OSStatus status = errSecParam; 383 384 SecAsn1Item encoded_message = { CFDataGetLength(message), (uint8_t*)CFDataGetBytePtr(message) }; 385 require_noerr_action_quiet(SecCmsMessageDecode(&encoded_message, NULL, NULL, NULL, NULL, NULL, NULL, &cmsg), 386 out, status = errSecDecode); 387 /* expected to be a signed data message at the top level */ 388 require_quiet(cinfo = SecCmsMessageContentLevel(cmsg, 0), out); 389 require_quiet(SecCmsContentInfoGetContentTypeTag(cinfo) == SEC_OID_PKCS7_SIGNED_DATA, out); 390 require_quiet(sigd = (SecCmsSignedDataRef)SecCmsContentInfoGetContent(cinfo), out); 391 392 if (detached_contents) 393 { 394 require_quiet(!SecCmsSignedDataHasDigests(sigd), out); 395 SECAlgorithmID **digestalgs = SecCmsSignedDataGetDigestAlgs(sigd); 396 SecCmsDigestContextRef digcx = SecCmsDigestContextStartMultiple(digestalgs); 397 SecCmsDigestContextUpdate(digcx, CFDataGetBytePtr(detached_contents), CFDataGetLength(detached_contents)); 398 SecCmsSignedDataSetDigestContext(sigd, digcx); 399 SecCmsDigestContextDestroy(digcx); 400 } 401 402 if (additional_certs) 403 require_noerr_quiet(SecCmsSignedDataAddCertList(sigd, additional_certs), out); 404 405 if (policy) { /* if no policy is given skip verification */ 406 /* find out about signers */ 407 int nsigners = SecCmsSignedDataSignerInfoCount(sigd); 408 require_quiet(nsigners == 1, out); 409 require_noerr_action_quiet(SecCmsSignedDataVerifySignerInfo(sigd, 0, NULL, policy, trustref), 410 out, status = errSecAuthFailed); 411 } 412 413 #if 0 414 if (nsigners > 1) 415 trustrefs = CFArrayCreateMutable(kCFAllocatorDefault, nsigners, &kCFTypeArrayCallBacks); 416 417 int j; 418 for (j = 0; j < nsigners; j++) 419 { 420 SecTrustRef trustRef; 421 require_noerr_action_quiet(SecCmsSignedDataVerifySignerInfo(sigd, j, NULL, policy, &trustRef), 422 out, status = errSecAuthFailed); 423 if ((j == 0) && (nsigners == 1)) 424 *trustref_or_cfarray_thereof = trustRef; 425 else { 426 CFArrayAppendValue(trustrefs, trustRef); 427 CFRelease(trustRef); 428 } 429 } 430 *trustref_or_cfarray_thereof = trustrefs; 431 trustrefs = NULL; 432#endif 433 434 status = errSecSuccess; 435 436 if (attached_contents) { 437 const SecAsn1Item *content = SecCmsMessageGetContent(cmsg); 438 if (content) 439 *attached_contents = CFDataCreate(kCFAllocatorDefault, content->Data, content->Length); 440 else 441 *attached_contents = NULL; 442 } 443 444 if (signed_attributes) { 445 CFMutableDictionaryRef attrs = CFDictionaryCreateMutable(kCFAllocatorDefault, 446 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); 447 require_quiet(attrs, out); 448 SecCmsAttribute **signed_attrs = sigd->signerInfos[0]->authAttr; 449 if (signed_attrs) while (*signed_attrs) { 450 CFDataRef type = CFDataCreate(kCFAllocatorDefault, (*signed_attrs)->type.Data, (*signed_attrs)->type.Length); 451 if (type) { 452 CFMutableArrayRef attr = copy_signed_attribute_values(*signed_attrs); 453 if (attr) { 454 CFMutableArrayRef existing_attrs = (CFMutableArrayRef)CFDictionaryGetValue(attrs, type); 455 if (existing_attrs) { 456 CFIndex count = CFArrayGetCount(attr); 457 if (count) 458 CFArrayAppendArray(existing_attrs, attr, CFRangeMake(0, count)); 459 } else 460 CFDictionarySetValue(attrs, type, attr); 461 CFRelease(attr); 462 } 463 CFRelease(type); 464 } 465 signed_attrs++; 466 } 467 CFMutableArrayRef certs = NULL; 468 469 SecAsn1Item **cert_datas = SecCmsSignedDataGetCertificateList(sigd); 470 certs = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks); 471 SecAsn1Item *cert_data; 472 if (cert_datas) while ((cert_data = *cert_datas) != NULL) { 473 SecCertificateRef cert = SecCertificateCreateWithBytes(NULL, cert_data->Data, cert_data->Length); 474 if (cert) { 475 CFArrayAppendValue(certs, cert); 476 CFRelease(cert); 477 } 478 cert_datas++; 479 } 480 481 CFDictionaryAddValue(attrs, kSecCMSAllCerts, certs); 482 483 /* Add "cooked" values separately */ 484 CFAbsoluteTime signing_time; 485 if (errSecSuccess == SecCmsSignerInfoGetSigningTime(sigd->signerInfos[0], &signing_time)) { 486 CFDateRef signing_date = CFDateCreate(kCFAllocatorDefault, signing_time); 487 if (signing_date){ 488 CFDictionarySetValue(attrs, kSecCMSSignDate, signing_date); 489 CFReleaseSafe(signing_date); 490 } 491 } 492 493 *signed_attributes = attrs; 494 CFReleaseSafe(certs); 495 } 496 497 498out: 499 if (cmsg) SecCmsMessageDestroy(cmsg); 500 return status; 501} 502 503OSStatus SecCMSVerifyCopyDataAndAttributes(CFDataRef message, CFDataRef detached_contents, 504 CFTypeRef policy, SecTrustRef *trustref, 505 CFDataRef *attached_contents, CFDictionaryRef *signed_attributes) 506{ 507 OSStatus status = SecCMSVerifySignedData_internal(message, detached_contents, policy, trustref, NULL, attached_contents, signed_attributes); 508 509 return status; 510} 511 512OSStatus SecCMSVerifySignedData(CFDataRef message, CFDataRef detached_contents, 513 CFTypeRef policy, SecTrustRef *trustref, CFArrayRef additional_certificates, 514 CFDataRef *attached_contents, CFDictionaryRef *message_attributes) 515{ 516 CFDictionaryRef signed_attributes = NULL; 517 OSStatus status = SecCMSVerifySignedData_internal(message, detached_contents, policy, trustref, additional_certificates, attached_contents, &signed_attributes); 518 if (!status && signed_attributes && message_attributes) { 519 *message_attributes = CFDictionaryCreate(kCFAllocatorDefault, &kSecCMSSignedAttributes, (const void **)&signed_attributes, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); 520 } 521 CFReleaseSafe(signed_attributes); 522 523 return status; 524} 525 526OSStatus SecCMSVerify(CFDataRef message, CFDataRef detached_contents, 527 CFTypeRef policy, SecTrustRef *trustref, 528 CFDataRef *attached_contents) { 529 return SecCMSVerifySignedData_internal(message, detached_contents, policy, trustref, NULL, attached_contents, NULL); 530} 531 532CFArrayRef SecCMSCertificatesOnlyMessageCopyCertificates(CFDataRef message) { 533 SecCmsMessageRef cmsg = NULL; 534 SecCmsContentInfoRef cinfo; 535 SecCmsSignedDataRef sigd = NULL; 536 CFMutableArrayRef certs = NULL; 537 538 SecAsn1Item encoded_message = { CFDataGetLength(message), (uint8_t*)CFDataGetBytePtr(message) }; 539 require_noerr_quiet(SecCmsMessageDecode(&encoded_message, NULL, NULL, NULL, NULL, NULL, NULL, &cmsg), out); 540 /* expected to be a signed data message at the top level */ 541 require(cinfo = SecCmsMessageContentLevel(cmsg, 0), out); 542 require(SecCmsContentInfoGetContentTypeTag(cinfo) == SEC_OID_PKCS7_SIGNED_DATA, out); 543 require(sigd = (SecCmsSignedDataRef)SecCmsContentInfoGetContent(cinfo), out); 544 545 /* find out about signers */ 546 int nsigners = SecCmsSignedDataSignerInfoCount(sigd); 547 require(nsigners == 0, out); 548 549 SecAsn1Item **cert_datas = SecCmsSignedDataGetCertificateList(sigd); 550 certs = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks); 551 SecAsn1Item *cert_data; 552 if (cert_datas) while ((cert_data = *cert_datas) != NULL) { 553 SecCertificateRef cert = SecCertificateCreateWithBytes(NULL, cert_data->Data, cert_data->Length); 554 if (cert) { 555 CFArrayAppendValue(certs, cert); 556 CFRelease(cert); 557 } 558 cert_datas++; 559 } 560 561out: 562 if (cmsg) 563 SecCmsMessageDestroy(cmsg); 564 565 return certs; 566} 567 568 569extern const SecAsn1Template SecCmsMessageTemplate[]; 570 571CFDataRef SecCMSCreateCertificatesOnlyMessage(CFTypeRef cert_or_array_thereof) { 572 OSStatus status = errSecParam; 573 SecCmsMessageRef cmsg = NULL; 574 SecCmsContentInfoRef cinfo; 575 SecCmsSignedDataRef sigd = NULL; 576 CFMutableDataRef cert_only_signed_data = NULL; 577 CFArrayRef cert_array = NULL; 578 CFIndex cert_array_count = 0; 579 SecCertificateRef cert = NULL; 580 581 require(cert_or_array_thereof, out); 582 583 require(cmsg = SecCmsMessageCreate(), out); 584 require(sigd = SecCmsSignedDataCreate(cmsg), out); 585 require_noerr(SecCmsContentInfoSetContentData(&(sigd->contentInfo), NULL, PR_TRUE), out); 586 require(cinfo = SecCmsMessageGetContentInfo(cmsg), out); 587 require_noerr(SecCmsContentInfoSetContentSignedData(cinfo, sigd), out); 588 long version = SEC_CMS_SIGNED_DATA_VERSION_BASIC; 589 require(SEC_ASN1EncodeInteger(cmsg->poolp, &(sigd->version), version), out); 590 591 if (CFGetTypeID(cert_or_array_thereof) == SecCertificateGetTypeID()) { 592 cert_array = CFArrayCreate(kCFAllocatorDefault, &cert_or_array_thereof, 1, &kCFTypeArrayCallBacks); 593 } else if (CFGetTypeID(cert_or_array_thereof) == CFArrayGetTypeID()) { 594 cert_array = CFArrayCreateCopy(kCFAllocatorDefault, (CFArrayRef)cert_or_array_thereof); 595 } 596 597 require(cert_array, out); 598 cert_array_count = CFArrayGetCount(cert_array); 599 require(cert_array_count > 0, out); 600 601 sigd->rawCerts = (SecAsn1Item * *)PORT_ArenaAlloc(cmsg->poolp, (cert_array_count + 1) * sizeof(SecAsn1Item *)); 602 require(sigd->rawCerts, out); 603 CFIndex ix; 604 for (ix = 0; ix < cert_array_count; ix++) { 605 cert = (SecCertificateRef)CFArrayGetValueAtIndex(cert_array, ix); 606 require(cert, out); 607 608 sigd->rawCerts[ix] = PORT_ArenaZAlloc(cmsg->poolp, sizeof(SecAsn1Item)); 609 SecAsn1Item cert_data = { SecCertificateGetLength(cert), 610 (uint8_t *)SecCertificateGetBytePtr(cert) }; 611 *(sigd->rawCerts[ix]) = cert_data; 612 } 613 sigd->rawCerts[ix] = NULL; 614 615 /* this is a SET OF, so we need to sort them guys - we have the DER already, though */ 616 if (cert_array_count > 1) 617 SecCmsArraySort((void **)sigd->rawCerts, SecCmsUtilDERCompare, NULL, NULL); 618 619 cert_only_signed_data = CFDataCreateMutable(kCFAllocatorDefault, 0); 620 SecAsn1Item cert_only_signed_data_item = {}; 621 require_quiet(SEC_ASN1EncodeItem(cmsg->poolp, &cert_only_signed_data_item, 622 cmsg, SecCmsMessageTemplate), out); 623 CFDataAppendBytes(cert_only_signed_data, cert_only_signed_data_item.Data, 624 cert_only_signed_data_item.Length); 625 626 status = errSecSuccess; 627out: 628 CFReleaseSafe(cert_array); 629 if (status) CFReleaseSafe(cert_only_signed_data); 630 if (cmsg) SecCmsMessageDestroy(cmsg); 631 return cert_only_signed_data; 632} 633 634CFDataRef SecCMSCreateCertificatesOnlyMessageIAP(SecCertificateRef cert) 635{ 636 static const uint8_t header[] = { 637 0x30, 0x82, 0x03, 0x6d, 0x06, 0x09, 0x2a, 0x86, 638 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x02, 0xa0, 639 0x82, 0x03, 0x5e, 0x30, 0x82, 0x03, 0x5a, 0x02, 640 0x01, 0x01, 0x31, 0x00, 0x30, 0x0b, 0x06, 0x09, 641 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 642 0x01, 0xa0, 0x82, 0x03, 0x40 643 }; 644 645 static const uint8_t trailer[] = { 646 0xa1, 0x00, 0x31, 0x00 647 }; 648 649 CFMutableDataRef message = NULL; 650 CFDataRef certdata; 651 const uint8_t *certbytes; 652 CFIndex certlen; 653 uint8_t *messagebytes; 654 uint16_t messagelen; 655 656 certdata = SecCertificateCopyData(cert); 657 require(certdata, out); 658 659 certbytes = CFDataGetBytePtr(certdata); 660 certlen = CFDataGetLength(certdata); 661 require(certlen > UINT8_MAX, out); 662 require(certlen < UINT16_MAX, out); 663 664 message = CFDataCreateMutable(kCFAllocatorDefault, 0); 665 require(message, out); 666 667 CFDataAppendBytes(message, header, sizeof(header)); 668 CFDataAppendBytes(message, certbytes, certlen); 669 CFDataAppendBytes(message, trailer, sizeof(trailer)); 670 671 messagebytes = CFDataGetMutableBytePtr(message); 672 messagelen = CFDataGetLength(message); 673 674 messagelen -= 4; 675 messagebytes[2] = messagelen >> 8; 676 messagebytes[3] = messagelen & 0xFF; 677 678 messagelen -= 15; 679 messagebytes[17] = messagelen >> 8; 680 messagebytes[18] = messagelen & 0xFF; 681 682 messagelen -= 4; 683 messagebytes[21] = messagelen >> 8; 684 messagebytes[22] = messagelen & 0xFF; 685 686 messagelen -= 26; 687 messagebytes[43] = messagelen >> 8; 688 messagebytes[44] = messagelen & 0xFF; 689 690out: 691 CFReleaseSafe(certdata); 692 return message; 693} 694 695#endif /* ENABLE_CMS */ 696 697