2 * Copyright (c) 2014-2016 Apple Inc. All Rights Reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
21 * @APPLE_LICENSE_HEADER_END@
25 #include <AssertMacros.h>
27 #include <security_asn1/secasn1.h>
29 #include <Security/SecCmsBase.h>
30 #include <Security/SecCmsMessage.h>
31 #include <Security/SecCmsSignedData.h>
32 #include <Security/SecCmsContentInfo.h>
33 #include <Security/SecCmsSignerInfo.h>
34 #include <Security/SecCertificate.h>
35 #include <Security/SecCertificatePriv.h>
36 #include <Security/SecCmsDecoder.h>
37 #include <Security/SecCmsEncoder.h>
38 #include <Security/SecCmsDigestContext.h>
47 CFTypeRef kSecCMSSignDigest
= CFSTR("kSecCMSSignDigest");
48 CFTypeRef kSecCMSSignDetached
= CFSTR("kSecCMSSignDetached");
49 CFTypeRef kSecCMSCertChainMode
= CFSTR("kSecCMSCertChainMode");
50 CFTypeRef kSecCMSAdditionalCerts
= CFSTR("kSecCMSAdditionalCerts");
51 CFTypeRef kSecCMSSignedAttributes
= CFSTR("kSecCMSSignedAttributes");
52 CFTypeRef kSecCMSSignDate
= CFSTR("kSecCMSSignDate");
53 CFTypeRef kSecCMSAllCerts
= CFSTR("kSecCMSAllCerts");
55 CFTypeRef kSecCMSSignHashAlgorithm
= CFSTR("kSecCMSSignHashAlgorithm");
56 CFTypeRef kSecCMSHashingAlgorithmSHA1
= CFSTR("kSecCMSHashingAlgorithmSHA1");
57 CFTypeRef kSecCMSHashingAlgorithmSHA256
= CFSTR("kSecCMSHashingAlgorithmSHA256");
58 CFTypeRef kSecCMSHashingAlgorithmSHA384
= CFSTR("kSecCMSHashingAlgorithmSHA384");
59 CFTypeRef kSecCMSHashingAlgorithmSHA512
= CFSTR("kSecCMSHashingAlgorithmSHA512");
61 static SecCmsAttribute
*
62 make_attr(PLArenaPool
*poolp
, SecAsn1Item
*type
, SecAsn1Item
*value
, bool encoded
)
64 SecAsn1Item
* copiedvalue
;
65 SecCmsAttribute
*attr
= (SecCmsAttribute
*)PORT_ArenaZAlloc(poolp
, sizeof(SecCmsAttribute
));
69 if (SECITEM_CopyItem(poolp
, &(attr
->type
), type
) != SECSuccess
)
73 if ((copiedvalue
= SECITEM_AllocItem(poolp
, NULL
, value
->Length
)) == NULL
)
76 if (SECITEM_CopyItem(poolp
, copiedvalue
, value
) != SECSuccess
)
79 if (SecCmsArrayAdd(poolp
, (void ***)&(attr
->values
), (void *)copiedvalue
) != SECSuccess
)
83 attr
->encoded
= encoded
;
90 signerinfo_add_auth_attr(SecCmsSignerInfoRef signerinfo
, /*SECOidTag oidtag*/
91 SecAsn1Item
*oid
, SecAsn1Item
*value
, bool encoded
)
93 PLArenaPool
*poolp
= signerinfo
->cmsg
->poolp
;
94 PORT_Assert (poolp
!= NULL
);
95 void *mark
= PORT_ArenaMark (poolp
);
97 SecCmsAttribute
*attr
= make_attr(poolp
, oid
, value
, encoded
);
98 if (!attr
|| SecCmsAttributeArrayAddAttr(poolp
, &(signerinfo
->authAttr
), attr
) != SECSuccess
)
101 PORT_ArenaUnmark (poolp
, mark
);
105 PORT_Assert (mark
!= NULL
);
106 PORT_ArenaRelease (poolp
, mark
);
110 static void sign_all_attributes(const void *key
, const void *value
, void *context
)
112 SecAsn1Item oid
= { CFDataGetLength(key
), (uint8_t*)CFDataGetBytePtr(key
) },
113 oid_value
= { CFDataGetLength(value
), (uint8_t*)CFDataGetBytePtr(value
) };
115 signerinfo_add_auth_attr((SecCmsSignerInfoRef
)context
, &oid
, &oid_value
, true);
118 static OSStatus
SecCMSSignDataOrDigestAndAttributes(SecIdentityRef identity
,
119 CFDataRef data
, bool detached
, bool data_is_digest
, SECOidTag sign_algorithm
,
120 CFMutableDataRef signed_data
, CFDictionaryRef signed_attributes
, SecCmsCertChainMode chainMode
, CFArrayRef additional_certs
)
122 SecCmsMessageRef cmsg
= NULL
;
123 SecCmsContentInfoRef cinfo
;
124 SecCmsSignedDataRef sigd
= NULL
;
125 SecCmsSignerInfoRef signerinfo
;
126 OSStatus status
= errSecParam
;
127 PLArenaPool
*arena
= NULL
;
129 require(!data_is_digest
|| detached
/* if digest, must be detached */, out
);
131 require(cmsg
= SecCmsMessageCreate(NULL
), out
);
132 require(sigd
= SecCmsSignedDataCreate(cmsg
), out
);
133 require(cinfo
= SecCmsMessageGetContentInfo(cmsg
), out
);
134 require_noerr(SecCmsContentInfoSetContentSignedData(cmsg
, cinfo
, sigd
), out
);
135 require(cinfo
= SecCmsSignedDataGetContentInfo(sigd
), out
);
136 require_noerr(SecCmsContentInfoSetContentData(cmsg
, cinfo
, NULL
, detached
), out
);
137 require(signerinfo
= SecCmsSignerInfoCreate(cmsg
, identity
, sign_algorithm
), out
);
138 if (additional_certs
)
139 require_noerr(SecCmsSignedDataAddCertList(sigd
, additional_certs
), out
);
140 require_noerr(SecCmsSignerInfoIncludeCerts(signerinfo
, chainMode
, certUsageAnyCA
), out
);
141 require_noerr(SecCmsSignerInfoAddSigningTime(signerinfo
, CFAbsoluteTimeGetCurrent()), out
);
143 if (signed_attributes
)
144 CFDictionaryApplyFunction(signed_attributes
, sign_all_attributes
, signerinfo
);
146 SecAsn1Item input
= {};
148 input
.Length
= CFDataGetLength(data
);
149 input
.Data
= (uint8_t*)CFDataGetBytePtr(data
);
152 CSSM_DATA cssm_signed_data
= {0, NULL
};
153 // make an encoder context
154 if ((arena
= PORT_NewArena(1024)) == NULL
) {
157 if (data_is_digest
) {
158 require_noerr(SecCmsSignedDataSetDigestValue(sigd
, sign_algorithm
, &input
), out
);
159 require_noerr(SecCmsMessageEncode(cmsg
, NULL
, (SecArenaPoolRef
)arena
, &cssm_signed_data
), out
);
162 require_noerr(SecCmsMessageEncode(cmsg
,(data
&& input
.Length
) ? &input
: NULL
,
163 (SecArenaPoolRef
)arena
, &cssm_signed_data
), out
);
165 if (signed_data
&& cssm_signed_data
.Data
) {
166 CFDataAppendBytes(signed_data
, cssm_signed_data
.Data
, cssm_signed_data
.Length
);
169 status
= errSecSuccess
;
171 if (arena
) PORT_FreeArena(arena
, PR_FALSE
);
172 if (cmsg
) SecCmsMessageDestroy(cmsg
);
176 OSStatus
SecCMSCreateSignedData(SecIdentityRef identity
, CFDataRef data
,
177 CFDictionaryRef parameters
, CFDictionaryRef signed_attributes
,
178 CFMutableDataRef signed_data
)
180 bool is_digest
= false, is_detached
= false;
181 CFStringRef algorithm_name
= NULL
;
182 SecCmsCertChainMode chain_mode
= SecCmsCMCertChain
;
183 CFArrayRef additional_certs
= NULL
;
186 is_digest
= CFDictionaryGetValueIfPresent(parameters
,
187 kSecCMSSignDigest
, NULL
);
188 is_detached
= CFDictionaryGetValueIfPresent(parameters
,
189 kSecCMSSignDetached
, NULL
);
190 algorithm_name
= CFDictionaryGetValue(parameters
,
191 kSecCMSSignHashAlgorithm
);
193 CFTypeRef chain_mode_param
= CFDictionaryGetValue(parameters
, kSecCMSCertChainMode
);
194 if (chain_mode_param
&& (CFGetTypeID(chain_mode_param
) == CFStringGetTypeID()))
195 chain_mode
= CFStringGetIntValue(chain_mode_param
);
197 CFTypeRef additional_certs_param
= CFDictionaryGetValue(parameters
, kSecCMSAdditionalCerts
);
198 if (additional_certs_param
&& (CFGetTypeID(additional_certs_param
) == CFArrayGetTypeID()))
199 additional_certs
= (CFArrayRef
)additional_certs_param
;
202 SECOidTag algorithm
= SEC_OID_SHA1
;
203 if (algorithm_name
) {
204 if (CFEqual(kSecCMSHashingAlgorithmSHA1
, algorithm_name
)) {
205 algorithm
= SEC_OID_SHA1
;
206 } else if (CFEqual(kSecCMSHashingAlgorithmSHA256
, algorithm_name
)) {
207 algorithm
= SEC_OID_SHA256
;
208 } else if (CFEqual(kSecCMSHashingAlgorithmSHA384
, algorithm_name
)) {
209 algorithm
= SEC_OID_SHA384
;
210 } else if (CFEqual(kSecCMSHashingAlgorithmSHA512
, algorithm_name
)) {
211 algorithm
= SEC_OID_SHA512
;
213 // signing with MD5 is no longer allowed
214 algorithm
= SEC_OID_UNKNOWN
;
218 return SecCMSSignDataOrDigestAndAttributes(identity
, data
,
219 is_detached
, is_digest
, algorithm
,
220 signed_data
, signed_attributes
, chain_mode
, additional_certs
);
224 SecCmsSignedDataSetDigestContext(SecCmsSignedDataRef sigd
,
225 SecCmsDigestContextRef digestContext
)
227 SecAsn1Item
* *digests
;
229 PLArenaPool
*arena
= NULL
;
231 if ((arena
= PORT_NewArena(1024)) == NULL
)
234 if (SecCmsDigestContextFinishMultiple(digestContext
, (SecArenaPoolRef
)arena
, &digests
) != SECSuccess
)
237 SECAlgorithmID
**digestAlgorithms
= SecCmsSignedDataGetDigestAlgs(sigd
);
238 if(digestAlgorithms
== NULL
) {
242 if (SecCmsSignedDataSetDigests(sigd
, digestAlgorithms
, digests
) != SECSuccess
)
248 PORT_FreeArena(arena
, PR_FALSE
);
249 return PORT_GetError();
252 static CFMutableArrayRef
copy_signed_attribute_values(SecCmsAttribute
*attr
)
254 CFMutableArrayRef array
= CFArrayCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeArrayCallBacks
);
255 SecAsn1Item
**item
= attr
->values
;
256 if (item
) while (*item
) {
257 CFDataRef asn1data
= CFDataCreate(kCFAllocatorDefault
, (*item
)->Data
, (*item
)->Length
);
259 CFArrayAppendValue(array
, asn1data
);
267 static OSStatus
SecCMSVerifySignedData_internal(CFDataRef message
, CFDataRef detached_contents
,
268 CFTypeRef policy
, SecTrustRef
*trustref
, CFArrayRef additional_certs
,
269 CFDataRef
*attached_contents
, CFDictionaryRef
*signed_attributes
)
271 SecCmsMessageRef cmsg
= NULL
;
272 SecCmsContentInfoRef cinfo
;
273 SecCmsSignedDataRef sigd
= NULL
;
274 OSStatus status
= errSecParam
;
276 SecAsn1Item encoded_message
= { CFDataGetLength(message
), (uint8_t*)CFDataGetBytePtr(message
) };
277 require_noerr_action_quiet(SecCmsMessageDecode(&encoded_message
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, &cmsg
),
278 out
, status
= errSecDecode
);
279 /* expected to be a signed data message at the top level */
280 require_quiet(cinfo
= SecCmsMessageContentLevel(cmsg
, 0), out
);
281 require_quiet(SecCmsContentInfoGetContentTypeTag(cinfo
) == SEC_OID_PKCS7_SIGNED_DATA
, out
);
282 require_quiet(sigd
= (SecCmsSignedDataRef
)SecCmsContentInfoGetContent(cinfo
), out
);
284 if (detached_contents
)
286 require_quiet(!SecCmsSignedDataHasDigests(sigd
), out
);
287 SECAlgorithmID
**digestalgs
= SecCmsSignedDataGetDigestAlgs(sigd
);
288 SecCmsDigestContextRef digcx
= SecCmsDigestContextStartMultiple(digestalgs
);
289 SecCmsDigestContextUpdate(digcx
, CFDataGetBytePtr(detached_contents
), CFDataGetLength(detached_contents
));
290 SecCmsSignedDataSetDigestContext(sigd
, digcx
);
293 if (additional_certs
)
294 require_noerr_quiet(SecCmsSignedDataAddCertList(sigd
, additional_certs
), out
);
296 if (policy
) { /* if no policy is given skip verification */
297 /* find out about signers */
298 int nsigners
= SecCmsSignedDataSignerInfoCount(sigd
);
299 require_quiet(nsigners
== 1, out
);
300 require_noerr_action_quiet(SecCmsSignedDataVerifySignerInfo(sigd
, 0, NULL
, policy
, trustref
),
301 out
, status
= errSecAuthFailed
);
304 status
= errSecSuccess
;
306 if (attached_contents
) {
307 const SecAsn1Item
*content
= SecCmsMessageGetContent(cmsg
);
309 *attached_contents
= CFDataCreate(kCFAllocatorDefault
, content
->Data
, content
->Length
);
311 *attached_contents
= NULL
;
314 if (signed_attributes
) {
315 CFMutableDictionaryRef attrs
= CFDictionaryCreateMutable(kCFAllocatorDefault
,
316 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
317 require_quiet(attrs
, out
);
318 SecCmsAttribute
**signed_attrs
= sigd
->signerInfos
[0]->authAttr
;
319 if (signed_attrs
) while (*signed_attrs
) {
320 CFDataRef type
= CFDataCreate(kCFAllocatorDefault
, (*signed_attrs
)->type
.Data
, (*signed_attrs
)->type
.Length
);
322 CFMutableArrayRef attr
= copy_signed_attribute_values(*signed_attrs
);
324 CFMutableArrayRef existing_attrs
= (CFMutableArrayRef
)CFDictionaryGetValue(attrs
, type
);
325 if (existing_attrs
) {
326 CFIndex count
= CFArrayGetCount(attr
);
328 CFArrayAppendArray(existing_attrs
, attr
, CFRangeMake(0, count
));
330 CFDictionarySetValue(attrs
, type
, attr
);
337 CFMutableArrayRef certs
= NULL
;
339 SecAsn1Item
**cert_datas
= SecCmsSignedDataGetCertificateList(sigd
);
340 certs
= CFArrayCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeArrayCallBacks
);
341 SecAsn1Item
*cert_data
;
342 if (cert_datas
) while ((cert_data
= *cert_datas
) != NULL
) {
343 SecCertificateRef cert
= SecCertificateCreateWithBytes(NULL
, cert_data
->Data
, cert_data
->Length
);
345 CFArrayAppendValue(certs
, cert
);
351 CFDictionaryAddValue(attrs
, kSecCMSAllCerts
, certs
);
353 /* Add "cooked" values separately */
354 CFAbsoluteTime signing_time
;
355 if (errSecSuccess
== SecCmsSignerInfoGetSigningTime(sigd
->signerInfos
[0], &signing_time
)) {
356 CFDateRef signing_date
= CFDateCreate(kCFAllocatorDefault
, signing_time
);
358 CFDictionarySetValue(attrs
, kSecCMSSignDate
, signing_date
);
359 if (signing_date
) CFRelease(signing_date
);
363 *signed_attributes
= attrs
;
364 if (certs
) CFRelease(certs
);
369 if (cmsg
) SecCmsMessageDestroy(cmsg
);
373 OSStatus
SecCMSVerifyCopyDataAndAttributes(CFDataRef message
, CFDataRef detached_contents
,
374 CFTypeRef policy
, SecTrustRef
*trustref
,
375 CFDataRef
*attached_contents
, CFDictionaryRef
*signed_attributes
)
377 OSStatus status
= SecCMSVerifySignedData_internal(message
, detached_contents
, policy
, trustref
, NULL
, attached_contents
, signed_attributes
);
382 OSStatus
SecCMSVerifySignedData(CFDataRef message
, CFDataRef detached_contents
,
383 CFTypeRef policy
, SecTrustRef
*trustref
, CFArrayRef additional_certificates
,
384 CFDataRef
*attached_contents
, CFDictionaryRef
*message_attributes
)
386 CFDictionaryRef signed_attributes
= NULL
;
387 OSStatus status
= SecCMSVerifySignedData_internal(message
, detached_contents
, policy
, trustref
, additional_certificates
, attached_contents
, &signed_attributes
);
388 if (!status
&& signed_attributes
&& message_attributes
) {
389 *message_attributes
= CFDictionaryCreate(kCFAllocatorDefault
, &kSecCMSSignedAttributes
, (const void **)&signed_attributes
, 1, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
391 if (signed_attributes
) CFRelease(signed_attributes
);
396 OSStatus
SecCMSVerify(CFDataRef message
, CFDataRef detached_contents
,
397 CFTypeRef policy
, SecTrustRef
*trustref
,
398 CFDataRef
*attached_contents
) {
399 return SecCMSVerifySignedData_internal(message
, detached_contents
, policy
, trustref
, NULL
, attached_contents
, NULL
);
402 /* Designed to match the sec submodule implementation available for iOS */
403 CFArrayRef
SecCMSCertificatesOnlyMessageCopyCertificates(CFDataRef message
) {
404 SecCmsMessageRef cmsg
= NULL
;
405 SecCmsContentInfoRef cinfo
;
406 SecCmsSignedDataRef sigd
= NULL
;
407 CFMutableArrayRef certs
= NULL
;
409 CSSM_DATA encoded_message
= { CFDataGetLength(message
), (uint8_t*)CFDataGetBytePtr(message
) };
410 require_noerr_quiet(SecCmsMessageDecode(&encoded_message
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, &cmsg
), out
);
411 /* expected to be a signed data message at the top level */
412 require(cinfo
= SecCmsMessageContentLevel(cmsg
, 0), out
);
413 require(SecCmsContentInfoGetContentTypeTag(cinfo
) == SEC_OID_PKCS7_SIGNED_DATA
, out
);
414 require(sigd
= (SecCmsSignedDataRef
)SecCmsContentInfoGetContent(cinfo
), out
);
416 /* find out about signers */
417 int nsigners
= SecCmsSignedDataSignerInfoCount(sigd
);
418 require(nsigners
== 0, out
);
420 CSSM_DATA_PTR
*cert_datas
= SecCmsSignedDataGetCertificateList(sigd
);
421 certs
= CFArrayCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeArrayCallBacks
);
422 CSSM_DATA_PTR cert_data
;
423 if (cert_datas
) while ((cert_data
= *cert_datas
) != NULL
) {
424 SecCertificateRef cert
= SecCertificateCreateWithBytes(NULL
, cert_data
->Data
, cert_data
->Length
);
426 CFArrayAppendValue(certs
, cert
);
434 SecCmsMessageDestroy(cmsg
);
440 extern const SecAsn1Template SecCmsMessageTemplate
[];
442 CFDataRef
SecCMSCreateCertificatesOnlyMessage(CFTypeRef cert_or_array_thereof
) {
443 OSStatus status
= errSecParam
;
444 SecCmsMessageRef cmsg
= NULL
;
445 SecCmsContentInfoRef cinfo
;
446 SecCmsSignedDataRef sigd
= NULL
;
447 CFMutableDataRef cert_only_signed_data
= NULL
;
448 CFArrayRef cert_array
= NULL
;
449 CFIndex cert_array_count
= 0;
450 SecCertificateRef cert
= NULL
;
452 require(cert_or_array_thereof
, out
);
454 require(cmsg
= SecCmsMessageCreate(NULL
), out
);
455 require(sigd
= SecCmsSignedDataCreate(cmsg
), out
);
456 require_noerr(SecCmsContentInfoSetContentData(cmsg
, &(sigd
->contentInfo
), NULL
, PR_TRUE
), out
);
457 require(cinfo
= SecCmsMessageGetContentInfo(cmsg
), out
);
458 require_noerr(SecCmsContentInfoSetContentSignedData(cmsg
, cinfo
, sigd
), out
);
459 long version
= SEC_CMS_SIGNED_DATA_VERSION_BASIC
;
460 require(SEC_ASN1EncodeInteger(cmsg
->poolp
, &(sigd
->version
), version
), out
);
462 if (CFGetTypeID(cert_or_array_thereof
) == SecCertificateGetTypeID()) {
463 cert_array
= CFArrayCreate(kCFAllocatorDefault
, &cert_or_array_thereof
, 1, &kCFTypeArrayCallBacks
);
464 } else if (CFGetTypeID(cert_or_array_thereof
) == CFArrayGetTypeID()) {
465 cert_array
= CFArrayCreateCopy(kCFAllocatorDefault
, (CFArrayRef
)cert_or_array_thereof
);
468 require(cert_array
, out
);
469 cert_array_count
= CFArrayGetCount(cert_array
);
470 require(cert_array_count
> 0, out
);
472 sigd
->rawCerts
= (SecAsn1Item
* *)PORT_ArenaAlloc(cmsg
->poolp
, (cert_array_count
+ 1) * sizeof(SecAsn1Item
*));
473 require(sigd
->rawCerts
, out
);
475 for (ix
= 0; ix
< cert_array_count
; ix
++) {
476 cert
= (SecCertificateRef
)CFArrayGetValueAtIndex(cert_array
, ix
);
479 sigd
->rawCerts
[ix
] = PORT_ArenaZAlloc(cmsg
->poolp
, sizeof(SecAsn1Item
));
480 SecAsn1Item cert_data
= { SecCertificateGetLength(cert
),
481 (uint8_t *)SecCertificateGetBytePtr(cert
) };
482 *(sigd
->rawCerts
[ix
]) = cert_data
;
484 sigd
->rawCerts
[ix
] = NULL
;
486 /* this is a SET OF, so we need to sort them guys - we have the DER already, though */
487 if (cert_array_count
> 1)
488 SecCmsArraySort((void **)sigd
->rawCerts
, SecCmsUtilDERCompare
, NULL
, NULL
);
490 cert_only_signed_data
= CFDataCreateMutable(kCFAllocatorDefault
, 0);
491 SecAsn1Item cert_only_signed_data_item
= {};
492 require_quiet(SEC_ASN1EncodeItem(cmsg
->poolp
, &cert_only_signed_data_item
,
493 cmsg
, SecCmsMessageTemplate
), out
);
494 CFDataAppendBytes(cert_only_signed_data
, cert_only_signed_data_item
.Data
,
495 cert_only_signed_data_item
.Length
);
497 status
= errSecSuccess
;
499 if (cert_array
) { CFRelease(cert_array
); }
500 if (status
&& cert_only_signed_data
) { CFRelease(cert_only_signed_data
); }
501 if (cmsg
) SecCmsMessageDestroy(cmsg
);
502 return cert_only_signed_data
;
505 CFDataRef
SecCMSCreateCertificatesOnlyMessageIAP(SecCertificateRef cert
)
507 static const uint8_t header
[] = {
508 0x30, 0x82, 0x03, 0x6d, 0x06, 0x09, 0x2a, 0x86,
509 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x02, 0xa0,
510 0x82, 0x03, 0x5e, 0x30, 0x82, 0x03, 0x5a, 0x02,
511 0x01, 0x01, 0x31, 0x00, 0x30, 0x0b, 0x06, 0x09,
512 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07,
513 0x01, 0xa0, 0x82, 0x03, 0x40
516 static const uint8_t trailer
[] = {
517 0xa1, 0x00, 0x31, 0x00
520 CFMutableDataRef message
= NULL
;
522 const uint8_t *certbytes
;
524 uint8_t *messagebytes
;
527 certdata
= SecCertificateCopyData(cert
);
528 require(certdata
, out
);
530 certbytes
= CFDataGetBytePtr(certdata
);
531 certlen
= CFDataGetLength(certdata
);
532 require(certlen
> UINT8_MAX
, out
);
533 require(certlen
< UINT16_MAX
, out
);
535 message
= CFDataCreateMutable(kCFAllocatorDefault
, 0);
536 require(message
, out
);
538 CFDataAppendBytes(message
, header
, sizeof(header
));
539 CFDataAppendBytes(message
, certbytes
, certlen
);
540 CFDataAppendBytes(message
, trailer
, sizeof(trailer
));
542 messagebytes
= CFDataGetMutableBytePtr(message
);
543 messagelen
= CFDataGetLength(message
);
546 messagebytes
[2] = messagelen
>> 8;
547 messagebytes
[3] = messagelen
& 0xFF;
550 messagebytes
[17] = messagelen
>> 8;
551 messagebytes
[18] = messagelen
& 0xFF;
554 messagebytes
[21] = messagelen
>> 8;
555 messagebytes
[22] = messagelen
& 0xFF;
558 messagebytes
[43] = messagelen
>> 8;
559 messagebytes
[44] = messagelen
& 0xFF;
562 if (certdata
!= NULL
)