]> git.saurik.com Git - apple/security.git/blob - OSX/libsecurity_smime/lib/SecCMS.c
6c3b49330d3a6b4c1a41b5b7679bbf7250a49d5b
[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 <SecCMS.h>
49
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
58 CFTypeRef kSecCMSBulkEncryptionAlgorithm = CFSTR("kSecCMSBulkEncryptionAlgorithm");
59 CFTypeRef kSecCMSEncryptionAlgorithmDESCBC = CFSTR("kSecCMSEncryptionAlgorithmDESCBC");
60 CFTypeRef kSecCMSEncryptionAlgorithmAESCBC = CFSTR("kSecCMSEncryptionAlgorithmAESCBC");
61
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");
67
68 static SecCmsAttribute *
69 make_attr(PLArenaPool *poolp, SecAsn1Item *type, SecAsn1Item *value, bool encoded)
70 {
71 SecAsn1Item * copiedvalue;
72 SecCmsAttribute *attr = (SecCmsAttribute *)PORT_ArenaZAlloc(poolp, sizeof(SecCmsAttribute));
73 if (attr == NULL)
74 goto loser;
75
76 if (SECITEM_CopyItem(poolp, &(attr->type), type) != SECSuccess)
77 goto loser;
78
79 if (value != NULL) {
80 if ((copiedvalue = SECITEM_AllocItem(poolp, NULL, value->Length)) == NULL)
81 goto loser;
82
83 if (SECITEM_CopyItem(poolp, copiedvalue, value) != SECSuccess)
84 goto loser;
85
86 if (SecCmsArrayAdd(poolp, (void ***)&(attr->values), (void *)copiedvalue) != SECSuccess)
87 goto loser;
88 }
89
90 attr->encoded = encoded;
91
92 loser:
93 return attr;
94 }
95
96 static void
97 signerinfo_add_auth_attr(SecCmsSignerInfoRef signerinfo, /*SECOidTag oidtag*/
98 SecAsn1Item *oid, SecAsn1Item *value, bool encoded)
99 {
100 PLArenaPool *poolp = signerinfo->cmsg->poolp;
101 PORT_Assert (poolp != NULL);
102 void *mark = PORT_ArenaMark (poolp);
103
104 SecCmsAttribute *attr = make_attr(poolp, oid, value, encoded);
105 if (!attr || SecCmsAttributeArrayAddAttr(poolp, &(signerinfo->authAttr), attr) != SECSuccess)
106 goto loser;
107
108 PORT_ArenaUnmark (poolp, mark);
109 return;
110
111 loser:
112 PORT_Assert (mark != NULL);
113 PORT_ArenaRelease (poolp, mark);
114 return;
115 }
116
117 static void sign_all_attributes(const void *key, const void *value, void *context)
118 {
119 SecAsn1Item oid = { CFDataGetLength(key), (uint8_t*)CFDataGetBytePtr(key) },
120 oid_value = { CFDataGetLength(value), (uint8_t*)CFDataGetBytePtr(value) };
121
122 signerinfo_add_auth_attr((SecCmsSignerInfoRef)context, &oid, &oid_value, true);
123 }
124
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)
128 {
129 SecCmsMessageRef cmsg = NULL;
130 SecCmsContentInfoRef cinfo;
131 SecCmsSignedDataRef sigd = NULL;
132 SecCmsSignerInfoRef signerinfo;
133 OSStatus status = errSecParam;
134 PLArenaPool *arena = NULL;
135
136 require(!data_is_digest || detached /* if digest, must be detached */, out);
137
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);
149
150 if (signed_attributes)
151 CFDictionaryApplyFunction(signed_attributes, sign_all_attributes, signerinfo);
152
153 require_noerr(SecCmsSignedDataAddSignerInfo(sigd, signerinfo), out);
154
155 SecAsn1Item input = {};
156 if (data) {
157 input.Length = CFDataGetLength(data);
158 input.Data = (uint8_t*)CFDataGetBytePtr(data);
159 }
160
161 CSSM_DATA cssm_signed_data = {0, NULL};
162 // make an encoder context
163 if ((arena = PORT_NewArena(1024)) == NULL) {
164 goto out;
165 }
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);
169 }
170 else
171 require_noerr(SecCmsMessageEncode(cmsg,(data && input.Length) ? &input : NULL,
172 (SecArenaPoolRef)arena, &cssm_signed_data), out);
173
174 if (signed_data && cssm_signed_data.Data) {
175 CFDataAppendBytes(signed_data, cssm_signed_data.Data, cssm_signed_data.Length);
176 }
177
178 status = errSecSuccess;
179 out:
180 if (arena) PORT_FreeArena(arena, PR_FALSE);
181 if (cmsg) SecCmsMessageDestroy(cmsg);
182 return status;
183 }
184
185 OSStatus SecCMSCreateSignedData(SecIdentityRef identity, CFDataRef data,
186 CFDictionaryRef parameters, CFDictionaryRef signed_attributes,
187 CFMutableDataRef signed_data)
188 {
189 bool is_digest = false, is_detached = false;
190 CFStringRef algorithm_name = NULL;
191 SecCmsCertChainMode chain_mode = SecCmsCMCertChain;
192 CFArrayRef additional_certs = NULL;
193
194 if (parameters) {
195 is_digest = CFDictionaryGetValueIfPresent(parameters,
196 kSecCMSSignDigest, NULL);
197 is_detached = CFDictionaryGetValueIfPresent(parameters,
198 kSecCMSSignDetached, NULL);
199 algorithm_name = CFDictionaryGetValue(parameters,
200 kSecCMSSignHashAlgorithm);
201
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);
205
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;
209 }
210
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;
221 } else {
222 // signing with MD5 is no longer allowed
223 algorithm = SEC_OID_UNKNOWN;
224 }
225 }
226
227 return SecCMSSignDataOrDigestAndAttributes(identity, data,
228 is_detached, is_digest, algorithm,
229 signed_data, signed_attributes, chain_mode, additional_certs);
230 }
231
232 static OSStatus
233 SecCmsSignedDataSetDigestContext(SecCmsSignedDataRef sigd,
234 SecCmsDigestContextRef digestContext)
235 {
236 SecAsn1Item * *digests;
237
238 PLArenaPool *arena = NULL;
239
240 if ((arena = PORT_NewArena(1024)) == NULL)
241 goto loser;
242
243 if (SecCmsDigestContextFinishMultiple(digestContext, (SecArenaPoolRef)arena, &digests) != SECSuccess)
244 goto loser;
245
246 SECAlgorithmID **digestAlgorithms = SecCmsSignedDataGetDigestAlgs(sigd);
247 if(digestAlgorithms == NULL) {
248 goto loser;
249 }
250
251 if (SecCmsSignedDataSetDigests(sigd, digestAlgorithms, digests) != SECSuccess)
252 goto loser;
253
254 if (arena) {
255 PORT_FreeArena(arena, PR_FALSE);
256 }
257 return 0;
258 loser:
259 if (arena)
260 PORT_FreeArena(arena, PR_FALSE);
261 return PORT_GetError();
262 }
263
264 static CFMutableArrayRef copy_signed_attribute_values(SecCmsAttribute *attr)
265 {
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);
270 if (asn1data) {
271 CFArrayAppendValue(array, asn1data);
272 CFRelease(asn1data);
273 }
274 item++;
275 }
276 return array;
277 }
278
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)
282 {
283 SecCmsMessageRef cmsg = NULL;
284 SecCmsContentInfoRef cinfo;
285 SecCmsSignedDataRef sigd = NULL;
286 OSStatus status = errSecParam;
287
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);
296
297 if (detached_contents)
298 {
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);
304 }
305
306 if (additional_certs)
307 require_noerr_quiet(SecCmsSignedDataAddCertList(sigd, additional_certs), out);
308
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);
315 }
316
317 status = errSecSuccess;
318
319 if (attached_contents) {
320 const SecAsn1Item *content = SecCmsMessageGetContent(cmsg);
321 if (content)
322 *attached_contents = CFDataCreate(kCFAllocatorDefault, content->Data, content->Length);
323 else
324 *attached_contents = NULL;
325 }
326
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);
334 if (type) {
335 CFMutableArrayRef attr = copy_signed_attribute_values(*signed_attrs);
336 if (attr) {
337 CFMutableArrayRef existing_attrs = (CFMutableArrayRef)CFDictionaryGetValue(attrs, type);
338 if (existing_attrs) {
339 CFIndex count = CFArrayGetCount(attr);
340 if (count)
341 CFArrayAppendArray(existing_attrs, attr, CFRangeMake(0, count));
342 } else
343 CFDictionarySetValue(attrs, type, attr);
344 CFRelease(attr);
345 }
346 CFRelease(type);
347 }
348 signed_attrs++;
349 }
350 CFMutableArrayRef certs = NULL;
351
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);
357 if (cert) {
358 CFArrayAppendValue(certs, cert);
359 CFRelease(cert);
360 }
361 cert_datas++;
362 }
363
364 CFDictionaryAddValue(attrs, kSecCMSAllCerts, certs);
365
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);
370 if (signing_date){
371 CFDictionarySetValue(attrs, kSecCMSSignDate, signing_date);
372 if (signing_date) CFRelease(signing_date);
373 }
374 }
375
376 *signed_attributes = attrs;
377 if (certs) CFRelease(certs);
378 }
379
380
381 out:
382 if (cmsg) SecCmsMessageDestroy(cmsg);
383 return status;
384 }
385
386 OSStatus SecCMSVerifyCopyDataAndAttributes(CFDataRef message, CFDataRef detached_contents,
387 CFTypeRef policy, SecTrustRef *trustref,
388 CFDataRef *attached_contents, CFDictionaryRef *signed_attributes)
389 {
390 OSStatus status = SecCMSVerifySignedData_internal(message, detached_contents, policy, trustref, NULL, attached_contents, signed_attributes);
391
392 return status;
393 }
394
395 OSStatus SecCMSVerifySignedData(CFDataRef message, CFDataRef detached_contents,
396 CFTypeRef policy, SecTrustRef *trustref, CFArrayRef additional_certificates,
397 CFDataRef *attached_contents, CFDictionaryRef *message_attributes)
398 {
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);
403 }
404 if (signed_attributes) CFRelease(signed_attributes);
405
406 return status;
407 }
408
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);
413 }
414
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;
421
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);
428
429 /* find out about signers */
430 int nsigners = SecCmsSignedDataSignerInfoCount(sigd);
431 require(nsigners == 0, out);
432
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);
438 if (cert) {
439 CFArrayAppendValue(certs, cert);
440 CFRelease(cert);
441 }
442 cert_datas++;
443 }
444
445 out:
446 if (cmsg)
447 SecCmsMessageDestroy(cmsg);
448
449 return certs;
450 }
451
452
453 extern const SecAsn1Template SecCmsMessageTemplate[];
454
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;
464
465 require(cert_or_array_thereof, out);
466
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);
474
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);
479 }
480
481 require(cert_array, out);
482 cert_array_count = CFArrayGetCount(cert_array);
483 require(cert_array_count > 0, out);
484
485 sigd->rawCerts = (SecAsn1Item * *)PORT_ArenaAlloc(cmsg->poolp, (cert_array_count + 1) * sizeof(SecAsn1Item *));
486 require(sigd->rawCerts, out);
487 CFIndex ix;
488 for (ix = 0; ix < cert_array_count; ix++) {
489 cert = (SecCertificateRef)CFArrayGetValueAtIndex(cert_array, ix);
490 require(cert, out);
491
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;
496 }
497 sigd->rawCerts[ix] = NULL;
498
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);
502
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);
509
510 status = errSecSuccess;
511 out:
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;
516 }
517
518 CFDataRef SecCMSCreateCertificatesOnlyMessageIAP(SecCertificateRef cert)
519 {
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
527 };
528
529 static const uint8_t trailer[] = {
530 0xa1, 0x00, 0x31, 0x00
531 };
532
533 CFMutableDataRef message = NULL;
534 CFDataRef certdata;
535 const uint8_t *certbytes;
536 CFIndex certlen;
537 uint8_t *messagebytes;
538 uint16_t messagelen;
539
540 certdata = SecCertificateCopyData(cert);
541 require(certdata, out);
542
543 certbytes = CFDataGetBytePtr(certdata);
544 certlen = CFDataGetLength(certdata);
545 require(certlen > UINT8_MAX, out);
546 require(certlen < UINT16_MAX, out);
547
548 message = CFDataCreateMutable(kCFAllocatorDefault, 0);
549 require(message, out);
550
551 CFDataAppendBytes(message, header, sizeof(header));
552 CFDataAppendBytes(message, certbytes, certlen);
553 CFDataAppendBytes(message, trailer, sizeof(trailer));
554
555 messagebytes = CFDataGetMutableBytePtr(message);
556 messagelen = CFDataGetLength(message);
557
558 messagelen -= 4;
559 messagebytes[2] = messagelen >> 8;
560 messagebytes[3] = messagelen & 0xFF;
561
562 messagelen -= 15;
563 messagebytes[17] = messagelen >> 8;
564 messagebytes[18] = messagelen & 0xFF;
565
566 messagelen -= 4;
567 messagebytes[21] = messagelen >> 8;
568 messagebytes[22] = messagelen & 0xFF;
569
570 messagelen -= 26;
571 messagebytes[43] = messagelen >> 8;
572 messagebytes[44] = messagelen & 0xFF;
573
574 out:
575 if (certdata != NULL)
576 {
577 CFRelease(certdata);
578 }
579 return message;
580 }
581
582 OSStatus SecCMSCreateEnvelopedData(CFTypeRef recipient_or_cfarray_thereof,
583 CFDictionaryRef params, CFDataRef data, CFMutableDataRef enveloped_data)
584 {
585 SecCmsMessageRef cmsg = NULL;
586 SecCmsContentInfoRef cinfo;
587 SecCmsEnvelopedDataRef envd = NULL;
588 SECOidTag algorithmTag = SEC_OID_DES_EDE3_CBC;
589 int keySize = 192;
590 OSStatus status = errSecParam;
591 PLArenaPool *arena = NULL;
592
593 if (params) {
594 CFStringRef algorithm_name = CFDictionaryGetValue(params, kSecCMSBulkEncryptionAlgorithm);
595 if (algorithm_name) {
596 if (CFEqual(kSecCMSEncryptionAlgorithmDESCBC, algorithm_name)) {
597 algorithmTag = SEC_OID_DES_CBC;
598 keySize = 64;
599 } else if (CFEqual(kSecCMSEncryptionAlgorithmAESCBC, algorithm_name)) {
600 algorithmTag = SEC_OID_AES_128_CBC;
601 keySize = 128;
602 }
603 }
604 }
605
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);
613
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);
621 }
622 } else if (CFGetTypeID(recipient_or_cfarray_thereof) == SecCertificateGetTypeID()) {
623 require(SecCmsRecipientInfoCreate(cmsg, (SecCertificateRef)recipient_or_cfarray_thereof), out);
624 } else
625 goto out;
626
627 SecAsn1Item input = {};
628 if (data) {
629 input.Length = CFDataGetLength(data);
630 input.Data = (uint8_t*)CFDataGetBytePtr(data);
631 }
632
633 CSSM_DATA cssm_enveloped_data = {0, NULL};
634 // make an encoder context
635 if ((arena = PORT_NewArena(1024)) == NULL) {
636 goto out;
637 }
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);
641 }
642
643 status = errSecSuccess;
644 out:
645 if (arena) PORT_FreeArena(arena, PR_FALSE);
646 if (cmsg) SecCmsMessageDestroy(cmsg);
647 return status;
648 }
649
650 OSStatus SecCMSDecryptEnvelopedData(CFDataRef message,
651 CFMutableDataRef data, SecCertificateRef *recipient)
652 {
653 SecCmsMessageRef cmsg = NULL;
654 SecCmsContentInfoRef cinfo;
655 SecCmsEnvelopedDataRef envd = NULL;
656 SecCertificateRef used_recipient = NULL;
657 OSStatus status = errSecParam;
658
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;
668 rinfo++;
669 }
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);
674 if (content)
675 CFDataAppendBytes(data, content->Data, content->Length);
676 if (recipient) {
677 CFRetainSafe(used_recipient);
678 *recipient = used_recipient;
679 }
680 status = errSecSuccess;
681 out:
682 if (cmsg) SecCmsMessageDestroy(cmsg);
683 return status;
684 }