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");
58 CFTypeRef kSecCMSHashAgilityV2
= CFSTR("kSecCMSHashAgilityV2");
59 CFTypeRef kSecCMSExpirationDate
= CFSTR("kSecCMSExpirationDate");
61 CFTypeRef kSecCMSBulkEncryptionAlgorithm
= CFSTR("kSecCMSBulkEncryptionAlgorithm");
62 CFTypeRef kSecCMSEncryptionAlgorithmDESCBC
= CFSTR("kSecCMSEncryptionAlgorithmDESCBC");
63 CFTypeRef kSecCMSEncryptionAlgorithmAESCBC
= CFSTR("kSecCMSEncryptionAlgorithmAESCBC");
65 CFTypeRef kSecCMSSignHashAlgorithm
= CFSTR("kSecCMSSignHashAlgorithm");
66 CFTypeRef kSecCMSHashingAlgorithmSHA1
= CFSTR("kSecCMSHashingAlgorithmSHA1");
67 CFTypeRef kSecCMSHashingAlgorithmSHA256
= CFSTR("kSecCMSHashingAlgorithmSHA256");
68 CFTypeRef kSecCMSHashingAlgorithmSHA384
= CFSTR("kSecCMSHashingAlgorithmSHA384");
69 CFTypeRef kSecCMSHashingAlgorithmSHA512
= CFSTR("kSecCMSHashingAlgorithmSHA512");
71 static SecCmsAttribute
*
72 make_attr(PLArenaPool
*poolp
, SecAsn1Item
*type
, SecAsn1Item
*value
, bool encoded
)
74 SecAsn1Item
* copiedvalue
;
75 SecCmsAttribute
*attr
= (SecCmsAttribute
*)PORT_ArenaZAlloc(poolp
, sizeof(SecCmsAttribute
));
79 if (SECITEM_CopyItem(poolp
, &(attr
->type
), type
) != SECSuccess
)
83 if ((copiedvalue
= SECITEM_AllocItem(poolp
, NULL
, value
->Length
)) == NULL
)
86 if (SECITEM_CopyItem(poolp
, copiedvalue
, value
) != SECSuccess
)
89 if (SecCmsArrayAdd(poolp
, (void ***)&(attr
->values
), (void *)copiedvalue
) != SECSuccess
)
93 attr
->encoded
= encoded
;
100 signerinfo_add_auth_attr(SecCmsSignerInfoRef signerinfo
, /*SECOidTag oidtag*/
101 SecAsn1Item
*oid
, SecAsn1Item
*value
, bool encoded
)
103 PLArenaPool
*poolp
= signerinfo
->cmsg
->poolp
;
104 PORT_Assert (poolp
!= NULL
);
105 void *mark
= PORT_ArenaMark (poolp
);
107 SecCmsAttribute
*attr
= make_attr(poolp
, oid
, value
, encoded
);
108 if (!attr
|| SecCmsAttributeArrayAddAttr(poolp
, &(signerinfo
->authAttr
), attr
) != SECSuccess
)
111 PORT_ArenaUnmark (poolp
, mark
);
115 PORT_Assert (mark
!= NULL
);
116 PORT_ArenaRelease (poolp
, mark
);
120 static void sign_all_attributes(const void *key
, const void *value
, void *context
)
122 SecAsn1Item oid
= { CFDataGetLength(key
), (uint8_t*)CFDataGetBytePtr(key
) },
123 oid_value
= { CFDataGetLength(value
), (uint8_t*)CFDataGetBytePtr(value
) };
125 signerinfo_add_auth_attr((SecCmsSignerInfoRef
)context
, &oid
, &oid_value
, true);
128 static OSStatus
SecCMSSignDataOrDigestAndAttributes(SecIdentityRef identity
,
129 CFDataRef data
, bool detached
, bool data_is_digest
, SECOidTag sign_algorithm
,
130 CFMutableDataRef signed_data
, CFDictionaryRef signed_attributes
, SecCmsCertChainMode chainMode
, CFArrayRef additional_certs
)
132 SecCmsMessageRef cmsg
= NULL
;
133 SecCmsContentInfoRef cinfo
;
134 SecCmsSignedDataRef sigd
= NULL
;
135 SecCmsSignerInfoRef signerinfo
;
136 OSStatus status
= errSecParam
;
137 PLArenaPool
*arena
= NULL
;
139 require(!data_is_digest
|| detached
/* if digest, must be detached */, out
);
141 require(cmsg
= SecCmsMessageCreate(NULL
), out
);
142 require(sigd
= SecCmsSignedDataCreate(cmsg
), out
);
143 require(cinfo
= SecCmsMessageGetContentInfo(cmsg
), out
);
144 require_noerr(SecCmsContentInfoSetContentSignedData(cmsg
, cinfo
, sigd
), out
);
145 require(cinfo
= SecCmsSignedDataGetContentInfo(sigd
), out
);
146 require_noerr(SecCmsContentInfoSetContentData(cmsg
, cinfo
, NULL
, detached
), out
);
147 require(signerinfo
= SecCmsSignerInfoCreate(cmsg
, identity
, sign_algorithm
), out
);
148 if (additional_certs
)
149 require_noerr(SecCmsSignedDataAddCertList(sigd
, additional_certs
), out
);
150 require_noerr(SecCmsSignerInfoIncludeCerts(signerinfo
, chainMode
, certUsageAnyCA
), out
);
151 require_noerr(SecCmsSignerInfoAddSigningTime(signerinfo
, CFAbsoluteTimeGetCurrent()), out
);
153 if (signed_attributes
)
154 CFDictionaryApplyFunction(signed_attributes
, sign_all_attributes
, signerinfo
);
156 require_noerr(SecCmsSignedDataAddSignerInfo(sigd
, signerinfo
), out
);
158 SecAsn1Item input
= {};
160 input
.Length
= CFDataGetLength(data
);
161 input
.Data
= (uint8_t*)CFDataGetBytePtr(data
);
164 CSSM_DATA cssm_signed_data
= {0, NULL
};
165 // make an encoder context
166 if ((arena
= PORT_NewArena(1024)) == NULL
) {
169 if (data_is_digest
) {
170 require_noerr(SecCmsSignedDataSetDigestValue(sigd
, sign_algorithm
, &input
), out
);
171 require_noerr(SecCmsMessageEncode(cmsg
, NULL
, (SecArenaPoolRef
)arena
, &cssm_signed_data
), out
);
174 require_noerr(SecCmsMessageEncode(cmsg
,(data
&& input
.Length
) ? &input
: NULL
,
175 (SecArenaPoolRef
)arena
, &cssm_signed_data
), out
);
177 if (signed_data
&& cssm_signed_data
.Data
) {
178 CFDataAppendBytes(signed_data
, cssm_signed_data
.Data
, cssm_signed_data
.Length
);
181 status
= errSecSuccess
;
183 if (arena
) PORT_FreeArena(arena
, PR_FALSE
);
184 if (cmsg
) SecCmsMessageDestroy(cmsg
);
188 OSStatus
SecCMSSignDataAndAttributes(SecIdentityRef identity
, CFDataRef data
, bool detached
,
189 CFMutableDataRef signed_data
, CFDictionaryRef signed_attributes
)
191 return SecCMSSignDataOrDigestAndAttributes(identity
, data
, detached
, false, SEC_OID_SHA1
,
192 signed_data
, signed_attributes
, SecCmsCMCertChain
, NULL
);
195 OSStatus
SecCMSSignDigestAndAttributes(SecIdentityRef identity
, CFDataRef digest
,
196 CFMutableDataRef signed_data
, CFDictionaryRef signed_attributes
)
198 return SecCMSSignDataOrDigestAndAttributes(identity
, digest
, true, true, SEC_OID_SHA1
,
199 signed_data
, signed_attributes
, SecCmsCMCertChain
, NULL
);
202 OSStatus
SecCMSCreateSignedData(SecIdentityRef identity
, CFDataRef data
,
203 CFDictionaryRef parameters
, CFDictionaryRef signed_attributes
,
204 CFMutableDataRef signed_data
)
206 bool is_digest
= false, is_detached
= false;
207 CFStringRef algorithm_name
= NULL
;
208 SecCmsCertChainMode chain_mode
= SecCmsCMCertChain
;
209 CFArrayRef additional_certs
= NULL
;
212 is_digest
= CFDictionaryGetValueIfPresent(parameters
,
213 kSecCMSSignDigest
, NULL
);
214 is_detached
= CFDictionaryGetValueIfPresent(parameters
,
215 kSecCMSSignDetached
, NULL
);
216 algorithm_name
= CFDictionaryGetValue(parameters
,
217 kSecCMSSignHashAlgorithm
);
219 CFTypeRef chain_mode_param
= CFDictionaryGetValue(parameters
, kSecCMSCertChainMode
);
220 if (chain_mode_param
&& (CFGetTypeID(chain_mode_param
) == CFStringGetTypeID()))
221 chain_mode
= CFStringGetIntValue(chain_mode_param
);
223 CFTypeRef additional_certs_param
= CFDictionaryGetValue(parameters
, kSecCMSAdditionalCerts
);
224 if (additional_certs_param
&& (CFGetTypeID(additional_certs_param
) == CFArrayGetTypeID()))
225 additional_certs
= (CFArrayRef
)additional_certs_param
;
228 SECOidTag algorithm
= SEC_OID_SHA1
;
229 if (algorithm_name
) {
230 if (CFEqual(kSecCMSHashingAlgorithmSHA1
, algorithm_name
)) {
231 algorithm
= SEC_OID_SHA1
;
232 } else if (CFEqual(kSecCMSHashingAlgorithmSHA256
, algorithm_name
)) {
233 algorithm
= SEC_OID_SHA256
;
234 } else if (CFEqual(kSecCMSHashingAlgorithmSHA384
, algorithm_name
)) {
235 algorithm
= SEC_OID_SHA384
;
236 } else if (CFEqual(kSecCMSHashingAlgorithmSHA512
, algorithm_name
)) {
237 algorithm
= SEC_OID_SHA512
;
239 // signing with MD5 is no longer allowed
240 algorithm
= SEC_OID_UNKNOWN
;
244 return SecCMSSignDataOrDigestAndAttributes(identity
, data
,
245 is_detached
, is_digest
, algorithm
,
246 signed_data
, signed_attributes
, chain_mode
, additional_certs
);
250 SecCmsSignedDataSetDigestContext(SecCmsSignedDataRef sigd
,
251 SecCmsDigestContextRef digestContext
)
253 SecAsn1Item
* *digests
;
255 PLArenaPool
*arena
= NULL
;
257 if ((arena
= PORT_NewArena(1024)) == NULL
)
260 if (SecCmsDigestContextFinishMultiple(digestContext
, (SecArenaPoolRef
)arena
, &digests
) != SECSuccess
)
263 SECAlgorithmID
**digestAlgorithms
= SecCmsSignedDataGetDigestAlgs(sigd
);
264 if(digestAlgorithms
== NULL
) {
268 if (SecCmsSignedDataSetDigests(sigd
, digestAlgorithms
, digests
) != SECSuccess
)
272 PORT_FreeArena(arena
, PR_FALSE
);
277 PORT_FreeArena(arena
, PR_FALSE
);
278 return PORT_GetError();
281 static CFMutableArrayRef
copy_signed_attribute_values(SecCmsAttribute
*attr
)
283 CFMutableArrayRef array
= CFArrayCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeArrayCallBacks
);
284 SecAsn1Item
**item
= attr
->values
;
285 if (item
) while (*item
) {
286 CFDataRef asn1data
= CFDataCreate(kCFAllocatorDefault
, (*item
)->Data
, (*item
)->Length
);
288 CFArrayAppendValue(array
, asn1data
);
296 static OSStatus
SecCMSVerifySignedData_internal(CFDataRef message
, CFDataRef detached_contents
,
297 CFTypeRef policy
, SecTrustRef
*trustref
, CFArrayRef additional_certs
,
298 CFDataRef
*attached_contents
, CFDictionaryRef
*signed_attributes
)
300 SecCmsMessageRef cmsg
= NULL
;
301 SecCmsContentInfoRef cinfo
;
302 SecCmsSignedDataRef sigd
= NULL
;
303 OSStatus status
= errSecParam
;
305 require(message
, out
);
306 SecAsn1Item encoded_message
= { CFDataGetLength(message
), (uint8_t*)CFDataGetBytePtr(message
) };
307 require_noerr_action_quiet(SecCmsMessageDecode(&encoded_message
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, &cmsg
),
308 out
, status
= errSecDecode
);
309 /* expected to be a signed data message at the top level */
310 require_quiet(cinfo
= SecCmsMessageContentLevel(cmsg
, 0), out
);
311 require_quiet(SecCmsContentInfoGetContentTypeTag(cinfo
) == SEC_OID_PKCS7_SIGNED_DATA
, out
);
312 require_quiet(sigd
= (SecCmsSignedDataRef
)SecCmsContentInfoGetContent(cinfo
), out
);
314 if (detached_contents
)
316 require_quiet(!SecCmsSignedDataHasDigests(sigd
), out
);
317 SECAlgorithmID
**digestalgs
= SecCmsSignedDataGetDigestAlgs(sigd
);
318 SecCmsDigestContextRef digcx
= SecCmsDigestContextStartMultiple(digestalgs
);
319 SecCmsDigestContextUpdate(digcx
, CFDataGetBytePtr(detached_contents
), CFDataGetLength(detached_contents
));
320 SecCmsSignedDataSetDigestContext(sigd
, digcx
);
323 if (additional_certs
)
324 require_noerr_quiet(SecCmsSignedDataAddCertList(sigd
, additional_certs
), out
);
326 if (policy
) { /* if no policy is given skip verification */
327 /* find out about signers */
328 int nsigners
= SecCmsSignedDataSignerInfoCount(sigd
);
329 require_quiet(nsigners
== 1, out
);
330 require_noerr_action_quiet(SecCmsSignedDataVerifySignerInfo(sigd
, 0, NULL
, policy
, trustref
),
331 out
, status
= errSecAuthFailed
);
334 status
= errSecSuccess
;
336 if (attached_contents
) {
337 const SecAsn1Item
*content
= SecCmsMessageGetContent(cmsg
);
339 *attached_contents
= CFDataCreate(kCFAllocatorDefault
, content
->Data
, content
->Length
);
341 *attached_contents
= NULL
;
344 if (signed_attributes
) {
345 CFMutableDictionaryRef attrs
= CFDictionaryCreateMutable(kCFAllocatorDefault
,
346 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
347 require_quiet(attrs
, out
);
348 SecCmsAttribute
**signed_attrs
= sigd
->signerInfos
[0]->authAttr
;
349 if (signed_attrs
) while (*signed_attrs
) {
350 CFDataRef type
= CFDataCreate(kCFAllocatorDefault
, (*signed_attrs
)->type
.Data
, (*signed_attrs
)->type
.Length
);
352 CFMutableArrayRef attr
= copy_signed_attribute_values(*signed_attrs
);
354 CFMutableArrayRef existing_attrs
= (CFMutableArrayRef
)CFDictionaryGetValue(attrs
, type
);
355 if (existing_attrs
) {
356 CFIndex count
= CFArrayGetCount(attr
);
358 CFArrayAppendArray(existing_attrs
, attr
, CFRangeMake(0, count
));
360 CFDictionarySetValue(attrs
, type
, attr
);
367 CFMutableArrayRef certs
= NULL
;
369 SecAsn1Item
**cert_datas
= SecCmsSignedDataGetCertificateList(sigd
);
370 certs
= CFArrayCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeArrayCallBacks
);
371 SecAsn1Item
*cert_data
;
372 if (cert_datas
) while ((cert_data
= *cert_datas
) != NULL
) {
373 SecCertificateRef cert
= SecCertificateCreateWithBytes(NULL
, cert_data
->Data
, cert_data
->Length
);
375 CFArrayAppendValue(certs
, cert
);
381 CFDictionaryAddValue(attrs
, kSecCMSAllCerts
, certs
);
383 /* Add "cooked" values separately */
384 CFAbsoluteTime signing_time
;
385 if (errSecSuccess
== SecCmsSignerInfoGetSigningTime(sigd
->signerInfos
[0], &signing_time
)) {
386 CFDateRef signing_date
= CFDateCreate(kCFAllocatorDefault
, signing_time
);
388 CFDictionarySetValue(attrs
, kSecCMSSignDate
, signing_date
);
389 if (signing_date
) CFRelease(signing_date
);
393 CFDataRef hash_agility_value
= NULL
;
394 if (errSecSuccess
== SecCmsSignerInfoGetAppleCodesigningHashAgility(sigd
->signerInfos
[0], &hash_agility_value
)) {
395 if (hash_agility_value
) {
396 CFDictionarySetValue(attrs
, kSecCMSHashAgility
, hash_agility_value
);
400 CFDictionaryRef hash_agility_values
= NULL
;
401 if (errSecSuccess
== SecCmsSignerInfoGetAppleCodesigningHashAgilityV2(sigd
->signerInfos
[0], &hash_agility_values
)) {
402 if (hash_agility_values
) {
403 CFDictionarySetValue(attrs
, kSecCMSHashAgilityV2
, hash_agility_values
);
407 CFAbsoluteTime expiration_time
;
408 if (errSecSuccess
== SecCmsSignerInfoGetAppleExpirationTime(sigd
->signerInfos
[0], &expiration_time
)) {
409 CFDateRef expiration_date
= CFDateCreate(NULL
, expiration_time
);
410 if (expiration_date
) {
411 CFDictionarySetValue(attrs
, kSecCMSExpirationDate
, expiration_date
);
412 CFRetainSafe(expiration_date
);
416 *signed_attributes
= attrs
;
417 if (certs
) CFRelease(certs
);
422 if (cmsg
) SecCmsMessageDestroy(cmsg
);
426 OSStatus
SecCMSVerifyCopyDataAndAttributes(CFDataRef message
, CFDataRef detached_contents
,
427 CFTypeRef policy
, SecTrustRef
*trustref
,
428 CFDataRef
*attached_contents
, CFDictionaryRef
*signed_attributes
)
430 OSStatus status
= SecCMSVerifySignedData_internal(message
, detached_contents
, policy
, trustref
, NULL
, attached_contents
, signed_attributes
);
435 OSStatus
SecCMSVerifySignedData(CFDataRef message
, CFDataRef detached_contents
,
436 CFTypeRef policy
, SecTrustRef
*trustref
, CFArrayRef additional_certificates
,
437 CFDataRef
*attached_contents
, CFDictionaryRef
*message_attributes
)
439 CFDictionaryRef signed_attributes
= NULL
;
440 OSStatus status
= SecCMSVerifySignedData_internal(message
, detached_contents
, policy
, trustref
, additional_certificates
, attached_contents
, &signed_attributes
);
441 if (!status
&& signed_attributes
&& message_attributes
) {
442 *message_attributes
= CFDictionaryCreate(kCFAllocatorDefault
, &kSecCMSSignedAttributes
, (const void **)&signed_attributes
, 1, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
444 if (signed_attributes
) CFRelease(signed_attributes
);
449 OSStatus
SecCMSVerify(CFDataRef message
, CFDataRef detached_contents
,
450 CFTypeRef policy
, SecTrustRef
*trustref
,
451 CFDataRef
*attached_contents
) {
452 return SecCMSVerifySignedData_internal(message
, detached_contents
, policy
, trustref
, NULL
, attached_contents
, NULL
);
455 /* Designed to match the sec submodule implementation available for iOS */
456 CFArrayRef
SecCMSCertificatesOnlyMessageCopyCertificates(CFDataRef message
) {
457 SecCmsMessageRef cmsg
= NULL
;
458 SecCmsContentInfoRef cinfo
;
459 SecCmsSignedDataRef sigd
= NULL
;
460 CFMutableArrayRef certs
= NULL
;
466 CSSM_DATA encoded_message
= { CFDataGetLength(message
), (uint8_t*)CFDataGetBytePtr(message
) };
467 require_noerr_quiet(SecCmsMessageDecode(&encoded_message
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, &cmsg
), out
);
468 /* expected to be a signed data message at the top level */
469 require(cinfo
= SecCmsMessageContentLevel(cmsg
, 0), out
);
470 require(SecCmsContentInfoGetContentTypeTag(cinfo
) == SEC_OID_PKCS7_SIGNED_DATA
, out
);
471 require(sigd
= (SecCmsSignedDataRef
)SecCmsContentInfoGetContent(cinfo
), out
);
473 /* find out about signers */
474 int nsigners
= SecCmsSignedDataSignerInfoCount(sigd
);
475 require(nsigners
== 0, out
);
477 CSSM_DATA_PTR
*cert_datas
= SecCmsSignedDataGetCertificateList(sigd
);
478 certs
= CFArrayCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeArrayCallBacks
);
479 CSSM_DATA_PTR cert_data
;
480 if (cert_datas
) while ((cert_data
= *cert_datas
) != NULL
) {
481 SecCertificateRef cert
= SecCertificateCreateWithBytes(NULL
, cert_data
->Data
, cert_data
->Length
);
483 CFArrayAppendValue(certs
, cert
);
490 if (cmsg
) { SecCmsMessageDestroy(cmsg
); }
491 if (certs
&& CFArrayGetCount(certs
) < 1) {
492 CFReleaseNull(certs
);
499 extern const SecAsn1Template SecCmsMessageTemplate
[];
501 CFDataRef
SecCMSCreateCertificatesOnlyMessage(CFTypeRef cert_or_array_thereof
) {
502 OSStatus status
= errSecParam
;
503 SecCmsMessageRef cmsg
= NULL
;
504 SecCmsContentInfoRef cinfo
;
505 SecCmsSignedDataRef sigd
= NULL
;
506 CFMutableDataRef cert_only_signed_data
= NULL
;
507 CFArrayRef cert_array
= NULL
;
508 CFIndex cert_array_count
= 0;
509 SecCertificateRef cert
= NULL
;
511 require(cert_or_array_thereof
, out
);
513 require(cmsg
= SecCmsMessageCreate(NULL
), out
);
514 require(sigd
= SecCmsSignedDataCreate(cmsg
), out
);
515 require_noerr(SecCmsContentInfoSetContentData(cmsg
, &(sigd
->contentInfo
), NULL
, PR_TRUE
), out
);
516 require(cinfo
= SecCmsMessageGetContentInfo(cmsg
), out
);
517 require_noerr(SecCmsContentInfoSetContentSignedData(cmsg
, cinfo
, sigd
), out
);
518 long version
= SEC_CMS_SIGNED_DATA_VERSION_BASIC
;
519 require(SEC_ASN1EncodeInteger(cmsg
->poolp
, &(sigd
->version
), version
), out
);
521 if (CFGetTypeID(cert_or_array_thereof
) == SecCertificateGetTypeID()) {
522 cert_array
= CFArrayCreate(kCFAllocatorDefault
, &cert_or_array_thereof
, 1, &kCFTypeArrayCallBacks
);
523 } else if (CFGetTypeID(cert_or_array_thereof
) == CFArrayGetTypeID()) {
524 cert_array
= CFArrayCreateCopy(kCFAllocatorDefault
, (CFArrayRef
)cert_or_array_thereof
);
527 require(cert_array
, out
);
528 cert_array_count
= CFArrayGetCount(cert_array
);
529 require(cert_array_count
> 0, out
);
531 sigd
->rawCerts
= (SecAsn1Item
* *)PORT_ArenaAlloc(cmsg
->poolp
, (cert_array_count
+ 1) * sizeof(SecAsn1Item
*));
532 require(sigd
->rawCerts
, out
);
534 for (ix
= 0; ix
< cert_array_count
; ix
++) {
535 cert
= (SecCertificateRef
)CFArrayGetValueAtIndex(cert_array
, ix
);
538 sigd
->rawCerts
[ix
] = PORT_ArenaZAlloc(cmsg
->poolp
, sizeof(SecAsn1Item
));
539 SecAsn1Item cert_data
= { SecCertificateGetLength(cert
),
540 (uint8_t *)SecCertificateGetBytePtr(cert
) };
541 *(sigd
->rawCerts
[ix
]) = cert_data
;
543 sigd
->rawCerts
[ix
] = NULL
;
545 /* this is a SET OF, so we need to sort them guys - we have the DER already, though */
546 if (cert_array_count
> 1)
547 SecCmsArraySort((void **)sigd
->rawCerts
, SecCmsUtilDERCompare
, NULL
, NULL
);
549 cert_only_signed_data
= CFDataCreateMutable(kCFAllocatorDefault
, 0);
550 SecAsn1Item cert_only_signed_data_item
= {};
551 require_quiet(SEC_ASN1EncodeItem(cmsg
->poolp
, &cert_only_signed_data_item
,
552 cmsg
, SecCmsMessageTemplate
), out
);
553 CFDataAppendBytes(cert_only_signed_data
, cert_only_signed_data_item
.Data
,
554 cert_only_signed_data_item
.Length
);
556 status
= errSecSuccess
;
558 if (cert_array
) { CFRelease(cert_array
); }
559 if (status
&& cert_only_signed_data
) { CFRelease(cert_only_signed_data
); }
560 if (cmsg
) SecCmsMessageDestroy(cmsg
);
561 return cert_only_signed_data
;
564 CFDataRef
SecCMSCreateCertificatesOnlyMessageIAP(SecCertificateRef cert
)
566 static const uint8_t header
[] = {
567 0x30, 0x82, 0x03, 0x6d, 0x06, 0x09, 0x2a, 0x86,
568 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x02, 0xa0,
569 0x82, 0x03, 0x5e, 0x30, 0x82, 0x03, 0x5a, 0x02,
570 0x01, 0x01, 0x31, 0x00, 0x30, 0x0b, 0x06, 0x09,
571 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07,
572 0x01, 0xa0, 0x82, 0x03, 0x40
575 static const uint8_t trailer
[] = {
576 0xa1, 0x00, 0x31, 0x00
579 CFMutableDataRef message
= NULL
;
581 const uint8_t *certbytes
;
583 uint8_t *messagebytes
;
586 certdata
= SecCertificateCopyData(cert
);
587 require(certdata
, out
);
589 certbytes
= CFDataGetBytePtr(certdata
);
590 certlen
= CFDataGetLength(certdata
);
591 require(certlen
> UINT8_MAX
, out
);
592 require(certlen
< UINT16_MAX
, out
);
594 message
= CFDataCreateMutable(kCFAllocatorDefault
, 0);
595 require(message
, out
);
597 CFDataAppendBytes(message
, header
, sizeof(header
));
598 CFDataAppendBytes(message
, certbytes
, certlen
);
599 CFDataAppendBytes(message
, trailer
, sizeof(trailer
));
601 messagebytes
= CFDataGetMutableBytePtr(message
);
602 messagelen
= CFDataGetLength(message
);
605 messagebytes
[2] = messagelen
>> 8;
606 messagebytes
[3] = messagelen
& 0xFF;
609 messagebytes
[17] = messagelen
>> 8;
610 messagebytes
[18] = messagelen
& 0xFF;
613 messagebytes
[21] = messagelen
>> 8;
614 messagebytes
[22] = messagelen
& 0xFF;
617 messagebytes
[43] = messagelen
>> 8;
618 messagebytes
[44] = messagelen
& 0xFF;
621 if (certdata
!= NULL
)
628 OSStatus
SecCMSCreateEnvelopedData(CFTypeRef recipient_or_cfarray_thereof
,
629 CFDictionaryRef params
, CFDataRef data
, CFMutableDataRef enveloped_data
)
631 SecCmsMessageRef cmsg
= NULL
;
632 SecCmsContentInfoRef cinfo
;
633 SecCmsEnvelopedDataRef envd
= NULL
;
634 SECOidTag algorithmTag
= SEC_OID_DES_EDE3_CBC
;
636 OSStatus status
= errSecParam
;
637 PLArenaPool
*arena
= NULL
;
640 CFStringRef algorithm_name
= CFDictionaryGetValue(params
, kSecCMSBulkEncryptionAlgorithm
);
641 if (algorithm_name
) {
642 if (CFEqual(kSecCMSEncryptionAlgorithmDESCBC
, algorithm_name
)) {
643 algorithmTag
= SEC_OID_DES_CBC
;
645 } else if (CFEqual(kSecCMSEncryptionAlgorithmAESCBC
, algorithm_name
)) {
646 algorithmTag
= SEC_OID_AES_128_CBC
;
652 require(cmsg
= SecCmsMessageCreate(NULL
), out
);
653 require(envd
= SecCmsEnvelopedDataCreate(cmsg
, algorithmTag
, keySize
), out
);
654 require(cinfo
= SecCmsMessageGetContentInfo(cmsg
), out
);
655 require_noerr(SecCmsContentInfoSetContentEnvelopedData(cmsg
, cinfo
, envd
), out
);
656 require(cinfo
= SecCmsEnvelopedDataGetContentInfo(envd
), out
);
657 require_noerr(SecCmsContentInfoSetContentData(cmsg
, cinfo
, NULL
, false), out
);
658 // == wrapper of: require(SECSuccess == SecCmsContentInfoSetContent(cinfo, SEC_OID_PKCS7_DATA, NULL), out);
660 if (CFGetTypeID(recipient_or_cfarray_thereof
) == CFArrayGetTypeID()) {
661 CFIndex dex
, numCerts
= CFArrayGetCount(recipient_or_cfarray_thereof
);
662 for(dex
=0; dex
<numCerts
; dex
++) {
663 SecCertificateRef recip
=
664 (SecCertificateRef
)CFArrayGetValueAtIndex(recipient_or_cfarray_thereof
, dex
);
665 SecCmsRecipientInfoRef rinfo
;
666 require(rinfo
= SecCmsRecipientInfoCreate(cmsg
, recip
), out
);
667 require_noerr(SecCmsEnvelopedDataAddRecipient(envd
, rinfo
), out
);
669 } else if (CFGetTypeID(recipient_or_cfarray_thereof
) == SecCertificateGetTypeID()) {
670 SecCmsRecipientInfoRef rinfo
;
671 require(rinfo
= SecCmsRecipientInfoCreate(cmsg
, (SecCertificateRef
)recipient_or_cfarray_thereof
), out
);
672 require_noerr(SecCmsEnvelopedDataAddRecipient(envd
, rinfo
), out
);
676 SecAsn1Item input
= {};
678 input
.Length
= CFDataGetLength(data
);
679 input
.Data
= (uint8_t*)CFDataGetBytePtr(data
);
682 CSSM_DATA cssm_enveloped_data
= {0, NULL
};
683 // make an encoder context
684 if ((arena
= PORT_NewArena(1024)) == NULL
) {
687 require_noerr(SecCmsMessageEncode(cmsg
, (data
&& input
.Length
) ? &input
: NULL
, (SecArenaPoolRef
)arena
, &cssm_enveloped_data
), out
);
688 if (enveloped_data
&& cssm_enveloped_data
.Data
) {
689 CFDataAppendBytes(enveloped_data
, cssm_enveloped_data
.Data
, cssm_enveloped_data
.Length
);
692 status
= errSecSuccess
;
694 if (arena
) PORT_FreeArena(arena
, PR_FALSE
);
695 if (cmsg
) SecCmsMessageDestroy(cmsg
);
699 OSStatus
SecCMSDecryptEnvelopedData(CFDataRef message
,
700 CFMutableDataRef data
, SecCertificateRef
*recipient
)
702 SecCmsMessageRef cmsg
= NULL
;
703 SecCmsContentInfoRef cinfo
;
704 SecCmsEnvelopedDataRef envd
= NULL
;
705 SecCertificateRef used_recipient
= NULL
;
706 OSStatus status
= errSecParam
;
708 SecAsn1Item encoded_message
= { CFDataGetLength(message
), (uint8_t*)CFDataGetBytePtr(message
) };
709 require_noerr_action_quiet(SecCmsMessageDecode(&encoded_message
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, &cmsg
),
710 out
, status
= errSecDecode
);
711 require_quiet(cinfo
= SecCmsMessageContentLevel(cmsg
, 0), out
);
712 require_quiet(SecCmsContentInfoGetContentTypeTag(cinfo
) == SEC_OID_PKCS7_ENVELOPED_DATA
, out
);
713 require_quiet(envd
= (SecCmsEnvelopedDataRef
)SecCmsContentInfoGetContent(cinfo
), out
);
714 SecCmsRecipientInfoRef
*rinfo
= envd
->recipientInfos
;
715 while (!used_recipient
&& *rinfo
) {
716 used_recipient
= (*rinfo
)->cert
;
719 require_quiet(2 == SecCmsMessageContentLevelCount(cmsg
), out
);
720 require_quiet(cinfo
= SecCmsMessageContentLevel(cmsg
, 1), out
);
721 require_quiet(SecCmsContentInfoGetContentTypeTag(cinfo
) == SEC_OID_PKCS7_DATA
, out
);
722 const SecAsn1Item
*content
= SecCmsMessageGetContent(cmsg
);
724 CFDataAppendBytes(data
, content
->Data
, content
->Length
);
726 CFRetainSafe(used_recipient
);
727 *recipient
= used_recipient
;
729 status
= errSecSuccess
;
731 if (cmsg
) SecCmsMessageDestroy(cmsg
);