2 * Copyright (c) 2008-2010 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@
29 * Created by Conrad Sauerwald on 2/11/08.
32 #include <AssertMacros.h>
34 #include <TargetConditionals.h>
35 #if (TARGET_OS_MAC && !(TARGET_OS_EMBEDDED || TARGET_OS_IPHONE))
42 #include <Security/SecBase.h>
43 #include <Security/SecCmsMessage.h>
44 #include <Security/SecCmsSignedData.h>
45 #include <Security/SecCmsEnvelopedData.h>
46 #include <Security/SecCmsContentInfo.h>
47 #include <Security/SecCmsSignerInfo.h>
48 #include <Security/SecCmsRecipientInfo.h>
49 #include <Security/SecCmsEncoder.h>
50 #include <Security/SecCmsDecoder.h>
51 #include <Security/SecCmsDigestContext.h>
52 #include <Security/cmstpriv.h>
54 #include <CoreFoundation/CFData.h>
56 #include <Security/SecInternal.h>
57 #include <Security/SecBasePriv.h>
58 #include <Security/SecCertificatePriv.h>
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>
70 CFTypeRef kSecCMSBulkEncryptionAlgorithm
= CFSTR("kSecCMSBulkEncryptionAlgorithm");
71 CFTypeRef kSecCMSSignDigest
= CFSTR("kSecCMSSignDigest");
72 CFTypeRef kSecCMSSignDetached
= CFSTR("kSecCMSSignDetached");
73 CFTypeRef kSecCMSSignHashAlgorithm
= CFSTR("kSecCMSSignHashAlgorithm");
74 CFTypeRef kSecCMSEncryptionAlgorithmDESCBC
= CFSTR("kSecCMSEncryptionAlgorithmDESCBC");
75 CFTypeRef kSecCMSEncryptionAlgorithmAESCBC
= CFSTR("kSecCMSEncryptionAlgorithmAESCBC");
76 CFTypeRef kSecCMSHashingAlgorithmMD5
= CFSTR("kSecCMSHashingAlgorithmMD5");
77 CFTypeRef kSecCMSCertChainMode
= CFSTR("kSecCMSCertChainMode");
78 CFTypeRef kSecCMSCertChainModeNone
= CFSTR("0");
79 CFTypeRef kSecCMSAdditionalCerts
= CFSTR("kSecCMSAdditionalCerts");
80 CFTypeRef kSecCMSSignedAttributes
= CFSTR("kSecCMSSignedAttributes");
82 OSStatus
SecCMSCreateEnvelopedData(CFTypeRef recipient_or_cfarray_thereof
,
83 CFDictionaryRef params
, CFDataRef data
, CFMutableDataRef enveloped_data
)
85 SecCmsMessageRef cmsg
= NULL
;
86 SecCmsContentInfoRef cinfo
;
87 SecCmsEnvelopedDataRef envd
= NULL
;
88 SECOidTag algorithmTag
= SEC_OID_DES_EDE3_CBC
;
90 OSStatus status
= errSecParam
;
93 CFStringRef algorithm_name
= CFDictionaryGetValue(params
, kSecCMSBulkEncryptionAlgorithm
);
95 if (CFEqual(kSecCMSEncryptionAlgorithmDESCBC
, algorithm_name
)) {
96 algorithmTag
= SEC_OID_DES_CBC
;
98 } else if (CFEqual(kSecCMSEncryptionAlgorithmAESCBC
, algorithm_name
)) {
99 algorithmTag
= SEC_OID_AES_128_CBC
;
105 require(cmsg
= SecCmsMessageCreate(), out
);
106 require(envd
= SecCmsEnvelopedDataCreate(cmsg
, algorithmTag
, keySize
), out
);
107 require(cinfo
= SecCmsMessageGetContentInfo(cmsg
), out
);
108 require_noerr(SecCmsContentInfoSetContentEnvelopedData(cinfo
, envd
), out
);
109 require(cinfo
= SecCmsEnvelopedDataGetContentInfo(envd
), out
);
110 require_noerr(SecCmsContentInfoSetContentData(cinfo
, NULL
, false), out
);
111 // == wrapper of: require(SECSuccess == SecCmsContentInfoSetContent(cinfo, SEC_OID_PKCS7_DATA, NULL), out);
113 if (CFGetTypeID(recipient_or_cfarray_thereof
) == CFArrayGetTypeID()) {
114 CFIndex dex
, numCerts
= CFArrayGetCount(recipient_or_cfarray_thereof
);
115 for(dex
=0; dex
<numCerts
; dex
++) {
116 SecCertificateRef recip
=
117 (SecCertificateRef
)CFArrayGetValueAtIndex(recipient_or_cfarray_thereof
, dex
);
118 SecCmsRecipientInfoRef rinfo
;
119 require(rinfo
= SecCmsRecipientInfoCreate(envd
, recip
), out
);
121 } else if (CFGetTypeID(recipient_or_cfarray_thereof
) == SecCertificateGetTypeID()) {
122 require(SecCmsRecipientInfoCreate(envd
, (SecCertificateRef
)recipient_or_cfarray_thereof
), out
);
126 SecAsn1Item input
= {};
128 input
.Length
= CFDataGetLength(data
);
129 input
.Data
= (uint8_t*)CFDataGetBytePtr(data
);
131 require_noerr(SecCmsMessageEncode(cmsg
, (data
&& input
.Length
) ? &input
: NULL
, enveloped_data
), out
);
135 if (cmsg
) SecCmsMessageDestroy(cmsg
);
139 OSStatus
SecCMSDecryptEnvelopedData(CFDataRef message
,
140 CFMutableDataRef data
, SecCertificateRef
*recipient
)
142 SecCmsMessageRef cmsg
= NULL
;
143 SecCmsContentInfoRef cinfo
;
144 SecCmsEnvelopedDataRef envd
= NULL
;
145 SecCertificateRef used_recipient
= NULL
;
146 OSStatus status
= errSecParam
;
148 SecAsn1Item encoded_message
= { CFDataGetLength(message
), (uint8_t*)CFDataGetBytePtr(message
) };
149 require_noerr_action_quiet(SecCmsMessageDecode(&encoded_message
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, &cmsg
),
150 out
, status
= errSecDecode
);
151 require_quiet(cinfo
= SecCmsMessageContentLevel(cmsg
, 0), out
);
152 require_quiet(SecCmsContentInfoGetContentTypeTag(cinfo
) == SEC_OID_PKCS7_ENVELOPED_DATA
, out
);
153 require_quiet(envd
= (SecCmsEnvelopedDataRef
)SecCmsContentInfoGetContent(cinfo
), out
);
154 SecCmsRecipientInfoRef
*rinfo
= envd
->recipientInfos
;
155 while (!used_recipient
&& *rinfo
) {
156 used_recipient
= (*rinfo
)->cert
;
159 require_quiet(2 == SecCmsMessageContentLevelCount(cmsg
), out
);
160 require_quiet(cinfo
= SecCmsMessageContentLevel(cmsg
, 1), out
);
161 require_quiet(SecCmsContentInfoGetContentTypeTag(cinfo
) == SEC_OID_PKCS7_DATA
, out
);
162 const SecAsn1Item
*content
= SecCmsMessageGetContent(cmsg
);
164 CFDataAppendBytes(data
, content
->Data
, content
->Length
);
166 CFRetain(used_recipient
);
167 *recipient
= used_recipient
;
171 if (cmsg
) SecCmsMessageDestroy(cmsg
);
175 static SecCmsAttribute
*
176 make_attr(PLArenaPool
*poolp
, SecAsn1Item
*type
, SecAsn1Item
*value
, bool encoded
)
178 SecAsn1Item
* copiedvalue
;
179 SecCmsAttribute
*attr
= (SecCmsAttribute
*)PORT_ArenaZAlloc(poolp
, sizeof(SecCmsAttribute
));
183 if (SECITEM_CopyItem(poolp
, &(attr
->type
), type
) != SECSuccess
)
187 if ((copiedvalue
= SECITEM_AllocItem(poolp
, NULL
, value
->Length
)) == NULL
)
190 if (SECITEM_CopyItem(poolp
, copiedvalue
, value
) != SECSuccess
)
193 SecCmsArrayAdd(poolp
, (void ***)&(attr
->values
), (void *)copiedvalue
);
196 attr
->encoded
= encoded
;
203 signerinfo_add_auth_attr(SecCmsSignerInfoRef signerinfo
, /*SECOidTag oidtag*/
204 SecAsn1Item
*oid
, SecAsn1Item
*value
, bool encoded
)
206 PLArenaPool
*poolp
= signerinfo
->signedData
->contentInfo
.cmsg
->poolp
;
207 PORT_Assert (poolp
!= NULL
);
208 void *mark
= PORT_ArenaMark (poolp
);
210 SecCmsAttribute
*attr
= make_attr(poolp
, oid
, value
, encoded
);
211 if (!attr
|| SecCmsAttributeArrayAddAttr(poolp
, &(signerinfo
->authAttr
), attr
) != SECSuccess
)
214 PORT_ArenaUnmark (poolp
, mark
);
218 PORT_Assert (mark
!= NULL
);
219 PORT_ArenaRelease (poolp
, mark
);
223 static void sign_all_attributes(const void *key
, const void *value
, void *context
)
225 SecAsn1Item oid
= { CFDataGetLength(key
), (uint8_t*)CFDataGetBytePtr(key
) },
226 oid_value
= { CFDataGetLength(value
), (uint8_t*)CFDataGetBytePtr(value
) };
228 signerinfo_add_auth_attr((SecCmsSignerInfoRef
)context
, &oid
, &oid_value
, true);
232 static void enveloped_data_add_unprotected_attr(SecCmsEnvelopedDataRef envd
,
233 SecAsn1Item
*oid
, SecAsn1Item
*value
, bool encoded
)
235 PLArenaPool
*poolp
= envd
->contentInfo
.cmsg
->poolp
;
236 PORT_Assert (poolp
!= NULL
);
237 void *mark
= PORT_ArenaMark (poolp
);
238 SecCmsAttribute
*attr
= make_attr(poolp
, oid
, value
, encoded
);
240 if (!attr
|| SecCmsAttributeArrayAddAttr(
242 &(envd
->unprotectedAttr
), attr
) != SECSuccess
)
245 PORT_ArenaUnmark (poolp
, mark
);
249 PORT_Assert (mark
!= NULL
);
250 PORT_ArenaRelease (poolp
, mark
);
256 static OSStatus
SecCMSSignDataOrDigestAndAttributes(SecIdentityRef identity
,
257 CFDataRef data
, bool detached
, bool data_is_digest
, SECOidTag sign_algorithm
,
258 CFMutableDataRef signed_data
, CFDictionaryRef signed_attributes
, SecCmsCertChainMode chainMode
, CFArrayRef additional_certs
)
260 SecCmsMessageRef cmsg
= NULL
;
261 SecCmsContentInfoRef cinfo
;
262 SecCmsSignedDataRef sigd
= NULL
;
263 SecCmsSignerInfoRef signerinfo
;
264 OSStatus status
= errSecParam
;
266 require(!data_is_digest
|| detached
/* if digest, must be detached */, out
);
268 require(cmsg
= SecCmsMessageCreate(), out
);
269 require(sigd
= SecCmsSignedDataCreate(cmsg
), out
);
270 require(cinfo
= SecCmsMessageGetContentInfo(cmsg
), out
);
271 require_noerr(SecCmsContentInfoSetContentSignedData(cinfo
, sigd
), out
);
272 require(cinfo
= SecCmsSignedDataGetContentInfo(sigd
), out
);
273 require_noerr(SecCmsContentInfoSetContentData(cinfo
, NULL
, detached
), out
);
274 require(signerinfo
= SecCmsSignerInfoCreate(sigd
, identity
, sign_algorithm
), out
);
275 if (additional_certs
)
276 require_noerr(SecCmsSignedDataAddCertList(sigd
, additional_certs
), out
);
277 require_noerr(SecCmsSignerInfoIncludeCerts(signerinfo
, chainMode
, certUsageAnyCA
), out
);
278 require_noerr(SecCmsSignerInfoAddSigningTime(signerinfo
, CFAbsoluteTimeGetCurrent()), out
);
280 if (signed_attributes
)
281 CFDictionaryApplyFunction(signed_attributes
, sign_all_attributes
, signerinfo
);
283 SecAsn1Item input
= {};
285 input
.Length
= CFDataGetLength(data
);
286 input
.Data
= (uint8_t*)CFDataGetBytePtr(data
);
288 if (data_is_digest
) {
289 require_noerr(SecCmsSignedDataSetDigestValue(sigd
, sign_algorithm
, &input
), out
);
290 require_noerr(SecCmsMessageEncode(cmsg
, NULL
, signed_data
), out
);
293 require_noerr(SecCmsMessageEncode(cmsg
, (data
&& input
.Length
) ? &input
: NULL
, signed_data
), out
);
297 if (cmsg
) SecCmsMessageDestroy(cmsg
);
301 OSStatus
SecCMSSignDataAndAttributes(SecIdentityRef identity
, CFDataRef data
, bool detached
,
302 CFMutableDataRef signed_data
, CFDictionaryRef signed_attributes
)
304 return SecCMSSignDataOrDigestAndAttributes(identity
, data
, detached
, false, SEC_OID_SHA1
,
305 signed_data
, signed_attributes
, SecCmsCMCertChain
, NULL
);
308 OSStatus
SecCMSSignDigestAndAttributes(SecIdentityRef identity
, CFDataRef digest
,
309 CFMutableDataRef signed_data
, CFDictionaryRef signed_attributes
)
311 return SecCMSSignDataOrDigestAndAttributes(identity
, digest
, true, true, SEC_OID_SHA1
,
312 signed_data
, signed_attributes
, SecCmsCMCertChain
, NULL
);
316 OSStatus
SecCMSCreateSignedData(SecIdentityRef identity
, CFDataRef data
,
317 CFDictionaryRef parameters
, CFDictionaryRef signed_attributes
,
318 CFMutableDataRef signed_data
)
320 bool is_digest
= false, is_detached
= false;
321 CFStringRef algorithm_name
= NULL
;
322 SecCmsCertChainMode chain_mode
= SecCmsCMCertChain
;
323 CFArrayRef additional_certs
= NULL
;
326 is_digest
= CFDictionaryGetValueIfPresent(parameters
,
327 kSecCMSSignDigest
, NULL
);
328 is_detached
= CFDictionaryGetValueIfPresent(parameters
,
329 kSecCMSSignDetached
, NULL
);
330 algorithm_name
= CFDictionaryGetValue(parameters
,
331 kSecCMSSignHashAlgorithm
);
333 CFTypeRef chain_mode_param
= CFDictionaryGetValue(parameters
, kSecCMSCertChainMode
);
334 if (chain_mode_param
&& (CFGetTypeID(chain_mode_param
) == CFStringGetTypeID()))
335 chain_mode
= CFStringGetIntValue(chain_mode_param
);
337 CFTypeRef additional_certs_param
= CFDictionaryGetValue(parameters
, kSecCMSAdditionalCerts
);
338 if (additional_certs_param
&& (CFGetTypeID(additional_certs_param
) == CFArrayGetTypeID()))
339 additional_certs
= (CFArrayRef
)additional_certs_param
;
342 SECOidTag algorithm
= SEC_OID_SHA1
;
343 if (algorithm_name
) {
344 if (CFEqual(kSecCMSHashingAlgorithmMD5
, algorithm_name
)) {
345 algorithm
= SEC_OID_MD5
;
347 algorithm
= SEC_OID_UNKNOWN
;
352 return SecCMSSignDataOrDigestAndAttributes(identity
, data
,
353 is_detached
, is_digest
, algorithm
,
354 signed_data
, signed_attributes
, chain_mode
, additional_certs
);
358 static CFMutableArrayRef
signed_attribute_values(SecCmsAttribute
*attr
)
360 CFMutableArrayRef array
= CFArrayCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeArrayCallBacks
);
361 SecAsn1Item
**item
= attr
->values
;
362 if (item
) while (*item
) {
363 CFDataRef asn1data
= CFDataCreate(kCFAllocatorDefault
, (*item
)->Data
, (*item
)->Length
);
365 CFArrayAppendValue(array
, asn1data
);
373 static OSStatus
SecCMSVerifySignedData_internal(CFDataRef message
, CFDataRef detached_contents
,
374 SecPolicyRef policy
, SecTrustRef
*trustref
, CFArrayRef additional_certs
,
375 CFDataRef
*attached_contents
, CFDictionaryRef
*signed_attributes
)
377 SecCmsMessageRef cmsg
= NULL
;
378 SecCmsContentInfoRef cinfo
;
379 SecCmsSignedDataRef sigd
= NULL
;
380 OSStatus status
= errSecParam
;
382 SecAsn1Item encoded_message
= { CFDataGetLength(message
), (uint8_t*)CFDataGetBytePtr(message
) };
383 require_noerr_action_quiet(SecCmsMessageDecode(&encoded_message
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, &cmsg
),
384 out
, status
= errSecDecode
);
385 /* expected to be a signed data message at the top level */
386 require_quiet(cinfo
= SecCmsMessageContentLevel(cmsg
, 0), out
);
387 require_quiet(SecCmsContentInfoGetContentTypeTag(cinfo
) == SEC_OID_PKCS7_SIGNED_DATA
, out
);
388 require_quiet(sigd
= (SecCmsSignedDataRef
)SecCmsContentInfoGetContent(cinfo
), out
);
390 if (detached_contents
)
392 require_quiet(!SecCmsSignedDataHasDigests(sigd
), out
);
393 SECAlgorithmID
**digestalgs
= SecCmsSignedDataGetDigestAlgs(sigd
);
394 SecCmsDigestContextRef digcx
= SecCmsDigestContextStartMultiple(digestalgs
);
395 SecCmsDigestContextUpdate(digcx
, CFDataGetBytePtr(detached_contents
), CFDataGetLength(detached_contents
));
396 SecCmsSignedDataSetDigestContext(sigd
, digcx
);
397 SecCmsDigestContextDestroy(digcx
);
400 if (additional_certs
)
401 require_noerr_quiet(SecCmsSignedDataAddCertList(sigd
, additional_certs
), out
);
403 if (policy
) { /* if no policy is given skip verification */
404 /* find out about signers */
405 int nsigners
= SecCmsSignedDataSignerInfoCount(sigd
);
406 require_quiet(nsigners
== 1, out
);
407 require_noerr_action_quiet(SecCmsSignedDataVerifySignerInfo(sigd
, 0, NULL
, policy
, trustref
),
408 out
, status
= errSecAuthFailed
);
413 trustrefs
= CFArrayCreateMutable(kCFAllocatorDefault
, nsigners
, &kCFTypeArrayCallBacks
);
416 for (j
= 0; j
< nsigners
; j
++)
418 SecTrustRef trustRef
;
419 require_noerr_action_quiet(SecCmsSignedDataVerifySignerInfo(sigd
, j
, NULL
, policy
, &trustRef
),
420 out
, status
= errSecAuthFailed
);
421 if ((j
== 0) && (nsigners
== 1))
422 *trustref_or_cfarray_thereof
= trustRef
;
424 CFArrayAppendValue(trustrefs
, trustRef
);
428 *trustref_or_cfarray_thereof
= trustrefs
;
434 if (attached_contents
) {
435 const SecAsn1Item
*content
= SecCmsMessageGetContent(cmsg
);
437 *attached_contents
= CFDataCreate(kCFAllocatorDefault
, content
->Data
, content
->Length
);
439 *attached_contents
= NULL
;
442 if (signed_attributes
) {
443 CFMutableDictionaryRef attrs
= CFDictionaryCreateMutable(kCFAllocatorDefault
,
444 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
445 require_quiet(attrs
, out
);
446 SecCmsAttribute
**signed_attrs
= sigd
->signerInfos
[0]->authAttr
;
447 if (signed_attrs
) while (*signed_attrs
) {
448 CFDataRef type
= CFDataCreate(kCFAllocatorDefault
, (*signed_attrs
)->type
.Data
, (*signed_attrs
)->type
.Length
);
450 CFMutableArrayRef attr
= signed_attribute_values(*signed_attrs
);
452 CFMutableArrayRef existing_attrs
= (CFMutableArrayRef
)CFDictionaryGetValue(attrs
, type
);
453 if (existing_attrs
) {
454 CFIndex count
= CFArrayGetCount(attr
);
456 CFArrayAppendArray(existing_attrs
, attr
, CFRangeMake(0, count
));
458 CFDictionarySetValue(attrs
, type
, attr
);
465 *signed_attributes
= attrs
;
469 if (cmsg
) SecCmsMessageDestroy(cmsg
);
473 OSStatus
SecCMSVerifyCopyDataAndAttributes(CFDataRef message
, CFDataRef detached_contents
,
474 SecPolicyRef policy
, SecTrustRef
*trustref
,
475 CFDataRef
*attached_contents
, CFDictionaryRef
*signed_attributes
)
477 return SecCMSVerifySignedData_internal(message
, detached_contents
, policy
, trustref
, NULL
, attached_contents
, signed_attributes
);
480 OSStatus
SecCMSVerifySignedData(CFDataRef message
, CFDataRef detached_contents
,
481 SecPolicyRef policy
, SecTrustRef
*trustref
, CFArrayRef additional_certificates
,
482 CFDataRef
*attached_contents
, CFDictionaryRef
*message_attributes
)
484 CFDictionaryRef signed_attributes
= NULL
;
485 OSStatus status
= SecCMSVerifySignedData_internal(message
, detached_contents
, policy
, trustref
, additional_certificates
, attached_contents
, &signed_attributes
);
486 if (!status
&& signed_attributes
&& message_attributes
) {
487 *message_attributes
= CFDictionaryCreate(kCFAllocatorDefault
, &kSecCMSSignedAttributes
, (const void **)&signed_attributes
, 1, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
489 CFReleaseSafe(signed_attributes
);
494 OSStatus
SecCMSVerify(CFDataRef message
, CFDataRef detached_contents
,
495 SecPolicyRef policy
, SecTrustRef
*trustref
,
496 CFDataRef
*attached_contents
) {
497 return SecCMSVerifySignedData_internal(message
, detached_contents
, policy
, trustref
, NULL
, attached_contents
, NULL
);
500 CFArrayRef
SecCMSCertificatesOnlyMessageCopyCertificates(CFDataRef message
) {
501 SecCmsMessageRef cmsg
= NULL
;
502 SecCmsContentInfoRef cinfo
;
503 SecCmsSignedDataRef sigd
= NULL
;
504 CFMutableArrayRef certs
= NULL
;
506 SecAsn1Item encoded_message
= { CFDataGetLength(message
), (uint8_t*)CFDataGetBytePtr(message
) };
507 require_noerr_quiet(SecCmsMessageDecode(&encoded_message
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, &cmsg
), out
);
508 /* expected to be a signed data message at the top level */
509 require(cinfo
= SecCmsMessageContentLevel(cmsg
, 0), out
);
510 require(SecCmsContentInfoGetContentTypeTag(cinfo
) == SEC_OID_PKCS7_SIGNED_DATA
, out
);
511 require(sigd
= (SecCmsSignedDataRef
)SecCmsContentInfoGetContent(cinfo
), out
);
513 /* find out about signers */
514 int nsigners
= SecCmsSignedDataSignerInfoCount(sigd
);
515 require(nsigners
== 0, out
);
517 SecAsn1Item
**cert_datas
= SecCmsSignedDataGetCertificateList(sigd
);
518 certs
= CFArrayCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeArrayCallBacks
);
519 SecAsn1Item
*cert_data
;
520 if (cert_datas
) while ((cert_data
= *cert_datas
) != NULL
) {
521 SecCertificateRef cert
= SecCertificateCreateWithBytes(NULL
, cert_data
->Data
, cert_data
->Length
);
523 CFArrayAppendValue(certs
, cert
);
531 SecCmsMessageDestroy(cmsg
);
537 extern const SecAsn1Template SecCmsMessageTemplate
[];
539 CFDataRef
SecCMSCreateCertificatesOnlyMessage(CFTypeRef cert_or_array_thereof
) {
540 OSStatus status
= errSecParam
;
541 SecCmsMessageRef cmsg
= NULL
;
542 SecCmsContentInfoRef cinfo
;
543 SecCmsSignedDataRef sigd
= NULL
;
544 CFMutableDataRef cert_only_signed_data
= NULL
;
545 CFArrayRef cert_array
= NULL
;
546 CFIndex cert_array_count
= 0;
547 SecCertificateRef cert
= NULL
;
549 require(cert_or_array_thereof
, out
);
551 require(cmsg
= SecCmsMessageCreate(), out
);
552 require(sigd
= SecCmsSignedDataCreate(cmsg
), out
);
553 require_noerr(SecCmsContentInfoSetContentData(&(sigd
->contentInfo
), NULL
, PR_TRUE
), out
);
554 require(cinfo
= SecCmsMessageGetContentInfo(cmsg
), out
);
555 require_noerr(SecCmsContentInfoSetContentSignedData(cinfo
, sigd
), out
);
556 long version
= SEC_CMS_SIGNED_DATA_VERSION_BASIC
;
557 require(SEC_ASN1EncodeInteger(cmsg
->poolp
, &(sigd
->version
), version
), out
);
559 if (CFGetTypeID(cert_or_array_thereof
) == SecCertificateGetTypeID()) {
560 cert_array
= CFArrayCreate(kCFAllocatorDefault
, &cert_or_array_thereof
, 1, &kCFTypeArrayCallBacks
);
561 } else if (CFGetTypeID(cert_or_array_thereof
) == CFArrayGetTypeID()) {
562 cert_array
= CFArrayCreateCopy(kCFAllocatorDefault
, (CFArrayRef
)cert_or_array_thereof
);
565 require(cert_array
, out
);
566 cert_array_count
= CFArrayGetCount(cert_array
);
567 require(cert_array_count
> 0, out
);
569 sigd
->rawCerts
= (SecAsn1Item
* *)PORT_ArenaAlloc(cmsg
->poolp
, (cert_array_count
+ 1) * sizeof(SecAsn1Item
*));
570 require(sigd
->rawCerts
, out
);
572 for (ix
= 0; ix
< cert_array_count
; ix
++) {
573 cert
= (SecCertificateRef
)CFArrayGetValueAtIndex(cert_array
, ix
);
576 sigd
->rawCerts
[ix
] = PORT_ArenaZAlloc(cmsg
->poolp
, sizeof(SecAsn1Item
));
577 SecAsn1Item cert_data
= { SecCertificateGetLength(cert
),
578 (uint8_t *)SecCertificateGetBytePtr(cert
) };
579 *(sigd
->rawCerts
[ix
]) = cert_data
;
581 sigd
->rawCerts
[ix
] = NULL
;
583 /* this is a SET OF, so we need to sort them guys - we have the DER already, though */
584 if (cert_array_count
> 1)
585 SecCmsArraySort((void **)sigd
->rawCerts
, SecCmsUtilDERCompare
, NULL
, NULL
);
587 cert_only_signed_data
= CFDataCreateMutable(kCFAllocatorDefault
, 0);
588 SecAsn1Item cert_only_signed_data_item
= {};
589 require_quiet(SEC_ASN1EncodeItem(cmsg
->poolp
, &cert_only_signed_data_item
,
590 cmsg
, SecCmsMessageTemplate
), out
);
591 CFDataAppendBytes(cert_only_signed_data
, cert_only_signed_data_item
.Data
,
592 cert_only_signed_data_item
.Length
);
596 CFReleaseSafe(cert_array
);
597 if (status
) CFReleaseSafe(cert_only_signed_data
);
598 if (cmsg
) SecCmsMessageDestroy(cmsg
);
599 return cert_only_signed_data
;
602 CFDataRef
SecCMSCreateCertificatesOnlyMessageIAP(SecCertificateRef cert
)
604 static const uint8_t header
[] = {
605 0x30, 0x82, 0x03, 0x6d, 0x06, 0x09, 0x2a, 0x86,
606 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x02, 0xa0,
607 0x82, 0x03, 0x5e, 0x30, 0x82, 0x03, 0x5a, 0x02,
608 0x01, 0x01, 0x31, 0x00, 0x30, 0x0b, 0x06, 0x09,
609 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07,
610 0x01, 0xa0, 0x82, 0x03, 0x40
613 static const uint8_t trailer
[] = {
614 0xa1, 0x00, 0x31, 0x00
617 CFMutableDataRef message
= NULL
;
619 const uint8_t *certbytes
;
621 uint8_t *messagebytes
;
624 certdata
= SecCertificateCopyData(cert
);
625 require(certdata
, out
);
627 certbytes
= CFDataGetBytePtr(certdata
);
628 certlen
= CFDataGetLength(certdata
);
629 require(certlen
> UINT8_MAX
, out
);
630 require(certlen
< UINT16_MAX
, out
);
632 message
= CFDataCreateMutable(kCFAllocatorDefault
, 0);
633 require(message
, out
);
635 CFDataAppendBytes(message
, header
, sizeof(header
));
636 CFDataAppendBytes(message
, certbytes
, certlen
);
637 CFDataAppendBytes(message
, trailer
, sizeof(trailer
));
639 messagebytes
= CFDataGetMutableBytePtr(message
);
640 messagelen
= CFDataGetLength(message
);
643 messagebytes
[2] = messagelen
>> 8;
644 messagebytes
[3] = messagelen
& 0xFF;
647 messagebytes
[17] = messagelen
>> 8;
648 messagebytes
[18] = messagelen
& 0xFF;
651 messagebytes
[21] = messagelen
>> 8;
652 messagebytes
[22] = messagelen
& 0xFF;
655 messagebytes
[43] = messagelen
>> 8;
656 messagebytes
[44] = messagelen
& 0xFF;
659 CFReleaseSafe(certdata
);
663 #endif /* ENABLE_CMS */