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>
71 CFTypeRef kSecCMSSignDigest
= CFSTR("kSecCMSSignDigest");
72 CFTypeRef kSecCMSSignDetached
= CFSTR("kSecCMSSignDetached");
73 CFTypeRef kSecCMSCertChainMode
= CFSTR("kSecCMSCertChainMode");
74 CFTypeRef kSecCMSCertChainModeNone
= CFSTR("0");
75 CFTypeRef kSecCMSAdditionalCerts
= CFSTR("kSecCMSAdditionalCerts");
76 CFTypeRef kSecCMSSignedAttributes
= CFSTR("kSecCMSSignedAttributes");
77 CFTypeRef kSecCMSSignDate
= CFSTR("kSecCMSSignDate");
78 CFTypeRef kSecCMSAllCerts
= CFSTR("kSecCMSAllCerts");
79 CFTypeRef kSecCMSHashAgility
= CFSTR("kSecCMSHashAgility");
80 CFTypeRef kSecCMSHashAgilityV2
= CFSTR("kSecCMSHashAgilityV2");
82 CFTypeRef kSecCMSBulkEncryptionAlgorithm
= CFSTR("kSecCMSBulkEncryptionAlgorithm");
83 CFTypeRef kSecCMSEncryptionAlgorithmDESCBC
= CFSTR("kSecCMSEncryptionAlgorithmDESCBC");
84 CFTypeRef kSecCMSEncryptionAlgorithmAESCBC
= CFSTR("kSecCMSEncryptionAlgorithmAESCBC");
86 CFTypeRef kSecCMSSignHashAlgorithm
= CFSTR("kSecCMSSignHashAlgorithm");
87 CFTypeRef kSecCMSHashingAlgorithmMD5
= CFSTR("kSecCMSHashingAlgorithmMD5");
88 CFTypeRef kSecCMSHashingAlgorithmSHA1
= CFSTR("kSecCMSHashingAlgorithmSHA1");
89 CFTypeRef kSecCMSHashingAlgorithmSHA256
= CFSTR("kSecCMSHashingAlgorithmSHA256");
90 CFTypeRef kSecCMSHashingAlgorithmSHA384
= CFSTR("kSecCMSHashingAlgorithmSHA384");
91 CFTypeRef kSecCMSHashingAlgorithmSHA512
= CFSTR("kSecCMSHashingAlgorithmSHA512");
93 OSStatus
SecCMSCreateEnvelopedData(CFTypeRef recipient_or_cfarray_thereof
,
94 CFDictionaryRef params
, CFDataRef data
, CFMutableDataRef enveloped_data
)
96 SecCmsMessageRef cmsg
= NULL
;
97 SecCmsContentInfoRef cinfo
;
98 SecCmsEnvelopedDataRef envd
= NULL
;
99 SECOidTag algorithmTag
= SEC_OID_DES_EDE3_CBC
;
101 OSStatus status
= errSecParam
;
104 CFStringRef algorithm_name
= CFDictionaryGetValue(params
, kSecCMSBulkEncryptionAlgorithm
);
105 if (algorithm_name
) {
106 if (CFEqual(kSecCMSEncryptionAlgorithmDESCBC
, algorithm_name
)) {
107 algorithmTag
= SEC_OID_DES_CBC
;
109 } else if (CFEqual(kSecCMSEncryptionAlgorithmAESCBC
, algorithm_name
)) {
110 algorithmTag
= SEC_OID_AES_128_CBC
;
116 require(cmsg
= SecCmsMessageCreate(), out
);
117 require(envd
= SecCmsEnvelopedDataCreate(cmsg
, algorithmTag
, keySize
), out
);
118 require(cinfo
= SecCmsMessageGetContentInfo(cmsg
), out
);
119 require_noerr(SecCmsContentInfoSetContentEnvelopedData(cinfo
, envd
), out
);
120 require(cinfo
= SecCmsEnvelopedDataGetContentInfo(envd
), out
);
121 require_noerr(SecCmsContentInfoSetContentData(cinfo
, NULL
, false), out
);
122 // == wrapper of: require(SECSuccess == SecCmsContentInfoSetContent(cinfo, SEC_OID_PKCS7_DATA, NULL), out);
124 if (CFGetTypeID(recipient_or_cfarray_thereof
) == CFArrayGetTypeID()) {
125 CFIndex dex
, numCerts
= CFArrayGetCount(recipient_or_cfarray_thereof
);
126 for(dex
=0; dex
<numCerts
; dex
++) {
127 SecCertificateRef recip
=
128 (SecCertificateRef
)CFArrayGetValueAtIndex(recipient_or_cfarray_thereof
, dex
);
129 SecCmsRecipientInfoRef rinfo
;
130 require(rinfo
= SecCmsRecipientInfoCreate(envd
, recip
), out
);
132 } else if (CFGetTypeID(recipient_or_cfarray_thereof
) == SecCertificateGetTypeID()) {
133 require(SecCmsRecipientInfoCreate(envd
, (SecCertificateRef
)recipient_or_cfarray_thereof
), out
);
137 SecAsn1Item input
= {};
139 input
.Length
= CFDataGetLength(data
);
140 input
.Data
= (uint8_t*)CFDataGetBytePtr(data
);
142 require_noerr(SecCmsMessageEncode(cmsg
, (data
&& input
.Length
) ? &input
: NULL
, enveloped_data
), out
);
144 status
= errSecSuccess
;
146 if (cmsg
) SecCmsMessageDestroy(cmsg
);
150 OSStatus
SecCMSDecryptEnvelopedData(CFDataRef message
,
151 CFMutableDataRef data
, SecCertificateRef
*recipient
)
153 SecCmsMessageRef cmsg
= NULL
;
154 SecCmsContentInfoRef cinfo
;
155 SecCmsEnvelopedDataRef envd
= NULL
;
156 SecCertificateRef used_recipient
= NULL
;
157 OSStatus status
= errSecParam
;
159 SecAsn1Item encoded_message
= { CFDataGetLength(message
), (uint8_t*)CFDataGetBytePtr(message
) };
160 require_noerr_action_quiet(SecCmsMessageDecode(&encoded_message
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, &cmsg
),
161 out
, status
= errSecDecode
);
162 require_quiet(cinfo
= SecCmsMessageContentLevel(cmsg
, 0), out
);
163 require_quiet(SecCmsContentInfoGetContentTypeTag(cinfo
) == SEC_OID_PKCS7_ENVELOPED_DATA
, out
);
164 require_quiet(envd
= (SecCmsEnvelopedDataRef
)SecCmsContentInfoGetContent(cinfo
), out
);
165 SecCmsRecipientInfoRef
*rinfo
= envd
->recipientInfos
;
166 while (!used_recipient
&& *rinfo
) {
167 used_recipient
= (*rinfo
)->cert
;
170 require_quiet(2 == SecCmsMessageContentLevelCount(cmsg
), out
);
171 require_quiet(cinfo
= SecCmsMessageContentLevel(cmsg
, 1), out
);
172 require_quiet(SecCmsContentInfoGetContentTypeTag(cinfo
) == SEC_OID_PKCS7_DATA
, out
);
173 const SecAsn1Item
*content
= SecCmsMessageGetContent(cmsg
);
175 CFDataAppendBytes(data
, content
->Data
, content
->Length
);
177 CFRetainSafe(used_recipient
);
178 *recipient
= used_recipient
;
180 status
= errSecSuccess
;
182 if (cmsg
) SecCmsMessageDestroy(cmsg
);
186 static SecCmsAttribute
*
187 make_attr(PLArenaPool
*poolp
, SecAsn1Item
*type
, SecAsn1Item
*value
, bool encoded
)
189 SecAsn1Item
* copiedvalue
;
190 SecCmsAttribute
*attr
= (SecCmsAttribute
*)PORT_ArenaZAlloc(poolp
, sizeof(SecCmsAttribute
));
194 if (SECITEM_CopyItem(poolp
, &(attr
->type
), type
) != SECSuccess
)
198 if ((copiedvalue
= SECITEM_AllocItem(poolp
, NULL
, value
->Length
)) == NULL
)
201 if (SECITEM_CopyItem(poolp
, copiedvalue
, value
) != SECSuccess
)
204 if (SecCmsArrayAdd(poolp
, (void ***)&(attr
->values
), (void *)copiedvalue
) != SECSuccess
)
208 attr
->encoded
= encoded
;
215 signerinfo_add_auth_attr(SecCmsSignerInfoRef signerinfo
, /*SECOidTag oidtag*/
216 SecAsn1Item
*oid
, SecAsn1Item
*value
, bool encoded
)
218 PLArenaPool
*poolp
= signerinfo
->signedData
->contentInfo
.cmsg
->poolp
;
219 PORT_Assert (poolp
!= NULL
);
220 void *mark
= PORT_ArenaMark (poolp
);
222 SecCmsAttribute
*attr
= make_attr(poolp
, oid
, value
, encoded
);
223 if (!attr
|| SecCmsAttributeArrayAddAttr(poolp
, &(signerinfo
->authAttr
), attr
) != SECSuccess
)
226 PORT_ArenaUnmark (poolp
, mark
);
230 PORT_Assert (mark
!= NULL
);
231 PORT_ArenaRelease (poolp
, mark
);
235 static void sign_all_attributes(const void *key
, const void *value
, void *context
)
237 SecAsn1Item oid
= { CFDataGetLength(key
), (uint8_t*)CFDataGetBytePtr(key
) },
238 oid_value
= { CFDataGetLength(value
), (uint8_t*)CFDataGetBytePtr(value
) };
240 signerinfo_add_auth_attr((SecCmsSignerInfoRef
)context
, &oid
, &oid_value
, true);
244 static void enveloped_data_add_unprotected_attr(SecCmsEnvelopedDataRef envd
,
245 SecAsn1Item
*oid
, SecAsn1Item
*value
, bool encoded
)
247 PLArenaPool
*poolp
= envd
->contentInfo
.cmsg
->poolp
;
248 PORT_Assert (poolp
!= NULL
);
249 void *mark
= PORT_ArenaMark (poolp
);
250 SecCmsAttribute
*attr
= make_attr(poolp
, oid
, value
, encoded
);
252 if (!attr
|| SecCmsAttributeArrayAddAttr(
254 &(envd
->unprotectedAttr
), attr
) != SECSuccess
)
257 PORT_ArenaUnmark (poolp
, mark
);
261 PORT_Assert (mark
!= NULL
);
262 PORT_ArenaRelease (poolp
, mark
);
268 static OSStatus
SecCMSSignDataOrDigestAndAttributes(SecIdentityRef identity
,
269 CFDataRef data
, bool detached
, bool data_is_digest
, SECOidTag sign_algorithm
,
270 CFMutableDataRef signed_data
, CFDictionaryRef signed_attributes
, SecCmsCertChainMode chainMode
, CFArrayRef additional_certs
)
272 SecCmsMessageRef cmsg
= NULL
;
273 SecCmsContentInfoRef cinfo
;
274 SecCmsSignedDataRef sigd
= NULL
;
275 SecCmsSignerInfoRef signerinfo
;
276 OSStatus status
= errSecParam
;
278 require(!data_is_digest
|| detached
/* if digest, must be detached */, out
);
280 require(cmsg
= SecCmsMessageCreate(), out
);
281 require(sigd
= SecCmsSignedDataCreate(cmsg
), out
);
282 require(cinfo
= SecCmsMessageGetContentInfo(cmsg
), out
);
283 require_noerr(SecCmsContentInfoSetContentSignedData(cinfo
, sigd
), out
);
284 require(cinfo
= SecCmsSignedDataGetContentInfo(sigd
), out
);
285 require_noerr(SecCmsContentInfoSetContentData(cinfo
, NULL
, detached
), out
);
286 require(signerinfo
= SecCmsSignerInfoCreate(sigd
, identity
, sign_algorithm
), out
);
287 if (additional_certs
)
288 require_noerr(SecCmsSignedDataAddCertList(sigd
, additional_certs
), out
);
289 require_noerr(SecCmsSignerInfoIncludeCerts(signerinfo
, chainMode
, certUsageAnyCA
), out
);
290 require_noerr(SecCmsSignerInfoAddSigningTime(signerinfo
, CFAbsoluteTimeGetCurrent()), out
);
292 if (signed_attributes
)
293 CFDictionaryApplyFunction(signed_attributes
, sign_all_attributes
, signerinfo
);
295 SecAsn1Item input
= {};
297 input
.Length
= CFDataGetLength(data
);
298 input
.Data
= (uint8_t*)CFDataGetBytePtr(data
);
300 if (data_is_digest
) {
301 require_noerr(SecCmsSignedDataSetDigestValue(sigd
, sign_algorithm
, &input
), out
);
302 require_noerr(SecCmsMessageEncode(cmsg
, NULL
, signed_data
), out
);
305 require_noerr(SecCmsMessageEncode(cmsg
, (data
&& input
.Length
) ? &input
: NULL
, signed_data
), out
);
307 status
= errSecSuccess
;
309 if (cmsg
) SecCmsMessageDestroy(cmsg
);
313 OSStatus
SecCMSSignDataAndAttributes(SecIdentityRef identity
, CFDataRef data
, bool detached
,
314 CFMutableDataRef signed_data
, CFDictionaryRef signed_attributes
)
316 return SecCMSSignDataOrDigestAndAttributes(identity
, data
, detached
, false, SEC_OID_SHA1
,
317 signed_data
, signed_attributes
, SecCmsCMCertChain
, NULL
);
320 OSStatus
SecCMSSignDigestAndAttributes(SecIdentityRef identity
, CFDataRef digest
,
321 CFMutableDataRef signed_data
, CFDictionaryRef signed_attributes
)
323 return SecCMSSignDataOrDigestAndAttributes(identity
, digest
, true, true, SEC_OID_SHA1
,
324 signed_data
, signed_attributes
, SecCmsCMCertChain
, NULL
);
328 OSStatus
SecCMSCreateSignedData(SecIdentityRef identity
, CFDataRef data
,
329 CFDictionaryRef parameters
, CFDictionaryRef signed_attributes
,
330 CFMutableDataRef signed_data
)
332 bool is_digest
= false, is_detached
= false;
333 CFStringRef algorithm_name
= NULL
;
334 SecCmsCertChainMode chain_mode
= SecCmsCMCertChain
;
335 CFArrayRef additional_certs
= NULL
;
338 is_digest
= CFDictionaryGetValueIfPresent(parameters
,
339 kSecCMSSignDigest
, NULL
);
340 is_detached
= CFDictionaryGetValueIfPresent(parameters
,
341 kSecCMSSignDetached
, NULL
);
342 algorithm_name
= CFDictionaryGetValue(parameters
,
343 kSecCMSSignHashAlgorithm
);
345 CFTypeRef chain_mode_param
= CFDictionaryGetValue(parameters
, kSecCMSCertChainMode
);
346 if (chain_mode_param
&& (CFGetTypeID(chain_mode_param
) == CFStringGetTypeID()))
347 chain_mode
= CFStringGetIntValue(chain_mode_param
);
349 CFTypeRef additional_certs_param
= CFDictionaryGetValue(parameters
, kSecCMSAdditionalCerts
);
350 if (additional_certs_param
&& (CFGetTypeID(additional_certs_param
) == CFArrayGetTypeID()))
351 additional_certs
= (CFArrayRef
)additional_certs_param
;
354 SECOidTag algorithm
= SEC_OID_SHA1
;
355 if (algorithm_name
) {
356 if (CFEqual(kSecCMSHashingAlgorithmSHA1
, algorithm_name
)) {
357 algorithm
= SEC_OID_SHA1
;
358 } else if (CFEqual(kSecCMSHashingAlgorithmSHA256
, algorithm_name
)) {
359 algorithm
= SEC_OID_SHA256
;
360 } else if (CFEqual(kSecCMSHashingAlgorithmSHA384
, algorithm_name
)) {
361 algorithm
= SEC_OID_SHA384
;
362 } else if (CFEqual(kSecCMSHashingAlgorithmSHA512
, algorithm_name
)) {
363 algorithm
= SEC_OID_SHA512
;
369 return SecCMSSignDataOrDigestAndAttributes(identity
, data
,
370 is_detached
, is_digest
, algorithm
,
371 signed_data
, signed_attributes
, chain_mode
, additional_certs
);
375 static CFMutableArrayRef
copy_signed_attribute_values(SecCmsAttribute
*attr
)
377 CFMutableArrayRef array
= CFArrayCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeArrayCallBacks
);
378 SecAsn1Item
**item
= attr
->values
;
379 if (item
) while (*item
) {
380 CFDataRef asn1data
= CFDataCreate(kCFAllocatorDefault
, (*item
)->Data
, (*item
)->Length
);
382 CFArrayAppendValue(array
, asn1data
);
390 static OSStatus
SecCMSVerifySignedData_internal(CFDataRef message
, CFDataRef detached_contents
,
391 CFTypeRef policy
, SecTrustRef
*trustref
, CFArrayRef additional_certs
,
392 CFDataRef
*attached_contents
, CFDictionaryRef
*signed_attributes
)
394 SecCmsMessageRef cmsg
= NULL
;
395 SecCmsContentInfoRef cinfo
;
396 SecCmsSignedDataRef sigd
= NULL
;
397 OSStatus status
= errSecParam
;
399 require(message
, out
);
400 SecAsn1Item encoded_message
= { CFDataGetLength(message
), (uint8_t*)CFDataGetBytePtr(message
) };
401 require_noerr_action_quiet(SecCmsMessageDecode(&encoded_message
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, &cmsg
),
402 out
, status
= errSecDecode
);
403 /* expected to be a signed data message at the top level */
404 require_quiet(cinfo
= SecCmsMessageContentLevel(cmsg
, 0), out
);
405 require_quiet(SecCmsContentInfoGetContentTypeTag(cinfo
) == SEC_OID_PKCS7_SIGNED_DATA
, out
);
406 require_quiet(sigd
= (SecCmsSignedDataRef
)SecCmsContentInfoGetContent(cinfo
), out
);
408 if (detached_contents
)
410 require_quiet(!SecCmsSignedDataHasDigests(sigd
), out
);
411 SECAlgorithmID
**digestalgs
= SecCmsSignedDataGetDigestAlgs(sigd
);
412 SecCmsDigestContextRef digcx
= SecCmsDigestContextStartMultiple(digestalgs
);
413 SecCmsDigestContextUpdate(digcx
, CFDataGetBytePtr(detached_contents
), CFDataGetLength(detached_contents
));
414 SecCmsSignedDataSetDigestContext(sigd
, digcx
);
415 SecCmsDigestContextDestroy(digcx
);
418 if (additional_certs
)
419 require_noerr_quiet(SecCmsSignedDataAddCertList(sigd
, additional_certs
), out
);
421 if (policy
) { /* if no policy is given skip verification */
422 /* find out about signers */
423 int nsigners
= SecCmsSignedDataSignerInfoCount(sigd
);
424 require_quiet(nsigners
== 1, out
);
425 require_noerr_action_quiet(SecCmsSignedDataVerifySignerInfo(sigd
, 0, NULL
, policy
, trustref
),
426 out
, status
= errSecAuthFailed
);
431 trustrefs
= CFArrayCreateMutable(kCFAllocatorDefault
, nsigners
, &kCFTypeArrayCallBacks
);
434 for (j
= 0; j
< nsigners
; j
++)
436 SecTrustRef trustRef
;
437 require_noerr_action_quiet(SecCmsSignedDataVerifySignerInfo(sigd
, j
, NULL
, policy
, &trustRef
),
438 out
, status
= errSecAuthFailed
);
439 if ((j
== 0) && (nsigners
== 1))
440 *trustref_or_cfarray_thereof
= trustRef
;
442 CFArrayAppendValue(trustrefs
, trustRef
);
446 *trustref_or_cfarray_thereof
= trustrefs
;
450 status
= errSecSuccess
;
452 if (attached_contents
) {
453 const SecAsn1Item
*content
= SecCmsMessageGetContent(cmsg
);
455 *attached_contents
= CFDataCreate(kCFAllocatorDefault
, content
->Data
, content
->Length
);
457 *attached_contents
= NULL
;
460 if (signed_attributes
) {
461 CFMutableDictionaryRef attrs
= CFDictionaryCreateMutable(kCFAllocatorDefault
,
462 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
463 require_quiet(attrs
, out
);
464 SecCmsAttribute
**signed_attrs
= sigd
->signerInfos
[0]->authAttr
;
465 if (signed_attrs
) while (*signed_attrs
) {
466 CFDataRef type
= CFDataCreate(kCFAllocatorDefault
, (*signed_attrs
)->type
.Data
, (*signed_attrs
)->type
.Length
);
468 CFMutableArrayRef attr
= copy_signed_attribute_values(*signed_attrs
);
470 CFMutableArrayRef existing_attrs
= (CFMutableArrayRef
)CFDictionaryGetValue(attrs
, type
);
471 if (existing_attrs
) {
472 CFIndex count
= CFArrayGetCount(attr
);
474 CFArrayAppendArray(existing_attrs
, attr
, CFRangeMake(0, count
));
476 CFDictionarySetValue(attrs
, type
, attr
);
483 CFMutableArrayRef certs
= NULL
;
485 SecAsn1Item
**cert_datas
= SecCmsSignedDataGetCertificateList(sigd
);
486 certs
= CFArrayCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeArrayCallBacks
);
487 SecAsn1Item
*cert_data
;
488 if (cert_datas
) while ((cert_data
= *cert_datas
) != NULL
) {
489 SecCertificateRef cert
= SecCertificateCreateWithBytes(NULL
, cert_data
->Data
, cert_data
->Length
);
491 CFArrayAppendValue(certs
, cert
);
497 CFDictionaryAddValue(attrs
, kSecCMSAllCerts
, certs
);
499 /* Add "cooked" values separately */
500 CFAbsoluteTime signing_time
;
501 if (errSecSuccess
== SecCmsSignerInfoGetSigningTime(sigd
->signerInfos
[0], &signing_time
)) {
502 CFDateRef signing_date
= CFDateCreate(kCFAllocatorDefault
, signing_time
);
504 CFDictionarySetValue(attrs
, kSecCMSSignDate
, signing_date
);
505 CFReleaseSafe(signing_date
);
509 CFDataRef hash_agility_value
= NULL
;
510 if (errSecSuccess
== SecCmsSignerInfoGetAppleCodesigningHashAgility(sigd
->signerInfos
[0], &hash_agility_value
)) {
511 if (hash_agility_value
) {
512 CFDictionarySetValue(attrs
, kSecCMSHashAgility
, hash_agility_value
);
516 CFDictionaryRef hash_agility_values
= NULL
;
517 if (errSecSuccess
== SecCmsSignerInfoGetAppleCodesigningHashAgilityV2(sigd
->signerInfos
[0], &hash_agility_values
)) {
518 if (hash_agility_values
) {
519 CFDictionarySetValue(attrs
, kSecCMSHashAgilityV2
, hash_agility_values
);
523 *signed_attributes
= attrs
;
524 CFReleaseSafe(certs
);
529 if (cmsg
) SecCmsMessageDestroy(cmsg
);
533 OSStatus
SecCMSVerifyCopyDataAndAttributes(CFDataRef message
, CFDataRef detached_contents
,
534 CFTypeRef policy
, SecTrustRef
*trustref
,
535 CFDataRef
*attached_contents
, CFDictionaryRef
*signed_attributes
)
537 OSStatus status
= SecCMSVerifySignedData_internal(message
, detached_contents
, policy
, trustref
, NULL
, attached_contents
, signed_attributes
);
542 OSStatus
SecCMSVerifySignedData(CFDataRef message
, CFDataRef detached_contents
,
543 CFTypeRef policy
, SecTrustRef
*trustref
, CFArrayRef additional_certificates
,
544 CFDataRef
*attached_contents
, CFDictionaryRef
*message_attributes
)
546 CFDictionaryRef signed_attributes
= NULL
;
547 OSStatus status
= SecCMSVerifySignedData_internal(message
, detached_contents
, policy
, trustref
, additional_certificates
, attached_contents
, &signed_attributes
);
548 if (!status
&& signed_attributes
&& message_attributes
) {
549 *message_attributes
= CFDictionaryCreate(kCFAllocatorDefault
, &kSecCMSSignedAttributes
, (const void **)&signed_attributes
, 1, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
551 CFReleaseSafe(signed_attributes
);
556 OSStatus
SecCMSVerify(CFDataRef message
, CFDataRef detached_contents
,
557 CFTypeRef policy
, SecTrustRef
*trustref
,
558 CFDataRef
*attached_contents
) {
559 return SecCMSVerifySignedData_internal(message
, detached_contents
, policy
, trustref
, NULL
, attached_contents
, NULL
);
562 CFArrayRef
SecCMSCertificatesOnlyMessageCopyCertificates(CFDataRef message
) {
563 SecCmsMessageRef cmsg
= NULL
;
564 SecCmsContentInfoRef cinfo
;
565 SecCmsSignedDataRef sigd
= NULL
;
566 CFMutableArrayRef certs
= NULL
;
568 SecAsn1Item encoded_message
= { CFDataGetLength(message
), (uint8_t*)CFDataGetBytePtr(message
) };
569 require_noerr_quiet(SecCmsMessageDecode(&encoded_message
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, &cmsg
), out
);
570 /* expected to be a signed data message at the top level */
571 require(cinfo
= SecCmsMessageContentLevel(cmsg
, 0), out
);
572 require(SecCmsContentInfoGetContentTypeTag(cinfo
) == SEC_OID_PKCS7_SIGNED_DATA
, out
);
573 require(sigd
= (SecCmsSignedDataRef
)SecCmsContentInfoGetContent(cinfo
), out
);
575 /* find out about signers */
576 int nsigners
= SecCmsSignedDataSignerInfoCount(sigd
);
577 require(nsigners
== 0, out
);
579 SecAsn1Item
**cert_datas
= SecCmsSignedDataGetCertificateList(sigd
);
580 certs
= CFArrayCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeArrayCallBacks
);
581 SecAsn1Item
*cert_data
;
582 if (cert_datas
) while ((cert_data
= *cert_datas
) != NULL
) {
583 SecCertificateRef cert
= SecCertificateCreateWithBytes(NULL
, cert_data
->Data
, cert_data
->Length
);
585 CFArrayAppendValue(certs
, cert
);
593 SecCmsMessageDestroy(cmsg
);
599 extern const SecAsn1Template SecCmsMessageTemplate
[];
601 CFDataRef
SecCMSCreateCertificatesOnlyMessage(CFTypeRef cert_or_array_thereof
) {
602 OSStatus status
= errSecParam
;
603 SecCmsMessageRef cmsg
= NULL
;
604 SecCmsContentInfoRef cinfo
;
605 SecCmsSignedDataRef sigd
= NULL
;
606 CFMutableDataRef cert_only_signed_data
= NULL
;
607 CFArrayRef cert_array
= NULL
;
608 CFIndex cert_array_count
= 0;
609 SecCertificateRef cert
= NULL
;
611 require(cert_or_array_thereof
, out
);
613 require(cmsg
= SecCmsMessageCreate(), out
);
614 require(sigd
= SecCmsSignedDataCreate(cmsg
), out
);
615 require_noerr(SecCmsContentInfoSetContentData(&(sigd
->contentInfo
), NULL
, PR_TRUE
), out
);
616 require(cinfo
= SecCmsMessageGetContentInfo(cmsg
), out
);
617 require_noerr(SecCmsContentInfoSetContentSignedData(cinfo
, sigd
), out
);
618 long version
= SEC_CMS_SIGNED_DATA_VERSION_BASIC
;
619 require(SEC_ASN1EncodeInteger(cmsg
->poolp
, &(sigd
->version
), version
), out
);
621 if (CFGetTypeID(cert_or_array_thereof
) == SecCertificateGetTypeID()) {
622 cert_array
= CFArrayCreate(kCFAllocatorDefault
, &cert_or_array_thereof
, 1, &kCFTypeArrayCallBacks
);
623 } else if (CFGetTypeID(cert_or_array_thereof
) == CFArrayGetTypeID()) {
624 cert_array
= CFArrayCreateCopy(kCFAllocatorDefault
, (CFArrayRef
)cert_or_array_thereof
);
627 require(cert_array
, out
);
628 cert_array_count
= CFArrayGetCount(cert_array
);
629 require(cert_array_count
> 0, out
);
631 sigd
->rawCerts
= (SecAsn1Item
* *)PORT_ArenaAlloc(cmsg
->poolp
, (cert_array_count
+ 1) * sizeof(SecAsn1Item
*));
632 require(sigd
->rawCerts
, out
);
634 for (ix
= 0; ix
< cert_array_count
; ix
++) {
635 cert
= (SecCertificateRef
)CFArrayGetValueAtIndex(cert_array
, ix
);
638 sigd
->rawCerts
[ix
] = PORT_ArenaZAlloc(cmsg
->poolp
, sizeof(SecAsn1Item
));
639 SecAsn1Item cert_data
= { SecCertificateGetLength(cert
),
640 (uint8_t *)SecCertificateGetBytePtr(cert
) };
641 *(sigd
->rawCerts
[ix
]) = cert_data
;
643 sigd
->rawCerts
[ix
] = NULL
;
645 /* this is a SET OF, so we need to sort them guys - we have the DER already, though */
646 if (cert_array_count
> 1)
647 SecCmsArraySort((void **)sigd
->rawCerts
, SecCmsUtilDERCompare
, NULL
, NULL
);
649 cert_only_signed_data
= CFDataCreateMutable(kCFAllocatorDefault
, 0);
650 SecAsn1Item cert_only_signed_data_item
= {};
651 require_quiet(SEC_ASN1EncodeItem(cmsg
->poolp
, &cert_only_signed_data_item
,
652 cmsg
, SecCmsMessageTemplate
), out
);
653 CFDataAppendBytes(cert_only_signed_data
, cert_only_signed_data_item
.Data
,
654 cert_only_signed_data_item
.Length
);
656 status
= errSecSuccess
;
658 CFReleaseSafe(cert_array
);
659 if (status
) CFReleaseSafe(cert_only_signed_data
);
660 if (cmsg
) SecCmsMessageDestroy(cmsg
);
661 return cert_only_signed_data
;
664 CFDataRef
SecCMSCreateCertificatesOnlyMessageIAP(SecCertificateRef cert
)
666 static const uint8_t header
[] = {
667 0x30, 0x82, 0x03, 0x6d, 0x06, 0x09, 0x2a, 0x86,
668 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x02, 0xa0,
669 0x82, 0x03, 0x5e, 0x30, 0x82, 0x03, 0x5a, 0x02,
670 0x01, 0x01, 0x31, 0x00, 0x30, 0x0b, 0x06, 0x09,
671 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07,
672 0x01, 0xa0, 0x82, 0x03, 0x40
675 static const uint8_t trailer
[] = {
676 0xa1, 0x00, 0x31, 0x00
679 CFMutableDataRef message
= NULL
;
681 const uint8_t *certbytes
;
683 uint8_t *messagebytes
;
686 certdata
= SecCertificateCopyData(cert
);
687 require(certdata
, out
);
689 certbytes
= CFDataGetBytePtr(certdata
);
690 certlen
= CFDataGetLength(certdata
);
691 require(certlen
> UINT8_MAX
, out
);
692 require(certlen
< UINT16_MAX
, out
);
694 message
= CFDataCreateMutable(kCFAllocatorDefault
, 0);
695 require(message
, out
);
697 CFDataAppendBytes(message
, header
, sizeof(header
));
698 CFDataAppendBytes(message
, certbytes
, certlen
);
699 CFDataAppendBytes(message
, trailer
, sizeof(trailer
));
701 messagebytes
= CFDataGetMutableBytePtr(message
);
702 messagelen
= CFDataGetLength(message
);
705 messagebytes
[2] = messagelen
>> 8;
706 messagebytes
[3] = messagelen
& 0xFF;
709 messagebytes
[17] = messagelen
>> 8;
710 messagebytes
[18] = messagelen
& 0xFF;
713 messagebytes
[21] = messagelen
>> 8;
714 messagebytes
[22] = messagelen
& 0xFF;
717 messagebytes
[43] = messagelen
>> 8;
718 messagebytes
[44] = messagelen
& 0xFF;
721 CFReleaseSafe(certdata
);
725 #endif /* ENABLE_CMS */