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");
80 CFTypeRef kSecCMSBulkEncryptionAlgorithm
= CFSTR("kSecCMSBulkEncryptionAlgorithm");
81 CFTypeRef kSecCMSEncryptionAlgorithmDESCBC
= CFSTR("kSecCMSEncryptionAlgorithmDESCBC");
82 CFTypeRef kSecCMSEncryptionAlgorithmAESCBC
= CFSTR("kSecCMSEncryptionAlgorithmAESCBC");
84 CFTypeRef kSecCMSSignHashAlgorithm
= CFSTR("kSecCMSSignHashAlgorithm");
85 CFTypeRef kSecCMSHashingAlgorithmMD5
= CFSTR("kSecCMSHashingAlgorithmMD5");
86 CFTypeRef kSecCMSHashingAlgorithmSHA1
= CFSTR("kSecCMSHashingAlgorithmSHA1");
87 CFTypeRef kSecCMSHashingAlgorithmSHA256
= CFSTR("kSecCMSHashingAlgorithmSHA256");
88 CFTypeRef kSecCMSHashingAlgorithmSHA384
= CFSTR("kSecCMSHashingAlgorithmSHA384");
89 CFTypeRef kSecCMSHashingAlgorithmSHA512
= CFSTR("kSecCMSHashingAlgorithmSHA512");
91 OSStatus
SecCMSCreateEnvelopedData(CFTypeRef recipient_or_cfarray_thereof
,
92 CFDictionaryRef params
, CFDataRef data
, CFMutableDataRef enveloped_data
)
94 SecCmsMessageRef cmsg
= NULL
;
95 SecCmsContentInfoRef cinfo
;
96 SecCmsEnvelopedDataRef envd
= NULL
;
97 SECOidTag algorithmTag
= SEC_OID_DES_EDE3_CBC
;
99 OSStatus status
= errSecParam
;
102 CFStringRef algorithm_name
= CFDictionaryGetValue(params
, kSecCMSBulkEncryptionAlgorithm
);
103 if (algorithm_name
) {
104 if (CFEqual(kSecCMSEncryptionAlgorithmDESCBC
, algorithm_name
)) {
105 algorithmTag
= SEC_OID_DES_CBC
;
107 } else if (CFEqual(kSecCMSEncryptionAlgorithmAESCBC
, algorithm_name
)) {
108 algorithmTag
= SEC_OID_AES_128_CBC
;
114 require(cmsg
= SecCmsMessageCreate(), out
);
115 require(envd
= SecCmsEnvelopedDataCreate(cmsg
, algorithmTag
, keySize
), out
);
116 require(cinfo
= SecCmsMessageGetContentInfo(cmsg
), out
);
117 require_noerr(SecCmsContentInfoSetContentEnvelopedData(cinfo
, envd
), out
);
118 require(cinfo
= SecCmsEnvelopedDataGetContentInfo(envd
), out
);
119 require_noerr(SecCmsContentInfoSetContentData(cinfo
, NULL
, false), out
);
120 // == wrapper of: require(SECSuccess == SecCmsContentInfoSetContent(cinfo, SEC_OID_PKCS7_DATA, NULL), out);
122 if (CFGetTypeID(recipient_or_cfarray_thereof
) == CFArrayGetTypeID()) {
123 CFIndex dex
, numCerts
= CFArrayGetCount(recipient_or_cfarray_thereof
);
124 for(dex
=0; dex
<numCerts
; dex
++) {
125 SecCertificateRef recip
=
126 (SecCertificateRef
)CFArrayGetValueAtIndex(recipient_or_cfarray_thereof
, dex
);
127 SecCmsRecipientInfoRef rinfo
;
128 require(rinfo
= SecCmsRecipientInfoCreate(envd
, recip
), out
);
130 } else if (CFGetTypeID(recipient_or_cfarray_thereof
) == SecCertificateGetTypeID()) {
131 require(SecCmsRecipientInfoCreate(envd
, (SecCertificateRef
)recipient_or_cfarray_thereof
), out
);
135 SecAsn1Item input
= {};
137 input
.Length
= CFDataGetLength(data
);
138 input
.Data
= (uint8_t*)CFDataGetBytePtr(data
);
140 require_noerr(SecCmsMessageEncode(cmsg
, (data
&& input
.Length
) ? &input
: NULL
, enveloped_data
), out
);
142 status
= errSecSuccess
;
144 if (cmsg
) SecCmsMessageDestroy(cmsg
);
148 OSStatus
SecCMSDecryptEnvelopedData(CFDataRef message
,
149 CFMutableDataRef data
, SecCertificateRef
*recipient
)
151 SecCmsMessageRef cmsg
= NULL
;
152 SecCmsContentInfoRef cinfo
;
153 SecCmsEnvelopedDataRef envd
= NULL
;
154 SecCertificateRef used_recipient
= NULL
;
155 OSStatus status
= errSecParam
;
157 SecAsn1Item encoded_message
= { CFDataGetLength(message
), (uint8_t*)CFDataGetBytePtr(message
) };
158 require_noerr_action_quiet(SecCmsMessageDecode(&encoded_message
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, &cmsg
),
159 out
, status
= errSecDecode
);
160 require_quiet(cinfo
= SecCmsMessageContentLevel(cmsg
, 0), out
);
161 require_quiet(SecCmsContentInfoGetContentTypeTag(cinfo
) == SEC_OID_PKCS7_ENVELOPED_DATA
, out
);
162 require_quiet(envd
= (SecCmsEnvelopedDataRef
)SecCmsContentInfoGetContent(cinfo
), out
);
163 SecCmsRecipientInfoRef
*rinfo
= envd
->recipientInfos
;
164 while (!used_recipient
&& *rinfo
) {
165 used_recipient
= (*rinfo
)->cert
;
168 require_quiet(2 == SecCmsMessageContentLevelCount(cmsg
), out
);
169 require_quiet(cinfo
= SecCmsMessageContentLevel(cmsg
, 1), out
);
170 require_quiet(SecCmsContentInfoGetContentTypeTag(cinfo
) == SEC_OID_PKCS7_DATA
, out
);
171 const SecAsn1Item
*content
= SecCmsMessageGetContent(cmsg
);
173 CFDataAppendBytes(data
, content
->Data
, content
->Length
);
175 CFRetainSafe(used_recipient
);
176 *recipient
= used_recipient
;
178 status
= errSecSuccess
;
180 if (cmsg
) SecCmsMessageDestroy(cmsg
);
184 static SecCmsAttribute
*
185 make_attr(PLArenaPool
*poolp
, SecAsn1Item
*type
, SecAsn1Item
*value
, bool encoded
)
187 SecAsn1Item
* copiedvalue
;
188 SecCmsAttribute
*attr
= (SecCmsAttribute
*)PORT_ArenaZAlloc(poolp
, sizeof(SecCmsAttribute
));
192 if (SECITEM_CopyItem(poolp
, &(attr
->type
), type
) != SECSuccess
)
196 if ((copiedvalue
= SECITEM_AllocItem(poolp
, NULL
, value
->Length
)) == NULL
)
199 if (SECITEM_CopyItem(poolp
, copiedvalue
, value
) != SECSuccess
)
202 if (SecCmsArrayAdd(poolp
, (void ***)&(attr
->values
), (void *)copiedvalue
) != SECSuccess
)
206 attr
->encoded
= encoded
;
213 signerinfo_add_auth_attr(SecCmsSignerInfoRef signerinfo
, /*SECOidTag oidtag*/
214 SecAsn1Item
*oid
, SecAsn1Item
*value
, bool encoded
)
216 PLArenaPool
*poolp
= signerinfo
->signedData
->contentInfo
.cmsg
->poolp
;
217 PORT_Assert (poolp
!= NULL
);
218 void *mark
= PORT_ArenaMark (poolp
);
220 SecCmsAttribute
*attr
= make_attr(poolp
, oid
, value
, encoded
);
221 if (!attr
|| SecCmsAttributeArrayAddAttr(poolp
, &(signerinfo
->authAttr
), attr
) != SECSuccess
)
224 PORT_ArenaUnmark (poolp
, mark
);
228 PORT_Assert (mark
!= NULL
);
229 PORT_ArenaRelease (poolp
, mark
);
233 static void sign_all_attributes(const void *key
, const void *value
, void *context
)
235 SecAsn1Item oid
= { CFDataGetLength(key
), (uint8_t*)CFDataGetBytePtr(key
) },
236 oid_value
= { CFDataGetLength(value
), (uint8_t*)CFDataGetBytePtr(value
) };
238 signerinfo_add_auth_attr((SecCmsSignerInfoRef
)context
, &oid
, &oid_value
, true);
242 static void enveloped_data_add_unprotected_attr(SecCmsEnvelopedDataRef envd
,
243 SecAsn1Item
*oid
, SecAsn1Item
*value
, bool encoded
)
245 PLArenaPool
*poolp
= envd
->contentInfo
.cmsg
->poolp
;
246 PORT_Assert (poolp
!= NULL
);
247 void *mark
= PORT_ArenaMark (poolp
);
248 SecCmsAttribute
*attr
= make_attr(poolp
, oid
, value
, encoded
);
250 if (!attr
|| SecCmsAttributeArrayAddAttr(
252 &(envd
->unprotectedAttr
), attr
) != SECSuccess
)
255 PORT_ArenaUnmark (poolp
, mark
);
259 PORT_Assert (mark
!= NULL
);
260 PORT_ArenaRelease (poolp
, mark
);
266 static OSStatus
SecCMSSignDataOrDigestAndAttributes(SecIdentityRef identity
,
267 CFDataRef data
, bool detached
, bool data_is_digest
, SECOidTag sign_algorithm
,
268 CFMutableDataRef signed_data
, CFDictionaryRef signed_attributes
, SecCmsCertChainMode chainMode
, CFArrayRef additional_certs
)
270 SecCmsMessageRef cmsg
= NULL
;
271 SecCmsContentInfoRef cinfo
;
272 SecCmsSignedDataRef sigd
= NULL
;
273 SecCmsSignerInfoRef signerinfo
;
274 OSStatus status
= errSecParam
;
276 require(!data_is_digest
|| detached
/* if digest, must be detached */, out
);
278 require(cmsg
= SecCmsMessageCreate(), out
);
279 require(sigd
= SecCmsSignedDataCreate(cmsg
), out
);
280 require(cinfo
= SecCmsMessageGetContentInfo(cmsg
), out
);
281 require_noerr(SecCmsContentInfoSetContentSignedData(cinfo
, sigd
), out
);
282 require(cinfo
= SecCmsSignedDataGetContentInfo(sigd
), out
);
283 require_noerr(SecCmsContentInfoSetContentData(cinfo
, NULL
, detached
), out
);
284 require(signerinfo
= SecCmsSignerInfoCreate(sigd
, identity
, sign_algorithm
), out
);
285 if (additional_certs
)
286 require_noerr(SecCmsSignedDataAddCertList(sigd
, additional_certs
), out
);
287 require_noerr(SecCmsSignerInfoIncludeCerts(signerinfo
, chainMode
, certUsageAnyCA
), out
);
288 require_noerr(SecCmsSignerInfoAddSigningTime(signerinfo
, CFAbsoluteTimeGetCurrent()), out
);
290 if (signed_attributes
)
291 CFDictionaryApplyFunction(signed_attributes
, sign_all_attributes
, signerinfo
);
293 SecAsn1Item input
= {};
295 input
.Length
= CFDataGetLength(data
);
296 input
.Data
= (uint8_t*)CFDataGetBytePtr(data
);
298 if (data_is_digest
) {
299 require_noerr(SecCmsSignedDataSetDigestValue(sigd
, sign_algorithm
, &input
), out
);
300 require_noerr(SecCmsMessageEncode(cmsg
, NULL
, signed_data
), out
);
303 require_noerr(SecCmsMessageEncode(cmsg
, (data
&& input
.Length
) ? &input
: NULL
, signed_data
), out
);
305 status
= errSecSuccess
;
307 if (cmsg
) SecCmsMessageDestroy(cmsg
);
311 OSStatus
SecCMSSignDataAndAttributes(SecIdentityRef identity
, CFDataRef data
, bool detached
,
312 CFMutableDataRef signed_data
, CFDictionaryRef signed_attributes
)
314 return SecCMSSignDataOrDigestAndAttributes(identity
, data
, detached
, false, SEC_OID_SHA1
,
315 signed_data
, signed_attributes
, SecCmsCMCertChain
, NULL
);
318 OSStatus
SecCMSSignDigestAndAttributes(SecIdentityRef identity
, CFDataRef digest
,
319 CFMutableDataRef signed_data
, CFDictionaryRef signed_attributes
)
321 return SecCMSSignDataOrDigestAndAttributes(identity
, digest
, true, true, SEC_OID_SHA1
,
322 signed_data
, signed_attributes
, SecCmsCMCertChain
, NULL
);
326 OSStatus
SecCMSCreateSignedData(SecIdentityRef identity
, CFDataRef data
,
327 CFDictionaryRef parameters
, CFDictionaryRef signed_attributes
,
328 CFMutableDataRef signed_data
)
330 bool is_digest
= false, is_detached
= false;
331 CFStringRef algorithm_name
= NULL
;
332 SecCmsCertChainMode chain_mode
= SecCmsCMCertChain
;
333 CFArrayRef additional_certs
= NULL
;
336 is_digest
= CFDictionaryGetValueIfPresent(parameters
,
337 kSecCMSSignDigest
, NULL
);
338 is_detached
= CFDictionaryGetValueIfPresent(parameters
,
339 kSecCMSSignDetached
, NULL
);
340 algorithm_name
= CFDictionaryGetValue(parameters
,
341 kSecCMSSignHashAlgorithm
);
343 CFTypeRef chain_mode_param
= CFDictionaryGetValue(parameters
, kSecCMSCertChainMode
);
344 if (chain_mode_param
&& (CFGetTypeID(chain_mode_param
) == CFStringGetTypeID()))
345 chain_mode
= CFStringGetIntValue(chain_mode_param
);
347 CFTypeRef additional_certs_param
= CFDictionaryGetValue(parameters
, kSecCMSAdditionalCerts
);
348 if (additional_certs_param
&& (CFGetTypeID(additional_certs_param
) == CFArrayGetTypeID()))
349 additional_certs
= (CFArrayRef
)additional_certs_param
;
352 SECOidTag algorithm
= SEC_OID_SHA1
;
353 if (algorithm_name
) {
354 if (CFEqual(kSecCMSHashingAlgorithmSHA1
, algorithm_name
)) {
355 algorithm
= SEC_OID_SHA1
;
356 } else if (CFEqual(kSecCMSHashingAlgorithmSHA256
, algorithm_name
)) {
357 algorithm
= SEC_OID_SHA256
;
358 } else if (CFEqual(kSecCMSHashingAlgorithmSHA384
, algorithm_name
)) {
359 algorithm
= SEC_OID_SHA384
;
360 } else if (CFEqual(kSecCMSHashingAlgorithmSHA512
, algorithm_name
)) {
361 algorithm
= SEC_OID_SHA512
;
363 // signing with MD5 is no longer allowed
364 algorithm
= SEC_OID_UNKNOWN
;
368 return SecCMSSignDataOrDigestAndAttributes(identity
, data
,
369 is_detached
, is_digest
, algorithm
,
370 signed_data
, signed_attributes
, chain_mode
, additional_certs
);
374 static CFMutableArrayRef
copy_signed_attribute_values(SecCmsAttribute
*attr
)
376 CFMutableArrayRef array
= CFArrayCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeArrayCallBacks
);
377 SecAsn1Item
**item
= attr
->values
;
378 if (item
) while (*item
) {
379 CFDataRef asn1data
= CFDataCreate(kCFAllocatorDefault
, (*item
)->Data
, (*item
)->Length
);
381 CFArrayAppendValue(array
, asn1data
);
389 static OSStatus
SecCMSVerifySignedData_internal(CFDataRef message
, CFDataRef detached_contents
,
390 CFTypeRef policy
, SecTrustRef
*trustref
, CFArrayRef additional_certs
,
391 CFDataRef
*attached_contents
, CFDictionaryRef
*signed_attributes
)
393 SecCmsMessageRef cmsg
= NULL
;
394 SecCmsContentInfoRef cinfo
;
395 SecCmsSignedDataRef sigd
= NULL
;
396 OSStatus status
= errSecParam
;
398 require(message
, out
);
399 SecAsn1Item encoded_message
= { CFDataGetLength(message
), (uint8_t*)CFDataGetBytePtr(message
) };
400 require_noerr_action_quiet(SecCmsMessageDecode(&encoded_message
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, &cmsg
),
401 out
, status
= errSecDecode
);
402 /* expected to be a signed data message at the top level */
403 require_quiet(cinfo
= SecCmsMessageContentLevel(cmsg
, 0), out
);
404 require_quiet(SecCmsContentInfoGetContentTypeTag(cinfo
) == SEC_OID_PKCS7_SIGNED_DATA
, out
);
405 require_quiet(sigd
= (SecCmsSignedDataRef
)SecCmsContentInfoGetContent(cinfo
), out
);
407 if (detached_contents
)
409 require_quiet(!SecCmsSignedDataHasDigests(sigd
), out
);
410 SECAlgorithmID
**digestalgs
= SecCmsSignedDataGetDigestAlgs(sigd
);
411 SecCmsDigestContextRef digcx
= SecCmsDigestContextStartMultiple(digestalgs
);
412 SecCmsDigestContextUpdate(digcx
, CFDataGetBytePtr(detached_contents
), CFDataGetLength(detached_contents
));
413 SecCmsSignedDataSetDigestContext(sigd
, digcx
);
414 SecCmsDigestContextDestroy(digcx
);
417 if (additional_certs
)
418 require_noerr_quiet(SecCmsSignedDataAddCertList(sigd
, additional_certs
), out
);
420 if (policy
) { /* if no policy is given skip verification */
421 /* find out about signers */
422 int nsigners
= SecCmsSignedDataSignerInfoCount(sigd
);
423 require_quiet(nsigners
== 1, out
);
424 require_noerr_action_quiet(SecCmsSignedDataVerifySignerInfo(sigd
, 0, NULL
, policy
, trustref
),
425 out
, status
= errSecAuthFailed
);
430 trustrefs
= CFArrayCreateMutable(kCFAllocatorDefault
, nsigners
, &kCFTypeArrayCallBacks
);
433 for (j
= 0; j
< nsigners
; j
++)
435 SecTrustRef trustRef
;
436 require_noerr_action_quiet(SecCmsSignedDataVerifySignerInfo(sigd
, j
, NULL
, policy
, &trustRef
),
437 out
, status
= errSecAuthFailed
);
438 if ((j
== 0) && (nsigners
== 1))
439 *trustref_or_cfarray_thereof
= trustRef
;
441 CFArrayAppendValue(trustrefs
, trustRef
);
445 *trustref_or_cfarray_thereof
= trustrefs
;
449 status
= errSecSuccess
;
451 if (attached_contents
) {
452 const SecAsn1Item
*content
= SecCmsMessageGetContent(cmsg
);
454 *attached_contents
= CFDataCreate(kCFAllocatorDefault
, content
->Data
, content
->Length
);
456 *attached_contents
= NULL
;
459 if (signed_attributes
) {
460 CFMutableDictionaryRef attrs
= CFDictionaryCreateMutable(kCFAllocatorDefault
,
461 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
462 require_quiet(attrs
, out
);
463 SecCmsAttribute
**signed_attrs
= sigd
->signerInfos
[0]->authAttr
;
464 if (signed_attrs
) while (*signed_attrs
) {
465 CFDataRef type
= CFDataCreate(kCFAllocatorDefault
, (*signed_attrs
)->type
.Data
, (*signed_attrs
)->type
.Length
);
467 CFMutableArrayRef attr
= copy_signed_attribute_values(*signed_attrs
);
469 CFMutableArrayRef existing_attrs
= (CFMutableArrayRef
)CFDictionaryGetValue(attrs
, type
);
470 if (existing_attrs
) {
471 CFIndex count
= CFArrayGetCount(attr
);
473 CFArrayAppendArray(existing_attrs
, attr
, CFRangeMake(0, count
));
475 CFDictionarySetValue(attrs
, type
, attr
);
482 CFMutableArrayRef certs
= NULL
;
484 SecAsn1Item
**cert_datas
= SecCmsSignedDataGetCertificateList(sigd
);
485 certs
= CFArrayCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeArrayCallBacks
);
486 SecAsn1Item
*cert_data
;
487 if (cert_datas
) while ((cert_data
= *cert_datas
) != NULL
) {
488 SecCertificateRef cert
= SecCertificateCreateWithBytes(NULL
, cert_data
->Data
, cert_data
->Length
);
490 CFArrayAppendValue(certs
, cert
);
496 CFDictionaryAddValue(attrs
, kSecCMSAllCerts
, certs
);
498 /* Add "cooked" values separately */
499 CFAbsoluteTime signing_time
;
500 if (errSecSuccess
== SecCmsSignerInfoGetSigningTime(sigd
->signerInfos
[0], &signing_time
)) {
501 CFDateRef signing_date
= CFDateCreate(kCFAllocatorDefault
, signing_time
);
503 CFDictionarySetValue(attrs
, kSecCMSSignDate
, signing_date
);
504 CFReleaseSafe(signing_date
);
508 *signed_attributes
= attrs
;
509 CFReleaseSafe(certs
);
514 if (cmsg
) SecCmsMessageDestroy(cmsg
);
518 OSStatus
SecCMSVerifyCopyDataAndAttributes(CFDataRef message
, CFDataRef detached_contents
,
519 CFTypeRef policy
, SecTrustRef
*trustref
,
520 CFDataRef
*attached_contents
, CFDictionaryRef
*signed_attributes
)
522 OSStatus status
= SecCMSVerifySignedData_internal(message
, detached_contents
, policy
, trustref
, NULL
, attached_contents
, signed_attributes
);
527 OSStatus
SecCMSVerifySignedData(CFDataRef message
, CFDataRef detached_contents
,
528 CFTypeRef policy
, SecTrustRef
*trustref
, CFArrayRef additional_certificates
,
529 CFDataRef
*attached_contents
, CFDictionaryRef
*message_attributes
)
531 CFDictionaryRef signed_attributes
= NULL
;
532 OSStatus status
= SecCMSVerifySignedData_internal(message
, detached_contents
, policy
, trustref
, additional_certificates
, attached_contents
, &signed_attributes
);
533 if (!status
&& signed_attributes
&& message_attributes
) {
534 *message_attributes
= CFDictionaryCreate(kCFAllocatorDefault
, &kSecCMSSignedAttributes
, (const void **)&signed_attributes
, 1, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
536 CFReleaseSafe(signed_attributes
);
541 OSStatus
SecCMSVerify(CFDataRef message
, CFDataRef detached_contents
,
542 CFTypeRef policy
, SecTrustRef
*trustref
,
543 CFDataRef
*attached_contents
) {
544 return SecCMSVerifySignedData_internal(message
, detached_contents
, policy
, trustref
, NULL
, attached_contents
, NULL
);
547 CFArrayRef
SecCMSCertificatesOnlyMessageCopyCertificates(CFDataRef message
) {
548 SecCmsMessageRef cmsg
= NULL
;
549 SecCmsContentInfoRef cinfo
;
550 SecCmsSignedDataRef sigd
= NULL
;
551 CFMutableArrayRef certs
= NULL
;
553 SecAsn1Item encoded_message
= { CFDataGetLength(message
), (uint8_t*)CFDataGetBytePtr(message
) };
554 require_noerr_quiet(SecCmsMessageDecode(&encoded_message
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, &cmsg
), out
);
555 /* expected to be a signed data message at the top level */
556 require(cinfo
= SecCmsMessageContentLevel(cmsg
, 0), out
);
557 require(SecCmsContentInfoGetContentTypeTag(cinfo
) == SEC_OID_PKCS7_SIGNED_DATA
, out
);
558 require(sigd
= (SecCmsSignedDataRef
)SecCmsContentInfoGetContent(cinfo
), out
);
560 /* find out about signers */
561 int nsigners
= SecCmsSignedDataSignerInfoCount(sigd
);
562 require(nsigners
== 0, out
);
564 SecAsn1Item
**cert_datas
= SecCmsSignedDataGetCertificateList(sigd
);
565 certs
= CFArrayCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeArrayCallBacks
);
566 SecAsn1Item
*cert_data
;
567 if (cert_datas
) while ((cert_data
= *cert_datas
) != NULL
) {
568 SecCertificateRef cert
= SecCertificateCreateWithBytes(NULL
, cert_data
->Data
, cert_data
->Length
);
570 CFArrayAppendValue(certs
, cert
);
578 SecCmsMessageDestroy(cmsg
);
584 extern const SecAsn1Template SecCmsMessageTemplate
[];
586 CFDataRef
SecCMSCreateCertificatesOnlyMessage(CFTypeRef cert_or_array_thereof
) {
587 OSStatus status
= errSecParam
;
588 SecCmsMessageRef cmsg
= NULL
;
589 SecCmsContentInfoRef cinfo
;
590 SecCmsSignedDataRef sigd
= NULL
;
591 CFMutableDataRef cert_only_signed_data
= NULL
;
592 CFArrayRef cert_array
= NULL
;
593 CFIndex cert_array_count
= 0;
594 SecCertificateRef cert
= NULL
;
596 require(cert_or_array_thereof
, out
);
598 require(cmsg
= SecCmsMessageCreate(), out
);
599 require(sigd
= SecCmsSignedDataCreate(cmsg
), out
);
600 require_noerr(SecCmsContentInfoSetContentData(&(sigd
->contentInfo
), NULL
, PR_TRUE
), out
);
601 require(cinfo
= SecCmsMessageGetContentInfo(cmsg
), out
);
602 require_noerr(SecCmsContentInfoSetContentSignedData(cinfo
, sigd
), out
);
603 long version
= SEC_CMS_SIGNED_DATA_VERSION_BASIC
;
604 require(SEC_ASN1EncodeInteger(cmsg
->poolp
, &(sigd
->version
), version
), out
);
606 if (CFGetTypeID(cert_or_array_thereof
) == SecCertificateGetTypeID()) {
607 cert_array
= CFArrayCreate(kCFAllocatorDefault
, &cert_or_array_thereof
, 1, &kCFTypeArrayCallBacks
);
608 } else if (CFGetTypeID(cert_or_array_thereof
) == CFArrayGetTypeID()) {
609 cert_array
= CFArrayCreateCopy(kCFAllocatorDefault
, (CFArrayRef
)cert_or_array_thereof
);
612 require(cert_array
, out
);
613 cert_array_count
= CFArrayGetCount(cert_array
);
614 require(cert_array_count
> 0, out
);
616 sigd
->rawCerts
= (SecAsn1Item
* *)PORT_ArenaAlloc(cmsg
->poolp
, (cert_array_count
+ 1) * sizeof(SecAsn1Item
*));
617 require(sigd
->rawCerts
, out
);
619 for (ix
= 0; ix
< cert_array_count
; ix
++) {
620 cert
= (SecCertificateRef
)CFArrayGetValueAtIndex(cert_array
, ix
);
623 sigd
->rawCerts
[ix
] = PORT_ArenaZAlloc(cmsg
->poolp
, sizeof(SecAsn1Item
));
624 SecAsn1Item cert_data
= { SecCertificateGetLength(cert
),
625 (uint8_t *)SecCertificateGetBytePtr(cert
) };
626 *(sigd
->rawCerts
[ix
]) = cert_data
;
628 sigd
->rawCerts
[ix
] = NULL
;
630 /* this is a SET OF, so we need to sort them guys - we have the DER already, though */
631 if (cert_array_count
> 1)
632 SecCmsArraySort((void **)sigd
->rawCerts
, SecCmsUtilDERCompare
, NULL
, NULL
);
634 cert_only_signed_data
= CFDataCreateMutable(kCFAllocatorDefault
, 0);
635 SecAsn1Item cert_only_signed_data_item
= {};
636 require_quiet(SEC_ASN1EncodeItem(cmsg
->poolp
, &cert_only_signed_data_item
,
637 cmsg
, SecCmsMessageTemplate
), out
);
638 CFDataAppendBytes(cert_only_signed_data
, cert_only_signed_data_item
.Data
,
639 cert_only_signed_data_item
.Length
);
641 status
= errSecSuccess
;
643 CFReleaseSafe(cert_array
);
644 if (status
) CFReleaseSafe(cert_only_signed_data
);
645 if (cmsg
) SecCmsMessageDestroy(cmsg
);
646 return cert_only_signed_data
;
649 CFDataRef
SecCMSCreateCertificatesOnlyMessageIAP(SecCertificateRef cert
)
651 static const uint8_t header
[] = {
652 0x30, 0x82, 0x03, 0x6d, 0x06, 0x09, 0x2a, 0x86,
653 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x02, 0xa0,
654 0x82, 0x03, 0x5e, 0x30, 0x82, 0x03, 0x5a, 0x02,
655 0x01, 0x01, 0x31, 0x00, 0x30, 0x0b, 0x06, 0x09,
656 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07,
657 0x01, 0xa0, 0x82, 0x03, 0x40
660 static const uint8_t trailer
[] = {
661 0xa1, 0x00, 0x31, 0x00
664 CFMutableDataRef message
= NULL
;
666 const uint8_t *certbytes
;
668 uint8_t *messagebytes
;
671 certdata
= SecCertificateCopyData(cert
);
672 require(certdata
, out
);
674 certbytes
= CFDataGetBytePtr(certdata
);
675 certlen
= CFDataGetLength(certdata
);
676 require(certlen
> UINT8_MAX
, out
);
677 require(certlen
< UINT16_MAX
, out
);
679 message
= CFDataCreateMutable(kCFAllocatorDefault
, 0);
680 require(message
, out
);
682 CFDataAppendBytes(message
, header
, sizeof(header
));
683 CFDataAppendBytes(message
, certbytes
, certlen
);
684 CFDataAppendBytes(message
, trailer
, sizeof(trailer
));
686 messagebytes
= CFDataGetMutableBytePtr(message
);
687 messagelen
= CFDataGetLength(message
);
690 messagebytes
[2] = messagelen
>> 8;
691 messagebytes
[3] = messagelen
& 0xFF;
694 messagebytes
[17] = messagelen
>> 8;
695 messagebytes
[18] = messagelen
& 0xFF;
698 messagebytes
[21] = messagelen
>> 8;
699 messagebytes
[22] = messagelen
& 0xFF;
702 messagebytes
[43] = messagelen
>> 8;
703 messagebytes
[44] = messagelen
& 0xFF;
706 CFReleaseSafe(certdata
);
710 #endif /* ENABLE_CMS */