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");
60 CFTypeRef kSecCMSBulkEncryptionAlgorithm
= CFSTR("kSecCMSBulkEncryptionAlgorithm");
61 CFTypeRef kSecCMSEncryptionAlgorithmDESCBC
= CFSTR("kSecCMSEncryptionAlgorithmDESCBC");
62 CFTypeRef kSecCMSEncryptionAlgorithmAESCBC
= CFSTR("kSecCMSEncryptionAlgorithmAESCBC");
64 CFTypeRef kSecCMSSignHashAlgorithm
= CFSTR("kSecCMSSignHashAlgorithm");
65 CFTypeRef kSecCMSHashingAlgorithmSHA1
= CFSTR("kSecCMSHashingAlgorithmSHA1");
66 CFTypeRef kSecCMSHashingAlgorithmSHA256
= CFSTR("kSecCMSHashingAlgorithmSHA256");
67 CFTypeRef kSecCMSHashingAlgorithmSHA384
= CFSTR("kSecCMSHashingAlgorithmSHA384");
68 CFTypeRef kSecCMSHashingAlgorithmSHA512
= CFSTR("kSecCMSHashingAlgorithmSHA512");
70 static SecCmsAttribute
*
71 make_attr(PLArenaPool
*poolp
, SecAsn1Item
*type
, SecAsn1Item
*value
, bool encoded
)
73 SecAsn1Item
* copiedvalue
;
74 SecCmsAttribute
*attr
= (SecCmsAttribute
*)PORT_ArenaZAlloc(poolp
, sizeof(SecCmsAttribute
));
78 if (SECITEM_CopyItem(poolp
, &(attr
->type
), type
) != SECSuccess
)
82 if ((copiedvalue
= SECITEM_AllocItem(poolp
, NULL
, value
->Length
)) == NULL
)
85 if (SECITEM_CopyItem(poolp
, copiedvalue
, value
) != SECSuccess
)
88 if (SecCmsArrayAdd(poolp
, (void ***)&(attr
->values
), (void *)copiedvalue
) != SECSuccess
)
92 attr
->encoded
= encoded
;
99 signerinfo_add_auth_attr(SecCmsSignerInfoRef signerinfo
, /*SECOidTag oidtag*/
100 SecAsn1Item
*oid
, SecAsn1Item
*value
, bool encoded
)
102 PLArenaPool
*poolp
= signerinfo
->cmsg
->poolp
;
103 PORT_Assert (poolp
!= NULL
);
104 void *mark
= PORT_ArenaMark (poolp
);
106 SecCmsAttribute
*attr
= make_attr(poolp
, oid
, value
, encoded
);
107 if (!attr
|| SecCmsAttributeArrayAddAttr(poolp
, &(signerinfo
->authAttr
), attr
) != SECSuccess
)
110 PORT_ArenaUnmark (poolp
, mark
);
114 PORT_Assert (mark
!= NULL
);
115 PORT_ArenaRelease (poolp
, mark
);
119 static void sign_all_attributes(const void *key
, const void *value
, void *context
)
121 SecAsn1Item oid
= { CFDataGetLength(key
), (uint8_t*)CFDataGetBytePtr(key
) },
122 oid_value
= { CFDataGetLength(value
), (uint8_t*)CFDataGetBytePtr(value
) };
124 signerinfo_add_auth_attr((SecCmsSignerInfoRef
)context
, &oid
, &oid_value
, true);
127 static OSStatus
SecCMSSignDataOrDigestAndAttributes(SecIdentityRef identity
,
128 CFDataRef data
, bool detached
, bool data_is_digest
, SECOidTag sign_algorithm
,
129 CFMutableDataRef signed_data
, CFDictionaryRef signed_attributes
, SecCmsCertChainMode chainMode
, CFArrayRef additional_certs
)
131 SecCmsMessageRef cmsg
= NULL
;
132 SecCmsContentInfoRef cinfo
;
133 SecCmsSignedDataRef sigd
= NULL
;
134 SecCmsSignerInfoRef signerinfo
;
135 OSStatus status
= errSecParam
;
136 PLArenaPool
*arena
= NULL
;
138 require(!data_is_digest
|| detached
/* if digest, must be detached */, out
);
140 require(cmsg
= SecCmsMessageCreate(NULL
), out
);
141 require(sigd
= SecCmsSignedDataCreate(cmsg
), out
);
142 require(cinfo
= SecCmsMessageGetContentInfo(cmsg
), out
);
143 require_noerr(SecCmsContentInfoSetContentSignedData(cmsg
, cinfo
, sigd
), out
);
144 require(cinfo
= SecCmsSignedDataGetContentInfo(sigd
), out
);
145 require_noerr(SecCmsContentInfoSetContentData(cmsg
, cinfo
, NULL
, detached
), out
);
146 require(signerinfo
= SecCmsSignerInfoCreate(cmsg
, identity
, sign_algorithm
), out
);
147 if (additional_certs
)
148 require_noerr(SecCmsSignedDataAddCertList(sigd
, additional_certs
), out
);
149 require_noerr(SecCmsSignerInfoIncludeCerts(signerinfo
, chainMode
, certUsageAnyCA
), out
);
150 require_noerr(SecCmsSignerInfoAddSigningTime(signerinfo
, CFAbsoluteTimeGetCurrent()), out
);
152 if (signed_attributes
)
153 CFDictionaryApplyFunction(signed_attributes
, sign_all_attributes
, signerinfo
);
155 require_noerr(SecCmsSignedDataAddSignerInfo(sigd
, signerinfo
), out
);
157 SecAsn1Item input
= {};
159 input
.Length
= CFDataGetLength(data
);
160 input
.Data
= (uint8_t*)CFDataGetBytePtr(data
);
163 CSSM_DATA cssm_signed_data
= {0, NULL
};
164 // make an encoder context
165 if ((arena
= PORT_NewArena(1024)) == NULL
) {
168 if (data_is_digest
) {
169 require_noerr(SecCmsSignedDataSetDigestValue(sigd
, sign_algorithm
, &input
), out
);
170 require_noerr(SecCmsMessageEncode(cmsg
, NULL
, (SecArenaPoolRef
)arena
, &cssm_signed_data
), out
);
173 require_noerr(SecCmsMessageEncode(cmsg
,(data
&& input
.Length
) ? &input
: NULL
,
174 (SecArenaPoolRef
)arena
, &cssm_signed_data
), out
);
176 if (signed_data
&& cssm_signed_data
.Data
) {
177 CFDataAppendBytes(signed_data
, cssm_signed_data
.Data
, cssm_signed_data
.Length
);
180 status
= errSecSuccess
;
182 if (arena
) PORT_FreeArena(arena
, PR_FALSE
);
183 if (cmsg
) SecCmsMessageDestroy(cmsg
);
187 OSStatus
SecCMSSignDataAndAttributes(SecIdentityRef identity
, CFDataRef data
, bool detached
,
188 CFMutableDataRef signed_data
, CFDictionaryRef signed_attributes
)
190 return SecCMSSignDataOrDigestAndAttributes(identity
, data
, detached
, false, SEC_OID_SHA1
,
191 signed_data
, signed_attributes
, SecCmsCMCertChain
, NULL
);
194 OSStatus
SecCMSSignDigestAndAttributes(SecIdentityRef identity
, CFDataRef digest
,
195 CFMutableDataRef signed_data
, CFDictionaryRef signed_attributes
)
197 return SecCMSSignDataOrDigestAndAttributes(identity
, digest
, true, true, SEC_OID_SHA1
,
198 signed_data
, signed_attributes
, SecCmsCMCertChain
, NULL
);
201 OSStatus
SecCMSCreateSignedData(SecIdentityRef identity
, CFDataRef data
,
202 CFDictionaryRef parameters
, CFDictionaryRef signed_attributes
,
203 CFMutableDataRef signed_data
)
205 bool is_digest
= false, is_detached
= false;
206 CFStringRef algorithm_name
= NULL
;
207 SecCmsCertChainMode chain_mode
= SecCmsCMCertChain
;
208 CFArrayRef additional_certs
= NULL
;
211 is_digest
= CFDictionaryGetValueIfPresent(parameters
,
212 kSecCMSSignDigest
, NULL
);
213 is_detached
= CFDictionaryGetValueIfPresent(parameters
,
214 kSecCMSSignDetached
, NULL
);
215 algorithm_name
= CFDictionaryGetValue(parameters
,
216 kSecCMSSignHashAlgorithm
);
218 CFTypeRef chain_mode_param
= CFDictionaryGetValue(parameters
, kSecCMSCertChainMode
);
219 if (chain_mode_param
&& (CFGetTypeID(chain_mode_param
) == CFStringGetTypeID()))
220 chain_mode
= CFStringGetIntValue(chain_mode_param
);
222 CFTypeRef additional_certs_param
= CFDictionaryGetValue(parameters
, kSecCMSAdditionalCerts
);
223 if (additional_certs_param
&& (CFGetTypeID(additional_certs_param
) == CFArrayGetTypeID()))
224 additional_certs
= (CFArrayRef
)additional_certs_param
;
227 SECOidTag algorithm
= SEC_OID_SHA1
;
228 if (algorithm_name
) {
229 if (CFEqual(kSecCMSHashingAlgorithmSHA1
, algorithm_name
)) {
230 algorithm
= SEC_OID_SHA1
;
231 } else if (CFEqual(kSecCMSHashingAlgorithmSHA256
, algorithm_name
)) {
232 algorithm
= SEC_OID_SHA256
;
233 } else if (CFEqual(kSecCMSHashingAlgorithmSHA384
, algorithm_name
)) {
234 algorithm
= SEC_OID_SHA384
;
235 } else if (CFEqual(kSecCMSHashingAlgorithmSHA512
, algorithm_name
)) {
236 algorithm
= SEC_OID_SHA512
;
238 // signing with MD5 is no longer allowed
239 algorithm
= SEC_OID_UNKNOWN
;
243 return SecCMSSignDataOrDigestAndAttributes(identity
, data
,
244 is_detached
, is_digest
, algorithm
,
245 signed_data
, signed_attributes
, chain_mode
, additional_certs
);
249 SecCmsSignedDataSetDigestContext(SecCmsSignedDataRef sigd
,
250 SecCmsDigestContextRef digestContext
)
252 SecAsn1Item
* *digests
;
254 PLArenaPool
*arena
= NULL
;
256 if ((arena
= PORT_NewArena(1024)) == NULL
)
259 if (SecCmsDigestContextFinishMultiple(digestContext
, (SecArenaPoolRef
)arena
, &digests
) != SECSuccess
)
262 SECAlgorithmID
**digestAlgorithms
= SecCmsSignedDataGetDigestAlgs(sigd
);
263 if(digestAlgorithms
== NULL
) {
267 if (SecCmsSignedDataSetDigests(sigd
, digestAlgorithms
, digests
) != SECSuccess
)
271 PORT_FreeArena(arena
, PR_FALSE
);
276 PORT_FreeArena(arena
, PR_FALSE
);
277 return PORT_GetError();
280 static CFMutableArrayRef
copy_signed_attribute_values(SecCmsAttribute
*attr
)
282 CFMutableArrayRef array
= CFArrayCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeArrayCallBacks
);
283 SecAsn1Item
**item
= attr
->values
;
284 if (item
) while (*item
) {
285 CFDataRef asn1data
= CFDataCreate(kCFAllocatorDefault
, (*item
)->Data
, (*item
)->Length
);
287 CFArrayAppendValue(array
, asn1data
);
295 static OSStatus
SecCMSVerifySignedData_internal(CFDataRef message
, CFDataRef detached_contents
,
296 CFTypeRef policy
, SecTrustRef
*trustref
, CFArrayRef additional_certs
,
297 CFDataRef
*attached_contents
, CFDictionaryRef
*signed_attributes
)
299 SecCmsMessageRef cmsg
= NULL
;
300 SecCmsContentInfoRef cinfo
;
301 SecCmsSignedDataRef sigd
= NULL
;
302 OSStatus status
= errSecParam
;
304 require(message
, out
);
305 SecAsn1Item encoded_message
= { CFDataGetLength(message
), (uint8_t*)CFDataGetBytePtr(message
) };
306 require_noerr_action_quiet(SecCmsMessageDecode(&encoded_message
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, &cmsg
),
307 out
, status
= errSecDecode
);
308 /* expected to be a signed data message at the top level */
309 require_quiet(cinfo
= SecCmsMessageContentLevel(cmsg
, 0), out
);
310 require_quiet(SecCmsContentInfoGetContentTypeTag(cinfo
) == SEC_OID_PKCS7_SIGNED_DATA
, out
);
311 require_quiet(sigd
= (SecCmsSignedDataRef
)SecCmsContentInfoGetContent(cinfo
), out
);
313 if (detached_contents
)
315 require_quiet(!SecCmsSignedDataHasDigests(sigd
), out
);
316 SECAlgorithmID
**digestalgs
= SecCmsSignedDataGetDigestAlgs(sigd
);
317 SecCmsDigestContextRef digcx
= SecCmsDigestContextStartMultiple(digestalgs
);
318 SecCmsDigestContextUpdate(digcx
, CFDataGetBytePtr(detached_contents
), CFDataGetLength(detached_contents
));
319 SecCmsSignedDataSetDigestContext(sigd
, digcx
);
322 if (additional_certs
)
323 require_noerr_quiet(SecCmsSignedDataAddCertList(sigd
, additional_certs
), out
);
325 if (policy
) { /* if no policy is given skip verification */
326 /* find out about signers */
327 int nsigners
= SecCmsSignedDataSignerInfoCount(sigd
);
328 require_quiet(nsigners
== 1, out
);
329 require_noerr_action_quiet(SecCmsSignedDataVerifySignerInfo(sigd
, 0, NULL
, policy
, trustref
),
330 out
, status
= errSecAuthFailed
);
333 status
= errSecSuccess
;
335 if (attached_contents
) {
336 const SecAsn1Item
*content
= SecCmsMessageGetContent(cmsg
);
338 *attached_contents
= CFDataCreate(kCFAllocatorDefault
, content
->Data
, content
->Length
);
340 *attached_contents
= NULL
;
343 if (signed_attributes
) {
344 CFMutableDictionaryRef attrs
= CFDictionaryCreateMutable(kCFAllocatorDefault
,
345 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
346 require_quiet(attrs
, out
);
347 SecCmsAttribute
**signed_attrs
= sigd
->signerInfos
[0]->authAttr
;
348 if (signed_attrs
) while (*signed_attrs
) {
349 CFDataRef type
= CFDataCreate(kCFAllocatorDefault
, (*signed_attrs
)->type
.Data
, (*signed_attrs
)->type
.Length
);
351 CFMutableArrayRef attr
= copy_signed_attribute_values(*signed_attrs
);
353 CFMutableArrayRef existing_attrs
= (CFMutableArrayRef
)CFDictionaryGetValue(attrs
, type
);
354 if (existing_attrs
) {
355 CFIndex count
= CFArrayGetCount(attr
);
357 CFArrayAppendArray(existing_attrs
, attr
, CFRangeMake(0, count
));
359 CFDictionarySetValue(attrs
, type
, attr
);
366 CFMutableArrayRef certs
= NULL
;
368 SecAsn1Item
**cert_datas
= SecCmsSignedDataGetCertificateList(sigd
);
369 certs
= CFArrayCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeArrayCallBacks
);
370 SecAsn1Item
*cert_data
;
371 if (cert_datas
) while ((cert_data
= *cert_datas
) != NULL
) {
372 SecCertificateRef cert
= SecCertificateCreateWithBytes(NULL
, cert_data
->Data
, cert_data
->Length
);
374 CFArrayAppendValue(certs
, cert
);
380 CFDictionaryAddValue(attrs
, kSecCMSAllCerts
, certs
);
382 /* Add "cooked" values separately */
383 CFAbsoluteTime signing_time
;
384 if (errSecSuccess
== SecCmsSignerInfoGetSigningTime(sigd
->signerInfos
[0], &signing_time
)) {
385 CFDateRef signing_date
= CFDateCreate(kCFAllocatorDefault
, signing_time
);
387 CFDictionarySetValue(attrs
, kSecCMSSignDate
, signing_date
);
388 if (signing_date
) CFRelease(signing_date
);
392 CFDataRef hash_agility_value
= NULL
;
393 if (errSecSuccess
== SecCmsSignerInfoGetAppleCodesigningHashAgility(sigd
->signerInfos
[0], &hash_agility_value
)) {
394 if (hash_agility_value
) {
395 CFDictionarySetValue(attrs
, kSecCMSHashAgility
, hash_agility_value
);
399 CFDictionaryRef hash_agility_values
= NULL
;
400 if (errSecSuccess
== SecCmsSignerInfoGetAppleCodesigningHashAgilityV2(sigd
->signerInfos
[0], &hash_agility_values
)) {
401 if (hash_agility_values
) {
402 CFDictionarySetValue(attrs
, kSecCMSHashAgilityV2
, hash_agility_values
);
406 *signed_attributes
= attrs
;
407 if (certs
) CFRelease(certs
);
412 if (cmsg
) SecCmsMessageDestroy(cmsg
);
416 OSStatus
SecCMSVerifyCopyDataAndAttributes(CFDataRef message
, CFDataRef detached_contents
,
417 CFTypeRef policy
, SecTrustRef
*trustref
,
418 CFDataRef
*attached_contents
, CFDictionaryRef
*signed_attributes
)
420 OSStatus status
= SecCMSVerifySignedData_internal(message
, detached_contents
, policy
, trustref
, NULL
, attached_contents
, signed_attributes
);
425 OSStatus
SecCMSVerifySignedData(CFDataRef message
, CFDataRef detached_contents
,
426 CFTypeRef policy
, SecTrustRef
*trustref
, CFArrayRef additional_certificates
,
427 CFDataRef
*attached_contents
, CFDictionaryRef
*message_attributes
)
429 CFDictionaryRef signed_attributes
= NULL
;
430 OSStatus status
= SecCMSVerifySignedData_internal(message
, detached_contents
, policy
, trustref
, additional_certificates
, attached_contents
, &signed_attributes
);
431 if (!status
&& signed_attributes
&& message_attributes
) {
432 *message_attributes
= CFDictionaryCreate(kCFAllocatorDefault
, &kSecCMSSignedAttributes
, (const void **)&signed_attributes
, 1, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
434 if (signed_attributes
) CFRelease(signed_attributes
);
439 OSStatus
SecCMSVerify(CFDataRef message
, CFDataRef detached_contents
,
440 CFTypeRef policy
, SecTrustRef
*trustref
,
441 CFDataRef
*attached_contents
) {
442 return SecCMSVerifySignedData_internal(message
, detached_contents
, policy
, trustref
, NULL
, attached_contents
, NULL
);
445 /* Designed to match the sec submodule implementation available for iOS */
446 CFArrayRef
SecCMSCertificatesOnlyMessageCopyCertificates(CFDataRef message
) {
447 SecCmsMessageRef cmsg
= NULL
;
448 SecCmsContentInfoRef cinfo
;
449 SecCmsSignedDataRef sigd
= NULL
;
450 CFMutableArrayRef certs
= NULL
;
452 CSSM_DATA encoded_message
= { CFDataGetLength(message
), (uint8_t*)CFDataGetBytePtr(message
) };
453 require_noerr_quiet(SecCmsMessageDecode(&encoded_message
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, &cmsg
), out
);
454 /* expected to be a signed data message at the top level */
455 require(cinfo
= SecCmsMessageContentLevel(cmsg
, 0), out
);
456 require(SecCmsContentInfoGetContentTypeTag(cinfo
) == SEC_OID_PKCS7_SIGNED_DATA
, out
);
457 require(sigd
= (SecCmsSignedDataRef
)SecCmsContentInfoGetContent(cinfo
), out
);
459 /* find out about signers */
460 int nsigners
= SecCmsSignedDataSignerInfoCount(sigd
);
461 require(nsigners
== 0, out
);
463 CSSM_DATA_PTR
*cert_datas
= SecCmsSignedDataGetCertificateList(sigd
);
464 certs
= CFArrayCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeArrayCallBacks
);
465 CSSM_DATA_PTR cert_data
;
466 if (cert_datas
) while ((cert_data
= *cert_datas
) != NULL
) {
467 SecCertificateRef cert
= SecCertificateCreateWithBytes(NULL
, cert_data
->Data
, cert_data
->Length
);
469 CFArrayAppendValue(certs
, cert
);
477 SecCmsMessageDestroy(cmsg
);
483 extern const SecAsn1Template SecCmsMessageTemplate
[];
485 CFDataRef
SecCMSCreateCertificatesOnlyMessage(CFTypeRef cert_or_array_thereof
) {
486 OSStatus status
= errSecParam
;
487 SecCmsMessageRef cmsg
= NULL
;
488 SecCmsContentInfoRef cinfo
;
489 SecCmsSignedDataRef sigd
= NULL
;
490 CFMutableDataRef cert_only_signed_data
= NULL
;
491 CFArrayRef cert_array
= NULL
;
492 CFIndex cert_array_count
= 0;
493 SecCertificateRef cert
= NULL
;
495 require(cert_or_array_thereof
, out
);
497 require(cmsg
= SecCmsMessageCreate(NULL
), out
);
498 require(sigd
= SecCmsSignedDataCreate(cmsg
), out
);
499 require_noerr(SecCmsContentInfoSetContentData(cmsg
, &(sigd
->contentInfo
), NULL
, PR_TRUE
), out
);
500 require(cinfo
= SecCmsMessageGetContentInfo(cmsg
), out
);
501 require_noerr(SecCmsContentInfoSetContentSignedData(cmsg
, cinfo
, sigd
), out
);
502 long version
= SEC_CMS_SIGNED_DATA_VERSION_BASIC
;
503 require(SEC_ASN1EncodeInteger(cmsg
->poolp
, &(sigd
->version
), version
), out
);
505 if (CFGetTypeID(cert_or_array_thereof
) == SecCertificateGetTypeID()) {
506 cert_array
= CFArrayCreate(kCFAllocatorDefault
, &cert_or_array_thereof
, 1, &kCFTypeArrayCallBacks
);
507 } else if (CFGetTypeID(cert_or_array_thereof
) == CFArrayGetTypeID()) {
508 cert_array
= CFArrayCreateCopy(kCFAllocatorDefault
, (CFArrayRef
)cert_or_array_thereof
);
511 require(cert_array
, out
);
512 cert_array_count
= CFArrayGetCount(cert_array
);
513 require(cert_array_count
> 0, out
);
515 sigd
->rawCerts
= (SecAsn1Item
* *)PORT_ArenaAlloc(cmsg
->poolp
, (cert_array_count
+ 1) * sizeof(SecAsn1Item
*));
516 require(sigd
->rawCerts
, out
);
518 for (ix
= 0; ix
< cert_array_count
; ix
++) {
519 cert
= (SecCertificateRef
)CFArrayGetValueAtIndex(cert_array
, ix
);
522 sigd
->rawCerts
[ix
] = PORT_ArenaZAlloc(cmsg
->poolp
, sizeof(SecAsn1Item
));
523 SecAsn1Item cert_data
= { SecCertificateGetLength(cert
),
524 (uint8_t *)SecCertificateGetBytePtr(cert
) };
525 *(sigd
->rawCerts
[ix
]) = cert_data
;
527 sigd
->rawCerts
[ix
] = NULL
;
529 /* this is a SET OF, so we need to sort them guys - we have the DER already, though */
530 if (cert_array_count
> 1)
531 SecCmsArraySort((void **)sigd
->rawCerts
, SecCmsUtilDERCompare
, NULL
, NULL
);
533 cert_only_signed_data
= CFDataCreateMutable(kCFAllocatorDefault
, 0);
534 SecAsn1Item cert_only_signed_data_item
= {};
535 require_quiet(SEC_ASN1EncodeItem(cmsg
->poolp
, &cert_only_signed_data_item
,
536 cmsg
, SecCmsMessageTemplate
), out
);
537 CFDataAppendBytes(cert_only_signed_data
, cert_only_signed_data_item
.Data
,
538 cert_only_signed_data_item
.Length
);
540 status
= errSecSuccess
;
542 if (cert_array
) { CFRelease(cert_array
); }
543 if (status
&& cert_only_signed_data
) { CFRelease(cert_only_signed_data
); }
544 if (cmsg
) SecCmsMessageDestroy(cmsg
);
545 return cert_only_signed_data
;
548 CFDataRef
SecCMSCreateCertificatesOnlyMessageIAP(SecCertificateRef cert
)
550 static const uint8_t header
[] = {
551 0x30, 0x82, 0x03, 0x6d, 0x06, 0x09, 0x2a, 0x86,
552 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x02, 0xa0,
553 0x82, 0x03, 0x5e, 0x30, 0x82, 0x03, 0x5a, 0x02,
554 0x01, 0x01, 0x31, 0x00, 0x30, 0x0b, 0x06, 0x09,
555 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07,
556 0x01, 0xa0, 0x82, 0x03, 0x40
559 static const uint8_t trailer
[] = {
560 0xa1, 0x00, 0x31, 0x00
563 CFMutableDataRef message
= NULL
;
565 const uint8_t *certbytes
;
567 uint8_t *messagebytes
;
570 certdata
= SecCertificateCopyData(cert
);
571 require(certdata
, out
);
573 certbytes
= CFDataGetBytePtr(certdata
);
574 certlen
= CFDataGetLength(certdata
);
575 require(certlen
> UINT8_MAX
, out
);
576 require(certlen
< UINT16_MAX
, out
);
578 message
= CFDataCreateMutable(kCFAllocatorDefault
, 0);
579 require(message
, out
);
581 CFDataAppendBytes(message
, header
, sizeof(header
));
582 CFDataAppendBytes(message
, certbytes
, certlen
);
583 CFDataAppendBytes(message
, trailer
, sizeof(trailer
));
585 messagebytes
= CFDataGetMutableBytePtr(message
);
586 messagelen
= CFDataGetLength(message
);
589 messagebytes
[2] = messagelen
>> 8;
590 messagebytes
[3] = messagelen
& 0xFF;
593 messagebytes
[17] = messagelen
>> 8;
594 messagebytes
[18] = messagelen
& 0xFF;
597 messagebytes
[21] = messagelen
>> 8;
598 messagebytes
[22] = messagelen
& 0xFF;
601 messagebytes
[43] = messagelen
>> 8;
602 messagebytes
[44] = messagelen
& 0xFF;
605 if (certdata
!= NULL
)
612 OSStatus
SecCMSCreateEnvelopedData(CFTypeRef recipient_or_cfarray_thereof
,
613 CFDictionaryRef params
, CFDataRef data
, CFMutableDataRef enveloped_data
)
615 SecCmsMessageRef cmsg
= NULL
;
616 SecCmsContentInfoRef cinfo
;
617 SecCmsEnvelopedDataRef envd
= NULL
;
618 SECOidTag algorithmTag
= SEC_OID_DES_EDE3_CBC
;
620 OSStatus status
= errSecParam
;
621 PLArenaPool
*arena
= NULL
;
624 CFStringRef algorithm_name
= CFDictionaryGetValue(params
, kSecCMSBulkEncryptionAlgorithm
);
625 if (algorithm_name
) {
626 if (CFEqual(kSecCMSEncryptionAlgorithmDESCBC
, algorithm_name
)) {
627 algorithmTag
= SEC_OID_DES_CBC
;
629 } else if (CFEqual(kSecCMSEncryptionAlgorithmAESCBC
, algorithm_name
)) {
630 algorithmTag
= SEC_OID_AES_128_CBC
;
636 require(cmsg
= SecCmsMessageCreate(NULL
), out
);
637 require(envd
= SecCmsEnvelopedDataCreate(cmsg
, algorithmTag
, keySize
), out
);
638 require(cinfo
= SecCmsMessageGetContentInfo(cmsg
), out
);
639 require_noerr(SecCmsContentInfoSetContentEnvelopedData(cmsg
, cinfo
, envd
), out
);
640 require(cinfo
= SecCmsEnvelopedDataGetContentInfo(envd
), out
);
641 require_noerr(SecCmsContentInfoSetContentData(cmsg
, cinfo
, NULL
, false), out
);
642 // == wrapper of: require(SECSuccess == SecCmsContentInfoSetContent(cinfo, SEC_OID_PKCS7_DATA, NULL), out);
644 if (CFGetTypeID(recipient_or_cfarray_thereof
) == CFArrayGetTypeID()) {
645 CFIndex dex
, numCerts
= CFArrayGetCount(recipient_or_cfarray_thereof
);
646 for(dex
=0; dex
<numCerts
; dex
++) {
647 SecCertificateRef recip
=
648 (SecCertificateRef
)CFArrayGetValueAtIndex(recipient_or_cfarray_thereof
, dex
);
649 SecCmsRecipientInfoRef rinfo
;
650 require(rinfo
= SecCmsRecipientInfoCreate(cmsg
, recip
), out
);
651 require_noerr(SecCmsEnvelopedDataAddRecipient(envd
, rinfo
), out
);
653 } else if (CFGetTypeID(recipient_or_cfarray_thereof
) == SecCertificateGetTypeID()) {
654 SecCmsRecipientInfoRef rinfo
;
655 require(rinfo
= SecCmsRecipientInfoCreate(cmsg
, (SecCertificateRef
)recipient_or_cfarray_thereof
), out
);
656 require_noerr(SecCmsEnvelopedDataAddRecipient(envd
, rinfo
), out
);
660 SecAsn1Item input
= {};
662 input
.Length
= CFDataGetLength(data
);
663 input
.Data
= (uint8_t*)CFDataGetBytePtr(data
);
666 CSSM_DATA cssm_enveloped_data
= {0, NULL
};
667 // make an encoder context
668 if ((arena
= PORT_NewArena(1024)) == NULL
) {
671 require_noerr(SecCmsMessageEncode(cmsg
, (data
&& input
.Length
) ? &input
: NULL
, (SecArenaPoolRef
)arena
, &cssm_enveloped_data
), out
);
672 if (enveloped_data
&& cssm_enveloped_data
.Data
) {
673 CFDataAppendBytes(enveloped_data
, cssm_enveloped_data
.Data
, cssm_enveloped_data
.Length
);
676 status
= errSecSuccess
;
678 if (arena
) PORT_FreeArena(arena
, PR_FALSE
);
679 if (cmsg
) SecCmsMessageDestroy(cmsg
);
683 OSStatus
SecCMSDecryptEnvelopedData(CFDataRef message
,
684 CFMutableDataRef data
, SecCertificateRef
*recipient
)
686 SecCmsMessageRef cmsg
= NULL
;
687 SecCmsContentInfoRef cinfo
;
688 SecCmsEnvelopedDataRef envd
= NULL
;
689 SecCertificateRef used_recipient
= NULL
;
690 OSStatus status
= errSecParam
;
692 SecAsn1Item encoded_message
= { CFDataGetLength(message
), (uint8_t*)CFDataGetBytePtr(message
) };
693 require_noerr_action_quiet(SecCmsMessageDecode(&encoded_message
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, &cmsg
),
694 out
, status
= errSecDecode
);
695 require_quiet(cinfo
= SecCmsMessageContentLevel(cmsg
, 0), out
);
696 require_quiet(SecCmsContentInfoGetContentTypeTag(cinfo
) == SEC_OID_PKCS7_ENVELOPED_DATA
, out
);
697 require_quiet(envd
= (SecCmsEnvelopedDataRef
)SecCmsContentInfoGetContent(cinfo
), out
);
698 SecCmsRecipientInfoRef
*rinfo
= envd
->recipientInfos
;
699 while (!used_recipient
&& *rinfo
) {
700 used_recipient
= (*rinfo
)->cert
;
703 require_quiet(2 == SecCmsMessageContentLevelCount(cmsg
), out
);
704 require_quiet(cinfo
= SecCmsMessageContentLevel(cmsg
, 1), out
);
705 require_quiet(SecCmsContentInfoGetContentTypeTag(cinfo
) == SEC_OID_PKCS7_DATA
, out
);
706 const SecAsn1Item
*content
= SecCmsMessageGetContent(cmsg
);
708 CFDataAppendBytes(data
, content
->Data
, content
->Length
);
710 CFRetainSafe(used_recipient
);
711 *recipient
= used_recipient
;
713 status
= errSecSuccess
;
715 if (cmsg
) SecCmsMessageDestroy(cmsg
);