2 * Copyright (c) 2014-2016 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@
25 #include <AssertMacros.h>
27 #include <security_asn1/secasn1.h>
29 #include <Security/SecCmsBase.h>
30 #include <Security/SecCmsMessage.h>
31 #include <Security/SecCmsSignedData.h>
32 #include <Security/SecCmsContentInfo.h>
33 #include <Security/SecCmsSignerInfo.h>
34 #include <Security/SecCertificate.h>
35 #include <Security/SecCertificatePriv.h>
36 #include <Security/SecCmsDecoder.h>
37 #include <Security/SecCmsEncoder.h>
38 #include <Security/SecCmsDigestContext.h>
39 #include <Security/SecCmsEnvelopedData.h>
40 #include <Security/SecCmsRecipientInfo.h>
41 #include <utilities/SecCFRelease.h>
50 CFTypeRef kSecCMSSignDigest
= CFSTR("kSecCMSSignDigest");
51 CFTypeRef kSecCMSSignDetached
= CFSTR("kSecCMSSignDetached");
52 CFTypeRef kSecCMSCertChainMode
= CFSTR("kSecCMSCertChainMode");
53 CFTypeRef kSecCMSAdditionalCerts
= CFSTR("kSecCMSAdditionalCerts");
54 CFTypeRef kSecCMSSignedAttributes
= CFSTR("kSecCMSSignedAttributes");
55 CFTypeRef kSecCMSSignDate
= CFSTR("kSecCMSSignDate");
56 CFTypeRef kSecCMSAllCerts
= CFSTR("kSecCMSAllCerts");
57 CFTypeRef kSecCMSHashAgility
= CFSTR("kSecCMSHashAgility");
59 CFTypeRef kSecCMSBulkEncryptionAlgorithm
= CFSTR("kSecCMSBulkEncryptionAlgorithm");
60 CFTypeRef kSecCMSEncryptionAlgorithmDESCBC
= CFSTR("kSecCMSEncryptionAlgorithmDESCBC");
61 CFTypeRef kSecCMSEncryptionAlgorithmAESCBC
= CFSTR("kSecCMSEncryptionAlgorithmAESCBC");
63 CFTypeRef kSecCMSSignHashAlgorithm
= CFSTR("kSecCMSSignHashAlgorithm");
64 CFTypeRef kSecCMSHashingAlgorithmSHA1
= CFSTR("kSecCMSHashingAlgorithmSHA1");
65 CFTypeRef kSecCMSHashingAlgorithmSHA256
= CFSTR("kSecCMSHashingAlgorithmSHA256");
66 CFTypeRef kSecCMSHashingAlgorithmSHA384
= CFSTR("kSecCMSHashingAlgorithmSHA384");
67 CFTypeRef kSecCMSHashingAlgorithmSHA512
= CFSTR("kSecCMSHashingAlgorithmSHA512");
69 static SecCmsAttribute
*
70 make_attr(PLArenaPool
*poolp
, SecAsn1Item
*type
, SecAsn1Item
*value
, bool encoded
)
72 SecAsn1Item
* copiedvalue
;
73 SecCmsAttribute
*attr
= (SecCmsAttribute
*)PORT_ArenaZAlloc(poolp
, sizeof(SecCmsAttribute
));
77 if (SECITEM_CopyItem(poolp
, &(attr
->type
), type
) != SECSuccess
)
81 if ((copiedvalue
= SECITEM_AllocItem(poolp
, NULL
, value
->Length
)) == NULL
)
84 if (SECITEM_CopyItem(poolp
, copiedvalue
, value
) != SECSuccess
)
87 if (SecCmsArrayAdd(poolp
, (void ***)&(attr
->values
), (void *)copiedvalue
) != SECSuccess
)
91 attr
->encoded
= encoded
;
98 signerinfo_add_auth_attr(SecCmsSignerInfoRef signerinfo
, /*SECOidTag oidtag*/
99 SecAsn1Item
*oid
, SecAsn1Item
*value
, bool encoded
)
101 PLArenaPool
*poolp
= signerinfo
->cmsg
->poolp
;
102 PORT_Assert (poolp
!= NULL
);
103 void *mark
= PORT_ArenaMark (poolp
);
105 SecCmsAttribute
*attr
= make_attr(poolp
, oid
, value
, encoded
);
106 if (!attr
|| SecCmsAttributeArrayAddAttr(poolp
, &(signerinfo
->authAttr
), attr
) != SECSuccess
)
109 PORT_ArenaUnmark (poolp
, mark
);
113 PORT_Assert (mark
!= NULL
);
114 PORT_ArenaRelease (poolp
, mark
);
118 static void sign_all_attributes(const void *key
, const void *value
, void *context
)
120 SecAsn1Item oid
= { CFDataGetLength(key
), (uint8_t*)CFDataGetBytePtr(key
) },
121 oid_value
= { CFDataGetLength(value
), (uint8_t*)CFDataGetBytePtr(value
) };
123 signerinfo_add_auth_attr((SecCmsSignerInfoRef
)context
, &oid
, &oid_value
, true);
126 static OSStatus
SecCMSSignDataOrDigestAndAttributes(SecIdentityRef identity
,
127 CFDataRef data
, bool detached
, bool data_is_digest
, SECOidTag sign_algorithm
,
128 CFMutableDataRef signed_data
, CFDictionaryRef signed_attributes
, SecCmsCertChainMode chainMode
, CFArrayRef additional_certs
)
130 SecCmsMessageRef cmsg
= NULL
;
131 SecCmsContentInfoRef cinfo
;
132 SecCmsSignedDataRef sigd
= NULL
;
133 SecCmsSignerInfoRef signerinfo
;
134 OSStatus status
= errSecParam
;
135 PLArenaPool
*arena
= NULL
;
137 require(!data_is_digest
|| detached
/* if digest, must be detached */, out
);
139 require(cmsg
= SecCmsMessageCreate(NULL
), out
);
140 require(sigd
= SecCmsSignedDataCreate(cmsg
), out
);
141 require(cinfo
= SecCmsMessageGetContentInfo(cmsg
), out
);
142 require_noerr(SecCmsContentInfoSetContentSignedData(cmsg
, cinfo
, sigd
), out
);
143 require(cinfo
= SecCmsSignedDataGetContentInfo(sigd
), out
);
144 require_noerr(SecCmsContentInfoSetContentData(cmsg
, cinfo
, NULL
, detached
), out
);
145 require(signerinfo
= SecCmsSignerInfoCreate(cmsg
, identity
, sign_algorithm
), out
);
146 if (additional_certs
)
147 require_noerr(SecCmsSignedDataAddCertList(sigd
, additional_certs
), out
);
148 require_noerr(SecCmsSignerInfoIncludeCerts(signerinfo
, chainMode
, certUsageAnyCA
), out
);
149 require_noerr(SecCmsSignerInfoAddSigningTime(signerinfo
, CFAbsoluteTimeGetCurrent()), out
);
151 if (signed_attributes
)
152 CFDictionaryApplyFunction(signed_attributes
, sign_all_attributes
, signerinfo
);
154 require_noerr(SecCmsSignedDataAddSignerInfo(sigd
, signerinfo
), out
);
156 SecAsn1Item input
= {};
158 input
.Length
= CFDataGetLength(data
);
159 input
.Data
= (uint8_t*)CFDataGetBytePtr(data
);
162 CSSM_DATA cssm_signed_data
= {0, NULL
};
163 // make an encoder context
164 if ((arena
= PORT_NewArena(1024)) == NULL
) {
167 if (data_is_digest
) {
168 require_noerr(SecCmsSignedDataSetDigestValue(sigd
, sign_algorithm
, &input
), out
);
169 require_noerr(SecCmsMessageEncode(cmsg
, NULL
, (SecArenaPoolRef
)arena
, &cssm_signed_data
), out
);
172 require_noerr(SecCmsMessageEncode(cmsg
,(data
&& input
.Length
) ? &input
: NULL
,
173 (SecArenaPoolRef
)arena
, &cssm_signed_data
), out
);
175 if (signed_data
&& cssm_signed_data
.Data
) {
176 CFDataAppendBytes(signed_data
, cssm_signed_data
.Data
, cssm_signed_data
.Length
);
179 status
= errSecSuccess
;
181 if (arena
) PORT_FreeArena(arena
, PR_FALSE
);
182 if (cmsg
) SecCmsMessageDestroy(cmsg
);
186 OSStatus
SecCMSSignDataAndAttributes(SecIdentityRef identity
, CFDataRef data
, bool detached
,
187 CFMutableDataRef signed_data
, CFDictionaryRef signed_attributes
)
189 return SecCMSSignDataOrDigestAndAttributes(identity
, data
, detached
, false, SEC_OID_SHA1
,
190 signed_data
, signed_attributes
, SecCmsCMCertChain
, NULL
);
193 OSStatus
SecCMSSignDigestAndAttributes(SecIdentityRef identity
, CFDataRef digest
,
194 CFMutableDataRef signed_data
, CFDictionaryRef signed_attributes
)
196 return SecCMSSignDataOrDigestAndAttributes(identity
, digest
, true, true, SEC_OID_SHA1
,
197 signed_data
, signed_attributes
, SecCmsCMCertChain
, NULL
);
200 OSStatus
SecCMSCreateSignedData(SecIdentityRef identity
, CFDataRef data
,
201 CFDictionaryRef parameters
, CFDictionaryRef signed_attributes
,
202 CFMutableDataRef signed_data
)
204 bool is_digest
= false, is_detached
= false;
205 CFStringRef algorithm_name
= NULL
;
206 SecCmsCertChainMode chain_mode
= SecCmsCMCertChain
;
207 CFArrayRef additional_certs
= NULL
;
210 is_digest
= CFDictionaryGetValueIfPresent(parameters
,
211 kSecCMSSignDigest
, NULL
);
212 is_detached
= CFDictionaryGetValueIfPresent(parameters
,
213 kSecCMSSignDetached
, NULL
);
214 algorithm_name
= CFDictionaryGetValue(parameters
,
215 kSecCMSSignHashAlgorithm
);
217 CFTypeRef chain_mode_param
= CFDictionaryGetValue(parameters
, kSecCMSCertChainMode
);
218 if (chain_mode_param
&& (CFGetTypeID(chain_mode_param
) == CFStringGetTypeID()))
219 chain_mode
= CFStringGetIntValue(chain_mode_param
);
221 CFTypeRef additional_certs_param
= CFDictionaryGetValue(parameters
, kSecCMSAdditionalCerts
);
222 if (additional_certs_param
&& (CFGetTypeID(additional_certs_param
) == CFArrayGetTypeID()))
223 additional_certs
= (CFArrayRef
)additional_certs_param
;
226 SECOidTag algorithm
= SEC_OID_SHA1
;
227 if (algorithm_name
) {
228 if (CFEqual(kSecCMSHashingAlgorithmSHA1
, algorithm_name
)) {
229 algorithm
= SEC_OID_SHA1
;
230 } else if (CFEqual(kSecCMSHashingAlgorithmSHA256
, algorithm_name
)) {
231 algorithm
= SEC_OID_SHA256
;
232 } else if (CFEqual(kSecCMSHashingAlgorithmSHA384
, algorithm_name
)) {
233 algorithm
= SEC_OID_SHA384
;
234 } else if (CFEqual(kSecCMSHashingAlgorithmSHA512
, algorithm_name
)) {
235 algorithm
= SEC_OID_SHA512
;
237 // signing with MD5 is no longer allowed
238 algorithm
= SEC_OID_UNKNOWN
;
242 return SecCMSSignDataOrDigestAndAttributes(identity
, data
,
243 is_detached
, is_digest
, algorithm
,
244 signed_data
, signed_attributes
, chain_mode
, additional_certs
);
248 SecCmsSignedDataSetDigestContext(SecCmsSignedDataRef sigd
,
249 SecCmsDigestContextRef digestContext
)
251 SecAsn1Item
* *digests
;
253 PLArenaPool
*arena
= NULL
;
255 if ((arena
= PORT_NewArena(1024)) == NULL
)
258 if (SecCmsDigestContextFinishMultiple(digestContext
, (SecArenaPoolRef
)arena
, &digests
) != SECSuccess
)
261 SECAlgorithmID
**digestAlgorithms
= SecCmsSignedDataGetDigestAlgs(sigd
);
262 if(digestAlgorithms
== NULL
) {
266 if (SecCmsSignedDataSetDigests(sigd
, digestAlgorithms
, digests
) != SECSuccess
)
270 PORT_FreeArena(arena
, PR_FALSE
);
275 PORT_FreeArena(arena
, PR_FALSE
);
276 return PORT_GetError();
279 static CFMutableArrayRef
copy_signed_attribute_values(SecCmsAttribute
*attr
)
281 CFMutableArrayRef array
= CFArrayCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeArrayCallBacks
);
282 SecAsn1Item
**item
= attr
->values
;
283 if (item
) while (*item
) {
284 CFDataRef asn1data
= CFDataCreate(kCFAllocatorDefault
, (*item
)->Data
, (*item
)->Length
);
286 CFArrayAppendValue(array
, asn1data
);
294 static OSStatus
SecCMSVerifySignedData_internal(CFDataRef message
, CFDataRef detached_contents
,
295 CFTypeRef policy
, SecTrustRef
*trustref
, CFArrayRef additional_certs
,
296 CFDataRef
*attached_contents
, CFDictionaryRef
*signed_attributes
)
298 SecCmsMessageRef cmsg
= NULL
;
299 SecCmsContentInfoRef cinfo
;
300 SecCmsSignedDataRef sigd
= NULL
;
301 OSStatus status
= errSecParam
;
303 require(message
, out
);
304 SecAsn1Item encoded_message
= { CFDataGetLength(message
), (uint8_t*)CFDataGetBytePtr(message
) };
305 require_noerr_action_quiet(SecCmsMessageDecode(&encoded_message
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, &cmsg
),
306 out
, status
= errSecDecode
);
307 /* expected to be a signed data message at the top level */
308 require_quiet(cinfo
= SecCmsMessageContentLevel(cmsg
, 0), out
);
309 require_quiet(SecCmsContentInfoGetContentTypeTag(cinfo
) == SEC_OID_PKCS7_SIGNED_DATA
, out
);
310 require_quiet(sigd
= (SecCmsSignedDataRef
)SecCmsContentInfoGetContent(cinfo
), out
);
312 if (detached_contents
)
314 require_quiet(!SecCmsSignedDataHasDigests(sigd
), out
);
315 SECAlgorithmID
**digestalgs
= SecCmsSignedDataGetDigestAlgs(sigd
);
316 SecCmsDigestContextRef digcx
= SecCmsDigestContextStartMultiple(digestalgs
);
317 SecCmsDigestContextUpdate(digcx
, CFDataGetBytePtr(detached_contents
), CFDataGetLength(detached_contents
));
318 SecCmsSignedDataSetDigestContext(sigd
, digcx
);
321 if (additional_certs
)
322 require_noerr_quiet(SecCmsSignedDataAddCertList(sigd
, additional_certs
), out
);
324 if (policy
) { /* if no policy is given skip verification */
325 /* find out about signers */
326 int nsigners
= SecCmsSignedDataSignerInfoCount(sigd
);
327 require_quiet(nsigners
== 1, out
);
328 require_noerr_action_quiet(SecCmsSignedDataVerifySignerInfo(sigd
, 0, NULL
, policy
, trustref
),
329 out
, status
= errSecAuthFailed
);
332 status
= errSecSuccess
;
334 if (attached_contents
) {
335 const SecAsn1Item
*content
= SecCmsMessageGetContent(cmsg
);
337 *attached_contents
= CFDataCreate(kCFAllocatorDefault
, content
->Data
, content
->Length
);
339 *attached_contents
= NULL
;
342 if (signed_attributes
) {
343 CFMutableDictionaryRef attrs
= CFDictionaryCreateMutable(kCFAllocatorDefault
,
344 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
345 require_quiet(attrs
, out
);
346 SecCmsAttribute
**signed_attrs
= sigd
->signerInfos
[0]->authAttr
;
347 if (signed_attrs
) while (*signed_attrs
) {
348 CFDataRef type
= CFDataCreate(kCFAllocatorDefault
, (*signed_attrs
)->type
.Data
, (*signed_attrs
)->type
.Length
);
350 CFMutableArrayRef attr
= copy_signed_attribute_values(*signed_attrs
);
352 CFMutableArrayRef existing_attrs
= (CFMutableArrayRef
)CFDictionaryGetValue(attrs
, type
);
353 if (existing_attrs
) {
354 CFIndex count
= CFArrayGetCount(attr
);
356 CFArrayAppendArray(existing_attrs
, attr
, CFRangeMake(0, count
));
358 CFDictionarySetValue(attrs
, type
, attr
);
365 CFMutableArrayRef certs
= NULL
;
367 SecAsn1Item
**cert_datas
= SecCmsSignedDataGetCertificateList(sigd
);
368 certs
= CFArrayCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeArrayCallBacks
);
369 SecAsn1Item
*cert_data
;
370 if (cert_datas
) while ((cert_data
= *cert_datas
) != NULL
) {
371 SecCertificateRef cert
= SecCertificateCreateWithBytes(NULL
, cert_data
->Data
, cert_data
->Length
);
373 CFArrayAppendValue(certs
, cert
);
379 CFDictionaryAddValue(attrs
, kSecCMSAllCerts
, certs
);
381 /* Add "cooked" values separately */
382 CFAbsoluteTime signing_time
;
383 if (errSecSuccess
== SecCmsSignerInfoGetSigningTime(sigd
->signerInfos
[0], &signing_time
)) {
384 CFDateRef signing_date
= CFDateCreate(kCFAllocatorDefault
, signing_time
);
386 CFDictionarySetValue(attrs
, kSecCMSSignDate
, signing_date
);
387 if (signing_date
) CFRelease(signing_date
);
391 CFDataRef hash_agility_value
= NULL
;
392 if (errSecSuccess
== SecCmsSignerInfoGetAppleCodesigningHashAgility(sigd
->signerInfos
[0], &hash_agility_value
)) {
393 if (hash_agility_value
) {
394 CFDictionarySetValue(attrs
, kSecCMSHashAgility
, hash_agility_value
);
398 *signed_attributes
= attrs
;
399 if (certs
) CFRelease(certs
);
404 if (cmsg
) SecCmsMessageDestroy(cmsg
);
408 OSStatus
SecCMSVerifyCopyDataAndAttributes(CFDataRef message
, CFDataRef detached_contents
,
409 CFTypeRef policy
, SecTrustRef
*trustref
,
410 CFDataRef
*attached_contents
, CFDictionaryRef
*signed_attributes
)
412 OSStatus status
= SecCMSVerifySignedData_internal(message
, detached_contents
, policy
, trustref
, NULL
, attached_contents
, signed_attributes
);
417 OSStatus
SecCMSVerifySignedData(CFDataRef message
, CFDataRef detached_contents
,
418 CFTypeRef policy
, SecTrustRef
*trustref
, CFArrayRef additional_certificates
,
419 CFDataRef
*attached_contents
, CFDictionaryRef
*message_attributes
)
421 CFDictionaryRef signed_attributes
= NULL
;
422 OSStatus status
= SecCMSVerifySignedData_internal(message
, detached_contents
, policy
, trustref
, additional_certificates
, attached_contents
, &signed_attributes
);
423 if (!status
&& signed_attributes
&& message_attributes
) {
424 *message_attributes
= CFDictionaryCreate(kCFAllocatorDefault
, &kSecCMSSignedAttributes
, (const void **)&signed_attributes
, 1, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
426 if (signed_attributes
) CFRelease(signed_attributes
);
431 OSStatus
SecCMSVerify(CFDataRef message
, CFDataRef detached_contents
,
432 CFTypeRef policy
, SecTrustRef
*trustref
,
433 CFDataRef
*attached_contents
) {
434 return SecCMSVerifySignedData_internal(message
, detached_contents
, policy
, trustref
, NULL
, attached_contents
, NULL
);
437 /* Designed to match the sec submodule implementation available for iOS */
438 CFArrayRef
SecCMSCertificatesOnlyMessageCopyCertificates(CFDataRef message
) {
439 SecCmsMessageRef cmsg
= NULL
;
440 SecCmsContentInfoRef cinfo
;
441 SecCmsSignedDataRef sigd
= NULL
;
442 CFMutableArrayRef certs
= NULL
;
444 CSSM_DATA encoded_message
= { CFDataGetLength(message
), (uint8_t*)CFDataGetBytePtr(message
) };
445 require_noerr_quiet(SecCmsMessageDecode(&encoded_message
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, &cmsg
), out
);
446 /* expected to be a signed data message at the top level */
447 require(cinfo
= SecCmsMessageContentLevel(cmsg
, 0), out
);
448 require(SecCmsContentInfoGetContentTypeTag(cinfo
) == SEC_OID_PKCS7_SIGNED_DATA
, out
);
449 require(sigd
= (SecCmsSignedDataRef
)SecCmsContentInfoGetContent(cinfo
), out
);
451 /* find out about signers */
452 int nsigners
= SecCmsSignedDataSignerInfoCount(sigd
);
453 require(nsigners
== 0, out
);
455 CSSM_DATA_PTR
*cert_datas
= SecCmsSignedDataGetCertificateList(sigd
);
456 certs
= CFArrayCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeArrayCallBacks
);
457 CSSM_DATA_PTR cert_data
;
458 if (cert_datas
) while ((cert_data
= *cert_datas
) != NULL
) {
459 SecCertificateRef cert
= SecCertificateCreateWithBytes(NULL
, cert_data
->Data
, cert_data
->Length
);
461 CFArrayAppendValue(certs
, cert
);
469 SecCmsMessageDestroy(cmsg
);
475 extern const SecAsn1Template SecCmsMessageTemplate
[];
477 CFDataRef
SecCMSCreateCertificatesOnlyMessage(CFTypeRef cert_or_array_thereof
) {
478 OSStatus status
= errSecParam
;
479 SecCmsMessageRef cmsg
= NULL
;
480 SecCmsContentInfoRef cinfo
;
481 SecCmsSignedDataRef sigd
= NULL
;
482 CFMutableDataRef cert_only_signed_data
= NULL
;
483 CFArrayRef cert_array
= NULL
;
484 CFIndex cert_array_count
= 0;
485 SecCertificateRef cert
= NULL
;
487 require(cert_or_array_thereof
, out
);
489 require(cmsg
= SecCmsMessageCreate(NULL
), out
);
490 require(sigd
= SecCmsSignedDataCreate(cmsg
), out
);
491 require_noerr(SecCmsContentInfoSetContentData(cmsg
, &(sigd
->contentInfo
), NULL
, PR_TRUE
), out
);
492 require(cinfo
= SecCmsMessageGetContentInfo(cmsg
), out
);
493 require_noerr(SecCmsContentInfoSetContentSignedData(cmsg
, cinfo
, sigd
), out
);
494 long version
= SEC_CMS_SIGNED_DATA_VERSION_BASIC
;
495 require(SEC_ASN1EncodeInteger(cmsg
->poolp
, &(sigd
->version
), version
), out
);
497 if (CFGetTypeID(cert_or_array_thereof
) == SecCertificateGetTypeID()) {
498 cert_array
= CFArrayCreate(kCFAllocatorDefault
, &cert_or_array_thereof
, 1, &kCFTypeArrayCallBacks
);
499 } else if (CFGetTypeID(cert_or_array_thereof
) == CFArrayGetTypeID()) {
500 cert_array
= CFArrayCreateCopy(kCFAllocatorDefault
, (CFArrayRef
)cert_or_array_thereof
);
503 require(cert_array
, out
);
504 cert_array_count
= CFArrayGetCount(cert_array
);
505 require(cert_array_count
> 0, out
);
507 sigd
->rawCerts
= (SecAsn1Item
* *)PORT_ArenaAlloc(cmsg
->poolp
, (cert_array_count
+ 1) * sizeof(SecAsn1Item
*));
508 require(sigd
->rawCerts
, out
);
510 for (ix
= 0; ix
< cert_array_count
; ix
++) {
511 cert
= (SecCertificateRef
)CFArrayGetValueAtIndex(cert_array
, ix
);
514 sigd
->rawCerts
[ix
] = PORT_ArenaZAlloc(cmsg
->poolp
, sizeof(SecAsn1Item
));
515 SecAsn1Item cert_data
= { SecCertificateGetLength(cert
),
516 (uint8_t *)SecCertificateGetBytePtr(cert
) };
517 *(sigd
->rawCerts
[ix
]) = cert_data
;
519 sigd
->rawCerts
[ix
] = NULL
;
521 /* this is a SET OF, so we need to sort them guys - we have the DER already, though */
522 if (cert_array_count
> 1)
523 SecCmsArraySort((void **)sigd
->rawCerts
, SecCmsUtilDERCompare
, NULL
, NULL
);
525 cert_only_signed_data
= CFDataCreateMutable(kCFAllocatorDefault
, 0);
526 SecAsn1Item cert_only_signed_data_item
= {};
527 require_quiet(SEC_ASN1EncodeItem(cmsg
->poolp
, &cert_only_signed_data_item
,
528 cmsg
, SecCmsMessageTemplate
), out
);
529 CFDataAppendBytes(cert_only_signed_data
, cert_only_signed_data_item
.Data
,
530 cert_only_signed_data_item
.Length
);
532 status
= errSecSuccess
;
534 if (cert_array
) { CFRelease(cert_array
); }
535 if (status
&& cert_only_signed_data
) { CFRelease(cert_only_signed_data
); }
536 if (cmsg
) SecCmsMessageDestroy(cmsg
);
537 return cert_only_signed_data
;
540 CFDataRef
SecCMSCreateCertificatesOnlyMessageIAP(SecCertificateRef cert
)
542 static const uint8_t header
[] = {
543 0x30, 0x82, 0x03, 0x6d, 0x06, 0x09, 0x2a, 0x86,
544 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x02, 0xa0,
545 0x82, 0x03, 0x5e, 0x30, 0x82, 0x03, 0x5a, 0x02,
546 0x01, 0x01, 0x31, 0x00, 0x30, 0x0b, 0x06, 0x09,
547 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07,
548 0x01, 0xa0, 0x82, 0x03, 0x40
551 static const uint8_t trailer
[] = {
552 0xa1, 0x00, 0x31, 0x00
555 CFMutableDataRef message
= NULL
;
557 const uint8_t *certbytes
;
559 uint8_t *messagebytes
;
562 certdata
= SecCertificateCopyData(cert
);
563 require(certdata
, out
);
565 certbytes
= CFDataGetBytePtr(certdata
);
566 certlen
= CFDataGetLength(certdata
);
567 require(certlen
> UINT8_MAX
, out
);
568 require(certlen
< UINT16_MAX
, out
);
570 message
= CFDataCreateMutable(kCFAllocatorDefault
, 0);
571 require(message
, out
);
573 CFDataAppendBytes(message
, header
, sizeof(header
));
574 CFDataAppendBytes(message
, certbytes
, certlen
);
575 CFDataAppendBytes(message
, trailer
, sizeof(trailer
));
577 messagebytes
= CFDataGetMutableBytePtr(message
);
578 messagelen
= CFDataGetLength(message
);
581 messagebytes
[2] = messagelen
>> 8;
582 messagebytes
[3] = messagelen
& 0xFF;
585 messagebytes
[17] = messagelen
>> 8;
586 messagebytes
[18] = messagelen
& 0xFF;
589 messagebytes
[21] = messagelen
>> 8;
590 messagebytes
[22] = messagelen
& 0xFF;
593 messagebytes
[43] = messagelen
>> 8;
594 messagebytes
[44] = messagelen
& 0xFF;
597 if (certdata
!= NULL
)
604 OSStatus
SecCMSCreateEnvelopedData(CFTypeRef recipient_or_cfarray_thereof
,
605 CFDictionaryRef params
, CFDataRef data
, CFMutableDataRef enveloped_data
)
607 SecCmsMessageRef cmsg
= NULL
;
608 SecCmsContentInfoRef cinfo
;
609 SecCmsEnvelopedDataRef envd
= NULL
;
610 SECOidTag algorithmTag
= SEC_OID_DES_EDE3_CBC
;
612 OSStatus status
= errSecParam
;
613 PLArenaPool
*arena
= NULL
;
616 CFStringRef algorithm_name
= CFDictionaryGetValue(params
, kSecCMSBulkEncryptionAlgorithm
);
617 if (algorithm_name
) {
618 if (CFEqual(kSecCMSEncryptionAlgorithmDESCBC
, algorithm_name
)) {
619 algorithmTag
= SEC_OID_DES_CBC
;
621 } else if (CFEqual(kSecCMSEncryptionAlgorithmAESCBC
, algorithm_name
)) {
622 algorithmTag
= SEC_OID_AES_128_CBC
;
628 require(cmsg
= SecCmsMessageCreate(NULL
), out
);
629 require(envd
= SecCmsEnvelopedDataCreate(cmsg
, algorithmTag
, keySize
), out
);
630 require(cinfo
= SecCmsMessageGetContentInfo(cmsg
), out
);
631 require_noerr(SecCmsContentInfoSetContentEnvelopedData(cmsg
, cinfo
, envd
), out
);
632 require(cinfo
= SecCmsEnvelopedDataGetContentInfo(envd
), out
);
633 require_noerr(SecCmsContentInfoSetContentData(cmsg
, cinfo
, NULL
, false), out
);
634 // == wrapper of: require(SECSuccess == SecCmsContentInfoSetContent(cinfo, SEC_OID_PKCS7_DATA, NULL), out);
636 if (CFGetTypeID(recipient_or_cfarray_thereof
) == CFArrayGetTypeID()) {
637 CFIndex dex
, numCerts
= CFArrayGetCount(recipient_or_cfarray_thereof
);
638 for(dex
=0; dex
<numCerts
; dex
++) {
639 SecCertificateRef recip
=
640 (SecCertificateRef
)CFArrayGetValueAtIndex(recipient_or_cfarray_thereof
, dex
);
641 SecCmsRecipientInfoRef rinfo
;
642 require(rinfo
= SecCmsRecipientInfoCreate(cmsg
, recip
), out
);
643 require_noerr(SecCmsEnvelopedDataAddRecipient(envd
, rinfo
), out
);
645 } else if (CFGetTypeID(recipient_or_cfarray_thereof
) == SecCertificateGetTypeID()) {
646 SecCmsRecipientInfoRef rinfo
;
647 require(rinfo
= SecCmsRecipientInfoCreate(cmsg
, (SecCertificateRef
)recipient_or_cfarray_thereof
), out
);
648 require_noerr(SecCmsEnvelopedDataAddRecipient(envd
, rinfo
), out
);
652 SecAsn1Item input
= {};
654 input
.Length
= CFDataGetLength(data
);
655 input
.Data
= (uint8_t*)CFDataGetBytePtr(data
);
658 CSSM_DATA cssm_enveloped_data
= {0, NULL
};
659 // make an encoder context
660 if ((arena
= PORT_NewArena(1024)) == NULL
) {
663 require_noerr(SecCmsMessageEncode(cmsg
, (data
&& input
.Length
) ? &input
: NULL
, (SecArenaPoolRef
)arena
, &cssm_enveloped_data
), out
);
664 if (enveloped_data
&& cssm_enveloped_data
.Data
) {
665 CFDataAppendBytes(enveloped_data
, cssm_enveloped_data
.Data
, cssm_enveloped_data
.Length
);
668 status
= errSecSuccess
;
670 if (arena
) PORT_FreeArena(arena
, PR_FALSE
);
671 if (cmsg
) SecCmsMessageDestroy(cmsg
);
675 OSStatus
SecCMSDecryptEnvelopedData(CFDataRef message
,
676 CFMutableDataRef data
, SecCertificateRef
*recipient
)
678 SecCmsMessageRef cmsg
= NULL
;
679 SecCmsContentInfoRef cinfo
;
680 SecCmsEnvelopedDataRef envd
= NULL
;
681 SecCertificateRef used_recipient
= NULL
;
682 OSStatus status
= errSecParam
;
684 SecAsn1Item encoded_message
= { CFDataGetLength(message
), (uint8_t*)CFDataGetBytePtr(message
) };
685 require_noerr_action_quiet(SecCmsMessageDecode(&encoded_message
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, &cmsg
),
686 out
, status
= errSecDecode
);
687 require_quiet(cinfo
= SecCmsMessageContentLevel(cmsg
, 0), out
);
688 require_quiet(SecCmsContentInfoGetContentTypeTag(cinfo
) == SEC_OID_PKCS7_ENVELOPED_DATA
, out
);
689 require_quiet(envd
= (SecCmsEnvelopedDataRef
)SecCmsContentInfoGetContent(cinfo
), out
);
690 SecCmsRecipientInfoRef
*rinfo
= envd
->recipientInfos
;
691 while (!used_recipient
&& *rinfo
) {
692 used_recipient
= (*rinfo
)->cert
;
695 require_quiet(2 == SecCmsMessageContentLevelCount(cmsg
), out
);
696 require_quiet(cinfo
= SecCmsMessageContentLevel(cmsg
, 1), out
);
697 require_quiet(SecCmsContentInfoGetContentTypeTag(cinfo
) == SEC_OID_PKCS7_DATA
, out
);
698 const SecAsn1Item
*content
= SecCmsMessageGetContent(cmsg
);
700 CFDataAppendBytes(data
, content
->Data
, content
->Length
);
702 CFRetainSafe(used_recipient
);
703 *recipient
= used_recipient
;
705 status
= errSecSuccess
;
707 if (cmsg
) SecCmsMessageDestroy(cmsg
);