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");
58 CFTypeRef kSecCMSBulkEncryptionAlgorithm
= CFSTR("kSecCMSBulkEncryptionAlgorithm");
59 CFTypeRef kSecCMSEncryptionAlgorithmDESCBC
= CFSTR("kSecCMSEncryptionAlgorithmDESCBC");
60 CFTypeRef kSecCMSEncryptionAlgorithmAESCBC
= CFSTR("kSecCMSEncryptionAlgorithmAESCBC");
62 CFTypeRef kSecCMSSignHashAlgorithm
= CFSTR("kSecCMSSignHashAlgorithm");
63 CFTypeRef kSecCMSHashingAlgorithmSHA1
= CFSTR("kSecCMSHashingAlgorithmSHA1");
64 CFTypeRef kSecCMSHashingAlgorithmSHA256
= CFSTR("kSecCMSHashingAlgorithmSHA256");
65 CFTypeRef kSecCMSHashingAlgorithmSHA384
= CFSTR("kSecCMSHashingAlgorithmSHA384");
66 CFTypeRef kSecCMSHashingAlgorithmSHA512
= CFSTR("kSecCMSHashingAlgorithmSHA512");
68 static SecCmsAttribute
*
69 make_attr(PLArenaPool
*poolp
, SecAsn1Item
*type
, SecAsn1Item
*value
, bool encoded
)
71 SecAsn1Item
* copiedvalue
;
72 SecCmsAttribute
*attr
= (SecCmsAttribute
*)PORT_ArenaZAlloc(poolp
, sizeof(SecCmsAttribute
));
76 if (SECITEM_CopyItem(poolp
, &(attr
->type
), type
) != SECSuccess
)
80 if ((copiedvalue
= SECITEM_AllocItem(poolp
, NULL
, value
->Length
)) == NULL
)
83 if (SECITEM_CopyItem(poolp
, copiedvalue
, value
) != SECSuccess
)
86 if (SecCmsArrayAdd(poolp
, (void ***)&(attr
->values
), (void *)copiedvalue
) != SECSuccess
)
90 attr
->encoded
= encoded
;
97 signerinfo_add_auth_attr(SecCmsSignerInfoRef signerinfo
, /*SECOidTag oidtag*/
98 SecAsn1Item
*oid
, SecAsn1Item
*value
, bool encoded
)
100 PLArenaPool
*poolp
= signerinfo
->cmsg
->poolp
;
101 PORT_Assert (poolp
!= NULL
);
102 void *mark
= PORT_ArenaMark (poolp
);
104 SecCmsAttribute
*attr
= make_attr(poolp
, oid
, value
, encoded
);
105 if (!attr
|| SecCmsAttributeArrayAddAttr(poolp
, &(signerinfo
->authAttr
), attr
) != SECSuccess
)
108 PORT_ArenaUnmark (poolp
, mark
);
112 PORT_Assert (mark
!= NULL
);
113 PORT_ArenaRelease (poolp
, mark
);
117 static void sign_all_attributes(const void *key
, const void *value
, void *context
)
119 SecAsn1Item oid
= { CFDataGetLength(key
), (uint8_t*)CFDataGetBytePtr(key
) },
120 oid_value
= { CFDataGetLength(value
), (uint8_t*)CFDataGetBytePtr(value
) };
122 signerinfo_add_auth_attr((SecCmsSignerInfoRef
)context
, &oid
, &oid_value
, true);
125 static OSStatus
SecCMSSignDataOrDigestAndAttributes(SecIdentityRef identity
,
126 CFDataRef data
, bool detached
, bool data_is_digest
, SECOidTag sign_algorithm
,
127 CFMutableDataRef signed_data
, CFDictionaryRef signed_attributes
, SecCmsCertChainMode chainMode
, CFArrayRef additional_certs
)
129 SecCmsMessageRef cmsg
= NULL
;
130 SecCmsContentInfoRef cinfo
;
131 SecCmsSignedDataRef sigd
= NULL
;
132 SecCmsSignerInfoRef signerinfo
;
133 OSStatus status
= errSecParam
;
134 PLArenaPool
*arena
= NULL
;
136 require(!data_is_digest
|| detached
/* if digest, must be detached */, out
);
138 require(cmsg
= SecCmsMessageCreate(NULL
), out
);
139 require(sigd
= SecCmsSignedDataCreate(cmsg
), out
);
140 require(cinfo
= SecCmsMessageGetContentInfo(cmsg
), out
);
141 require_noerr(SecCmsContentInfoSetContentSignedData(cmsg
, cinfo
, sigd
), out
);
142 require(cinfo
= SecCmsSignedDataGetContentInfo(sigd
), out
);
143 require_noerr(SecCmsContentInfoSetContentData(cmsg
, cinfo
, NULL
, detached
), out
);
144 require(signerinfo
= SecCmsSignerInfoCreate(cmsg
, identity
, sign_algorithm
), out
);
145 if (additional_certs
)
146 require_noerr(SecCmsSignedDataAddCertList(sigd
, additional_certs
), out
);
147 require_noerr(SecCmsSignerInfoIncludeCerts(signerinfo
, chainMode
, certUsageAnyCA
), out
);
148 require_noerr(SecCmsSignerInfoAddSigningTime(signerinfo
, CFAbsoluteTimeGetCurrent()), out
);
150 if (signed_attributes
)
151 CFDictionaryApplyFunction(signed_attributes
, sign_all_attributes
, signerinfo
);
153 require_noerr(SecCmsSignedDataAddSignerInfo(sigd
, signerinfo
), out
);
155 SecAsn1Item input
= {};
157 input
.Length
= CFDataGetLength(data
);
158 input
.Data
= (uint8_t*)CFDataGetBytePtr(data
);
161 CSSM_DATA cssm_signed_data
= {0, NULL
};
162 // make an encoder context
163 if ((arena
= PORT_NewArena(1024)) == NULL
) {
166 if (data_is_digest
) {
167 require_noerr(SecCmsSignedDataSetDigestValue(sigd
, sign_algorithm
, &input
), out
);
168 require_noerr(SecCmsMessageEncode(cmsg
, NULL
, (SecArenaPoolRef
)arena
, &cssm_signed_data
), out
);
171 require_noerr(SecCmsMessageEncode(cmsg
,(data
&& input
.Length
) ? &input
: NULL
,
172 (SecArenaPoolRef
)arena
, &cssm_signed_data
), out
);
174 if (signed_data
&& cssm_signed_data
.Data
) {
175 CFDataAppendBytes(signed_data
, cssm_signed_data
.Data
, cssm_signed_data
.Length
);
178 status
= errSecSuccess
;
180 if (arena
) PORT_FreeArena(arena
, PR_FALSE
);
181 if (cmsg
) SecCmsMessageDestroy(cmsg
);
185 OSStatus
SecCMSCreateSignedData(SecIdentityRef identity
, CFDataRef data
,
186 CFDictionaryRef parameters
, CFDictionaryRef signed_attributes
,
187 CFMutableDataRef signed_data
)
189 bool is_digest
= false, is_detached
= false;
190 CFStringRef algorithm_name
= NULL
;
191 SecCmsCertChainMode chain_mode
= SecCmsCMCertChain
;
192 CFArrayRef additional_certs
= NULL
;
195 is_digest
= CFDictionaryGetValueIfPresent(parameters
,
196 kSecCMSSignDigest
, NULL
);
197 is_detached
= CFDictionaryGetValueIfPresent(parameters
,
198 kSecCMSSignDetached
, NULL
);
199 algorithm_name
= CFDictionaryGetValue(parameters
,
200 kSecCMSSignHashAlgorithm
);
202 CFTypeRef chain_mode_param
= CFDictionaryGetValue(parameters
, kSecCMSCertChainMode
);
203 if (chain_mode_param
&& (CFGetTypeID(chain_mode_param
) == CFStringGetTypeID()))
204 chain_mode
= CFStringGetIntValue(chain_mode_param
);
206 CFTypeRef additional_certs_param
= CFDictionaryGetValue(parameters
, kSecCMSAdditionalCerts
);
207 if (additional_certs_param
&& (CFGetTypeID(additional_certs_param
) == CFArrayGetTypeID()))
208 additional_certs
= (CFArrayRef
)additional_certs_param
;
211 SECOidTag algorithm
= SEC_OID_SHA1
;
212 if (algorithm_name
) {
213 if (CFEqual(kSecCMSHashingAlgorithmSHA1
, algorithm_name
)) {
214 algorithm
= SEC_OID_SHA1
;
215 } else if (CFEqual(kSecCMSHashingAlgorithmSHA256
, algorithm_name
)) {
216 algorithm
= SEC_OID_SHA256
;
217 } else if (CFEqual(kSecCMSHashingAlgorithmSHA384
, algorithm_name
)) {
218 algorithm
= SEC_OID_SHA384
;
219 } else if (CFEqual(kSecCMSHashingAlgorithmSHA512
, algorithm_name
)) {
220 algorithm
= SEC_OID_SHA512
;
222 // signing with MD5 is no longer allowed
223 algorithm
= SEC_OID_UNKNOWN
;
227 return SecCMSSignDataOrDigestAndAttributes(identity
, data
,
228 is_detached
, is_digest
, algorithm
,
229 signed_data
, signed_attributes
, chain_mode
, additional_certs
);
233 SecCmsSignedDataSetDigestContext(SecCmsSignedDataRef sigd
,
234 SecCmsDigestContextRef digestContext
)
236 SecAsn1Item
* *digests
;
238 PLArenaPool
*arena
= NULL
;
240 if ((arena
= PORT_NewArena(1024)) == NULL
)
243 if (SecCmsDigestContextFinishMultiple(digestContext
, (SecArenaPoolRef
)arena
, &digests
) != SECSuccess
)
246 SECAlgorithmID
**digestAlgorithms
= SecCmsSignedDataGetDigestAlgs(sigd
);
247 if(digestAlgorithms
== NULL
) {
251 if (SecCmsSignedDataSetDigests(sigd
, digestAlgorithms
, digests
) != SECSuccess
)
255 PORT_FreeArena(arena
, PR_FALSE
);
260 PORT_FreeArena(arena
, PR_FALSE
);
261 return PORT_GetError();
264 static CFMutableArrayRef
copy_signed_attribute_values(SecCmsAttribute
*attr
)
266 CFMutableArrayRef array
= CFArrayCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeArrayCallBacks
);
267 SecAsn1Item
**item
= attr
->values
;
268 if (item
) while (*item
) {
269 CFDataRef asn1data
= CFDataCreate(kCFAllocatorDefault
, (*item
)->Data
, (*item
)->Length
);
271 CFArrayAppendValue(array
, asn1data
);
279 static OSStatus
SecCMSVerifySignedData_internal(CFDataRef message
, CFDataRef detached_contents
,
280 CFTypeRef policy
, SecTrustRef
*trustref
, CFArrayRef additional_certs
,
281 CFDataRef
*attached_contents
, CFDictionaryRef
*signed_attributes
)
283 SecCmsMessageRef cmsg
= NULL
;
284 SecCmsContentInfoRef cinfo
;
285 SecCmsSignedDataRef sigd
= NULL
;
286 OSStatus status
= errSecParam
;
288 require(message
, out
);
289 SecAsn1Item encoded_message
= { CFDataGetLength(message
), (uint8_t*)CFDataGetBytePtr(message
) };
290 require_noerr_action_quiet(SecCmsMessageDecode(&encoded_message
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, &cmsg
),
291 out
, status
= errSecDecode
);
292 /* expected to be a signed data message at the top level */
293 require_quiet(cinfo
= SecCmsMessageContentLevel(cmsg
, 0), out
);
294 require_quiet(SecCmsContentInfoGetContentTypeTag(cinfo
) == SEC_OID_PKCS7_SIGNED_DATA
, out
);
295 require_quiet(sigd
= (SecCmsSignedDataRef
)SecCmsContentInfoGetContent(cinfo
), out
);
297 if (detached_contents
)
299 require_quiet(!SecCmsSignedDataHasDigests(sigd
), out
);
300 SECAlgorithmID
**digestalgs
= SecCmsSignedDataGetDigestAlgs(sigd
);
301 SecCmsDigestContextRef digcx
= SecCmsDigestContextStartMultiple(digestalgs
);
302 SecCmsDigestContextUpdate(digcx
, CFDataGetBytePtr(detached_contents
), CFDataGetLength(detached_contents
));
303 SecCmsSignedDataSetDigestContext(sigd
, digcx
);
306 if (additional_certs
)
307 require_noerr_quiet(SecCmsSignedDataAddCertList(sigd
, additional_certs
), out
);
309 if (policy
) { /* if no policy is given skip verification */
310 /* find out about signers */
311 int nsigners
= SecCmsSignedDataSignerInfoCount(sigd
);
312 require_quiet(nsigners
== 1, out
);
313 require_noerr_action_quiet(SecCmsSignedDataVerifySignerInfo(sigd
, 0, NULL
, policy
, trustref
),
314 out
, status
= errSecAuthFailed
);
317 status
= errSecSuccess
;
319 if (attached_contents
) {
320 const SecAsn1Item
*content
= SecCmsMessageGetContent(cmsg
);
322 *attached_contents
= CFDataCreate(kCFAllocatorDefault
, content
->Data
, content
->Length
);
324 *attached_contents
= NULL
;
327 if (signed_attributes
) {
328 CFMutableDictionaryRef attrs
= CFDictionaryCreateMutable(kCFAllocatorDefault
,
329 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
330 require_quiet(attrs
, out
);
331 SecCmsAttribute
**signed_attrs
= sigd
->signerInfos
[0]->authAttr
;
332 if (signed_attrs
) while (*signed_attrs
) {
333 CFDataRef type
= CFDataCreate(kCFAllocatorDefault
, (*signed_attrs
)->type
.Data
, (*signed_attrs
)->type
.Length
);
335 CFMutableArrayRef attr
= copy_signed_attribute_values(*signed_attrs
);
337 CFMutableArrayRef existing_attrs
= (CFMutableArrayRef
)CFDictionaryGetValue(attrs
, type
);
338 if (existing_attrs
) {
339 CFIndex count
= CFArrayGetCount(attr
);
341 CFArrayAppendArray(existing_attrs
, attr
, CFRangeMake(0, count
));
343 CFDictionarySetValue(attrs
, type
, attr
);
350 CFMutableArrayRef certs
= NULL
;
352 SecAsn1Item
**cert_datas
= SecCmsSignedDataGetCertificateList(sigd
);
353 certs
= CFArrayCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeArrayCallBacks
);
354 SecAsn1Item
*cert_data
;
355 if (cert_datas
) while ((cert_data
= *cert_datas
) != NULL
) {
356 SecCertificateRef cert
= SecCertificateCreateWithBytes(NULL
, cert_data
->Data
, cert_data
->Length
);
358 CFArrayAppendValue(certs
, cert
);
364 CFDictionaryAddValue(attrs
, kSecCMSAllCerts
, certs
);
366 /* Add "cooked" values separately */
367 CFAbsoluteTime signing_time
;
368 if (errSecSuccess
== SecCmsSignerInfoGetSigningTime(sigd
->signerInfos
[0], &signing_time
)) {
369 CFDateRef signing_date
= CFDateCreate(kCFAllocatorDefault
, signing_time
);
371 CFDictionarySetValue(attrs
, kSecCMSSignDate
, signing_date
);
372 if (signing_date
) CFRelease(signing_date
);
376 *signed_attributes
= attrs
;
377 if (certs
) CFRelease(certs
);
382 if (cmsg
) SecCmsMessageDestroy(cmsg
);
386 OSStatus
SecCMSVerifyCopyDataAndAttributes(CFDataRef message
, CFDataRef detached_contents
,
387 CFTypeRef policy
, SecTrustRef
*trustref
,
388 CFDataRef
*attached_contents
, CFDictionaryRef
*signed_attributes
)
390 OSStatus status
= SecCMSVerifySignedData_internal(message
, detached_contents
, policy
, trustref
, NULL
, attached_contents
, signed_attributes
);
395 OSStatus
SecCMSVerifySignedData(CFDataRef message
, CFDataRef detached_contents
,
396 CFTypeRef policy
, SecTrustRef
*trustref
, CFArrayRef additional_certificates
,
397 CFDataRef
*attached_contents
, CFDictionaryRef
*message_attributes
)
399 CFDictionaryRef signed_attributes
= NULL
;
400 OSStatus status
= SecCMSVerifySignedData_internal(message
, detached_contents
, policy
, trustref
, additional_certificates
, attached_contents
, &signed_attributes
);
401 if (!status
&& signed_attributes
&& message_attributes
) {
402 *message_attributes
= CFDictionaryCreate(kCFAllocatorDefault
, &kSecCMSSignedAttributes
, (const void **)&signed_attributes
, 1, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
404 if (signed_attributes
) CFRelease(signed_attributes
);
409 OSStatus
SecCMSVerify(CFDataRef message
, CFDataRef detached_contents
,
410 CFTypeRef policy
, SecTrustRef
*trustref
,
411 CFDataRef
*attached_contents
) {
412 return SecCMSVerifySignedData_internal(message
, detached_contents
, policy
, trustref
, NULL
, attached_contents
, NULL
);
415 /* Designed to match the sec submodule implementation available for iOS */
416 CFArrayRef
SecCMSCertificatesOnlyMessageCopyCertificates(CFDataRef message
) {
417 SecCmsMessageRef cmsg
= NULL
;
418 SecCmsContentInfoRef cinfo
;
419 SecCmsSignedDataRef sigd
= NULL
;
420 CFMutableArrayRef certs
= NULL
;
422 CSSM_DATA encoded_message
= { CFDataGetLength(message
), (uint8_t*)CFDataGetBytePtr(message
) };
423 require_noerr_quiet(SecCmsMessageDecode(&encoded_message
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, &cmsg
), out
);
424 /* expected to be a signed data message at the top level */
425 require(cinfo
= SecCmsMessageContentLevel(cmsg
, 0), out
);
426 require(SecCmsContentInfoGetContentTypeTag(cinfo
) == SEC_OID_PKCS7_SIGNED_DATA
, out
);
427 require(sigd
= (SecCmsSignedDataRef
)SecCmsContentInfoGetContent(cinfo
), out
);
429 /* find out about signers */
430 int nsigners
= SecCmsSignedDataSignerInfoCount(sigd
);
431 require(nsigners
== 0, out
);
433 CSSM_DATA_PTR
*cert_datas
= SecCmsSignedDataGetCertificateList(sigd
);
434 certs
= CFArrayCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeArrayCallBacks
);
435 CSSM_DATA_PTR cert_data
;
436 if (cert_datas
) while ((cert_data
= *cert_datas
) != NULL
) {
437 SecCertificateRef cert
= SecCertificateCreateWithBytes(NULL
, cert_data
->Data
, cert_data
->Length
);
439 CFArrayAppendValue(certs
, cert
);
447 SecCmsMessageDestroy(cmsg
);
453 extern const SecAsn1Template SecCmsMessageTemplate
[];
455 CFDataRef
SecCMSCreateCertificatesOnlyMessage(CFTypeRef cert_or_array_thereof
) {
456 OSStatus status
= errSecParam
;
457 SecCmsMessageRef cmsg
= NULL
;
458 SecCmsContentInfoRef cinfo
;
459 SecCmsSignedDataRef sigd
= NULL
;
460 CFMutableDataRef cert_only_signed_data
= NULL
;
461 CFArrayRef cert_array
= NULL
;
462 CFIndex cert_array_count
= 0;
463 SecCertificateRef cert
= NULL
;
465 require(cert_or_array_thereof
, out
);
467 require(cmsg
= SecCmsMessageCreate(NULL
), out
);
468 require(sigd
= SecCmsSignedDataCreate(cmsg
), out
);
469 require_noerr(SecCmsContentInfoSetContentData(cmsg
, &(sigd
->contentInfo
), NULL
, PR_TRUE
), out
);
470 require(cinfo
= SecCmsMessageGetContentInfo(cmsg
), out
);
471 require_noerr(SecCmsContentInfoSetContentSignedData(cmsg
, cinfo
, sigd
), out
);
472 long version
= SEC_CMS_SIGNED_DATA_VERSION_BASIC
;
473 require(SEC_ASN1EncodeInteger(cmsg
->poolp
, &(sigd
->version
), version
), out
);
475 if (CFGetTypeID(cert_or_array_thereof
) == SecCertificateGetTypeID()) {
476 cert_array
= CFArrayCreate(kCFAllocatorDefault
, &cert_or_array_thereof
, 1, &kCFTypeArrayCallBacks
);
477 } else if (CFGetTypeID(cert_or_array_thereof
) == CFArrayGetTypeID()) {
478 cert_array
= CFArrayCreateCopy(kCFAllocatorDefault
, (CFArrayRef
)cert_or_array_thereof
);
481 require(cert_array
, out
);
482 cert_array_count
= CFArrayGetCount(cert_array
);
483 require(cert_array_count
> 0, out
);
485 sigd
->rawCerts
= (SecAsn1Item
* *)PORT_ArenaAlloc(cmsg
->poolp
, (cert_array_count
+ 1) * sizeof(SecAsn1Item
*));
486 require(sigd
->rawCerts
, out
);
488 for (ix
= 0; ix
< cert_array_count
; ix
++) {
489 cert
= (SecCertificateRef
)CFArrayGetValueAtIndex(cert_array
, ix
);
492 sigd
->rawCerts
[ix
] = PORT_ArenaZAlloc(cmsg
->poolp
, sizeof(SecAsn1Item
));
493 SecAsn1Item cert_data
= { SecCertificateGetLength(cert
),
494 (uint8_t *)SecCertificateGetBytePtr(cert
) };
495 *(sigd
->rawCerts
[ix
]) = cert_data
;
497 sigd
->rawCerts
[ix
] = NULL
;
499 /* this is a SET OF, so we need to sort them guys - we have the DER already, though */
500 if (cert_array_count
> 1)
501 SecCmsArraySort((void **)sigd
->rawCerts
, SecCmsUtilDERCompare
, NULL
, NULL
);
503 cert_only_signed_data
= CFDataCreateMutable(kCFAllocatorDefault
, 0);
504 SecAsn1Item cert_only_signed_data_item
= {};
505 require_quiet(SEC_ASN1EncodeItem(cmsg
->poolp
, &cert_only_signed_data_item
,
506 cmsg
, SecCmsMessageTemplate
), out
);
507 CFDataAppendBytes(cert_only_signed_data
, cert_only_signed_data_item
.Data
,
508 cert_only_signed_data_item
.Length
);
510 status
= errSecSuccess
;
512 if (cert_array
) { CFRelease(cert_array
); }
513 if (status
&& cert_only_signed_data
) { CFRelease(cert_only_signed_data
); }
514 if (cmsg
) SecCmsMessageDestroy(cmsg
);
515 return cert_only_signed_data
;
518 CFDataRef
SecCMSCreateCertificatesOnlyMessageIAP(SecCertificateRef cert
)
520 static const uint8_t header
[] = {
521 0x30, 0x82, 0x03, 0x6d, 0x06, 0x09, 0x2a, 0x86,
522 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x02, 0xa0,
523 0x82, 0x03, 0x5e, 0x30, 0x82, 0x03, 0x5a, 0x02,
524 0x01, 0x01, 0x31, 0x00, 0x30, 0x0b, 0x06, 0x09,
525 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07,
526 0x01, 0xa0, 0x82, 0x03, 0x40
529 static const uint8_t trailer
[] = {
530 0xa1, 0x00, 0x31, 0x00
533 CFMutableDataRef message
= NULL
;
535 const uint8_t *certbytes
;
537 uint8_t *messagebytes
;
540 certdata
= SecCertificateCopyData(cert
);
541 require(certdata
, out
);
543 certbytes
= CFDataGetBytePtr(certdata
);
544 certlen
= CFDataGetLength(certdata
);
545 require(certlen
> UINT8_MAX
, out
);
546 require(certlen
< UINT16_MAX
, out
);
548 message
= CFDataCreateMutable(kCFAllocatorDefault
, 0);
549 require(message
, out
);
551 CFDataAppendBytes(message
, header
, sizeof(header
));
552 CFDataAppendBytes(message
, certbytes
, certlen
);
553 CFDataAppendBytes(message
, trailer
, sizeof(trailer
));
555 messagebytes
= CFDataGetMutableBytePtr(message
);
556 messagelen
= CFDataGetLength(message
);
559 messagebytes
[2] = messagelen
>> 8;
560 messagebytes
[3] = messagelen
& 0xFF;
563 messagebytes
[17] = messagelen
>> 8;
564 messagebytes
[18] = messagelen
& 0xFF;
567 messagebytes
[21] = messagelen
>> 8;
568 messagebytes
[22] = messagelen
& 0xFF;
571 messagebytes
[43] = messagelen
>> 8;
572 messagebytes
[44] = messagelen
& 0xFF;
575 if (certdata
!= NULL
)
582 OSStatus
SecCMSCreateEnvelopedData(CFTypeRef recipient_or_cfarray_thereof
,
583 CFDictionaryRef params
, CFDataRef data
, CFMutableDataRef enveloped_data
)
585 SecCmsMessageRef cmsg
= NULL
;
586 SecCmsContentInfoRef cinfo
;
587 SecCmsEnvelopedDataRef envd
= NULL
;
588 SECOidTag algorithmTag
= SEC_OID_DES_EDE3_CBC
;
590 OSStatus status
= errSecParam
;
591 PLArenaPool
*arena
= NULL
;
594 CFStringRef algorithm_name
= CFDictionaryGetValue(params
, kSecCMSBulkEncryptionAlgorithm
);
595 if (algorithm_name
) {
596 if (CFEqual(kSecCMSEncryptionAlgorithmDESCBC
, algorithm_name
)) {
597 algorithmTag
= SEC_OID_DES_CBC
;
599 } else if (CFEqual(kSecCMSEncryptionAlgorithmAESCBC
, algorithm_name
)) {
600 algorithmTag
= SEC_OID_AES_128_CBC
;
606 require(cmsg
= SecCmsMessageCreate(NULL
), out
);
607 require(envd
= SecCmsEnvelopedDataCreate(cmsg
, algorithmTag
, keySize
), out
);
608 require(cinfo
= SecCmsMessageGetContentInfo(cmsg
), out
);
609 require_noerr(SecCmsContentInfoSetContentEnvelopedData(cmsg
, cinfo
, envd
), out
);
610 require(cinfo
= SecCmsEnvelopedDataGetContentInfo(envd
), out
);
611 require_noerr(SecCmsContentInfoSetContentData(cmsg
, cinfo
, NULL
, false), out
);
612 // == wrapper of: require(SECSuccess == SecCmsContentInfoSetContent(cinfo, SEC_OID_PKCS7_DATA, NULL), out);
614 if (CFGetTypeID(recipient_or_cfarray_thereof
) == CFArrayGetTypeID()) {
615 CFIndex dex
, numCerts
= CFArrayGetCount(recipient_or_cfarray_thereof
);
616 for(dex
=0; dex
<numCerts
; dex
++) {
617 SecCertificateRef recip
=
618 (SecCertificateRef
)CFArrayGetValueAtIndex(recipient_or_cfarray_thereof
, dex
);
619 SecCmsRecipientInfoRef rinfo
;
620 require(rinfo
= SecCmsRecipientInfoCreate(cmsg
, recip
), out
);
622 } else if (CFGetTypeID(recipient_or_cfarray_thereof
) == SecCertificateGetTypeID()) {
623 require(SecCmsRecipientInfoCreate(cmsg
, (SecCertificateRef
)recipient_or_cfarray_thereof
), out
);
627 SecAsn1Item input
= {};
629 input
.Length
= CFDataGetLength(data
);
630 input
.Data
= (uint8_t*)CFDataGetBytePtr(data
);
633 CSSM_DATA cssm_enveloped_data
= {0, NULL
};
634 // make an encoder context
635 if ((arena
= PORT_NewArena(1024)) == NULL
) {
638 require_noerr(SecCmsMessageEncode(cmsg
, (data
&& input
.Length
) ? &input
: NULL
, (SecArenaPoolRef
)arena
, &cssm_enveloped_data
), out
);
639 if (enveloped_data
&& cssm_enveloped_data
.Data
) {
640 CFDataAppendBytes(enveloped_data
, cssm_enveloped_data
.Data
, cssm_enveloped_data
.Length
);
643 status
= errSecSuccess
;
645 if (arena
) PORT_FreeArena(arena
, PR_FALSE
);
646 if (cmsg
) SecCmsMessageDestroy(cmsg
);
650 OSStatus
SecCMSDecryptEnvelopedData(CFDataRef message
,
651 CFMutableDataRef data
, SecCertificateRef
*recipient
)
653 SecCmsMessageRef cmsg
= NULL
;
654 SecCmsContentInfoRef cinfo
;
655 SecCmsEnvelopedDataRef envd
= NULL
;
656 SecCertificateRef used_recipient
= NULL
;
657 OSStatus status
= errSecParam
;
659 SecAsn1Item encoded_message
= { CFDataGetLength(message
), (uint8_t*)CFDataGetBytePtr(message
) };
660 require_noerr_action_quiet(SecCmsMessageDecode(&encoded_message
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, &cmsg
),
661 out
, status
= errSecDecode
);
662 require_quiet(cinfo
= SecCmsMessageContentLevel(cmsg
, 0), out
);
663 require_quiet(SecCmsContentInfoGetContentTypeTag(cinfo
) == SEC_OID_PKCS7_ENVELOPED_DATA
, out
);
664 require_quiet(envd
= (SecCmsEnvelopedDataRef
)SecCmsContentInfoGetContent(cinfo
), out
);
665 SecCmsRecipientInfoRef
*rinfo
= envd
->recipientInfos
;
666 while (!used_recipient
&& *rinfo
) {
667 used_recipient
= (*rinfo
)->cert
;
670 require_quiet(2 == SecCmsMessageContentLevelCount(cmsg
), out
);
671 require_quiet(cinfo
= SecCmsMessageContentLevel(cmsg
, 1), out
);
672 require_quiet(SecCmsContentInfoGetContentTypeTag(cinfo
) == SEC_OID_PKCS7_DATA
, out
);
673 const SecAsn1Item
*content
= SecCmsMessageGetContent(cmsg
);
675 CFDataAppendBytes(data
, content
->Data
, content
->Length
);
677 CFRetainSafe(used_recipient
);
678 *recipient
= used_recipient
;
680 status
= errSecSuccess
;
682 if (cmsg
) SecCmsMessageDestroy(cmsg
);