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");
81 CFTypeRef kSecCMSBulkEncryptionAlgorithm
= CFSTR("kSecCMSBulkEncryptionAlgorithm");
82 CFTypeRef kSecCMSEncryptionAlgorithmDESCBC
= CFSTR("kSecCMSEncryptionAlgorithmDESCBC");
83 CFTypeRef kSecCMSEncryptionAlgorithmAESCBC
= CFSTR("kSecCMSEncryptionAlgorithmAESCBC");
85 CFTypeRef kSecCMSSignHashAlgorithm
= CFSTR("kSecCMSSignHashAlgorithm");
86 CFTypeRef kSecCMSHashingAlgorithmMD5
= CFSTR("kSecCMSHashingAlgorithmMD5");
87 CFTypeRef kSecCMSHashingAlgorithmSHA1
= CFSTR("kSecCMSHashingAlgorithmSHA1");
88 CFTypeRef kSecCMSHashingAlgorithmSHA256
= CFSTR("kSecCMSHashingAlgorithmSHA256");
89 CFTypeRef kSecCMSHashingAlgorithmSHA384
= CFSTR("kSecCMSHashingAlgorithmSHA384");
90 CFTypeRef kSecCMSHashingAlgorithmSHA512
= CFSTR("kSecCMSHashingAlgorithmSHA512");
92 OSStatus
SecCMSCreateEnvelopedData(CFTypeRef recipient_or_cfarray_thereof
,
93 CFDictionaryRef params
, CFDataRef data
, CFMutableDataRef enveloped_data
)
95 SecCmsMessageRef cmsg
= NULL
;
96 SecCmsContentInfoRef cinfo
;
97 SecCmsEnvelopedDataRef envd
= NULL
;
98 SECOidTag algorithmTag
= SEC_OID_DES_EDE3_CBC
;
100 OSStatus status
= errSecParam
;
103 CFStringRef algorithm_name
= CFDictionaryGetValue(params
, kSecCMSBulkEncryptionAlgorithm
);
104 if (algorithm_name
) {
105 if (CFEqual(kSecCMSEncryptionAlgorithmDESCBC
, algorithm_name
)) {
106 algorithmTag
= SEC_OID_DES_CBC
;
108 } else if (CFEqual(kSecCMSEncryptionAlgorithmAESCBC
, algorithm_name
)) {
109 algorithmTag
= SEC_OID_AES_128_CBC
;
115 require(cmsg
= SecCmsMessageCreate(), out
);
116 require(envd
= SecCmsEnvelopedDataCreate(cmsg
, algorithmTag
, keySize
), out
);
117 require(cinfo
= SecCmsMessageGetContentInfo(cmsg
), out
);
118 require_noerr(SecCmsContentInfoSetContentEnvelopedData(cinfo
, envd
), out
);
119 require(cinfo
= SecCmsEnvelopedDataGetContentInfo(envd
), out
);
120 require_noerr(SecCmsContentInfoSetContentData(cinfo
, NULL
, false), out
);
121 // == wrapper of: require(SECSuccess == SecCmsContentInfoSetContent(cinfo, SEC_OID_PKCS7_DATA, NULL), out);
123 if (CFGetTypeID(recipient_or_cfarray_thereof
) == CFArrayGetTypeID()) {
124 CFIndex dex
, numCerts
= CFArrayGetCount(recipient_or_cfarray_thereof
);
125 for(dex
=0; dex
<numCerts
; dex
++) {
126 SecCertificateRef recip
=
127 (SecCertificateRef
)CFArrayGetValueAtIndex(recipient_or_cfarray_thereof
, dex
);
128 SecCmsRecipientInfoRef rinfo
;
129 require(rinfo
= SecCmsRecipientInfoCreate(envd
, recip
), out
);
131 } else if (CFGetTypeID(recipient_or_cfarray_thereof
) == SecCertificateGetTypeID()) {
132 require(SecCmsRecipientInfoCreate(envd
, (SecCertificateRef
)recipient_or_cfarray_thereof
), out
);
136 SecAsn1Item input
= {};
138 input
.Length
= CFDataGetLength(data
);
139 input
.Data
= (uint8_t*)CFDataGetBytePtr(data
);
141 require_noerr(SecCmsMessageEncode(cmsg
, (data
&& input
.Length
) ? &input
: NULL
, enveloped_data
), out
);
143 status
= errSecSuccess
;
145 if (cmsg
) SecCmsMessageDestroy(cmsg
);
149 OSStatus
SecCMSDecryptEnvelopedData(CFDataRef message
,
150 CFMutableDataRef data
, SecCertificateRef
*recipient
)
152 SecCmsMessageRef cmsg
= NULL
;
153 SecCmsContentInfoRef cinfo
;
154 SecCmsEnvelopedDataRef envd
= NULL
;
155 SecCertificateRef used_recipient
= NULL
;
156 OSStatus status
= errSecParam
;
158 SecAsn1Item encoded_message
= { CFDataGetLength(message
), (uint8_t*)CFDataGetBytePtr(message
) };
159 require_noerr_action_quiet(SecCmsMessageDecode(&encoded_message
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, &cmsg
),
160 out
, status
= errSecDecode
);
161 require_quiet(cinfo
= SecCmsMessageContentLevel(cmsg
, 0), out
);
162 require_quiet(SecCmsContentInfoGetContentTypeTag(cinfo
) == SEC_OID_PKCS7_ENVELOPED_DATA
, out
);
163 require_quiet(envd
= (SecCmsEnvelopedDataRef
)SecCmsContentInfoGetContent(cinfo
), out
);
164 SecCmsRecipientInfoRef
*rinfo
= envd
->recipientInfos
;
165 while (!used_recipient
&& *rinfo
) {
166 used_recipient
= (*rinfo
)->cert
;
169 require_quiet(2 == SecCmsMessageContentLevelCount(cmsg
), out
);
170 require_quiet(cinfo
= SecCmsMessageContentLevel(cmsg
, 1), out
);
171 require_quiet(SecCmsContentInfoGetContentTypeTag(cinfo
) == SEC_OID_PKCS7_DATA
, out
);
172 const SecAsn1Item
*content
= SecCmsMessageGetContent(cmsg
);
174 CFDataAppendBytes(data
, content
->Data
, content
->Length
);
176 CFRetainSafe(used_recipient
);
177 *recipient
= used_recipient
;
179 status
= errSecSuccess
;
181 if (cmsg
) SecCmsMessageDestroy(cmsg
);
185 static SecCmsAttribute
*
186 make_attr(PLArenaPool
*poolp
, SecAsn1Item
*type
, SecAsn1Item
*value
, bool encoded
)
188 SecAsn1Item
* copiedvalue
;
189 SecCmsAttribute
*attr
= (SecCmsAttribute
*)PORT_ArenaZAlloc(poolp
, sizeof(SecCmsAttribute
));
193 if (SECITEM_CopyItem(poolp
, &(attr
->type
), type
) != SECSuccess
)
197 if ((copiedvalue
= SECITEM_AllocItem(poolp
, NULL
, value
->Length
)) == NULL
)
200 if (SECITEM_CopyItem(poolp
, copiedvalue
, value
) != SECSuccess
)
203 if (SecCmsArrayAdd(poolp
, (void ***)&(attr
->values
), (void *)copiedvalue
) != SECSuccess
)
207 attr
->encoded
= encoded
;
214 signerinfo_add_auth_attr(SecCmsSignerInfoRef signerinfo
, /*SECOidTag oidtag*/
215 SecAsn1Item
*oid
, SecAsn1Item
*value
, bool encoded
)
217 PLArenaPool
*poolp
= signerinfo
->signedData
->contentInfo
.cmsg
->poolp
;
218 PORT_Assert (poolp
!= NULL
);
219 void *mark
= PORT_ArenaMark (poolp
);
221 SecCmsAttribute
*attr
= make_attr(poolp
, oid
, value
, encoded
);
222 if (!attr
|| SecCmsAttributeArrayAddAttr(poolp
, &(signerinfo
->authAttr
), attr
) != SECSuccess
)
225 PORT_ArenaUnmark (poolp
, mark
);
229 PORT_Assert (mark
!= NULL
);
230 PORT_ArenaRelease (poolp
, mark
);
234 static void sign_all_attributes(const void *key
, const void *value
, void *context
)
236 SecAsn1Item oid
= { CFDataGetLength(key
), (uint8_t*)CFDataGetBytePtr(key
) },
237 oid_value
= { CFDataGetLength(value
), (uint8_t*)CFDataGetBytePtr(value
) };
239 signerinfo_add_auth_attr((SecCmsSignerInfoRef
)context
, &oid
, &oid_value
, true);
243 static void enveloped_data_add_unprotected_attr(SecCmsEnvelopedDataRef envd
,
244 SecAsn1Item
*oid
, SecAsn1Item
*value
, bool encoded
)
246 PLArenaPool
*poolp
= envd
->contentInfo
.cmsg
->poolp
;
247 PORT_Assert (poolp
!= NULL
);
248 void *mark
= PORT_ArenaMark (poolp
);
249 SecCmsAttribute
*attr
= make_attr(poolp
, oid
, value
, encoded
);
251 if (!attr
|| SecCmsAttributeArrayAddAttr(
253 &(envd
->unprotectedAttr
), attr
) != SECSuccess
)
256 PORT_ArenaUnmark (poolp
, mark
);
260 PORT_Assert (mark
!= NULL
);
261 PORT_ArenaRelease (poolp
, mark
);
267 static OSStatus
SecCMSSignDataOrDigestAndAttributes(SecIdentityRef identity
,
268 CFDataRef data
, bool detached
, bool data_is_digest
, SECOidTag sign_algorithm
,
269 CFMutableDataRef signed_data
, CFDictionaryRef signed_attributes
, SecCmsCertChainMode chainMode
, CFArrayRef additional_certs
)
271 SecCmsMessageRef cmsg
= NULL
;
272 SecCmsContentInfoRef cinfo
;
273 SecCmsSignedDataRef sigd
= NULL
;
274 SecCmsSignerInfoRef signerinfo
;
275 OSStatus status
= errSecParam
;
277 require(!data_is_digest
|| detached
/* if digest, must be detached */, out
);
279 require(cmsg
= SecCmsMessageCreate(), out
);
280 require(sigd
= SecCmsSignedDataCreate(cmsg
), out
);
281 require(cinfo
= SecCmsMessageGetContentInfo(cmsg
), out
);
282 require_noerr(SecCmsContentInfoSetContentSignedData(cinfo
, sigd
), out
);
283 require(cinfo
= SecCmsSignedDataGetContentInfo(sigd
), out
);
284 require_noerr(SecCmsContentInfoSetContentData(cinfo
, NULL
, detached
), out
);
285 require(signerinfo
= SecCmsSignerInfoCreate(sigd
, identity
, sign_algorithm
), out
);
286 if (additional_certs
)
287 require_noerr(SecCmsSignedDataAddCertList(sigd
, additional_certs
), out
);
288 require_noerr(SecCmsSignerInfoIncludeCerts(signerinfo
, chainMode
, certUsageAnyCA
), out
);
289 require_noerr(SecCmsSignerInfoAddSigningTime(signerinfo
, CFAbsoluteTimeGetCurrent()), out
);
291 if (signed_attributes
)
292 CFDictionaryApplyFunction(signed_attributes
, sign_all_attributes
, signerinfo
);
294 SecAsn1Item input
= {};
296 input
.Length
= CFDataGetLength(data
);
297 input
.Data
= (uint8_t*)CFDataGetBytePtr(data
);
299 if (data_is_digest
) {
300 require_noerr(SecCmsSignedDataSetDigestValue(sigd
, sign_algorithm
, &input
), out
);
301 require_noerr(SecCmsMessageEncode(cmsg
, NULL
, signed_data
), out
);
304 require_noerr(SecCmsMessageEncode(cmsg
, (data
&& input
.Length
) ? &input
: NULL
, signed_data
), out
);
306 status
= errSecSuccess
;
308 if (cmsg
) SecCmsMessageDestroy(cmsg
);
312 OSStatus
SecCMSSignDataAndAttributes(SecIdentityRef identity
, CFDataRef data
, bool detached
,
313 CFMutableDataRef signed_data
, CFDictionaryRef signed_attributes
)
315 return SecCMSSignDataOrDigestAndAttributes(identity
, data
, detached
, false, SEC_OID_SHA1
,
316 signed_data
, signed_attributes
, SecCmsCMCertChain
, NULL
);
319 OSStatus
SecCMSSignDigestAndAttributes(SecIdentityRef identity
, CFDataRef digest
,
320 CFMutableDataRef signed_data
, CFDictionaryRef signed_attributes
)
322 return SecCMSSignDataOrDigestAndAttributes(identity
, digest
, true, true, SEC_OID_SHA1
,
323 signed_data
, signed_attributes
, SecCmsCMCertChain
, NULL
);
327 OSStatus
SecCMSCreateSignedData(SecIdentityRef identity
, CFDataRef data
,
328 CFDictionaryRef parameters
, CFDictionaryRef signed_attributes
,
329 CFMutableDataRef signed_data
)
331 bool is_digest
= false, is_detached
= false;
332 CFStringRef algorithm_name
= NULL
;
333 SecCmsCertChainMode chain_mode
= SecCmsCMCertChain
;
334 CFArrayRef additional_certs
= NULL
;
337 is_digest
= CFDictionaryGetValueIfPresent(parameters
,
338 kSecCMSSignDigest
, NULL
);
339 is_detached
= CFDictionaryGetValueIfPresent(parameters
,
340 kSecCMSSignDetached
, NULL
);
341 algorithm_name
= CFDictionaryGetValue(parameters
,
342 kSecCMSSignHashAlgorithm
);
344 CFTypeRef chain_mode_param
= CFDictionaryGetValue(parameters
, kSecCMSCertChainMode
);
345 if (chain_mode_param
&& (CFGetTypeID(chain_mode_param
) == CFStringGetTypeID()))
346 chain_mode
= CFStringGetIntValue(chain_mode_param
);
348 CFTypeRef additional_certs_param
= CFDictionaryGetValue(parameters
, kSecCMSAdditionalCerts
);
349 if (additional_certs_param
&& (CFGetTypeID(additional_certs_param
) == CFArrayGetTypeID()))
350 additional_certs
= (CFArrayRef
)additional_certs_param
;
353 SECOidTag algorithm
= SEC_OID_SHA1
;
354 if (algorithm_name
) {
355 if (CFEqual(kSecCMSHashingAlgorithmSHA1
, algorithm_name
)) {
356 algorithm
= SEC_OID_SHA1
;
357 } else if (CFEqual(kSecCMSHashingAlgorithmSHA256
, algorithm_name
)) {
358 algorithm
= SEC_OID_SHA256
;
359 } else if (CFEqual(kSecCMSHashingAlgorithmSHA384
, algorithm_name
)) {
360 algorithm
= SEC_OID_SHA384
;
361 } else if (CFEqual(kSecCMSHashingAlgorithmSHA512
, algorithm_name
)) {
362 algorithm
= SEC_OID_SHA512
;
364 // signing with MD5 is no longer allowed
365 algorithm
= SEC_OID_UNKNOWN
;
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 *signed_attributes
= attrs
;
517 CFReleaseSafe(certs
);
522 if (cmsg
) SecCmsMessageDestroy(cmsg
);
526 OSStatus
SecCMSVerifyCopyDataAndAttributes(CFDataRef message
, CFDataRef detached_contents
,
527 CFTypeRef policy
, SecTrustRef
*trustref
,
528 CFDataRef
*attached_contents
, CFDictionaryRef
*signed_attributes
)
530 OSStatus status
= SecCMSVerifySignedData_internal(message
, detached_contents
, policy
, trustref
, NULL
, attached_contents
, signed_attributes
);
535 OSStatus
SecCMSVerifySignedData(CFDataRef message
, CFDataRef detached_contents
,
536 CFTypeRef policy
, SecTrustRef
*trustref
, CFArrayRef additional_certificates
,
537 CFDataRef
*attached_contents
, CFDictionaryRef
*message_attributes
)
539 CFDictionaryRef signed_attributes
= NULL
;
540 OSStatus status
= SecCMSVerifySignedData_internal(message
, detached_contents
, policy
, trustref
, additional_certificates
, attached_contents
, &signed_attributes
);
541 if (!status
&& signed_attributes
&& message_attributes
) {
542 *message_attributes
= CFDictionaryCreate(kCFAllocatorDefault
, &kSecCMSSignedAttributes
, (const void **)&signed_attributes
, 1, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
544 CFReleaseSafe(signed_attributes
);
549 OSStatus
SecCMSVerify(CFDataRef message
, CFDataRef detached_contents
,
550 CFTypeRef policy
, SecTrustRef
*trustref
,
551 CFDataRef
*attached_contents
) {
552 return SecCMSVerifySignedData_internal(message
, detached_contents
, policy
, trustref
, NULL
, attached_contents
, NULL
);
555 CFArrayRef
SecCMSCertificatesOnlyMessageCopyCertificates(CFDataRef message
) {
556 SecCmsMessageRef cmsg
= NULL
;
557 SecCmsContentInfoRef cinfo
;
558 SecCmsSignedDataRef sigd
= NULL
;
559 CFMutableArrayRef certs
= NULL
;
561 SecAsn1Item encoded_message
= { CFDataGetLength(message
), (uint8_t*)CFDataGetBytePtr(message
) };
562 require_noerr_quiet(SecCmsMessageDecode(&encoded_message
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, &cmsg
), out
);
563 /* expected to be a signed data message at the top level */
564 require(cinfo
= SecCmsMessageContentLevel(cmsg
, 0), out
);
565 require(SecCmsContentInfoGetContentTypeTag(cinfo
) == SEC_OID_PKCS7_SIGNED_DATA
, out
);
566 require(sigd
= (SecCmsSignedDataRef
)SecCmsContentInfoGetContent(cinfo
), out
);
568 /* find out about signers */
569 int nsigners
= SecCmsSignedDataSignerInfoCount(sigd
);
570 require(nsigners
== 0, out
);
572 SecAsn1Item
**cert_datas
= SecCmsSignedDataGetCertificateList(sigd
);
573 certs
= CFArrayCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeArrayCallBacks
);
574 SecAsn1Item
*cert_data
;
575 if (cert_datas
) while ((cert_data
= *cert_datas
) != NULL
) {
576 SecCertificateRef cert
= SecCertificateCreateWithBytes(NULL
, cert_data
->Data
, cert_data
->Length
);
578 CFArrayAppendValue(certs
, cert
);
586 SecCmsMessageDestroy(cmsg
);
592 extern const SecAsn1Template SecCmsMessageTemplate
[];
594 CFDataRef
SecCMSCreateCertificatesOnlyMessage(CFTypeRef cert_or_array_thereof
) {
595 OSStatus status
= errSecParam
;
596 SecCmsMessageRef cmsg
= NULL
;
597 SecCmsContentInfoRef cinfo
;
598 SecCmsSignedDataRef sigd
= NULL
;
599 CFMutableDataRef cert_only_signed_data
= NULL
;
600 CFArrayRef cert_array
= NULL
;
601 CFIndex cert_array_count
= 0;
602 SecCertificateRef cert
= NULL
;
604 require(cert_or_array_thereof
, out
);
606 require(cmsg
= SecCmsMessageCreate(), out
);
607 require(sigd
= SecCmsSignedDataCreate(cmsg
), out
);
608 require_noerr(SecCmsContentInfoSetContentData(&(sigd
->contentInfo
), NULL
, PR_TRUE
), out
);
609 require(cinfo
= SecCmsMessageGetContentInfo(cmsg
), out
);
610 require_noerr(SecCmsContentInfoSetContentSignedData(cinfo
, sigd
), out
);
611 long version
= SEC_CMS_SIGNED_DATA_VERSION_BASIC
;
612 require(SEC_ASN1EncodeInteger(cmsg
->poolp
, &(sigd
->version
), version
), out
);
614 if (CFGetTypeID(cert_or_array_thereof
) == SecCertificateGetTypeID()) {
615 cert_array
= CFArrayCreate(kCFAllocatorDefault
, &cert_or_array_thereof
, 1, &kCFTypeArrayCallBacks
);
616 } else if (CFGetTypeID(cert_or_array_thereof
) == CFArrayGetTypeID()) {
617 cert_array
= CFArrayCreateCopy(kCFAllocatorDefault
, (CFArrayRef
)cert_or_array_thereof
);
620 require(cert_array
, out
);
621 cert_array_count
= CFArrayGetCount(cert_array
);
622 require(cert_array_count
> 0, out
);
624 sigd
->rawCerts
= (SecAsn1Item
* *)PORT_ArenaAlloc(cmsg
->poolp
, (cert_array_count
+ 1) * sizeof(SecAsn1Item
*));
625 require(sigd
->rawCerts
, out
);
627 for (ix
= 0; ix
< cert_array_count
; ix
++) {
628 cert
= (SecCertificateRef
)CFArrayGetValueAtIndex(cert_array
, ix
);
631 sigd
->rawCerts
[ix
] = PORT_ArenaZAlloc(cmsg
->poolp
, sizeof(SecAsn1Item
));
632 SecAsn1Item cert_data
= { SecCertificateGetLength(cert
),
633 (uint8_t *)SecCertificateGetBytePtr(cert
) };
634 *(sigd
->rawCerts
[ix
]) = cert_data
;
636 sigd
->rawCerts
[ix
] = NULL
;
638 /* this is a SET OF, so we need to sort them guys - we have the DER already, though */
639 if (cert_array_count
> 1)
640 SecCmsArraySort((void **)sigd
->rawCerts
, SecCmsUtilDERCompare
, NULL
, NULL
);
642 cert_only_signed_data
= CFDataCreateMutable(kCFAllocatorDefault
, 0);
643 SecAsn1Item cert_only_signed_data_item
= {};
644 require_quiet(SEC_ASN1EncodeItem(cmsg
->poolp
, &cert_only_signed_data_item
,
645 cmsg
, SecCmsMessageTemplate
), out
);
646 CFDataAppendBytes(cert_only_signed_data
, cert_only_signed_data_item
.Data
,
647 cert_only_signed_data_item
.Length
);
649 status
= errSecSuccess
;
651 CFReleaseSafe(cert_array
);
652 if (status
) CFReleaseSafe(cert_only_signed_data
);
653 if (cmsg
) SecCmsMessageDestroy(cmsg
);
654 return cert_only_signed_data
;
657 CFDataRef
SecCMSCreateCertificatesOnlyMessageIAP(SecCertificateRef cert
)
659 static const uint8_t header
[] = {
660 0x30, 0x82, 0x03, 0x6d, 0x06, 0x09, 0x2a, 0x86,
661 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x02, 0xa0,
662 0x82, 0x03, 0x5e, 0x30, 0x82, 0x03, 0x5a, 0x02,
663 0x01, 0x01, 0x31, 0x00, 0x30, 0x0b, 0x06, 0x09,
664 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07,
665 0x01, 0xa0, 0x82, 0x03, 0x40
668 static const uint8_t trailer
[] = {
669 0xa1, 0x00, 0x31, 0x00
672 CFMutableDataRef message
= NULL
;
674 const uint8_t *certbytes
;
676 uint8_t *messagebytes
;
679 certdata
= SecCertificateCopyData(cert
);
680 require(certdata
, out
);
682 certbytes
= CFDataGetBytePtr(certdata
);
683 certlen
= CFDataGetLength(certdata
);
684 require(certlen
> UINT8_MAX
, out
);
685 require(certlen
< UINT16_MAX
, out
);
687 message
= CFDataCreateMutable(kCFAllocatorDefault
, 0);
688 require(message
, out
);
690 CFDataAppendBytes(message
, header
, sizeof(header
));
691 CFDataAppendBytes(message
, certbytes
, certlen
);
692 CFDataAppendBytes(message
, trailer
, sizeof(trailer
));
694 messagebytes
= CFDataGetMutableBytePtr(message
);
695 messagelen
= CFDataGetLength(message
);
698 messagebytes
[2] = messagelen
>> 8;
699 messagebytes
[3] = messagelen
& 0xFF;
702 messagebytes
[17] = messagelen
>> 8;
703 messagebytes
[18] = messagelen
& 0xFF;
706 messagebytes
[21] = messagelen
>> 8;
707 messagebytes
[22] = messagelen
& 0xFF;
710 messagebytes
[43] = messagelen
>> 8;
711 messagebytes
[44] = messagelen
& 0xFF;
714 CFReleaseSafe(certdata
);
718 #endif /* ENABLE_CMS */