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 SecAsn1Item encoded_message
= { CFDataGetLength(message
), (uint8_t*)CFDataGetBytePtr(message
) };
399 require_noerr_action_quiet(SecCmsMessageDecode(&encoded_message
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, &cmsg
),
400 out
, status
= errSecDecode
);
401 /* expected to be a signed data message at the top level */
402 require_quiet(cinfo
= SecCmsMessageContentLevel(cmsg
, 0), out
);
403 require_quiet(SecCmsContentInfoGetContentTypeTag(cinfo
) == SEC_OID_PKCS7_SIGNED_DATA
, out
);
404 require_quiet(sigd
= (SecCmsSignedDataRef
)SecCmsContentInfoGetContent(cinfo
), out
);
406 if (detached_contents
)
408 require_quiet(!SecCmsSignedDataHasDigests(sigd
), out
);
409 SECAlgorithmID
**digestalgs
= SecCmsSignedDataGetDigestAlgs(sigd
);
410 SecCmsDigestContextRef digcx
= SecCmsDigestContextStartMultiple(digestalgs
);
411 SecCmsDigestContextUpdate(digcx
, CFDataGetBytePtr(detached_contents
), CFDataGetLength(detached_contents
));
412 SecCmsSignedDataSetDigestContext(sigd
, digcx
);
413 SecCmsDigestContextDestroy(digcx
);
416 if (additional_certs
)
417 require_noerr_quiet(SecCmsSignedDataAddCertList(sigd
, additional_certs
), out
);
419 if (policy
) { /* if no policy is given skip verification */
420 /* find out about signers */
421 int nsigners
= SecCmsSignedDataSignerInfoCount(sigd
);
422 require_quiet(nsigners
== 1, out
);
423 require_noerr_action_quiet(SecCmsSignedDataVerifySignerInfo(sigd
, 0, NULL
, policy
, trustref
),
424 out
, status
= errSecAuthFailed
);
429 trustrefs
= CFArrayCreateMutable(kCFAllocatorDefault
, nsigners
, &kCFTypeArrayCallBacks
);
432 for (j
= 0; j
< nsigners
; j
++)
434 SecTrustRef trustRef
;
435 require_noerr_action_quiet(SecCmsSignedDataVerifySignerInfo(sigd
, j
, NULL
, policy
, &trustRef
),
436 out
, status
= errSecAuthFailed
);
437 if ((j
== 0) && (nsigners
== 1))
438 *trustref_or_cfarray_thereof
= trustRef
;
440 CFArrayAppendValue(trustrefs
, trustRef
);
444 *trustref_or_cfarray_thereof
= trustrefs
;
448 status
= errSecSuccess
;
450 if (attached_contents
) {
451 const SecAsn1Item
*content
= SecCmsMessageGetContent(cmsg
);
453 *attached_contents
= CFDataCreate(kCFAllocatorDefault
, content
->Data
, content
->Length
);
455 *attached_contents
= NULL
;
458 if (signed_attributes
) {
459 CFMutableDictionaryRef attrs
= CFDictionaryCreateMutable(kCFAllocatorDefault
,
460 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
461 require_quiet(attrs
, out
);
462 SecCmsAttribute
**signed_attrs
= sigd
->signerInfos
[0]->authAttr
;
463 if (signed_attrs
) while (*signed_attrs
) {
464 CFDataRef type
= CFDataCreate(kCFAllocatorDefault
, (*signed_attrs
)->type
.Data
, (*signed_attrs
)->type
.Length
);
466 CFMutableArrayRef attr
= copy_signed_attribute_values(*signed_attrs
);
468 CFMutableArrayRef existing_attrs
= (CFMutableArrayRef
)CFDictionaryGetValue(attrs
, type
);
469 if (existing_attrs
) {
470 CFIndex count
= CFArrayGetCount(attr
);
472 CFArrayAppendArray(existing_attrs
, attr
, CFRangeMake(0, count
));
474 CFDictionarySetValue(attrs
, type
, attr
);
481 CFMutableArrayRef certs
= NULL
;
483 SecAsn1Item
**cert_datas
= SecCmsSignedDataGetCertificateList(sigd
);
484 certs
= CFArrayCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeArrayCallBacks
);
485 SecAsn1Item
*cert_data
;
486 if (cert_datas
) while ((cert_data
= *cert_datas
) != NULL
) {
487 SecCertificateRef cert
= SecCertificateCreateWithBytes(NULL
, cert_data
->Data
, cert_data
->Length
);
489 CFArrayAppendValue(certs
, cert
);
495 CFDictionaryAddValue(attrs
, kSecCMSAllCerts
, certs
);
497 /* Add "cooked" values separately */
498 CFAbsoluteTime signing_time
;
499 if (errSecSuccess
== SecCmsSignerInfoGetSigningTime(sigd
->signerInfos
[0], &signing_time
)) {
500 CFDateRef signing_date
= CFDateCreate(kCFAllocatorDefault
, signing_time
);
502 CFDictionarySetValue(attrs
, kSecCMSSignDate
, signing_date
);
503 CFReleaseSafe(signing_date
);
507 *signed_attributes
= attrs
;
508 CFReleaseSafe(certs
);
513 if (cmsg
) SecCmsMessageDestroy(cmsg
);
517 OSStatus
SecCMSVerifyCopyDataAndAttributes(CFDataRef message
, CFDataRef detached_contents
,
518 CFTypeRef policy
, SecTrustRef
*trustref
,
519 CFDataRef
*attached_contents
, CFDictionaryRef
*signed_attributes
)
521 OSStatus status
= SecCMSVerifySignedData_internal(message
, detached_contents
, policy
, trustref
, NULL
, attached_contents
, signed_attributes
);
526 OSStatus
SecCMSVerifySignedData(CFDataRef message
, CFDataRef detached_contents
,
527 CFTypeRef policy
, SecTrustRef
*trustref
, CFArrayRef additional_certificates
,
528 CFDataRef
*attached_contents
, CFDictionaryRef
*message_attributes
)
530 CFDictionaryRef signed_attributes
= NULL
;
531 OSStatus status
= SecCMSVerifySignedData_internal(message
, detached_contents
, policy
, trustref
, additional_certificates
, attached_contents
, &signed_attributes
);
532 if (!status
&& signed_attributes
&& message_attributes
) {
533 *message_attributes
= CFDictionaryCreate(kCFAllocatorDefault
, &kSecCMSSignedAttributes
, (const void **)&signed_attributes
, 1, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
535 CFReleaseSafe(signed_attributes
);
540 OSStatus
SecCMSVerify(CFDataRef message
, CFDataRef detached_contents
,
541 CFTypeRef policy
, SecTrustRef
*trustref
,
542 CFDataRef
*attached_contents
) {
543 return SecCMSVerifySignedData_internal(message
, detached_contents
, policy
, trustref
, NULL
, attached_contents
, NULL
);
546 CFArrayRef
SecCMSCertificatesOnlyMessageCopyCertificates(CFDataRef message
) {
547 SecCmsMessageRef cmsg
= NULL
;
548 SecCmsContentInfoRef cinfo
;
549 SecCmsSignedDataRef sigd
= NULL
;
550 CFMutableArrayRef certs
= NULL
;
552 SecAsn1Item encoded_message
= { CFDataGetLength(message
), (uint8_t*)CFDataGetBytePtr(message
) };
553 require_noerr_quiet(SecCmsMessageDecode(&encoded_message
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, &cmsg
), out
);
554 /* expected to be a signed data message at the top level */
555 require(cinfo
= SecCmsMessageContentLevel(cmsg
, 0), out
);
556 require(SecCmsContentInfoGetContentTypeTag(cinfo
) == SEC_OID_PKCS7_SIGNED_DATA
, out
);
557 require(sigd
= (SecCmsSignedDataRef
)SecCmsContentInfoGetContent(cinfo
), out
);
559 /* find out about signers */
560 int nsigners
= SecCmsSignedDataSignerInfoCount(sigd
);
561 require(nsigners
== 0, out
);
563 SecAsn1Item
**cert_datas
= SecCmsSignedDataGetCertificateList(sigd
);
564 certs
= CFArrayCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeArrayCallBacks
);
565 SecAsn1Item
*cert_data
;
566 if (cert_datas
) while ((cert_data
= *cert_datas
) != NULL
) {
567 SecCertificateRef cert
= SecCertificateCreateWithBytes(NULL
, cert_data
->Data
, cert_data
->Length
);
569 CFArrayAppendValue(certs
, cert
);
577 SecCmsMessageDestroy(cmsg
);
583 extern const SecAsn1Template SecCmsMessageTemplate
[];
585 CFDataRef
SecCMSCreateCertificatesOnlyMessage(CFTypeRef cert_or_array_thereof
) {
586 OSStatus status
= errSecParam
;
587 SecCmsMessageRef cmsg
= NULL
;
588 SecCmsContentInfoRef cinfo
;
589 SecCmsSignedDataRef sigd
= NULL
;
590 CFMutableDataRef cert_only_signed_data
= NULL
;
591 CFArrayRef cert_array
= NULL
;
592 CFIndex cert_array_count
= 0;
593 SecCertificateRef cert
= NULL
;
595 require(cert_or_array_thereof
, out
);
597 require(cmsg
= SecCmsMessageCreate(), out
);
598 require(sigd
= SecCmsSignedDataCreate(cmsg
), out
);
599 require_noerr(SecCmsContentInfoSetContentData(&(sigd
->contentInfo
), NULL
, PR_TRUE
), out
);
600 require(cinfo
= SecCmsMessageGetContentInfo(cmsg
), out
);
601 require_noerr(SecCmsContentInfoSetContentSignedData(cinfo
, sigd
), out
);
602 long version
= SEC_CMS_SIGNED_DATA_VERSION_BASIC
;
603 require(SEC_ASN1EncodeInteger(cmsg
->poolp
, &(sigd
->version
), version
), out
);
605 if (CFGetTypeID(cert_or_array_thereof
) == SecCertificateGetTypeID()) {
606 cert_array
= CFArrayCreate(kCFAllocatorDefault
, &cert_or_array_thereof
, 1, &kCFTypeArrayCallBacks
);
607 } else if (CFGetTypeID(cert_or_array_thereof
) == CFArrayGetTypeID()) {
608 cert_array
= CFArrayCreateCopy(kCFAllocatorDefault
, (CFArrayRef
)cert_or_array_thereof
);
611 require(cert_array
, out
);
612 cert_array_count
= CFArrayGetCount(cert_array
);
613 require(cert_array_count
> 0, out
);
615 sigd
->rawCerts
= (SecAsn1Item
* *)PORT_ArenaAlloc(cmsg
->poolp
, (cert_array_count
+ 1) * sizeof(SecAsn1Item
*));
616 require(sigd
->rawCerts
, out
);
618 for (ix
= 0; ix
< cert_array_count
; ix
++) {
619 cert
= (SecCertificateRef
)CFArrayGetValueAtIndex(cert_array
, ix
);
622 sigd
->rawCerts
[ix
] = PORT_ArenaZAlloc(cmsg
->poolp
, sizeof(SecAsn1Item
));
623 SecAsn1Item cert_data
= { SecCertificateGetLength(cert
),
624 (uint8_t *)SecCertificateGetBytePtr(cert
) };
625 *(sigd
->rawCerts
[ix
]) = cert_data
;
627 sigd
->rawCerts
[ix
] = NULL
;
629 /* this is a SET OF, so we need to sort them guys - we have the DER already, though */
630 if (cert_array_count
> 1)
631 SecCmsArraySort((void **)sigd
->rawCerts
, SecCmsUtilDERCompare
, NULL
, NULL
);
633 cert_only_signed_data
= CFDataCreateMutable(kCFAllocatorDefault
, 0);
634 SecAsn1Item cert_only_signed_data_item
= {};
635 require_quiet(SEC_ASN1EncodeItem(cmsg
->poolp
, &cert_only_signed_data_item
,
636 cmsg
, SecCmsMessageTemplate
), out
);
637 CFDataAppendBytes(cert_only_signed_data
, cert_only_signed_data_item
.Data
,
638 cert_only_signed_data_item
.Length
);
640 status
= errSecSuccess
;
642 CFReleaseSafe(cert_array
);
643 if (status
) CFReleaseSafe(cert_only_signed_data
);
644 if (cmsg
) SecCmsMessageDestroy(cmsg
);
645 return cert_only_signed_data
;
648 CFDataRef
SecCMSCreateCertificatesOnlyMessageIAP(SecCertificateRef cert
)
650 static const uint8_t header
[] = {
651 0x30, 0x82, 0x03, 0x6d, 0x06, 0x09, 0x2a, 0x86,
652 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x02, 0xa0,
653 0x82, 0x03, 0x5e, 0x30, 0x82, 0x03, 0x5a, 0x02,
654 0x01, 0x01, 0x31, 0x00, 0x30, 0x0b, 0x06, 0x09,
655 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07,
656 0x01, 0xa0, 0x82, 0x03, 0x40
659 static const uint8_t trailer
[] = {
660 0xa1, 0x00, 0x31, 0x00
663 CFMutableDataRef message
= NULL
;
665 const uint8_t *certbytes
;
667 uint8_t *messagebytes
;
670 certdata
= SecCertificateCopyData(cert
);
671 require(certdata
, out
);
673 certbytes
= CFDataGetBytePtr(certdata
);
674 certlen
= CFDataGetLength(certdata
);
675 require(certlen
> UINT8_MAX
, out
);
676 require(certlen
< UINT16_MAX
, out
);
678 message
= CFDataCreateMutable(kCFAllocatorDefault
, 0);
679 require(message
, out
);
681 CFDataAppendBytes(message
, header
, sizeof(header
));
682 CFDataAppendBytes(message
, certbytes
, certlen
);
683 CFDataAppendBytes(message
, trailer
, sizeof(trailer
));
685 messagebytes
= CFDataGetMutableBytePtr(message
);
686 messagelen
= CFDataGetLength(message
);
689 messagebytes
[2] = messagelen
>> 8;
690 messagebytes
[3] = messagelen
& 0xFF;
693 messagebytes
[17] = messagelen
>> 8;
694 messagebytes
[18] = messagelen
& 0xFF;
697 messagebytes
[21] = messagelen
>> 8;
698 messagebytes
[22] = messagelen
& 0xFF;
701 messagebytes
[43] = messagelen
>> 8;
702 messagebytes
[44] = messagelen
& 0xFF;
705 CFReleaseSafe(certdata
);
709 #endif /* ENABLE_CMS */