2 * Copyright (c) 2008-2010,2012-2014 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@
31 #include <AssertMacros.h>
33 #include <TargetConditionals.h>
34 #if (TARGET_OS_MAC && !(TARGET_OS_EMBEDDED || TARGET_OS_IPHONE))
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>
53 #include <CoreFoundation/CFData.h>
55 #include <Security/SecInternal.h>
56 #include <Security/SecBasePriv.h>
57 #include <Security/SecCertificatePriv.h>
60 #include <Security/SecTrustPriv.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");
81 CFTypeRef kSecCMSSignDate
= CFSTR("kSecCMSSignDate");
82 CFTypeRef kSecCMSAllCerts
= CFSTR("kSecCMSAllCerts");
84 OSStatus
SecCMSCreateEnvelopedData(CFTypeRef recipient_or_cfarray_thereof
,
85 CFDictionaryRef params
, CFDataRef data
, CFMutableDataRef enveloped_data
)
87 SecCmsMessageRef cmsg
= NULL
;
88 SecCmsContentInfoRef cinfo
;
89 SecCmsEnvelopedDataRef envd
= NULL
;
90 SECOidTag algorithmTag
= SEC_OID_DES_EDE3_CBC
;
92 OSStatus status
= errSecParam
;
95 CFStringRef algorithm_name
= CFDictionaryGetValue(params
, kSecCMSBulkEncryptionAlgorithm
);
97 if (CFEqual(kSecCMSEncryptionAlgorithmDESCBC
, algorithm_name
)) {
98 algorithmTag
= SEC_OID_DES_CBC
;
100 } else if (CFEqual(kSecCMSEncryptionAlgorithmAESCBC
, algorithm_name
)) {
101 algorithmTag
= SEC_OID_AES_128_CBC
;
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);
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
);
123 } else if (CFGetTypeID(recipient_or_cfarray_thereof
) == SecCertificateGetTypeID()) {
124 require(SecCmsRecipientInfoCreate(envd
, (SecCertificateRef
)recipient_or_cfarray_thereof
), out
);
128 SecAsn1Item input
= {};
130 input
.Length
= CFDataGetLength(data
);
131 input
.Data
= (uint8_t*)CFDataGetBytePtr(data
);
133 require_noerr(SecCmsMessageEncode(cmsg
, (data
&& input
.Length
) ? &input
: NULL
, enveloped_data
), out
);
135 status
= errSecSuccess
;
137 if (cmsg
) SecCmsMessageDestroy(cmsg
);
141 OSStatus
SecCMSDecryptEnvelopedData(CFDataRef message
,
142 CFMutableDataRef data
, SecCertificateRef
*recipient
)
144 SecCmsMessageRef cmsg
= NULL
;
145 SecCmsContentInfoRef cinfo
;
146 SecCmsEnvelopedDataRef envd
= NULL
;
147 SecCertificateRef used_recipient
= NULL
;
148 OSStatus status
= errSecParam
;
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
;
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
);
166 CFDataAppendBytes(data
, content
->Data
, content
->Length
);
168 CFRetainSafe(used_recipient
);
169 *recipient
= used_recipient
;
171 status
= errSecSuccess
;
173 if (cmsg
) SecCmsMessageDestroy(cmsg
);
177 static SecCmsAttribute
*
178 make_attr(PLArenaPool
*poolp
, SecAsn1Item
*type
, SecAsn1Item
*value
, bool encoded
)
180 SecAsn1Item
* copiedvalue
;
181 SecCmsAttribute
*attr
= (SecCmsAttribute
*)PORT_ArenaZAlloc(poolp
, sizeof(SecCmsAttribute
));
185 if (SECITEM_CopyItem(poolp
, &(attr
->type
), type
) != SECSuccess
)
189 if ((copiedvalue
= SECITEM_AllocItem(poolp
, NULL
, value
->Length
)) == NULL
)
192 if (SECITEM_CopyItem(poolp
, copiedvalue
, value
) != SECSuccess
)
195 if (SecCmsArrayAdd(poolp
, (void ***)&(attr
->values
), (void *)copiedvalue
) != SECSuccess
)
199 attr
->encoded
= encoded
;
206 signerinfo_add_auth_attr(SecCmsSignerInfoRef signerinfo
, /*SECOidTag oidtag*/
207 SecAsn1Item
*oid
, SecAsn1Item
*value
, bool encoded
)
209 PLArenaPool
*poolp
= signerinfo
->signedData
->contentInfo
.cmsg
->poolp
;
210 PORT_Assert (poolp
!= NULL
);
211 void *mark
= PORT_ArenaMark (poolp
);
213 SecCmsAttribute
*attr
= make_attr(poolp
, oid
, value
, encoded
);
214 if (!attr
|| SecCmsAttributeArrayAddAttr(poolp
, &(signerinfo
->authAttr
), attr
) != SECSuccess
)
217 PORT_ArenaUnmark (poolp
, mark
);
221 PORT_Assert (mark
!= NULL
);
222 PORT_ArenaRelease (poolp
, mark
);
226 static void sign_all_attributes(const void *key
, const void *value
, void *context
)
228 SecAsn1Item oid
= { CFDataGetLength(key
), (uint8_t*)CFDataGetBytePtr(key
) },
229 oid_value
= { CFDataGetLength(value
), (uint8_t*)CFDataGetBytePtr(value
) };
231 signerinfo_add_auth_attr((SecCmsSignerInfoRef
)context
, &oid
, &oid_value
, true);
235 static void enveloped_data_add_unprotected_attr(SecCmsEnvelopedDataRef envd
,
236 SecAsn1Item
*oid
, SecAsn1Item
*value
, bool encoded
)
238 PLArenaPool
*poolp
= envd
->contentInfo
.cmsg
->poolp
;
239 PORT_Assert (poolp
!= NULL
);
240 void *mark
= PORT_ArenaMark (poolp
);
241 SecCmsAttribute
*attr
= make_attr(poolp
, oid
, value
, encoded
);
243 if (!attr
|| SecCmsAttributeArrayAddAttr(
245 &(envd
->unprotectedAttr
), attr
) != SECSuccess
)
248 PORT_ArenaUnmark (poolp
, mark
);
252 PORT_Assert (mark
!= NULL
);
253 PORT_ArenaRelease (poolp
, mark
);
259 static OSStatus
SecCMSSignDataOrDigestAndAttributes(SecIdentityRef identity
,
260 CFDataRef data
, bool detached
, bool data_is_digest
, SECOidTag sign_algorithm
,
261 CFMutableDataRef signed_data
, CFDictionaryRef signed_attributes
, SecCmsCertChainMode chainMode
, CFArrayRef additional_certs
)
263 SecCmsMessageRef cmsg
= NULL
;
264 SecCmsContentInfoRef cinfo
;
265 SecCmsSignedDataRef sigd
= NULL
;
266 SecCmsSignerInfoRef signerinfo
;
267 OSStatus status
= errSecParam
;
269 require(!data_is_digest
|| detached
/* if digest, must be detached */, out
);
271 require(cmsg
= SecCmsMessageCreate(), out
);
272 require(sigd
= SecCmsSignedDataCreate(cmsg
), out
);
273 require(cinfo
= SecCmsMessageGetContentInfo(cmsg
), out
);
274 require_noerr(SecCmsContentInfoSetContentSignedData(cinfo
, sigd
), out
);
275 require(cinfo
= SecCmsSignedDataGetContentInfo(sigd
), out
);
276 require_noerr(SecCmsContentInfoSetContentData(cinfo
, NULL
, detached
), out
);
277 require(signerinfo
= SecCmsSignerInfoCreate(sigd
, identity
, sign_algorithm
), out
);
278 if (additional_certs
)
279 require_noerr(SecCmsSignedDataAddCertList(sigd
, additional_certs
), out
);
280 require_noerr(SecCmsSignerInfoIncludeCerts(signerinfo
, chainMode
, certUsageAnyCA
), out
);
281 require_noerr(SecCmsSignerInfoAddSigningTime(signerinfo
, CFAbsoluteTimeGetCurrent()), out
);
283 if (signed_attributes
)
284 CFDictionaryApplyFunction(signed_attributes
, sign_all_attributes
, signerinfo
);
286 SecAsn1Item input
= {};
288 input
.Length
= CFDataGetLength(data
);
289 input
.Data
= (uint8_t*)CFDataGetBytePtr(data
);
291 if (data_is_digest
) {
292 require_noerr(SecCmsSignedDataSetDigestValue(sigd
, sign_algorithm
, &input
), out
);
293 require_noerr(SecCmsMessageEncode(cmsg
, NULL
, signed_data
), out
);
296 require_noerr(SecCmsMessageEncode(cmsg
, (data
&& input
.Length
) ? &input
: NULL
, signed_data
), out
);
298 status
= errSecSuccess
;
300 if (cmsg
) SecCmsMessageDestroy(cmsg
);
304 OSStatus
SecCMSSignDataAndAttributes(SecIdentityRef identity
, CFDataRef data
, bool detached
,
305 CFMutableDataRef signed_data
, CFDictionaryRef signed_attributes
)
307 return SecCMSSignDataOrDigestAndAttributes(identity
, data
, detached
, false, SEC_OID_SHA1
,
308 signed_data
, signed_attributes
, SecCmsCMCertChain
, NULL
);
311 OSStatus
SecCMSSignDigestAndAttributes(SecIdentityRef identity
, CFDataRef digest
,
312 CFMutableDataRef signed_data
, CFDictionaryRef signed_attributes
)
314 return SecCMSSignDataOrDigestAndAttributes(identity
, digest
, true, true, SEC_OID_SHA1
,
315 signed_data
, signed_attributes
, SecCmsCMCertChain
, NULL
);
319 OSStatus
SecCMSCreateSignedData(SecIdentityRef identity
, CFDataRef data
,
320 CFDictionaryRef parameters
, CFDictionaryRef signed_attributes
,
321 CFMutableDataRef signed_data
)
323 bool is_digest
= false, is_detached
= false;
324 CFStringRef algorithm_name
= NULL
;
325 SecCmsCertChainMode chain_mode
= SecCmsCMCertChain
;
326 CFArrayRef additional_certs
= NULL
;
329 is_digest
= CFDictionaryGetValueIfPresent(parameters
,
330 kSecCMSSignDigest
, NULL
);
331 is_detached
= CFDictionaryGetValueIfPresent(parameters
,
332 kSecCMSSignDetached
, NULL
);
333 algorithm_name
= CFDictionaryGetValue(parameters
,
334 kSecCMSSignHashAlgorithm
);
336 CFTypeRef chain_mode_param
= CFDictionaryGetValue(parameters
, kSecCMSCertChainMode
);
337 if (chain_mode_param
&& (CFGetTypeID(chain_mode_param
) == CFStringGetTypeID()))
338 chain_mode
= CFStringGetIntValue(chain_mode_param
);
340 CFTypeRef additional_certs_param
= CFDictionaryGetValue(parameters
, kSecCMSAdditionalCerts
);
341 if (additional_certs_param
&& (CFGetTypeID(additional_certs_param
) == CFArrayGetTypeID()))
342 additional_certs
= (CFArrayRef
)additional_certs_param
;
345 SECOidTag algorithm
= SEC_OID_SHA1
;
346 if (algorithm_name
) {
347 if (CFEqual(kSecCMSHashingAlgorithmMD5
, algorithm_name
)) {
348 algorithm
= SEC_OID_MD5
;
350 algorithm
= SEC_OID_UNKNOWN
;
355 return SecCMSSignDataOrDigestAndAttributes(identity
, data
,
356 is_detached
, is_digest
, algorithm
,
357 signed_data
, signed_attributes
, chain_mode
, additional_certs
);
361 static CFMutableArrayRef
copy_signed_attribute_values(SecCmsAttribute
*attr
)
363 CFMutableArrayRef array
= CFArrayCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeArrayCallBacks
);
364 SecAsn1Item
**item
= attr
->values
;
365 if (item
) while (*item
) {
366 CFDataRef asn1data
= CFDataCreate(kCFAllocatorDefault
, (*item
)->Data
, (*item
)->Length
);
368 CFArrayAppendValue(array
, asn1data
);
376 static OSStatus
SecCMSVerifySignedData_internal(CFDataRef message
, CFDataRef detached_contents
,
377 CFTypeRef policy
, SecTrustRef
*trustref
, CFArrayRef additional_certs
,
378 CFDataRef
*attached_contents
, CFDictionaryRef
*signed_attributes
)
380 SecCmsMessageRef cmsg
= NULL
;
381 SecCmsContentInfoRef cinfo
;
382 SecCmsSignedDataRef sigd
= NULL
;
383 OSStatus status
= errSecParam
;
385 SecAsn1Item encoded_message
= { CFDataGetLength(message
), (uint8_t*)CFDataGetBytePtr(message
) };
386 require_noerr_action_quiet(SecCmsMessageDecode(&encoded_message
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, &cmsg
),
387 out
, status
= errSecDecode
);
388 /* expected to be a signed data message at the top level */
389 require_quiet(cinfo
= SecCmsMessageContentLevel(cmsg
, 0), out
);
390 require_quiet(SecCmsContentInfoGetContentTypeTag(cinfo
) == SEC_OID_PKCS7_SIGNED_DATA
, out
);
391 require_quiet(sigd
= (SecCmsSignedDataRef
)SecCmsContentInfoGetContent(cinfo
), out
);
393 if (detached_contents
)
395 require_quiet(!SecCmsSignedDataHasDigests(sigd
), out
);
396 SECAlgorithmID
**digestalgs
= SecCmsSignedDataGetDigestAlgs(sigd
);
397 SecCmsDigestContextRef digcx
= SecCmsDigestContextStartMultiple(digestalgs
);
398 SecCmsDigestContextUpdate(digcx
, CFDataGetBytePtr(detached_contents
), CFDataGetLength(detached_contents
));
399 SecCmsSignedDataSetDigestContext(sigd
, digcx
);
400 SecCmsDigestContextDestroy(digcx
);
403 if (additional_certs
)
404 require_noerr_quiet(SecCmsSignedDataAddCertList(sigd
, additional_certs
), out
);
406 if (policy
) { /* if no policy is given skip verification */
407 /* find out about signers */
408 int nsigners
= SecCmsSignedDataSignerInfoCount(sigd
);
409 require_quiet(nsigners
== 1, out
);
410 require_noerr_action_quiet(SecCmsSignedDataVerifySignerInfo(sigd
, 0, NULL
, policy
, trustref
),
411 out
, status
= errSecAuthFailed
);
416 trustrefs
= CFArrayCreateMutable(kCFAllocatorDefault
, nsigners
, &kCFTypeArrayCallBacks
);
419 for (j
= 0; j
< nsigners
; j
++)
421 SecTrustRef trustRef
;
422 require_noerr_action_quiet(SecCmsSignedDataVerifySignerInfo(sigd
, j
, NULL
, policy
, &trustRef
),
423 out
, status
= errSecAuthFailed
);
424 if ((j
== 0) && (nsigners
== 1))
425 *trustref_or_cfarray_thereof
= trustRef
;
427 CFArrayAppendValue(trustrefs
, trustRef
);
431 *trustref_or_cfarray_thereof
= trustrefs
;
435 status
= errSecSuccess
;
437 if (attached_contents
) {
438 const SecAsn1Item
*content
= SecCmsMessageGetContent(cmsg
);
440 *attached_contents
= CFDataCreate(kCFAllocatorDefault
, content
->Data
, content
->Length
);
442 *attached_contents
= NULL
;
445 if (signed_attributes
) {
446 CFMutableDictionaryRef attrs
= CFDictionaryCreateMutable(kCFAllocatorDefault
,
447 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
448 require_quiet(attrs
, out
);
449 SecCmsAttribute
**signed_attrs
= sigd
->signerInfos
[0]->authAttr
;
450 if (signed_attrs
) while (*signed_attrs
) {
451 CFDataRef type
= CFDataCreate(kCFAllocatorDefault
, (*signed_attrs
)->type
.Data
, (*signed_attrs
)->type
.Length
);
453 CFMutableArrayRef attr
= copy_signed_attribute_values(*signed_attrs
);
455 CFMutableArrayRef existing_attrs
= (CFMutableArrayRef
)CFDictionaryGetValue(attrs
, type
);
456 if (existing_attrs
) {
457 CFIndex count
= CFArrayGetCount(attr
);
459 CFArrayAppendArray(existing_attrs
, attr
, CFRangeMake(0, count
));
461 CFDictionarySetValue(attrs
, type
, attr
);
468 CFMutableArrayRef certs
= NULL
;
470 SecAsn1Item
**cert_datas
= SecCmsSignedDataGetCertificateList(sigd
);
471 certs
= CFArrayCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeArrayCallBacks
);
472 SecAsn1Item
*cert_data
;
473 if (cert_datas
) while ((cert_data
= *cert_datas
) != NULL
) {
474 SecCertificateRef cert
= SecCertificateCreateWithBytes(NULL
, cert_data
->Data
, cert_data
->Length
);
476 CFArrayAppendValue(certs
, cert
);
482 CFDictionaryAddValue(attrs
, kSecCMSAllCerts
, certs
);
484 /* Add "cooked" values separately */
485 CFAbsoluteTime signing_time
;
486 if (errSecSuccess
== SecCmsSignerInfoGetSigningTime(sigd
->signerInfos
[0], &signing_time
)) {
487 CFDateRef signing_date
= CFDateCreate(kCFAllocatorDefault
, signing_time
);
489 CFDictionarySetValue(attrs
, kSecCMSSignDate
, signing_date
);
490 CFReleaseSafe(signing_date
);
494 *signed_attributes
= attrs
;
495 CFReleaseSafe(certs
);
500 if (cmsg
) SecCmsMessageDestroy(cmsg
);
504 OSStatus
SecCMSVerifyCopyDataAndAttributes(CFDataRef message
, CFDataRef detached_contents
,
505 CFTypeRef policy
, SecTrustRef
*trustref
,
506 CFDataRef
*attached_contents
, CFDictionaryRef
*signed_attributes
)
508 OSStatus status
= SecCMSVerifySignedData_internal(message
, detached_contents
, policy
, trustref
, NULL
, attached_contents
, signed_attributes
);
513 OSStatus
SecCMSVerifySignedData(CFDataRef message
, CFDataRef detached_contents
,
514 CFTypeRef policy
, SecTrustRef
*trustref
, CFArrayRef additional_certificates
,
515 CFDataRef
*attached_contents
, CFDictionaryRef
*message_attributes
)
517 CFDictionaryRef signed_attributes
= NULL
;
518 OSStatus status
= SecCMSVerifySignedData_internal(message
, detached_contents
, policy
, trustref
, additional_certificates
, attached_contents
, &signed_attributes
);
519 if (!status
&& signed_attributes
&& message_attributes
) {
520 *message_attributes
= CFDictionaryCreate(kCFAllocatorDefault
, &kSecCMSSignedAttributes
, (const void **)&signed_attributes
, 1, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
522 CFReleaseSafe(signed_attributes
);
527 OSStatus
SecCMSVerify(CFDataRef message
, CFDataRef detached_contents
,
528 CFTypeRef policy
, SecTrustRef
*trustref
,
529 CFDataRef
*attached_contents
) {
530 return SecCMSVerifySignedData_internal(message
, detached_contents
, policy
, trustref
, NULL
, attached_contents
, NULL
);
533 CFArrayRef
SecCMSCertificatesOnlyMessageCopyCertificates(CFDataRef message
) {
534 SecCmsMessageRef cmsg
= NULL
;
535 SecCmsContentInfoRef cinfo
;
536 SecCmsSignedDataRef sigd
= NULL
;
537 CFMutableArrayRef certs
= NULL
;
539 SecAsn1Item encoded_message
= { CFDataGetLength(message
), (uint8_t*)CFDataGetBytePtr(message
) };
540 require_noerr_quiet(SecCmsMessageDecode(&encoded_message
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, &cmsg
), out
);
541 /* expected to be a signed data message at the top level */
542 require(cinfo
= SecCmsMessageContentLevel(cmsg
, 0), out
);
543 require(SecCmsContentInfoGetContentTypeTag(cinfo
) == SEC_OID_PKCS7_SIGNED_DATA
, out
);
544 require(sigd
= (SecCmsSignedDataRef
)SecCmsContentInfoGetContent(cinfo
), out
);
546 /* find out about signers */
547 int nsigners
= SecCmsSignedDataSignerInfoCount(sigd
);
548 require(nsigners
== 0, out
);
550 SecAsn1Item
**cert_datas
= SecCmsSignedDataGetCertificateList(sigd
);
551 certs
= CFArrayCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeArrayCallBacks
);
552 SecAsn1Item
*cert_data
;
553 if (cert_datas
) while ((cert_data
= *cert_datas
) != NULL
) {
554 SecCertificateRef cert
= SecCertificateCreateWithBytes(NULL
, cert_data
->Data
, cert_data
->Length
);
556 CFArrayAppendValue(certs
, cert
);
564 SecCmsMessageDestroy(cmsg
);
570 extern const SecAsn1Template SecCmsMessageTemplate
[];
572 CFDataRef
SecCMSCreateCertificatesOnlyMessage(CFTypeRef cert_or_array_thereof
) {
573 OSStatus status
= errSecParam
;
574 SecCmsMessageRef cmsg
= NULL
;
575 SecCmsContentInfoRef cinfo
;
576 SecCmsSignedDataRef sigd
= NULL
;
577 CFMutableDataRef cert_only_signed_data
= NULL
;
578 CFArrayRef cert_array
= NULL
;
579 CFIndex cert_array_count
= 0;
580 SecCertificateRef cert
= NULL
;
582 require(cert_or_array_thereof
, out
);
584 require(cmsg
= SecCmsMessageCreate(), out
);
585 require(sigd
= SecCmsSignedDataCreate(cmsg
), out
);
586 require_noerr(SecCmsContentInfoSetContentData(&(sigd
->contentInfo
), NULL
, PR_TRUE
), out
);
587 require(cinfo
= SecCmsMessageGetContentInfo(cmsg
), out
);
588 require_noerr(SecCmsContentInfoSetContentSignedData(cinfo
, sigd
), out
);
589 long version
= SEC_CMS_SIGNED_DATA_VERSION_BASIC
;
590 require(SEC_ASN1EncodeInteger(cmsg
->poolp
, &(sigd
->version
), version
), out
);
592 if (CFGetTypeID(cert_or_array_thereof
) == SecCertificateGetTypeID()) {
593 cert_array
= CFArrayCreate(kCFAllocatorDefault
, &cert_or_array_thereof
, 1, &kCFTypeArrayCallBacks
);
594 } else if (CFGetTypeID(cert_or_array_thereof
) == CFArrayGetTypeID()) {
595 cert_array
= CFArrayCreateCopy(kCFAllocatorDefault
, (CFArrayRef
)cert_or_array_thereof
);
598 require(cert_array
, out
);
599 cert_array_count
= CFArrayGetCount(cert_array
);
600 require(cert_array_count
> 0, out
);
602 sigd
->rawCerts
= (SecAsn1Item
* *)PORT_ArenaAlloc(cmsg
->poolp
, (cert_array_count
+ 1) * sizeof(SecAsn1Item
*));
603 require(sigd
->rawCerts
, out
);
605 for (ix
= 0; ix
< cert_array_count
; ix
++) {
606 cert
= (SecCertificateRef
)CFArrayGetValueAtIndex(cert_array
, ix
);
609 sigd
->rawCerts
[ix
] = PORT_ArenaZAlloc(cmsg
->poolp
, sizeof(SecAsn1Item
));
610 SecAsn1Item cert_data
= { SecCertificateGetLength(cert
),
611 (uint8_t *)SecCertificateGetBytePtr(cert
) };
612 *(sigd
->rawCerts
[ix
]) = cert_data
;
614 sigd
->rawCerts
[ix
] = NULL
;
616 /* this is a SET OF, so we need to sort them guys - we have the DER already, though */
617 if (cert_array_count
> 1)
618 SecCmsArraySort((void **)sigd
->rawCerts
, SecCmsUtilDERCompare
, NULL
, NULL
);
620 cert_only_signed_data
= CFDataCreateMutable(kCFAllocatorDefault
, 0);
621 SecAsn1Item cert_only_signed_data_item
= {};
622 require_quiet(SEC_ASN1EncodeItem(cmsg
->poolp
, &cert_only_signed_data_item
,
623 cmsg
, SecCmsMessageTemplate
), out
);
624 CFDataAppendBytes(cert_only_signed_data
, cert_only_signed_data_item
.Data
,
625 cert_only_signed_data_item
.Length
);
627 status
= errSecSuccess
;
629 CFReleaseSafe(cert_array
);
630 if (status
) CFReleaseSafe(cert_only_signed_data
);
631 if (cmsg
) SecCmsMessageDestroy(cmsg
);
632 return cert_only_signed_data
;
635 CFDataRef
SecCMSCreateCertificatesOnlyMessageIAP(SecCertificateRef cert
)
637 static const uint8_t header
[] = {
638 0x30, 0x82, 0x03, 0x6d, 0x06, 0x09, 0x2a, 0x86,
639 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x02, 0xa0,
640 0x82, 0x03, 0x5e, 0x30, 0x82, 0x03, 0x5a, 0x02,
641 0x01, 0x01, 0x31, 0x00, 0x30, 0x0b, 0x06, 0x09,
642 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07,
643 0x01, 0xa0, 0x82, 0x03, 0x40
646 static const uint8_t trailer
[] = {
647 0xa1, 0x00, 0x31, 0x00
650 CFMutableDataRef message
= NULL
;
652 const uint8_t *certbytes
;
654 uint8_t *messagebytes
;
657 certdata
= SecCertificateCopyData(cert
);
658 require(certdata
, out
);
660 certbytes
= CFDataGetBytePtr(certdata
);
661 certlen
= CFDataGetLength(certdata
);
662 require(certlen
> UINT8_MAX
, out
);
663 require(certlen
< UINT16_MAX
, out
);
665 message
= CFDataCreateMutable(kCFAllocatorDefault
, 0);
666 require(message
, out
);
668 CFDataAppendBytes(message
, header
, sizeof(header
));
669 CFDataAppendBytes(message
, certbytes
, certlen
);
670 CFDataAppendBytes(message
, trailer
, sizeof(trailer
));
672 messagebytes
= CFDataGetMutableBytePtr(message
);
673 messagelen
= CFDataGetLength(message
);
676 messagebytes
[2] = messagelen
>> 8;
677 messagebytes
[3] = messagelen
& 0xFF;
680 messagebytes
[17] = messagelen
>> 8;
681 messagebytes
[18] = messagelen
& 0xFF;
684 messagebytes
[21] = messagelen
>> 8;
685 messagebytes
[22] = messagelen
& 0xFF;
688 messagebytes
[43] = messagelen
>> 8;
689 messagebytes
[44] = messagelen
& 0xFF;
692 CFReleaseSafe(certdata
);
696 #endif /* ENABLE_CMS */