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");
81 CFTypeRef kSecCMSExpirationDate
= CFSTR("kSecCMSExpirationDate");
83 CFTypeRef kSecCMSBulkEncryptionAlgorithm
= CFSTR("kSecCMSBulkEncryptionAlgorithm");
84 CFTypeRef kSecCMSEncryptionAlgorithmDESCBC
= CFSTR("kSecCMSEncryptionAlgorithmDESCBC");
85 CFTypeRef kSecCMSEncryptionAlgorithmAESCBC
= CFSTR("kSecCMSEncryptionAlgorithmAESCBC");
87 CFTypeRef kSecCMSSignHashAlgorithm
= CFSTR("kSecCMSSignHashAlgorithm");
88 CFTypeRef kSecCMSHashingAlgorithmMD5
= CFSTR("kSecCMSHashingAlgorithmMD5");
89 CFTypeRef kSecCMSHashingAlgorithmSHA1
= CFSTR("kSecCMSHashingAlgorithmSHA1");
90 CFTypeRef kSecCMSHashingAlgorithmSHA256
= CFSTR("kSecCMSHashingAlgorithmSHA256");
91 CFTypeRef kSecCMSHashingAlgorithmSHA384
= CFSTR("kSecCMSHashingAlgorithmSHA384");
92 CFTypeRef kSecCMSHashingAlgorithmSHA512
= CFSTR("kSecCMSHashingAlgorithmSHA512");
94 OSStatus
SecCMSCreateEnvelopedData(CFTypeRef recipient_or_cfarray_thereof
,
95 CFDictionaryRef params
, CFDataRef data
, CFMutableDataRef enveloped_data
)
97 SecCmsMessageRef cmsg
= NULL
;
98 SecCmsContentInfoRef cinfo
;
99 SecCmsEnvelopedDataRef envd
= NULL
;
100 SECOidTag algorithmTag
= SEC_OID_DES_EDE3_CBC
;
102 OSStatus status
= errSecParam
;
105 CFStringRef algorithm_name
= CFDictionaryGetValue(params
, kSecCMSBulkEncryptionAlgorithm
);
106 if (algorithm_name
) {
107 if (CFEqual(kSecCMSEncryptionAlgorithmDESCBC
, algorithm_name
)) {
108 algorithmTag
= SEC_OID_DES_CBC
;
110 } else if (CFEqual(kSecCMSEncryptionAlgorithmAESCBC
, algorithm_name
)) {
111 algorithmTag
= SEC_OID_AES_128_CBC
;
117 require(cmsg
= SecCmsMessageCreate(), out
);
118 require(envd
= SecCmsEnvelopedDataCreate(cmsg
, algorithmTag
, keySize
), out
);
119 require(cinfo
= SecCmsMessageGetContentInfo(cmsg
), out
);
120 require_noerr(SecCmsContentInfoSetContentEnvelopedData(cinfo
, envd
), out
);
121 require(cinfo
= SecCmsEnvelopedDataGetContentInfo(envd
), out
);
122 require_noerr(SecCmsContentInfoSetContentData(cinfo
, NULL
, false), out
);
123 // == wrapper of: require(SECSuccess == SecCmsContentInfoSetContent(cinfo, SEC_OID_PKCS7_DATA, NULL), out);
125 if (CFGetTypeID(recipient_or_cfarray_thereof
) == CFArrayGetTypeID()) {
126 CFIndex dex
, numCerts
= CFArrayGetCount(recipient_or_cfarray_thereof
);
127 for(dex
=0; dex
<numCerts
; dex
++) {
128 SecCertificateRef recip
=
129 (SecCertificateRef
)CFArrayGetValueAtIndex(recipient_or_cfarray_thereof
, dex
);
130 SecCmsRecipientInfoRef rinfo
;
131 require(rinfo
= SecCmsRecipientInfoCreate(envd
, recip
), out
);
133 } else if (CFGetTypeID(recipient_or_cfarray_thereof
) == SecCertificateGetTypeID()) {
134 require(SecCmsRecipientInfoCreate(envd
, (SecCertificateRef
)recipient_or_cfarray_thereof
), out
);
138 SecAsn1Item input
= {};
140 input
.Length
= CFDataGetLength(data
);
141 input
.Data
= (uint8_t*)CFDataGetBytePtr(data
);
143 require_noerr(SecCmsMessageEncode(cmsg
, (data
&& input
.Length
) ? &input
: NULL
, enveloped_data
), out
);
145 status
= errSecSuccess
;
147 if (cmsg
) SecCmsMessageDestroy(cmsg
);
151 OSStatus
SecCMSDecryptEnvelopedData(CFDataRef message
,
152 CFMutableDataRef data
, SecCertificateRef
*recipient
)
154 SecCmsMessageRef cmsg
= NULL
;
155 SecCmsContentInfoRef cinfo
;
156 SecCmsEnvelopedDataRef envd
= NULL
;
157 SecCertificateRef used_recipient
= NULL
;
158 OSStatus status
= errSecParam
;
160 SecAsn1Item encoded_message
= { CFDataGetLength(message
), (uint8_t*)CFDataGetBytePtr(message
) };
161 require_noerr_action_quiet(SecCmsMessageDecode(&encoded_message
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, &cmsg
),
162 out
, status
= errSecDecode
);
163 require_quiet(cinfo
= SecCmsMessageContentLevel(cmsg
, 0), out
);
164 require_quiet(SecCmsContentInfoGetContentTypeTag(cinfo
) == SEC_OID_PKCS7_ENVELOPED_DATA
, out
);
165 require_quiet(envd
= (SecCmsEnvelopedDataRef
)SecCmsContentInfoGetContent(cinfo
), out
);
166 SecCmsRecipientInfoRef
*rinfo
= envd
->recipientInfos
;
167 while (!used_recipient
&& *rinfo
) {
168 used_recipient
= (*rinfo
)->cert
;
171 require_quiet(2 == SecCmsMessageContentLevelCount(cmsg
), out
);
172 require_quiet(cinfo
= SecCmsMessageContentLevel(cmsg
, 1), out
);
173 require_quiet(SecCmsContentInfoGetContentTypeTag(cinfo
) == SEC_OID_PKCS7_DATA
, out
);
174 const SecAsn1Item
*content
= SecCmsMessageGetContent(cmsg
);
176 CFDataAppendBytes(data
, content
->Data
, content
->Length
);
178 CFRetainSafe(used_recipient
);
179 *recipient
= used_recipient
;
181 status
= errSecSuccess
;
183 if (cmsg
) SecCmsMessageDestroy(cmsg
);
187 static SecCmsAttribute
*
188 make_attr(PLArenaPool
*poolp
, SecAsn1Item
*type
, SecAsn1Item
*value
, bool encoded
)
190 SecAsn1Item
* copiedvalue
;
191 SecCmsAttribute
*attr
= (SecCmsAttribute
*)PORT_ArenaZAlloc(poolp
, sizeof(SecCmsAttribute
));
195 if (SECITEM_CopyItem(poolp
, &(attr
->type
), type
) != SECSuccess
)
199 if ((copiedvalue
= SECITEM_AllocItem(poolp
, NULL
, value
->Length
)) == NULL
)
202 if (SECITEM_CopyItem(poolp
, copiedvalue
, value
) != SECSuccess
)
205 if (SecCmsArrayAdd(poolp
, (void ***)&(attr
->values
), (void *)copiedvalue
) != SECSuccess
)
209 attr
->encoded
= encoded
;
216 signerinfo_add_auth_attr(SecCmsSignerInfoRef signerinfo
, /*SECOidTag oidtag*/
217 SecAsn1Item
*oid
, SecAsn1Item
*value
, bool encoded
)
219 PLArenaPool
*poolp
= signerinfo
->signedData
->contentInfo
.cmsg
->poolp
;
220 PORT_Assert (poolp
!= NULL
);
221 void *mark
= PORT_ArenaMark (poolp
);
223 SecCmsAttribute
*attr
= make_attr(poolp
, oid
, value
, encoded
);
224 if (!attr
|| SecCmsAttributeArrayAddAttr(poolp
, &(signerinfo
->authAttr
), attr
) != SECSuccess
)
227 PORT_ArenaUnmark (poolp
, mark
);
231 PORT_Assert (mark
!= NULL
);
232 PORT_ArenaRelease (poolp
, mark
);
236 static void sign_all_attributes(const void *key
, const void *value
, void *context
)
238 SecAsn1Item oid
= { CFDataGetLength(key
), (uint8_t*)CFDataGetBytePtr(key
) },
239 oid_value
= { CFDataGetLength(value
), (uint8_t*)CFDataGetBytePtr(value
) };
241 signerinfo_add_auth_attr((SecCmsSignerInfoRef
)context
, &oid
, &oid_value
, true);
245 static void enveloped_data_add_unprotected_attr(SecCmsEnvelopedDataRef envd
,
246 SecAsn1Item
*oid
, SecAsn1Item
*value
, bool encoded
)
248 PLArenaPool
*poolp
= envd
->contentInfo
.cmsg
->poolp
;
249 PORT_Assert (poolp
!= NULL
);
250 void *mark
= PORT_ArenaMark (poolp
);
251 SecCmsAttribute
*attr
= make_attr(poolp
, oid
, value
, encoded
);
253 if (!attr
|| SecCmsAttributeArrayAddAttr(
255 &(envd
->unprotectedAttr
), attr
) != SECSuccess
)
258 PORT_ArenaUnmark (poolp
, mark
);
262 PORT_Assert (mark
!= NULL
);
263 PORT_ArenaRelease (poolp
, mark
);
269 static OSStatus
SecCMSSignDataOrDigestAndAttributes(SecIdentityRef identity
,
270 CFDataRef data
, bool detached
, bool data_is_digest
, SECOidTag sign_algorithm
,
271 CFMutableDataRef signed_data
, CFDictionaryRef signed_attributes
, SecCmsCertChainMode chainMode
, CFArrayRef additional_certs
)
273 SecCmsMessageRef cmsg
= NULL
;
274 SecCmsContentInfoRef cinfo
;
275 SecCmsSignedDataRef sigd
= NULL
;
276 SecCmsSignerInfoRef signerinfo
;
277 OSStatus status
= errSecParam
;
279 require(!data_is_digest
|| detached
/* if digest, must be detached */, out
);
281 require(cmsg
= SecCmsMessageCreate(), out
);
282 require(sigd
= SecCmsSignedDataCreate(cmsg
), out
);
283 require(cinfo
= SecCmsMessageGetContentInfo(cmsg
), out
);
284 require_noerr(SecCmsContentInfoSetContentSignedData(cinfo
, sigd
), out
);
285 require(cinfo
= SecCmsSignedDataGetContentInfo(sigd
), out
);
286 require_noerr(SecCmsContentInfoSetContentData(cinfo
, NULL
, detached
), out
);
287 require(signerinfo
= SecCmsSignerInfoCreate(sigd
, identity
, sign_algorithm
), out
);
288 if (additional_certs
)
289 require_noerr(SecCmsSignedDataAddCertList(sigd
, additional_certs
), out
);
290 require_noerr(SecCmsSignerInfoIncludeCerts(signerinfo
, chainMode
, certUsageAnyCA
), out
);
291 require_noerr(SecCmsSignerInfoAddSigningTime(signerinfo
, CFAbsoluteTimeGetCurrent()), out
);
293 if (signed_attributes
)
294 CFDictionaryApplyFunction(signed_attributes
, sign_all_attributes
, signerinfo
);
296 SecAsn1Item input
= {};
298 input
.Length
= CFDataGetLength(data
);
299 input
.Data
= (uint8_t*)CFDataGetBytePtr(data
);
301 if (data_is_digest
) {
302 require_noerr(SecCmsSignedDataSetDigestValue(sigd
, sign_algorithm
, &input
), out
);
303 require_noerr(SecCmsMessageEncode(cmsg
, NULL
, signed_data
), out
);
306 require_noerr(SecCmsMessageEncode(cmsg
, (data
&& input
.Length
) ? &input
: NULL
, signed_data
), out
);
308 status
= errSecSuccess
;
310 if (cmsg
) SecCmsMessageDestroy(cmsg
);
314 OSStatus
SecCMSSignDataAndAttributes(SecIdentityRef identity
, CFDataRef data
, bool detached
,
315 CFMutableDataRef signed_data
, CFDictionaryRef signed_attributes
)
317 return SecCMSSignDataOrDigestAndAttributes(identity
, data
, detached
, false, SEC_OID_SHA1
,
318 signed_data
, signed_attributes
, SecCmsCMCertChain
, NULL
);
321 OSStatus
SecCMSSignDigestAndAttributes(SecIdentityRef identity
, CFDataRef digest
,
322 CFMutableDataRef signed_data
, CFDictionaryRef signed_attributes
)
324 return SecCMSSignDataOrDigestAndAttributes(identity
, digest
, true, true, SEC_OID_SHA1
,
325 signed_data
, signed_attributes
, SecCmsCMCertChain
, NULL
);
329 OSStatus
SecCMSCreateSignedData(SecIdentityRef identity
, CFDataRef data
,
330 CFDictionaryRef parameters
, CFDictionaryRef signed_attributes
,
331 CFMutableDataRef signed_data
)
333 bool is_digest
= false, is_detached
= false;
334 CFStringRef algorithm_name
= NULL
;
335 SecCmsCertChainMode chain_mode
= SecCmsCMCertChain
;
336 CFArrayRef additional_certs
= NULL
;
339 is_digest
= CFDictionaryGetValueIfPresent(parameters
,
340 kSecCMSSignDigest
, NULL
);
341 is_detached
= CFDictionaryGetValueIfPresent(parameters
,
342 kSecCMSSignDetached
, NULL
);
343 algorithm_name
= CFDictionaryGetValue(parameters
,
344 kSecCMSSignHashAlgorithm
);
346 CFTypeRef chain_mode_param
= CFDictionaryGetValue(parameters
, kSecCMSCertChainMode
);
347 if (chain_mode_param
&& (CFGetTypeID(chain_mode_param
) == CFStringGetTypeID()))
348 chain_mode
= CFStringGetIntValue(chain_mode_param
);
350 CFTypeRef additional_certs_param
= CFDictionaryGetValue(parameters
, kSecCMSAdditionalCerts
);
351 if (additional_certs_param
&& (CFGetTypeID(additional_certs_param
) == CFArrayGetTypeID()))
352 additional_certs
= (CFArrayRef
)additional_certs_param
;
355 SECOidTag algorithm
= SEC_OID_SHA1
;
356 if (algorithm_name
) {
357 if (CFEqual(kSecCMSHashingAlgorithmSHA1
, algorithm_name
)) {
358 algorithm
= SEC_OID_SHA1
;
359 } else if (CFEqual(kSecCMSHashingAlgorithmSHA256
, algorithm_name
)) {
360 algorithm
= SEC_OID_SHA256
;
361 } else if (CFEqual(kSecCMSHashingAlgorithmSHA384
, algorithm_name
)) {
362 algorithm
= SEC_OID_SHA384
;
363 } else if (CFEqual(kSecCMSHashingAlgorithmSHA512
, algorithm_name
)) {
364 algorithm
= SEC_OID_SHA512
;
370 return SecCMSSignDataOrDigestAndAttributes(identity
, data
,
371 is_detached
, is_digest
, algorithm
,
372 signed_data
, signed_attributes
, chain_mode
, additional_certs
);
376 static CFMutableArrayRef
copy_signed_attribute_values(SecCmsAttribute
*attr
)
378 CFMutableArrayRef array
= CFArrayCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeArrayCallBacks
);
379 SecAsn1Item
**item
= attr
->values
;
380 if (item
) while (*item
) {
381 CFDataRef asn1data
= CFDataCreate(kCFAllocatorDefault
, (*item
)->Data
, (*item
)->Length
);
383 CFArrayAppendValue(array
, asn1data
);
391 static OSStatus
SecCMSVerifySignedData_internal(CFDataRef message
, CFDataRef detached_contents
,
392 CFTypeRef policy
, SecTrustRef
*trustref
, CFArrayRef additional_certs
,
393 CFDataRef
*attached_contents
, CFDictionaryRef
*signed_attributes
)
395 SecCmsMessageRef cmsg
= NULL
;
396 SecCmsContentInfoRef cinfo
;
397 SecCmsSignedDataRef sigd
= NULL
;
398 OSStatus status
= errSecParam
;
400 require(message
, out
);
401 SecAsn1Item encoded_message
= { CFDataGetLength(message
), (uint8_t*)CFDataGetBytePtr(message
) };
402 require_noerr_action_quiet(SecCmsMessageDecode(&encoded_message
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, &cmsg
),
403 out
, status
= errSecDecode
);
404 /* expected to be a signed data message at the top level */
405 require_quiet(cinfo
= SecCmsMessageContentLevel(cmsg
, 0), out
);
406 require_quiet(SecCmsContentInfoGetContentTypeTag(cinfo
) == SEC_OID_PKCS7_SIGNED_DATA
, out
);
407 require_quiet(sigd
= (SecCmsSignedDataRef
)SecCmsContentInfoGetContent(cinfo
), out
);
409 if (detached_contents
)
411 require_quiet(!SecCmsSignedDataHasDigests(sigd
), out
);
412 SECAlgorithmID
**digestalgs
= SecCmsSignedDataGetDigestAlgs(sigd
);
413 SecCmsDigestContextRef digcx
= SecCmsDigestContextStartMultiple(digestalgs
);
414 SecCmsDigestContextUpdate(digcx
, CFDataGetBytePtr(detached_contents
), CFDataGetLength(detached_contents
));
415 SecCmsSignedDataSetDigestContext(sigd
, digcx
);
416 SecCmsDigestContextDestroy(digcx
);
419 if (additional_certs
)
420 require_noerr_quiet(SecCmsSignedDataAddCertList(sigd
, additional_certs
), out
);
422 if (policy
) { /* if no policy is given skip verification */
423 /* find out about signers */
424 int nsigners
= SecCmsSignedDataSignerInfoCount(sigd
);
425 require_quiet(nsigners
== 1, out
);
426 require_noerr_action_quiet(SecCmsSignedDataVerifySignerInfo(sigd
, 0, NULL
, policy
, trustref
),
427 out
, status
= errSecAuthFailed
);
432 trustrefs
= CFArrayCreateMutable(kCFAllocatorDefault
, nsigners
, &kCFTypeArrayCallBacks
);
435 for (j
= 0; j
< nsigners
; j
++)
437 SecTrustRef trustRef
;
438 require_noerr_action_quiet(SecCmsSignedDataVerifySignerInfo(sigd
, j
, NULL
, policy
, &trustRef
),
439 out
, status
= errSecAuthFailed
);
440 if ((j
== 0) && (nsigners
== 1))
441 *trustref_or_cfarray_thereof
= trustRef
;
443 CFArrayAppendValue(trustrefs
, trustRef
);
447 *trustref_or_cfarray_thereof
= trustrefs
;
451 status
= errSecSuccess
;
453 if (attached_contents
) {
454 const SecAsn1Item
*content
= SecCmsMessageGetContent(cmsg
);
456 *attached_contents
= CFDataCreate(kCFAllocatorDefault
, content
->Data
, content
->Length
);
458 *attached_contents
= NULL
;
461 if (signed_attributes
) {
462 CFMutableDictionaryRef attrs
= CFDictionaryCreateMutable(kCFAllocatorDefault
,
463 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
464 require_quiet(attrs
, out
);
465 SecCmsAttribute
**signed_attrs
= sigd
->signerInfos
[0]->authAttr
;
466 if (signed_attrs
) while (*signed_attrs
) {
467 CFDataRef type
= CFDataCreate(kCFAllocatorDefault
, (*signed_attrs
)->type
.Data
, (*signed_attrs
)->type
.Length
);
469 CFMutableArrayRef attr
= copy_signed_attribute_values(*signed_attrs
);
471 CFMutableArrayRef existing_attrs
= (CFMutableArrayRef
)CFDictionaryGetValue(attrs
, type
);
472 if (existing_attrs
) {
473 CFIndex count
= CFArrayGetCount(attr
);
475 CFArrayAppendArray(existing_attrs
, attr
, CFRangeMake(0, count
));
477 CFDictionarySetValue(attrs
, type
, attr
);
484 CFMutableArrayRef certs
= NULL
;
486 SecAsn1Item
**cert_datas
= SecCmsSignedDataGetCertificateList(sigd
);
487 certs
= CFArrayCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeArrayCallBacks
);
488 SecAsn1Item
*cert_data
;
489 if (cert_datas
) while ((cert_data
= *cert_datas
) != NULL
) {
490 SecCertificateRef cert
= SecCertificateCreateWithBytes(NULL
, cert_data
->Data
, cert_data
->Length
);
492 CFArrayAppendValue(certs
, cert
);
498 CFDictionaryAddValue(attrs
, kSecCMSAllCerts
, certs
);
500 /* Add "cooked" values separately */
501 CFAbsoluteTime signing_time
;
502 if (errSecSuccess
== SecCmsSignerInfoGetSigningTime(sigd
->signerInfos
[0], &signing_time
)) {
503 CFDateRef signing_date
= CFDateCreate(kCFAllocatorDefault
, signing_time
);
505 CFDictionarySetValue(attrs
, kSecCMSSignDate
, signing_date
);
506 CFReleaseSafe(signing_date
);
510 CFDataRef hash_agility_value
= NULL
;
511 if (errSecSuccess
== SecCmsSignerInfoGetAppleCodesigningHashAgility(sigd
->signerInfos
[0], &hash_agility_value
)) {
512 if (hash_agility_value
) {
513 CFDictionarySetValue(attrs
, kSecCMSHashAgility
, hash_agility_value
);
517 CFDictionaryRef hash_agility_values
= NULL
;
518 if (errSecSuccess
== SecCmsSignerInfoGetAppleCodesigningHashAgilityV2(sigd
->signerInfos
[0], &hash_agility_values
)) {
519 if (hash_agility_values
) {
520 CFDictionarySetValue(attrs
, kSecCMSHashAgilityV2
, hash_agility_values
);
524 CFAbsoluteTime expiration_time
;
525 if (errSecSuccess
== SecCmsSignerInfoGetAppleExpirationTime(sigd
->signerInfos
[0], &expiration_time
)) {
526 CFDateRef expiration_date
= CFDateCreate(NULL
, expiration_time
);
527 if (expiration_date
) {
528 CFDictionarySetValue(attrs
, kSecCMSExpirationDate
, expiration_date
);
529 CFReleaseSafe(expiration_date
);
533 *signed_attributes
= attrs
;
534 CFReleaseSafe(certs
);
539 if (cmsg
) SecCmsMessageDestroy(cmsg
);
543 OSStatus
SecCMSVerifyCopyDataAndAttributes(CFDataRef message
, CFDataRef detached_contents
,
544 CFTypeRef policy
, SecTrustRef
*trustref
,
545 CFDataRef
*attached_contents
, CFDictionaryRef
*signed_attributes
)
547 OSStatus status
= SecCMSVerifySignedData_internal(message
, detached_contents
, policy
, trustref
, NULL
, attached_contents
, signed_attributes
);
552 OSStatus
SecCMSVerifySignedData(CFDataRef message
, CFDataRef detached_contents
,
553 CFTypeRef policy
, SecTrustRef
*trustref
, CFArrayRef additional_certificates
,
554 CFDataRef
*attached_contents
, CFDictionaryRef
*message_attributes
)
556 CFDictionaryRef signed_attributes
= NULL
;
557 OSStatus status
= SecCMSVerifySignedData_internal(message
, detached_contents
, policy
, trustref
, additional_certificates
, attached_contents
, &signed_attributes
);
558 if (!status
&& signed_attributes
&& message_attributes
) {
559 *message_attributes
= CFDictionaryCreate(kCFAllocatorDefault
, &kSecCMSSignedAttributes
, (const void **)&signed_attributes
, 1, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
561 CFReleaseSafe(signed_attributes
);
566 OSStatus
SecCMSVerify(CFDataRef message
, CFDataRef detached_contents
,
567 CFTypeRef policy
, SecTrustRef
*trustref
,
568 CFDataRef
*attached_contents
) {
569 return SecCMSVerifySignedData_internal(message
, detached_contents
, policy
, trustref
, NULL
, attached_contents
, NULL
);
572 CFArrayRef
SecCMSCertificatesOnlyMessageCopyCertificates(CFDataRef message
) {
573 SecCmsMessageRef cmsg
= NULL
;
574 SecCmsContentInfoRef cinfo
;
575 SecCmsSignedDataRef sigd
= NULL
;
576 CFMutableArrayRef certs
= NULL
;
582 SecAsn1Item encoded_message
= { CFDataGetLength(message
), (uint8_t*)CFDataGetBytePtr(message
) };
583 require_noerr_quiet(SecCmsMessageDecode(&encoded_message
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, &cmsg
), out
);
584 /* expected to be a signed data message at the top level */
585 require(cinfo
= SecCmsMessageContentLevel(cmsg
, 0), out
);
586 require(SecCmsContentInfoGetContentTypeTag(cinfo
) == SEC_OID_PKCS7_SIGNED_DATA
, out
);
587 require(sigd
= (SecCmsSignedDataRef
)SecCmsContentInfoGetContent(cinfo
), out
);
589 /* find out about signers */
590 int nsigners
= SecCmsSignedDataSignerInfoCount(sigd
);
591 require(nsigners
== 0, out
);
593 SecAsn1Item
**cert_datas
= SecCmsSignedDataGetCertificateList(sigd
);
594 certs
= CFArrayCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeArrayCallBacks
);
595 SecAsn1Item
*cert_data
;
596 if (cert_datas
) while ((cert_data
= *cert_datas
) != NULL
) {
597 SecCertificateRef cert
= SecCertificateCreateWithBytes(NULL
, cert_data
->Data
, cert_data
->Length
);
599 CFArrayAppendValue(certs
, cert
);
606 if (cmsg
) { SecCmsMessageDestroy(cmsg
); }
607 if (certs
&& CFArrayGetCount(certs
) < 1) {
608 CFReleaseNull(certs
);
615 extern const SecAsn1Template SecCmsMessageTemplate
[];
617 CFDataRef
SecCMSCreateCertificatesOnlyMessage(CFTypeRef cert_or_array_thereof
) {
618 OSStatus status
= errSecParam
;
619 SecCmsMessageRef cmsg
= NULL
;
620 SecCmsContentInfoRef cinfo
;
621 SecCmsSignedDataRef sigd
= NULL
;
622 CFMutableDataRef cert_only_signed_data
= NULL
;
623 CFArrayRef cert_array
= NULL
;
624 CFIndex cert_array_count
= 0;
625 SecCertificateRef cert
= NULL
;
627 require(cert_or_array_thereof
, out
);
629 require(cmsg
= SecCmsMessageCreate(), out
);
630 require(sigd
= SecCmsSignedDataCreate(cmsg
), out
);
631 require_noerr(SecCmsContentInfoSetContentData(&(sigd
->contentInfo
), NULL
, PR_TRUE
), out
);
632 require(cinfo
= SecCmsMessageGetContentInfo(cmsg
), out
);
633 require_noerr(SecCmsContentInfoSetContentSignedData(cinfo
, sigd
), out
);
634 long version
= SEC_CMS_SIGNED_DATA_VERSION_BASIC
;
635 require(SEC_ASN1EncodeInteger(cmsg
->poolp
, &(sigd
->version
), version
), out
);
637 if (CFGetTypeID(cert_or_array_thereof
) == SecCertificateGetTypeID()) {
638 cert_array
= CFArrayCreate(kCFAllocatorDefault
, &cert_or_array_thereof
, 1, &kCFTypeArrayCallBacks
);
639 } else if (CFGetTypeID(cert_or_array_thereof
) == CFArrayGetTypeID()) {
640 cert_array
= CFArrayCreateCopy(kCFAllocatorDefault
, (CFArrayRef
)cert_or_array_thereof
);
643 require(cert_array
, out
);
644 cert_array_count
= CFArrayGetCount(cert_array
);
645 require(cert_array_count
> 0, out
);
647 sigd
->rawCerts
= (SecAsn1Item
* *)PORT_ArenaAlloc(cmsg
->poolp
, (cert_array_count
+ 1) * sizeof(SecAsn1Item
*));
648 require(sigd
->rawCerts
, out
);
650 for (ix
= 0; ix
< cert_array_count
; ix
++) {
651 cert
= (SecCertificateRef
)CFArrayGetValueAtIndex(cert_array
, ix
);
654 sigd
->rawCerts
[ix
] = PORT_ArenaZAlloc(cmsg
->poolp
, sizeof(SecAsn1Item
));
655 SecAsn1Item cert_data
= { SecCertificateGetLength(cert
),
656 (uint8_t *)SecCertificateGetBytePtr(cert
) };
657 *(sigd
->rawCerts
[ix
]) = cert_data
;
659 sigd
->rawCerts
[ix
] = NULL
;
661 /* this is a SET OF, so we need to sort them guys - we have the DER already, though */
662 if (cert_array_count
> 1)
663 SecCmsArraySort((void **)sigd
->rawCerts
, SecCmsUtilDERCompare
, NULL
, NULL
);
665 cert_only_signed_data
= CFDataCreateMutable(kCFAllocatorDefault
, 0);
666 SecAsn1Item cert_only_signed_data_item
= {};
667 require_quiet(SEC_ASN1EncodeItem(cmsg
->poolp
, &cert_only_signed_data_item
,
668 cmsg
, SecCmsMessageTemplate
), out
);
669 CFDataAppendBytes(cert_only_signed_data
, cert_only_signed_data_item
.Data
,
670 cert_only_signed_data_item
.Length
);
672 status
= errSecSuccess
;
674 CFReleaseSafe(cert_array
);
675 if (status
) CFReleaseSafe(cert_only_signed_data
);
676 if (cmsg
) SecCmsMessageDestroy(cmsg
);
677 return cert_only_signed_data
;
680 CFDataRef
SecCMSCreateCertificatesOnlyMessageIAP(SecCertificateRef cert
)
682 static const uint8_t header
[] = {
683 0x30, 0x82, 0x03, 0x6d, 0x06, 0x09, 0x2a, 0x86,
684 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x02, 0xa0,
685 0x82, 0x03, 0x5e, 0x30, 0x82, 0x03, 0x5a, 0x02,
686 0x01, 0x01, 0x31, 0x00, 0x30, 0x0b, 0x06, 0x09,
687 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07,
688 0x01, 0xa0, 0x82, 0x03, 0x40
691 static const uint8_t trailer
[] = {
692 0xa1, 0x00, 0x31, 0x00
695 CFMutableDataRef message
= NULL
;
697 const uint8_t *certbytes
;
699 uint8_t *messagebytes
;
702 certdata
= SecCertificateCopyData(cert
);
703 require(certdata
, out
);
705 certbytes
= CFDataGetBytePtr(certdata
);
706 certlen
= CFDataGetLength(certdata
);
707 require(certlen
> UINT8_MAX
, out
);
708 require(certlen
< UINT16_MAX
, out
);
710 message
= CFDataCreateMutable(kCFAllocatorDefault
, 0);
711 require(message
, out
);
713 CFDataAppendBytes(message
, header
, sizeof(header
));
714 CFDataAppendBytes(message
, certbytes
, certlen
);
715 CFDataAppendBytes(message
, trailer
, sizeof(trailer
));
717 messagebytes
= CFDataGetMutableBytePtr(message
);
718 messagelen
= CFDataGetLength(message
);
721 messagebytes
[2] = messagelen
>> 8;
722 messagebytes
[3] = messagelen
& 0xFF;
725 messagebytes
[17] = messagelen
>> 8;
726 messagebytes
[18] = messagelen
& 0xFF;
729 messagebytes
[21] = messagelen
>> 8;
730 messagebytes
[22] = messagelen
& 0xFF;
733 messagebytes
[43] = messagelen
>> 8;
734 messagebytes
[44] = messagelen
& 0xFF;
737 CFReleaseSafe(certdata
);
741 #endif /* ENABLE_CMS */