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>
48 #include <Security/SecCMS.h>
50 CFTypeRef kSecCMSSignDigest
= CFSTR("kSecCMSSignDigest");
51 CFTypeRef kSecCMSSignDetached
= CFSTR("kSecCMSSignDetached");
52 CFTypeRef kSecCMSCertChainMode
= CFSTR("kSecCMSCertChainMode");
53 CFTypeRef kSecCMSCertChainModeNone
= CFSTR("0");
54 CFTypeRef kSecCMSAdditionalCerts
= CFSTR("kSecCMSAdditionalCerts");
55 CFTypeRef kSecCMSSignedAttributes
= CFSTR("kSecCMSSignedAttributes");
56 CFTypeRef kSecCMSSignDate
= CFSTR("kSecCMSSignDate");
57 CFTypeRef kSecCMSAllCerts
= CFSTR("kSecCMSAllCerts");
58 CFTypeRef kSecCMSHashAgility
= CFSTR("kSecCMSHashAgility");
59 CFTypeRef kSecCMSHashAgilityV2
= CFSTR("kSecCMSHashAgilityV2");
60 CFTypeRef kSecCMSExpirationDate
= CFSTR("kSecCMSExpirationDate");
62 CFTypeRef kSecCMSBulkEncryptionAlgorithm
= CFSTR("kSecCMSBulkEncryptionAlgorithm");
63 CFTypeRef kSecCMSEncryptionAlgorithmDESCBC
= CFSTR("kSecCMSEncryptionAlgorithmDESCBC");
64 CFTypeRef kSecCMSEncryptionAlgorithmAESCBC
= CFSTR("kSecCMSEncryptionAlgorithmAESCBC");
66 CFTypeRef kSecCMSSignHashAlgorithm
= CFSTR("kSecCMSSignHashAlgorithm");
67 CFTypeRef kSecCMSHashingAlgorithmMD5
= CFSTR("kSecCMSHashingAlgorithmMD5");
68 CFTypeRef kSecCMSHashingAlgorithmSHA1
= CFSTR("kSecCMSHashingAlgorithmSHA1");
69 CFTypeRef kSecCMSHashingAlgorithmSHA256
= CFSTR("kSecCMSHashingAlgorithmSHA256");
70 CFTypeRef kSecCMSHashingAlgorithmSHA384
= CFSTR("kSecCMSHashingAlgorithmSHA384");
71 CFTypeRef kSecCMSHashingAlgorithmSHA512
= CFSTR("kSecCMSHashingAlgorithmSHA512");
73 static SecCmsAttribute
*
74 make_attr(PLArenaPool
*poolp
, SecAsn1Item
*type
, SecAsn1Item
*value
, bool encoded
)
76 SecAsn1Item
* copiedvalue
;
77 SecCmsAttribute
*attr
= (SecCmsAttribute
*)PORT_ArenaZAlloc(poolp
, sizeof(SecCmsAttribute
));
81 if (SECITEM_CopyItem(poolp
, &(attr
->type
), type
) != SECSuccess
)
85 if ((copiedvalue
= SECITEM_AllocItem(poolp
, NULL
, value
->Length
)) == NULL
)
88 if (SECITEM_CopyItem(poolp
, copiedvalue
, value
) != SECSuccess
)
91 if (SecCmsArrayAdd(poolp
, (void ***)&(attr
->values
), (void *)copiedvalue
) != SECSuccess
)
95 attr
->encoded
= encoded
;
102 signerinfo_add_auth_attr(SecCmsSignerInfoRef signerinfo
, /*SECOidTag oidtag*/
103 SecAsn1Item
*oid
, SecAsn1Item
*value
, bool encoded
)
105 PLArenaPool
*poolp
= signerinfo
->cmsg
->poolp
;
106 PORT_Assert (poolp
!= NULL
);
107 void *mark
= PORT_ArenaMark (poolp
);
109 SecCmsAttribute
*attr
= make_attr(poolp
, oid
, value
, encoded
);
110 if (!attr
|| SecCmsAttributeArrayAddAttr(poolp
, &(signerinfo
->authAttr
), attr
) != SECSuccess
)
113 PORT_ArenaUnmark (poolp
, mark
);
117 PORT_Assert (mark
!= NULL
);
118 PORT_ArenaRelease (poolp
, mark
);
122 static void sign_all_attributes(const void *key
, const void *value
, void *context
)
124 SecAsn1Item oid
= { CFDataGetLength(key
), (uint8_t*)CFDataGetBytePtr(key
) },
125 oid_value
= { CFDataGetLength(value
), (uint8_t*)CFDataGetBytePtr(value
) };
127 signerinfo_add_auth_attr((SecCmsSignerInfoRef
)context
, &oid
, &oid_value
, true);
130 static OSStatus
SecCMSSignDataOrDigestAndAttributes(SecIdentityRef identity
,
131 CFDataRef data
, bool detached
, bool data_is_digest
, SECOidTag sign_algorithm
,
132 CFMutableDataRef signed_data
, CFDictionaryRef signed_attributes
, SecCmsCertChainMode chainMode
, CFArrayRef additional_certs
)
134 SecCmsMessageRef cmsg
= NULL
;
135 SecCmsContentInfoRef cinfo
;
136 SecCmsSignedDataRef sigd
= NULL
;
137 SecCmsSignerInfoRef signerinfo
;
138 OSStatus status
= errSecParam
;
139 PLArenaPool
*arena
= NULL
;
141 require(!data_is_digest
|| detached
/* if digest, must be detached */, out
);
143 require(cmsg
= SecCmsMessageCreate(NULL
), out
);
144 require(sigd
= SecCmsSignedDataCreate(cmsg
), out
);
145 require(cinfo
= SecCmsMessageGetContentInfo(cmsg
), out
);
146 require_noerr(SecCmsContentInfoSetContentSignedData(cmsg
, cinfo
, sigd
), out
);
147 require(cinfo
= SecCmsSignedDataGetContentInfo(sigd
), out
);
148 require_noerr(SecCmsContentInfoSetContentData(cmsg
, cinfo
, NULL
, detached
), out
);
149 require(signerinfo
= SecCmsSignerInfoCreate(cmsg
, identity
, sign_algorithm
), out
);
150 if (additional_certs
)
151 require_noerr(SecCmsSignedDataAddCertList(sigd
, additional_certs
), out
);
152 require_noerr(SecCmsSignerInfoIncludeCerts(signerinfo
, chainMode
, certUsageAnyCA
), out
);
153 require_noerr(SecCmsSignerInfoAddSigningTime(signerinfo
, CFAbsoluteTimeGetCurrent()), out
);
155 if (signed_attributes
)
156 CFDictionaryApplyFunction(signed_attributes
, sign_all_attributes
, signerinfo
);
158 require_noerr(SecCmsSignedDataAddSignerInfo(sigd
, signerinfo
), out
);
160 SecAsn1Item input
= {};
162 input
.Length
= CFDataGetLength(data
);
163 input
.Data
= (uint8_t*)CFDataGetBytePtr(data
);
166 CSSM_DATA cssm_signed_data
= {0, NULL
};
167 // make an encoder context
168 if ((arena
= PORT_NewArena(1024)) == NULL
) {
171 if (data_is_digest
) {
172 require_noerr(SecCmsSignedDataSetDigestValue(sigd
, sign_algorithm
, &input
), out
);
173 require_noerr(SecCmsMessageEncode(cmsg
, NULL
, (SecArenaPoolRef
)arena
, &cssm_signed_data
), out
);
176 require_noerr(SecCmsMessageEncode(cmsg
,(data
&& input
.Length
) ? &input
: NULL
,
177 (SecArenaPoolRef
)arena
, &cssm_signed_data
), out
);
179 if (signed_data
&& cssm_signed_data
.Data
) {
180 CFDataAppendBytes(signed_data
, cssm_signed_data
.Data
, cssm_signed_data
.Length
);
183 status
= errSecSuccess
;
185 if (arena
) PORT_FreeArena(arena
, PR_FALSE
);
186 if (cmsg
) SecCmsMessageDestroy(cmsg
);
190 OSStatus
SecCMSSignDataAndAttributes(SecIdentityRef identity
, CFDataRef data
, bool detached
,
191 CFMutableDataRef signed_data
, CFDictionaryRef signed_attributes
)
193 return SecCMSSignDataOrDigestAndAttributes(identity
, data
, detached
, false, SEC_OID_SHA1
,
194 signed_data
, signed_attributes
, SecCmsCMCertChain
, NULL
);
197 OSStatus
SecCMSSignDigestAndAttributes(SecIdentityRef identity
, CFDataRef digest
,
198 CFMutableDataRef signed_data
, CFDictionaryRef signed_attributes
)
200 return SecCMSSignDataOrDigestAndAttributes(identity
, digest
, true, true, SEC_OID_SHA1
,
201 signed_data
, signed_attributes
, SecCmsCMCertChain
, NULL
);
204 OSStatus
SecCMSCreateSignedData(SecIdentityRef identity
, CFDataRef data
,
205 CFDictionaryRef parameters
, CFDictionaryRef signed_attributes
,
206 CFMutableDataRef signed_data
)
208 bool is_digest
= false, is_detached
= false;
209 CFStringRef algorithm_name
= NULL
;
210 SecCmsCertChainMode chain_mode
= SecCmsCMCertChain
;
211 CFArrayRef additional_certs
= NULL
;
214 is_digest
= CFDictionaryGetValueIfPresent(parameters
,
215 kSecCMSSignDigest
, NULL
);
216 is_detached
= CFDictionaryGetValueIfPresent(parameters
,
217 kSecCMSSignDetached
, NULL
);
218 algorithm_name
= CFDictionaryGetValue(parameters
,
219 kSecCMSSignHashAlgorithm
);
221 CFTypeRef chain_mode_param
= CFDictionaryGetValue(parameters
, kSecCMSCertChainMode
);
222 if (chain_mode_param
&& (CFGetTypeID(chain_mode_param
) == CFStringGetTypeID()))
223 chain_mode
= CFStringGetIntValue(chain_mode_param
);
225 CFTypeRef additional_certs_param
= CFDictionaryGetValue(parameters
, kSecCMSAdditionalCerts
);
226 if (additional_certs_param
&& (CFGetTypeID(additional_certs_param
) == CFArrayGetTypeID()))
227 additional_certs
= (CFArrayRef
)additional_certs_param
;
230 SECOidTag algorithm
= SEC_OID_SHA1
;
231 if (algorithm_name
) {
232 if (CFEqual(kSecCMSHashingAlgorithmSHA1
, algorithm_name
)) {
233 algorithm
= SEC_OID_SHA1
;
234 } else if (CFEqual(kSecCMSHashingAlgorithmSHA256
, algorithm_name
)) {
235 algorithm
= SEC_OID_SHA256
;
236 } else if (CFEqual(kSecCMSHashingAlgorithmSHA384
, algorithm_name
)) {
237 algorithm
= SEC_OID_SHA384
;
238 } else if (CFEqual(kSecCMSHashingAlgorithmSHA512
, algorithm_name
)) {
239 algorithm
= SEC_OID_SHA512
;
241 // signing with MD5 is no longer allowed
242 algorithm
= SEC_OID_UNKNOWN
;
246 return SecCMSSignDataOrDigestAndAttributes(identity
, data
,
247 is_detached
, is_digest
, algorithm
,
248 signed_data
, signed_attributes
, chain_mode
, additional_certs
);
252 SecCmsSignedDataSetDigestContext(SecCmsSignedDataRef sigd
,
253 SecCmsDigestContextRef digestContext
)
255 SecAsn1Item
* *digests
;
257 PLArenaPool
*arena
= NULL
;
259 if ((arena
= PORT_NewArena(1024)) == NULL
)
262 if (SecCmsDigestContextFinishMultiple(digestContext
, (SecArenaPoolRef
)arena
, &digests
) != SECSuccess
)
265 SECAlgorithmID
**digestAlgorithms
= SecCmsSignedDataGetDigestAlgs(sigd
);
266 if(digestAlgorithms
== NULL
) {
270 if (SecCmsSignedDataSetDigests(sigd
, digestAlgorithms
, digests
) != SECSuccess
)
274 PORT_FreeArena(arena
, PR_FALSE
);
279 PORT_FreeArena(arena
, PR_FALSE
);
280 return PORT_GetError();
283 static CFMutableArrayRef
copy_signed_attribute_values(SecCmsAttribute
*attr
)
285 CFMutableArrayRef array
= CFArrayCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeArrayCallBacks
);
286 SecAsn1Item
**item
= attr
->values
;
287 if (item
) while (*item
) {
288 CFDataRef asn1data
= CFDataCreate(kCFAllocatorDefault
, (*item
)->Data
, (*item
)->Length
);
290 CFArrayAppendValue(array
, asn1data
);
298 static OSStatus
SecCMSVerifySignedData_internal(CFDataRef message
, CFDataRef detached_contents
,
299 CFTypeRef policy
, SecTrustRef
*trustref
, CFArrayRef additional_certs
,
300 CFDataRef
*attached_contents
, CFDictionaryRef
*signed_attributes
)
302 SecCmsMessageRef cmsg
= NULL
;
303 SecCmsContentInfoRef cinfo
;
304 SecCmsSignedDataRef sigd
= NULL
;
305 OSStatus status
= errSecParam
;
307 require(message
, out
);
308 SecAsn1Item encoded_message
= { CFDataGetLength(message
), (uint8_t*)CFDataGetBytePtr(message
) };
309 require_noerr_action_quiet(SecCmsMessageDecode(&encoded_message
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, &cmsg
),
310 out
, status
= errSecDecode
);
311 /* expected to be a signed data message at the top level */
312 require_quiet(cinfo
= SecCmsMessageContentLevel(cmsg
, 0), out
);
313 require_quiet(SecCmsContentInfoGetContentTypeTag(cinfo
) == SEC_OID_PKCS7_SIGNED_DATA
, out
);
314 require_quiet(sigd
= (SecCmsSignedDataRef
)SecCmsContentInfoGetContent(cinfo
), out
);
316 if (detached_contents
)
318 require_quiet(!SecCmsSignedDataHasDigests(sigd
), out
);
319 SECAlgorithmID
**digestalgs
= SecCmsSignedDataGetDigestAlgs(sigd
);
320 SecCmsDigestContextRef digcx
= SecCmsDigestContextStartMultiple(digestalgs
);
321 SecCmsDigestContextUpdate(digcx
, CFDataGetBytePtr(detached_contents
), CFDataGetLength(detached_contents
));
322 SecCmsSignedDataSetDigestContext(sigd
, digcx
);
325 if (additional_certs
)
326 require_noerr_quiet(SecCmsSignedDataAddCertList(sigd
, additional_certs
), out
);
328 if (policy
) { /* if no policy is given skip verification */
329 /* find out about signers */
330 int nsigners
= SecCmsSignedDataSignerInfoCount(sigd
);
331 require_quiet(nsigners
== 1, out
);
332 require_noerr_action_quiet(SecCmsSignedDataVerifySignerInfo(sigd
, 0, NULL
, policy
, trustref
),
333 out
, status
= errSecAuthFailed
);
336 status
= errSecSuccess
;
338 if (attached_contents
) {
339 const SecAsn1Item
*content
= SecCmsMessageGetContent(cmsg
);
341 *attached_contents
= CFDataCreate(kCFAllocatorDefault
, content
->Data
, content
->Length
);
343 *attached_contents
= NULL
;
346 if (signed_attributes
) {
347 CFMutableDictionaryRef attrs
= CFDictionaryCreateMutable(kCFAllocatorDefault
,
348 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
349 require_quiet(attrs
, out
);
350 SecCmsAttribute
**signed_attrs
= sigd
->signerInfos
[0]->authAttr
;
351 if (signed_attrs
) while (*signed_attrs
) {
352 CFDataRef type
= CFDataCreate(kCFAllocatorDefault
, (*signed_attrs
)->type
.Data
, (*signed_attrs
)->type
.Length
);
354 CFMutableArrayRef attr
= copy_signed_attribute_values(*signed_attrs
);
356 CFMutableArrayRef existing_attrs
= (CFMutableArrayRef
)CFDictionaryGetValue(attrs
, type
);
357 if (existing_attrs
) {
358 CFIndex count
= CFArrayGetCount(attr
);
360 CFArrayAppendArray(existing_attrs
, attr
, CFRangeMake(0, count
));
362 CFDictionarySetValue(attrs
, type
, attr
);
369 CFMutableArrayRef certs
= NULL
;
371 SecAsn1Item
**cert_datas
= SecCmsSignedDataGetCertificateList(sigd
);
372 certs
= CFArrayCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeArrayCallBacks
);
373 SecAsn1Item
*cert_data
;
374 if (cert_datas
) while ((cert_data
= *cert_datas
) != NULL
) {
375 SecCertificateRef cert
= SecCertificateCreateWithBytes(NULL
, cert_data
->Data
, cert_data
->Length
);
377 CFArrayAppendValue(certs
, cert
);
383 CFDictionaryAddValue(attrs
, kSecCMSAllCerts
, certs
);
385 /* Add "cooked" values separately */
386 CFAbsoluteTime signing_time
;
387 if (errSecSuccess
== SecCmsSignerInfoGetSigningTime(sigd
->signerInfos
[0], &signing_time
)) {
388 CFDateRef signing_date
= CFDateCreate(kCFAllocatorDefault
, signing_time
);
390 CFDictionarySetValue(attrs
, kSecCMSSignDate
, signing_date
);
391 if (signing_date
) CFRelease(signing_date
);
395 CFDataRef hash_agility_value
= NULL
;
396 if (errSecSuccess
== SecCmsSignerInfoGetAppleCodesigningHashAgility(sigd
->signerInfos
[0], &hash_agility_value
)) {
397 if (hash_agility_value
) {
398 CFDictionarySetValue(attrs
, kSecCMSHashAgility
, hash_agility_value
);
402 CFDictionaryRef hash_agility_values
= NULL
;
403 if (errSecSuccess
== SecCmsSignerInfoGetAppleCodesigningHashAgilityV2(sigd
->signerInfos
[0], &hash_agility_values
)) {
404 if (hash_agility_values
) {
405 CFDictionarySetValue(attrs
, kSecCMSHashAgilityV2
, hash_agility_values
);
409 CFAbsoluteTime expiration_time
;
410 if (errSecSuccess
== SecCmsSignerInfoGetAppleExpirationTime(sigd
->signerInfos
[0], &expiration_time
)) {
411 CFDateRef expiration_date
= CFDateCreate(NULL
, expiration_time
);
412 if (expiration_date
) {
413 CFDictionarySetValue(attrs
, kSecCMSExpirationDate
, expiration_date
);
414 CFReleaseSafe(expiration_date
);
418 *signed_attributes
= attrs
;
419 if (certs
) CFRelease(certs
);
424 if (cmsg
) SecCmsMessageDestroy(cmsg
);
428 OSStatus
SecCMSVerifyCopyDataAndAttributes(CFDataRef message
, CFDataRef detached_contents
,
429 CFTypeRef policy
, SecTrustRef
*trustref
,
430 CFDataRef
*attached_contents
, CFDictionaryRef
*signed_attributes
)
432 OSStatus status
= SecCMSVerifySignedData_internal(message
, detached_contents
, policy
, trustref
, NULL
, attached_contents
, signed_attributes
);
437 OSStatus
SecCMSVerifySignedData(CFDataRef message
, CFDataRef detached_contents
,
438 CFTypeRef policy
, SecTrustRef
*trustref
, CFArrayRef additional_certificates
,
439 CFDataRef
*attached_contents
, CFDictionaryRef
*message_attributes
)
441 CFDictionaryRef signed_attributes
= NULL
;
442 OSStatus status
= SecCMSVerifySignedData_internal(message
, detached_contents
, policy
, trustref
, additional_certificates
, attached_contents
, &signed_attributes
);
443 if (!status
&& signed_attributes
&& message_attributes
) {
444 *message_attributes
= CFDictionaryCreate(kCFAllocatorDefault
, &kSecCMSSignedAttributes
, (const void **)&signed_attributes
, 1, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
446 if (signed_attributes
) CFRelease(signed_attributes
);
451 OSStatus
SecCMSVerify(CFDataRef message
, CFDataRef detached_contents
,
452 CFTypeRef policy
, SecTrustRef
*trustref
,
453 CFDataRef
*attached_contents
) {
454 return SecCMSVerifySignedData_internal(message
, detached_contents
, policy
, trustref
, NULL
, attached_contents
, NULL
);
457 /* Designed to match the sec submodule implementation available for iOS */
458 CFArrayRef
SecCMSCertificatesOnlyMessageCopyCertificates(CFDataRef message
) {
459 SecCmsMessageRef cmsg
= NULL
;
460 SecCmsContentInfoRef cinfo
;
461 SecCmsSignedDataRef sigd
= NULL
;
462 CFMutableArrayRef certs
= NULL
;
468 CSSM_DATA encoded_message
= { CFDataGetLength(message
), (uint8_t*)CFDataGetBytePtr(message
) };
469 require_noerr_quiet(SecCmsMessageDecode(&encoded_message
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, &cmsg
), out
);
470 /* expected to be a signed data message at the top level */
471 require(cinfo
= SecCmsMessageContentLevel(cmsg
, 0), out
);
472 require(SecCmsContentInfoGetContentTypeTag(cinfo
) == SEC_OID_PKCS7_SIGNED_DATA
, out
);
473 require(sigd
= (SecCmsSignedDataRef
)SecCmsContentInfoGetContent(cinfo
), out
);
475 /* find out about signers */
476 int nsigners
= SecCmsSignedDataSignerInfoCount(sigd
);
477 require(nsigners
== 0, out
);
479 CSSM_DATA_PTR
*cert_datas
= SecCmsSignedDataGetCertificateList(sigd
);
480 certs
= CFArrayCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeArrayCallBacks
);
481 CSSM_DATA_PTR cert_data
;
482 if (cert_datas
) while ((cert_data
= *cert_datas
) != NULL
) {
483 SecCertificateRef cert
= SecCertificateCreateWithBytes(NULL
, cert_data
->Data
, cert_data
->Length
);
485 CFArrayAppendValue(certs
, cert
);
492 if (cmsg
) { SecCmsMessageDestroy(cmsg
); }
493 if (certs
&& CFArrayGetCount(certs
) < 1) {
494 CFReleaseNull(certs
);
501 extern const SecAsn1Template SecCmsMessageTemplate
[];
503 CFDataRef
SecCMSCreateCertificatesOnlyMessage(CFTypeRef cert_or_array_thereof
) {
504 OSStatus status
= errSecParam
;
505 SecCmsMessageRef cmsg
= NULL
;
506 SecCmsContentInfoRef cinfo
;
507 SecCmsSignedDataRef sigd
= NULL
;
508 CFMutableDataRef cert_only_signed_data
= NULL
;
509 CFArrayRef cert_array
= NULL
;
510 CFIndex cert_array_count
= 0;
511 SecCertificateRef cert
= NULL
;
513 require(cert_or_array_thereof
, out
);
515 require(cmsg
= SecCmsMessageCreate(NULL
), out
);
516 require(sigd
= SecCmsSignedDataCreate(cmsg
), out
);
517 require_noerr(SecCmsContentInfoSetContentData(cmsg
, &(sigd
->contentInfo
), NULL
, PR_TRUE
), out
);
518 require(cinfo
= SecCmsMessageGetContentInfo(cmsg
), out
);
519 require_noerr(SecCmsContentInfoSetContentSignedData(cmsg
, cinfo
, sigd
), out
);
520 long version
= SEC_CMS_SIGNED_DATA_VERSION_BASIC
;
521 require(SEC_ASN1EncodeInteger(cmsg
->poolp
, &(sigd
->version
), version
), out
);
523 if (CFGetTypeID(cert_or_array_thereof
) == SecCertificateGetTypeID()) {
524 cert_array
= CFArrayCreate(kCFAllocatorDefault
, &cert_or_array_thereof
, 1, &kCFTypeArrayCallBacks
);
525 } else if (CFGetTypeID(cert_or_array_thereof
) == CFArrayGetTypeID()) {
526 cert_array
= CFArrayCreateCopy(kCFAllocatorDefault
, (CFArrayRef
)cert_or_array_thereof
);
529 require(cert_array
, out
);
530 cert_array_count
= CFArrayGetCount(cert_array
);
531 require(cert_array_count
> 0, out
);
533 sigd
->rawCerts
= (SecAsn1Item
* *)PORT_ArenaAlloc(cmsg
->poolp
, (cert_array_count
+ 1) * sizeof(SecAsn1Item
*));
534 require(sigd
->rawCerts
, out
);
536 for (ix
= 0; ix
< cert_array_count
; ix
++) {
537 cert
= (SecCertificateRef
)CFArrayGetValueAtIndex(cert_array
, ix
);
540 sigd
->rawCerts
[ix
] = PORT_ArenaZAlloc(cmsg
->poolp
, sizeof(SecAsn1Item
));
541 SecAsn1Item cert_data
= { SecCertificateGetLength(cert
),
542 (uint8_t *)SecCertificateGetBytePtr(cert
) };
543 *(sigd
->rawCerts
[ix
]) = cert_data
;
545 sigd
->rawCerts
[ix
] = NULL
;
547 /* this is a SET OF, so we need to sort them guys - we have the DER already, though */
548 if (cert_array_count
> 1)
549 SecCmsArraySort((void **)sigd
->rawCerts
, SecCmsUtilDERCompare
, NULL
, NULL
);
551 cert_only_signed_data
= CFDataCreateMutable(kCFAllocatorDefault
, 0);
552 SecAsn1Item cert_only_signed_data_item
= {};
553 require_quiet(SEC_ASN1EncodeItem(cmsg
->poolp
, &cert_only_signed_data_item
,
554 cmsg
, SecCmsMessageTemplate
), out
);
555 CFDataAppendBytes(cert_only_signed_data
, cert_only_signed_data_item
.Data
,
556 cert_only_signed_data_item
.Length
);
558 status
= errSecSuccess
;
560 if (cert_array
) { CFRelease(cert_array
); }
561 if (status
&& cert_only_signed_data
) { CFRelease(cert_only_signed_data
); }
562 if (cmsg
) SecCmsMessageDestroy(cmsg
);
563 return cert_only_signed_data
;
566 CFDataRef
SecCMSCreateCertificatesOnlyMessageIAP(SecCertificateRef cert
)
568 static const uint8_t header
[] = {
569 0x30, 0x82, 0x03, 0x6d, 0x06, 0x09, 0x2a, 0x86,
570 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x02, 0xa0,
571 0x82, 0x03, 0x5e, 0x30, 0x82, 0x03, 0x5a, 0x02,
572 0x01, 0x01, 0x31, 0x00, 0x30, 0x0b, 0x06, 0x09,
573 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07,
574 0x01, 0xa0, 0x82, 0x03, 0x40
577 static const uint8_t trailer
[] = {
578 0xa1, 0x00, 0x31, 0x00
581 CFMutableDataRef message
= NULL
;
583 const uint8_t *certbytes
;
585 uint8_t *messagebytes
;
588 certdata
= SecCertificateCopyData(cert
);
589 require(certdata
, out
);
591 certbytes
= CFDataGetBytePtr(certdata
);
592 certlen
= CFDataGetLength(certdata
);
593 require(certlen
> UINT8_MAX
, out
);
594 require(certlen
< UINT16_MAX
, out
);
596 message
= CFDataCreateMutable(kCFAllocatorDefault
, 0);
597 require(message
, out
);
599 CFDataAppendBytes(message
, header
, sizeof(header
));
600 CFDataAppendBytes(message
, certbytes
, certlen
);
601 CFDataAppendBytes(message
, trailer
, sizeof(trailer
));
603 messagebytes
= CFDataGetMutableBytePtr(message
);
604 messagelen
= CFDataGetLength(message
);
607 messagebytes
[2] = messagelen
>> 8;
608 messagebytes
[3] = messagelen
& 0xFF;
611 messagebytes
[17] = messagelen
>> 8;
612 messagebytes
[18] = messagelen
& 0xFF;
615 messagebytes
[21] = messagelen
>> 8;
616 messagebytes
[22] = messagelen
& 0xFF;
619 messagebytes
[43] = messagelen
>> 8;
620 messagebytes
[44] = messagelen
& 0xFF;
623 if (certdata
!= NULL
)
630 OSStatus
SecCMSCreateEnvelopedData(CFTypeRef recipient_or_cfarray_thereof
,
631 CFDictionaryRef params
, CFDataRef data
, CFMutableDataRef enveloped_data
)
633 SecCmsMessageRef cmsg
= NULL
;
634 SecCmsContentInfoRef cinfo
;
635 SecCmsEnvelopedDataRef envd
= NULL
;
636 SECOidTag algorithmTag
= SEC_OID_DES_EDE3_CBC
;
638 OSStatus status
= errSecParam
;
639 PLArenaPool
*arena
= NULL
;
642 CFStringRef algorithm_name
= CFDictionaryGetValue(params
, kSecCMSBulkEncryptionAlgorithm
);
643 if (algorithm_name
) {
644 if (CFEqual(kSecCMSEncryptionAlgorithmDESCBC
, algorithm_name
)) {
645 algorithmTag
= SEC_OID_DES_CBC
;
647 } else if (CFEqual(kSecCMSEncryptionAlgorithmAESCBC
, algorithm_name
)) {
648 algorithmTag
= SEC_OID_AES_128_CBC
;
654 require(cmsg
= SecCmsMessageCreate(NULL
), out
);
655 require(envd
= SecCmsEnvelopedDataCreate(cmsg
, algorithmTag
, keySize
), out
);
656 require(cinfo
= SecCmsMessageGetContentInfo(cmsg
), out
);
657 require_noerr(SecCmsContentInfoSetContentEnvelopedData(cmsg
, cinfo
, envd
), out
);
658 require(cinfo
= SecCmsEnvelopedDataGetContentInfo(envd
), out
);
659 require_noerr(SecCmsContentInfoSetContentData(cmsg
, cinfo
, NULL
, false), out
);
660 // == wrapper of: require(SECSuccess == SecCmsContentInfoSetContent(cinfo, SEC_OID_PKCS7_DATA, NULL), out);
662 if (CFGetTypeID(recipient_or_cfarray_thereof
) == CFArrayGetTypeID()) {
663 CFIndex dex
, numCerts
= CFArrayGetCount(recipient_or_cfarray_thereof
);
664 for(dex
=0; dex
<numCerts
; dex
++) {
665 SecCertificateRef recip
=
666 (SecCertificateRef
)CFArrayGetValueAtIndex(recipient_or_cfarray_thereof
, dex
);
667 SecCmsRecipientInfoRef rinfo
;
668 require(rinfo
= SecCmsRecipientInfoCreate(cmsg
, recip
), out
);
669 require_noerr(SecCmsEnvelopedDataAddRecipient(envd
, rinfo
), out
);
671 } else if (CFGetTypeID(recipient_or_cfarray_thereof
) == SecCertificateGetTypeID()) {
672 SecCmsRecipientInfoRef rinfo
;
673 require(rinfo
= SecCmsRecipientInfoCreate(cmsg
, (SecCertificateRef
)recipient_or_cfarray_thereof
), out
);
674 require_noerr(SecCmsEnvelopedDataAddRecipient(envd
, rinfo
), out
);
678 SecAsn1Item input
= {};
680 input
.Length
= CFDataGetLength(data
);
681 input
.Data
= (uint8_t*)CFDataGetBytePtr(data
);
684 CSSM_DATA cssm_enveloped_data
= {0, NULL
};
685 // make an encoder context
686 if ((arena
= PORT_NewArena(1024)) == NULL
) {
689 require_noerr(SecCmsMessageEncode(cmsg
, (data
&& input
.Length
) ? &input
: NULL
, (SecArenaPoolRef
)arena
, &cssm_enveloped_data
), out
);
690 if (enveloped_data
&& cssm_enveloped_data
.Data
) {
691 CFDataAppendBytes(enveloped_data
, cssm_enveloped_data
.Data
, cssm_enveloped_data
.Length
);
694 status
= errSecSuccess
;
696 if (arena
) PORT_FreeArena(arena
, PR_FALSE
);
697 if (cmsg
) SecCmsMessageDestroy(cmsg
);
701 OSStatus
SecCMSDecryptEnvelopedData(CFDataRef message
,
702 CFMutableDataRef data
, SecCertificateRef
*recipient
)
704 SecCmsMessageRef cmsg
= NULL
;
705 SecCmsContentInfoRef cinfo
;
706 SecCmsEnvelopedDataRef envd
= NULL
;
707 SecCertificateRef used_recipient
= NULL
;
708 OSStatus status
= errSecParam
;
710 SecAsn1Item encoded_message
= { CFDataGetLength(message
), (uint8_t*)CFDataGetBytePtr(message
) };
711 require_noerr_action_quiet(SecCmsMessageDecode(&encoded_message
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, &cmsg
),
712 out
, status
= errSecDecode
);
713 require_quiet(cinfo
= SecCmsMessageContentLevel(cmsg
, 0), out
);
714 require_quiet(SecCmsContentInfoGetContentTypeTag(cinfo
) == SEC_OID_PKCS7_ENVELOPED_DATA
, out
);
715 require_quiet(envd
= (SecCmsEnvelopedDataRef
)SecCmsContentInfoGetContent(cinfo
), out
);
716 SecCmsRecipientInfoRef
*rinfo
= envd
->recipientInfos
;
717 while (!used_recipient
&& *rinfo
) {
718 used_recipient
= (*rinfo
)->cert
;
721 require_quiet(2 == SecCmsMessageContentLevelCount(cmsg
), out
);
722 require_quiet(cinfo
= SecCmsMessageContentLevel(cmsg
, 1), out
);
723 require_quiet(SecCmsContentInfoGetContentTypeTag(cinfo
) == SEC_OID_PKCS7_DATA
, out
);
724 const SecAsn1Item
*content
= SecCmsMessageGetContent(cmsg
);
726 CFDataAppendBytes(data
, content
->Data
, content
->Length
);
728 CFRetainSafe(used_recipient
);
729 *recipient
= used_recipient
;
731 status
= errSecSuccess
;
733 if (cmsg
) SecCmsMessageDestroy(cmsg
);