]> git.saurik.com Git - apple/security.git/blob - OSX/libsecurity_smime/lib/SecCMS.c
Security-59306.101.1.tar.gz
[apple/security.git] / OSX / libsecurity_smime / lib / SecCMS.c
1 /*
2 * Copyright (c) 2014-2016 Apple Inc. All Rights Reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
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
11 * file.
12 *
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.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24
25 #include <AssertMacros.h>
26
27 #include <security_asn1/secasn1.h>
28
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>
42 #include <secitem.h>
43 #include <cmslocal.h>
44
45 #include "cmstpriv.h"
46 #include "cmspriv.h"
47
48 #include <Security/SecCMS.h>
49
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");
61
62 CFTypeRef kSecCMSBulkEncryptionAlgorithm = CFSTR("kSecCMSBulkEncryptionAlgorithm");
63 CFTypeRef kSecCMSEncryptionAlgorithmDESCBC = CFSTR("kSecCMSEncryptionAlgorithmDESCBC");
64 CFTypeRef kSecCMSEncryptionAlgorithmAESCBC = CFSTR("kSecCMSEncryptionAlgorithmAESCBC");
65
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");
72
73 static SecCmsAttribute *
74 make_attr(PLArenaPool *poolp, SecAsn1Item *type, SecAsn1Item *value, bool encoded)
75 {
76 SecAsn1Item * copiedvalue;
77 SecCmsAttribute *attr = (SecCmsAttribute *)PORT_ArenaZAlloc(poolp, sizeof(SecCmsAttribute));
78 if (attr == NULL)
79 goto loser;
80
81 if (SECITEM_CopyItem(poolp, &(attr->type), type) != SECSuccess)
82 goto loser;
83
84 if (value != NULL) {
85 if ((copiedvalue = SECITEM_AllocItem(poolp, NULL, value->Length)) == NULL)
86 goto loser;
87
88 if (SECITEM_CopyItem(poolp, copiedvalue, value) != SECSuccess)
89 goto loser;
90
91 if (SecCmsArrayAdd(poolp, (void ***)&(attr->values), (void *)copiedvalue) != SECSuccess)
92 goto loser;
93 }
94
95 attr->encoded = encoded;
96
97 loser:
98 return attr;
99 }
100
101 static void
102 signerinfo_add_auth_attr(SecCmsSignerInfoRef signerinfo, /*SECOidTag oidtag*/
103 SecAsn1Item *oid, SecAsn1Item *value, bool encoded)
104 {
105 PLArenaPool *poolp = signerinfo->cmsg->poolp;
106 PORT_Assert (poolp != NULL);
107 void *mark = PORT_ArenaMark (poolp);
108
109 SecCmsAttribute *attr = make_attr(poolp, oid, value, encoded);
110 if (!attr || SecCmsAttributeArrayAddAttr(poolp, &(signerinfo->authAttr), attr) != SECSuccess)
111 goto loser;
112
113 PORT_ArenaUnmark (poolp, mark);
114 return;
115
116 loser:
117 PORT_Assert (mark != NULL);
118 PORT_ArenaRelease (poolp, mark);
119 return;
120 }
121
122 static void sign_all_attributes(const void *key, const void *value, void *context)
123 {
124 SecAsn1Item oid = { CFDataGetLength(key), (uint8_t*)CFDataGetBytePtr(key) },
125 oid_value = { CFDataGetLength(value), (uint8_t*)CFDataGetBytePtr(value) };
126
127 signerinfo_add_auth_attr((SecCmsSignerInfoRef)context, &oid, &oid_value, true);
128 }
129
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)
133 {
134 SecCmsMessageRef cmsg = NULL;
135 SecCmsContentInfoRef cinfo;
136 SecCmsSignedDataRef sigd = NULL;
137 SecCmsSignerInfoRef signerinfo;
138 OSStatus status = errSecParam;
139 PLArenaPool *arena = NULL;
140
141 require(!data_is_digest || detached /* if digest, must be detached */, out);
142
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);
154
155 if (signed_attributes)
156 CFDictionaryApplyFunction(signed_attributes, sign_all_attributes, signerinfo);
157
158 require_noerr(SecCmsSignedDataAddSignerInfo(sigd, signerinfo), out);
159
160 SecAsn1Item input = {};
161 if (data) {
162 input.Length = CFDataGetLength(data);
163 input.Data = (uint8_t*)CFDataGetBytePtr(data);
164 }
165
166 CSSM_DATA cssm_signed_data = {0, NULL};
167 // make an encoder context
168 if ((arena = PORT_NewArena(1024)) == NULL) {
169 goto out;
170 }
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);
174 }
175 else
176 require_noerr(SecCmsMessageEncode(cmsg,(data && input.Length) ? &input : NULL,
177 (SecArenaPoolRef)arena, &cssm_signed_data), out);
178
179 if (signed_data && cssm_signed_data.Data) {
180 CFDataAppendBytes(signed_data, cssm_signed_data.Data, cssm_signed_data.Length);
181 }
182
183 status = errSecSuccess;
184 out:
185 if (arena) PORT_FreeArena(arena, PR_FALSE);
186 if (cmsg) SecCmsMessageDestroy(cmsg);
187 return status;
188 }
189
190 OSStatus SecCMSSignDataAndAttributes(SecIdentityRef identity, CFDataRef data, bool detached,
191 CFMutableDataRef signed_data, CFDictionaryRef signed_attributes)
192 {
193 return SecCMSSignDataOrDigestAndAttributes(identity, data, detached, false, SEC_OID_SHA1,
194 signed_data, signed_attributes, SecCmsCMCertChain, NULL);
195 }
196
197 OSStatus SecCMSSignDigestAndAttributes(SecIdentityRef identity, CFDataRef digest,
198 CFMutableDataRef signed_data, CFDictionaryRef signed_attributes)
199 {
200 return SecCMSSignDataOrDigestAndAttributes(identity, digest, true, true, SEC_OID_SHA1,
201 signed_data, signed_attributes, SecCmsCMCertChain, NULL);
202 }
203
204 OSStatus SecCMSCreateSignedData(SecIdentityRef identity, CFDataRef data,
205 CFDictionaryRef parameters, CFDictionaryRef signed_attributes,
206 CFMutableDataRef signed_data)
207 {
208 bool is_digest = false, is_detached = false;
209 CFStringRef algorithm_name = NULL;
210 SecCmsCertChainMode chain_mode = SecCmsCMCertChain;
211 CFArrayRef additional_certs = NULL;
212
213 if (parameters) {
214 is_digest = CFDictionaryGetValueIfPresent(parameters,
215 kSecCMSSignDigest, NULL);
216 is_detached = CFDictionaryGetValueIfPresent(parameters,
217 kSecCMSSignDetached, NULL);
218 algorithm_name = CFDictionaryGetValue(parameters,
219 kSecCMSSignHashAlgorithm);
220
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);
224
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;
228 }
229
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;
240 } else {
241 // signing with MD5 is no longer allowed
242 algorithm = SEC_OID_UNKNOWN;
243 }
244 }
245
246 return SecCMSSignDataOrDigestAndAttributes(identity, data,
247 is_detached, is_digest, algorithm,
248 signed_data, signed_attributes, chain_mode, additional_certs);
249 }
250
251 static OSStatus
252 SecCmsSignedDataSetDigestContext(SecCmsSignedDataRef sigd,
253 SecCmsDigestContextRef digestContext)
254 {
255 SecAsn1Item * *digests;
256
257 PLArenaPool *arena = NULL;
258
259 if ((arena = PORT_NewArena(1024)) == NULL)
260 goto loser;
261
262 if (SecCmsDigestContextFinishMultiple(digestContext, (SecArenaPoolRef)arena, &digests) != SECSuccess)
263 goto loser;
264
265 SECAlgorithmID **digestAlgorithms = SecCmsSignedDataGetDigestAlgs(sigd);
266 if(digestAlgorithms == NULL) {
267 goto loser;
268 }
269
270 if (SecCmsSignedDataSetDigests(sigd, digestAlgorithms, digests) != SECSuccess)
271 goto loser;
272
273 if (arena) {
274 PORT_FreeArena(arena, PR_FALSE);
275 }
276 return 0;
277 loser:
278 if (arena)
279 PORT_FreeArena(arena, PR_FALSE);
280 return PORT_GetError();
281 }
282
283 static CFMutableArrayRef copy_signed_attribute_values(SecCmsAttribute *attr)
284 {
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);
289 if (asn1data) {
290 CFArrayAppendValue(array, asn1data);
291 CFRelease(asn1data);
292 }
293 item++;
294 }
295 return array;
296 }
297
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)
301 {
302 SecCmsMessageRef cmsg = NULL;
303 SecCmsContentInfoRef cinfo;
304 SecCmsSignedDataRef sigd = NULL;
305 OSStatus status = errSecParam;
306
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);
315
316 if (detached_contents)
317 {
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);
323 }
324
325 if (additional_certs)
326 require_noerr_quiet(SecCmsSignedDataAddCertList(sigd, additional_certs), out);
327
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);
334 }
335
336 status = errSecSuccess;
337
338 if (attached_contents) {
339 const SecAsn1Item *content = SecCmsMessageGetContent(cmsg);
340 if (content)
341 *attached_contents = CFDataCreate(kCFAllocatorDefault, content->Data, content->Length);
342 else
343 *attached_contents = NULL;
344 }
345
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);
353 if (type) {
354 CFMutableArrayRef attr = copy_signed_attribute_values(*signed_attrs);
355 if (attr) {
356 CFMutableArrayRef existing_attrs = (CFMutableArrayRef)CFDictionaryGetValue(attrs, type);
357 if (existing_attrs) {
358 CFIndex count = CFArrayGetCount(attr);
359 if (count)
360 CFArrayAppendArray(existing_attrs, attr, CFRangeMake(0, count));
361 } else
362 CFDictionarySetValue(attrs, type, attr);
363 CFRelease(attr);
364 }
365 CFRelease(type);
366 }
367 signed_attrs++;
368 }
369 CFMutableArrayRef certs = NULL;
370
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);
376 if (cert) {
377 CFArrayAppendValue(certs, cert);
378 CFRelease(cert);
379 }
380 cert_datas++;
381 }
382
383 CFDictionaryAddValue(attrs, kSecCMSAllCerts, certs);
384
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);
389 if (signing_date){
390 CFDictionarySetValue(attrs, kSecCMSSignDate, signing_date);
391 if (signing_date) CFRelease(signing_date);
392 }
393 }
394
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);
399 }
400 }
401
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);
406 }
407 }
408
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);
415 }
416 }
417
418 *signed_attributes = attrs;
419 if (certs) CFRelease(certs);
420 }
421
422
423 out:
424 if (cmsg) SecCmsMessageDestroy(cmsg);
425 return status;
426 }
427
428 OSStatus SecCMSVerifyCopyDataAndAttributes(CFDataRef message, CFDataRef detached_contents,
429 CFTypeRef policy, SecTrustRef *trustref,
430 CFDataRef *attached_contents, CFDictionaryRef *signed_attributes)
431 {
432 OSStatus status = SecCMSVerifySignedData_internal(message, detached_contents, policy, trustref, NULL, attached_contents, signed_attributes);
433
434 return status;
435 }
436
437 OSStatus SecCMSVerifySignedData(CFDataRef message, CFDataRef detached_contents,
438 CFTypeRef policy, SecTrustRef *trustref, CFArrayRef additional_certificates,
439 CFDataRef *attached_contents, CFDictionaryRef *message_attributes)
440 {
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);
445 }
446 if (signed_attributes) CFRelease(signed_attributes);
447
448 return status;
449 }
450
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);
455 }
456
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;
463
464 if (!message) {
465 return NULL;
466 }
467
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);
474
475 /* find out about signers */
476 int nsigners = SecCmsSignedDataSignerInfoCount(sigd);
477 require(nsigners == 0, out);
478
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);
484 if (cert) {
485 CFArrayAppendValue(certs, cert);
486 CFRelease(cert);
487 }
488 cert_datas++;
489 }
490
491 out:
492 if (cmsg) { SecCmsMessageDestroy(cmsg); }
493 if (certs && CFArrayGetCount(certs) < 1) {
494 CFReleaseNull(certs);
495 }
496
497 return certs;
498 }
499
500
501 extern const SecAsn1Template SecCmsMessageTemplate[];
502
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;
512
513 require(cert_or_array_thereof, out);
514
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);
522
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);
527 }
528
529 require(cert_array, out);
530 cert_array_count = CFArrayGetCount(cert_array);
531 require(cert_array_count > 0, out);
532
533 sigd->rawCerts = (SecAsn1Item * *)PORT_ArenaAlloc(cmsg->poolp, (cert_array_count + 1) * sizeof(SecAsn1Item *));
534 require(sigd->rawCerts, out);
535 CFIndex ix;
536 for (ix = 0; ix < cert_array_count; ix++) {
537 cert = (SecCertificateRef)CFArrayGetValueAtIndex(cert_array, ix);
538 require(cert, out);
539
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;
544 }
545 sigd->rawCerts[ix] = NULL;
546
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);
550
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);
557
558 status = errSecSuccess;
559 out:
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;
564 }
565
566 CFDataRef SecCMSCreateCertificatesOnlyMessageIAP(SecCertificateRef cert)
567 {
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
575 };
576
577 static const uint8_t trailer[] = {
578 0xa1, 0x00, 0x31, 0x00
579 };
580
581 CFMutableDataRef message = NULL;
582 CFDataRef certdata;
583 const uint8_t *certbytes;
584 CFIndex certlen;
585 uint8_t *messagebytes;
586 uint16_t messagelen;
587
588 certdata = SecCertificateCopyData(cert);
589 require(certdata, out);
590
591 certbytes = CFDataGetBytePtr(certdata);
592 certlen = CFDataGetLength(certdata);
593 require(certlen > UINT8_MAX, out);
594 require(certlen < UINT16_MAX, out);
595
596 message = CFDataCreateMutable(kCFAllocatorDefault, 0);
597 require(message, out);
598
599 CFDataAppendBytes(message, header, sizeof(header));
600 CFDataAppendBytes(message, certbytes, certlen);
601 CFDataAppendBytes(message, trailer, sizeof(trailer));
602
603 messagebytes = CFDataGetMutableBytePtr(message);
604 messagelen = CFDataGetLength(message);
605
606 messagelen -= 4;
607 messagebytes[2] = messagelen >> 8;
608 messagebytes[3] = messagelen & 0xFF;
609
610 messagelen -= 15;
611 messagebytes[17] = messagelen >> 8;
612 messagebytes[18] = messagelen & 0xFF;
613
614 messagelen -= 4;
615 messagebytes[21] = messagelen >> 8;
616 messagebytes[22] = messagelen & 0xFF;
617
618 messagelen -= 26;
619 messagebytes[43] = messagelen >> 8;
620 messagebytes[44] = messagelen & 0xFF;
621
622 out:
623 if (certdata != NULL)
624 {
625 CFRelease(certdata);
626 }
627 return message;
628 }
629
630 OSStatus SecCMSCreateEnvelopedData(CFTypeRef recipient_or_cfarray_thereof,
631 CFDictionaryRef params, CFDataRef data, CFMutableDataRef enveloped_data)
632 {
633 SecCmsMessageRef cmsg = NULL;
634 SecCmsContentInfoRef cinfo;
635 SecCmsEnvelopedDataRef envd = NULL;
636 SECOidTag algorithmTag = SEC_OID_DES_EDE3_CBC;
637 int keySize = 192;
638 OSStatus status = errSecParam;
639 PLArenaPool *arena = NULL;
640
641 if (params) {
642 CFStringRef algorithm_name = CFDictionaryGetValue(params, kSecCMSBulkEncryptionAlgorithm);
643 if (algorithm_name) {
644 if (CFEqual(kSecCMSEncryptionAlgorithmDESCBC, algorithm_name)) {
645 algorithmTag = SEC_OID_DES_CBC;
646 keySize = 64;
647 } else if (CFEqual(kSecCMSEncryptionAlgorithmAESCBC, algorithm_name)) {
648 algorithmTag = SEC_OID_AES_128_CBC;
649 keySize = 128;
650 }
651 }
652 }
653
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);
661
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);
670 }
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);
675 } else
676 goto out;
677
678 SecAsn1Item input = {};
679 if (data) {
680 input.Length = CFDataGetLength(data);
681 input.Data = (uint8_t*)CFDataGetBytePtr(data);
682 }
683
684 CSSM_DATA cssm_enveloped_data = {0, NULL};
685 // make an encoder context
686 if ((arena = PORT_NewArena(1024)) == NULL) {
687 goto out;
688 }
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);
692 }
693
694 status = errSecSuccess;
695 out:
696 if (arena) PORT_FreeArena(arena, PR_FALSE);
697 if (cmsg) SecCmsMessageDestroy(cmsg);
698 return status;
699 }
700
701 OSStatus SecCMSDecryptEnvelopedData(CFDataRef message,
702 CFMutableDataRef data, SecCertificateRef *recipient)
703 {
704 SecCmsMessageRef cmsg = NULL;
705 SecCmsContentInfoRef cinfo;
706 SecCmsEnvelopedDataRef envd = NULL;
707 SecCertificateRef used_recipient = NULL;
708 OSStatus status = errSecParam;
709
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;
719 rinfo++;
720 }
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);
725 if (content)
726 CFDataAppendBytes(data, content->Data, content->Length);
727 if (recipient) {
728 CFRetainSafe(used_recipient);
729 *recipient = used_recipient;
730 }
731 status = errSecSuccess;
732 out:
733 if (cmsg) SecCmsMessageDestroy(cmsg);
734 return status;
735 }