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>
61 #include <Security/SecTrustPriv.h>
64 #include <security_asn1/secasn1.h>
65 #include <security_asn1/secerr.h>
66 #include <security_asn1/secport.h>
67 #include <Security/SecAsn1Item.h>
68 #include <security_smime/secoid.h>
69 #include <security_smime/cmslocal.h>
71 CFTypeRef kSecCMSBulkEncryptionAlgorithm
= CFSTR("kSecCMSBulkEncryptionAlgorithm");
72 CFTypeRef kSecCMSSignDigest
= CFSTR("kSecCMSSignDigest");
73 CFTypeRef kSecCMSSignDetached
= CFSTR("kSecCMSSignDetached");
74 CFTypeRef kSecCMSSignHashAlgorithm
= CFSTR("kSecCMSSignHashAlgorithm");
75 CFTypeRef kSecCMSEncryptionAlgorithmDESCBC
= CFSTR("kSecCMSEncryptionAlgorithmDESCBC");
76 CFTypeRef kSecCMSEncryptionAlgorithmAESCBC
= CFSTR("kSecCMSEncryptionAlgorithmAESCBC");
77 CFTypeRef kSecCMSHashingAlgorithmMD5
= CFSTR("kSecCMSHashingAlgorithmMD5");
78 CFTypeRef kSecCMSCertChainMode
= CFSTR("kSecCMSCertChainMode");
79 CFTypeRef kSecCMSCertChainModeNone
= CFSTR("0");
80 CFTypeRef kSecCMSAdditionalCerts
= CFSTR("kSecCMSAdditionalCerts");
81 CFTypeRef kSecCMSSignedAttributes
= CFSTR("kSecCMSSignedAttributes");
82 CFTypeRef kSecCMSSignDate
= CFSTR("kSecCMSSignDate");
83 CFTypeRef kSecCMSAllCerts
= CFSTR("kSecCMSAllCerts");
85 OSStatus
SecCMSCreateEnvelopedData(CFTypeRef recipient_or_cfarray_thereof
,
86 CFDictionaryRef params
, CFDataRef data
, CFMutableDataRef enveloped_data
)
88 SecCmsMessageRef cmsg
= NULL
;
89 SecCmsContentInfoRef cinfo
;
90 SecCmsEnvelopedDataRef envd
= NULL
;
91 SECOidTag algorithmTag
= SEC_OID_DES_EDE3_CBC
;
93 OSStatus status
= errSecParam
;
96 CFStringRef algorithm_name
= CFDictionaryGetValue(params
, kSecCMSBulkEncryptionAlgorithm
);
98 if (CFEqual(kSecCMSEncryptionAlgorithmDESCBC
, algorithm_name
)) {
99 algorithmTag
= SEC_OID_DES_CBC
;
101 } else if (CFEqual(kSecCMSEncryptionAlgorithmAESCBC
, algorithm_name
)) {
102 algorithmTag
= SEC_OID_AES_128_CBC
;
108 require(cmsg
= SecCmsMessageCreate(), out
);
109 require(envd
= SecCmsEnvelopedDataCreate(cmsg
, algorithmTag
, keySize
), out
);
110 require(cinfo
= SecCmsMessageGetContentInfo(cmsg
), out
);
111 require_noerr(SecCmsContentInfoSetContentEnvelopedData(cinfo
, envd
), out
);
112 require(cinfo
= SecCmsEnvelopedDataGetContentInfo(envd
), out
);
113 require_noerr(SecCmsContentInfoSetContentData(cinfo
, NULL
, false), out
);
114 // == wrapper of: require(SECSuccess == SecCmsContentInfoSetContent(cinfo, SEC_OID_PKCS7_DATA, NULL), out);
116 if (CFGetTypeID(recipient_or_cfarray_thereof
) == CFArrayGetTypeID()) {
117 CFIndex dex
, numCerts
= CFArrayGetCount(recipient_or_cfarray_thereof
);
118 for(dex
=0; dex
<numCerts
; dex
++) {
119 SecCertificateRef recip
=
120 (SecCertificateRef
)CFArrayGetValueAtIndex(recipient_or_cfarray_thereof
, dex
);
121 SecCmsRecipientInfoRef rinfo
;
122 require(rinfo
= SecCmsRecipientInfoCreate(envd
, recip
), out
);
124 } else if (CFGetTypeID(recipient_or_cfarray_thereof
) == SecCertificateGetTypeID()) {
125 require(SecCmsRecipientInfoCreate(envd
, (SecCertificateRef
)recipient_or_cfarray_thereof
), out
);
129 SecAsn1Item input
= {};
131 input
.Length
= CFDataGetLength(data
);
132 input
.Data
= (uint8_t*)CFDataGetBytePtr(data
);
134 require_noerr(SecCmsMessageEncode(cmsg
, (data
&& input
.Length
) ? &input
: NULL
, enveloped_data
), out
);
136 status
= errSecSuccess
;
138 if (cmsg
) SecCmsMessageDestroy(cmsg
);
142 OSStatus
SecCMSDecryptEnvelopedData(CFDataRef message
,
143 CFMutableDataRef data
, SecCertificateRef
*recipient
)
145 SecCmsMessageRef cmsg
= NULL
;
146 SecCmsContentInfoRef cinfo
;
147 SecCmsEnvelopedDataRef envd
= NULL
;
148 SecCertificateRef used_recipient
= NULL
;
149 OSStatus status
= errSecParam
;
151 SecAsn1Item encoded_message
= { CFDataGetLength(message
), (uint8_t*)CFDataGetBytePtr(message
) };
152 require_noerr_action_quiet(SecCmsMessageDecode(&encoded_message
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, &cmsg
),
153 out
, status
= errSecDecode
);
154 require_quiet(cinfo
= SecCmsMessageContentLevel(cmsg
, 0), out
);
155 require_quiet(SecCmsContentInfoGetContentTypeTag(cinfo
) == SEC_OID_PKCS7_ENVELOPED_DATA
, out
);
156 require_quiet(envd
= (SecCmsEnvelopedDataRef
)SecCmsContentInfoGetContent(cinfo
), out
);
157 SecCmsRecipientInfoRef
*rinfo
= envd
->recipientInfos
;
158 while (!used_recipient
&& *rinfo
) {
159 used_recipient
= (*rinfo
)->cert
;
162 require_quiet(2 == SecCmsMessageContentLevelCount(cmsg
), out
);
163 require_quiet(cinfo
= SecCmsMessageContentLevel(cmsg
, 1), out
);
164 require_quiet(SecCmsContentInfoGetContentTypeTag(cinfo
) == SEC_OID_PKCS7_DATA
, out
);
165 const SecAsn1Item
*content
= SecCmsMessageGetContent(cmsg
);
167 CFDataAppendBytes(data
, content
->Data
, content
->Length
);
169 CFRetainSafe(used_recipient
);
170 *recipient
= used_recipient
;
172 status
= errSecSuccess
;
174 if (cmsg
) SecCmsMessageDestroy(cmsg
);
178 static SecCmsAttribute
*
179 make_attr(PLArenaPool
*poolp
, SecAsn1Item
*type
, SecAsn1Item
*value
, bool encoded
)
181 SecAsn1Item
* copiedvalue
;
182 SecCmsAttribute
*attr
= (SecCmsAttribute
*)PORT_ArenaZAlloc(poolp
, sizeof(SecCmsAttribute
));
186 if (SECITEM_CopyItem(poolp
, &(attr
->type
), type
) != SECSuccess
)
190 if ((copiedvalue
= SECITEM_AllocItem(poolp
, NULL
, value
->Length
)) == NULL
)
193 if (SECITEM_CopyItem(poolp
, copiedvalue
, value
) != SECSuccess
)
196 SecCmsArrayAdd(poolp
, (void ***)&(attr
->values
), (void *)copiedvalue
);
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
;
499 if (cmsg
) SecCmsMessageDestroy(cmsg
);
503 OSStatus
SecCMSVerifyCopyDataAndAttributes(CFDataRef message
, CFDataRef detached_contents
,
504 CFTypeRef policy
, SecTrustRef
*trustref
,
505 CFDataRef
*attached_contents
, CFDictionaryRef
*signed_attributes
)
507 OSStatus status
= SecCMSVerifySignedData_internal(message
, detached_contents
, policy
, trustref
, NULL
, attached_contents
, signed_attributes
);
512 OSStatus
SecCMSVerifySignedData(CFDataRef message
, CFDataRef detached_contents
,
513 CFTypeRef policy
, SecTrustRef
*trustref
, CFArrayRef additional_certificates
,
514 CFDataRef
*attached_contents
, CFDictionaryRef
*message_attributes
)
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
);
521 CFReleaseSafe(signed_attributes
);
526 OSStatus
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
);
532 CFArrayRef
SecCMSCertificatesOnlyMessageCopyCertificates(CFDataRef message
) {
533 SecCmsMessageRef cmsg
= NULL
;
534 SecCmsContentInfoRef cinfo
;
535 SecCmsSignedDataRef sigd
= NULL
;
536 CFMutableArrayRef certs
= NULL
;
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
);
545 /* find out about signers */
546 int nsigners
= SecCmsSignedDataSignerInfoCount(sigd
);
547 require(nsigners
== 0, out
);
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
);
555 CFArrayAppendValue(certs
, cert
);
563 SecCmsMessageDestroy(cmsg
);
569 extern const SecAsn1Template SecCmsMessageTemplate
[];
571 CFDataRef
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
;
581 require(cert_or_array_thereof
, out
);
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
);
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
);
597 require(cert_array
, out
);
598 cert_array_count
= CFArrayGetCount(cert_array
);
599 require(cert_array_count
> 0, out
);
601 sigd
->rawCerts
= (SecAsn1Item
* *)PORT_ArenaAlloc(cmsg
->poolp
, (cert_array_count
+ 1) * sizeof(SecAsn1Item
*));
602 require(sigd
->rawCerts
, out
);
604 for (ix
= 0; ix
< cert_array_count
; ix
++) {
605 cert
= (SecCertificateRef
)CFArrayGetValueAtIndex(cert_array
, ix
);
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
;
613 sigd
->rawCerts
[ix
] = NULL
;
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
);
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
);
626 status
= errSecSuccess
;
628 CFReleaseSafe(cert_array
);
629 if (status
) CFReleaseSafe(cert_only_signed_data
);
630 if (cmsg
) SecCmsMessageDestroy(cmsg
);
631 return cert_only_signed_data
;
634 CFDataRef
SecCMSCreateCertificatesOnlyMessageIAP(SecCertificateRef cert
)
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
645 static const uint8_t trailer
[] = {
646 0xa1, 0x00, 0x31, 0x00
649 CFMutableDataRef message
= NULL
;
651 const uint8_t *certbytes
;
653 uint8_t *messagebytes
;
656 certdata
= SecCertificateCopyData(cert
);
657 require(certdata
, out
);
659 certbytes
= CFDataGetBytePtr(certdata
);
660 certlen
= CFDataGetLength(certdata
);
661 require(certlen
> UINT8_MAX
, out
);
662 require(certlen
< UINT16_MAX
, out
);
664 message
= CFDataCreateMutable(kCFAllocatorDefault
, 0);
665 require(message
, out
);
667 CFDataAppendBytes(message
, header
, sizeof(header
));
668 CFDataAppendBytes(message
, certbytes
, certlen
);
669 CFDataAppendBytes(message
, trailer
, sizeof(trailer
));
671 messagebytes
= CFDataGetMutableBytePtr(message
);
672 messagelen
= CFDataGetLength(message
);
675 messagebytes
[2] = messagelen
>> 8;
676 messagebytes
[3] = messagelen
& 0xFF;
679 messagebytes
[17] = messagelen
>> 8;
680 messagebytes
[18] = messagelen
& 0xFF;
683 messagebytes
[21] = messagelen
>> 8;
684 messagebytes
[22] = messagelen
& 0xFF;
687 messagebytes
[43] = messagelen
>> 8;
688 messagebytes
[44] = messagelen
& 0xFF;
691 CFReleaseSafe(certdata
);
695 #endif /* ENABLE_CMS */