]> git.saurik.com Git - apple/security.git/blob - OSX/libsecurity_smime/lib/SecCMS.c
Security-58286.20.16.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 <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 CFTypeRef kSecCMSHashAgility = CFSTR("kSecCMSHashAgility");
58
59 CFTypeRef kSecCMSBulkEncryptionAlgorithm = CFSTR("kSecCMSBulkEncryptionAlgorithm");
60 CFTypeRef kSecCMSEncryptionAlgorithmDESCBC = CFSTR("kSecCMSEncryptionAlgorithmDESCBC");
61 CFTypeRef kSecCMSEncryptionAlgorithmAESCBC = CFSTR("kSecCMSEncryptionAlgorithmAESCBC");
62
63 CFTypeRef kSecCMSSignHashAlgorithm = CFSTR("kSecCMSSignHashAlgorithm");
64 CFTypeRef kSecCMSHashingAlgorithmSHA1 = CFSTR("kSecCMSHashingAlgorithmSHA1");
65 CFTypeRef kSecCMSHashingAlgorithmSHA256 = CFSTR("kSecCMSHashingAlgorithmSHA256");
66 CFTypeRef kSecCMSHashingAlgorithmSHA384 = CFSTR("kSecCMSHashingAlgorithmSHA384");
67 CFTypeRef kSecCMSHashingAlgorithmSHA512 = CFSTR("kSecCMSHashingAlgorithmSHA512");
68
69 static SecCmsAttribute *
70 make_attr(PLArenaPool *poolp, SecAsn1Item *type, SecAsn1Item *value, bool encoded)
71 {
72 SecAsn1Item * copiedvalue;
73 SecCmsAttribute *attr = (SecCmsAttribute *)PORT_ArenaZAlloc(poolp, sizeof(SecCmsAttribute));
74 if (attr == NULL)
75 goto loser;
76
77 if (SECITEM_CopyItem(poolp, &(attr->type), type) != SECSuccess)
78 goto loser;
79
80 if (value != NULL) {
81 if ((copiedvalue = SECITEM_AllocItem(poolp, NULL, value->Length)) == NULL)
82 goto loser;
83
84 if (SECITEM_CopyItem(poolp, copiedvalue, value) != SECSuccess)
85 goto loser;
86
87 if (SecCmsArrayAdd(poolp, (void ***)&(attr->values), (void *)copiedvalue) != SECSuccess)
88 goto loser;
89 }
90
91 attr->encoded = encoded;
92
93 loser:
94 return attr;
95 }
96
97 static void
98 signerinfo_add_auth_attr(SecCmsSignerInfoRef signerinfo, /*SECOidTag oidtag*/
99 SecAsn1Item *oid, SecAsn1Item *value, bool encoded)
100 {
101 PLArenaPool *poolp = signerinfo->cmsg->poolp;
102 PORT_Assert (poolp != NULL);
103 void *mark = PORT_ArenaMark (poolp);
104
105 SecCmsAttribute *attr = make_attr(poolp, oid, value, encoded);
106 if (!attr || SecCmsAttributeArrayAddAttr(poolp, &(signerinfo->authAttr), attr) != SECSuccess)
107 goto loser;
108
109 PORT_ArenaUnmark (poolp, mark);
110 return;
111
112 loser:
113 PORT_Assert (mark != NULL);
114 PORT_ArenaRelease (poolp, mark);
115 return;
116 }
117
118 static void sign_all_attributes(const void *key, const void *value, void *context)
119 {
120 SecAsn1Item oid = { CFDataGetLength(key), (uint8_t*)CFDataGetBytePtr(key) },
121 oid_value = { CFDataGetLength(value), (uint8_t*)CFDataGetBytePtr(value) };
122
123 signerinfo_add_auth_attr((SecCmsSignerInfoRef)context, &oid, &oid_value, true);
124 }
125
126 static OSStatus SecCMSSignDataOrDigestAndAttributes(SecIdentityRef identity,
127 CFDataRef data, bool detached, bool data_is_digest, SECOidTag sign_algorithm,
128 CFMutableDataRef signed_data, CFDictionaryRef signed_attributes, SecCmsCertChainMode chainMode, CFArrayRef additional_certs)
129 {
130 SecCmsMessageRef cmsg = NULL;
131 SecCmsContentInfoRef cinfo;
132 SecCmsSignedDataRef sigd = NULL;
133 SecCmsSignerInfoRef signerinfo;
134 OSStatus status = errSecParam;
135 PLArenaPool *arena = NULL;
136
137 require(!data_is_digest || detached /* if digest, must be detached */, out);
138
139 require(cmsg = SecCmsMessageCreate(NULL), out);
140 require(sigd = SecCmsSignedDataCreate(cmsg), out);
141 require(cinfo = SecCmsMessageGetContentInfo(cmsg), out);
142 require_noerr(SecCmsContentInfoSetContentSignedData(cmsg, cinfo, sigd), out);
143 require(cinfo = SecCmsSignedDataGetContentInfo(sigd), out);
144 require_noerr(SecCmsContentInfoSetContentData(cmsg, cinfo, NULL, detached), out);
145 require(signerinfo = SecCmsSignerInfoCreate(cmsg, identity, sign_algorithm), out);
146 if (additional_certs)
147 require_noerr(SecCmsSignedDataAddCertList(sigd, additional_certs), out);
148 require_noerr(SecCmsSignerInfoIncludeCerts(signerinfo, chainMode, certUsageAnyCA), out);
149 require_noerr(SecCmsSignerInfoAddSigningTime(signerinfo, CFAbsoluteTimeGetCurrent()), out);
150
151 if (signed_attributes)
152 CFDictionaryApplyFunction(signed_attributes, sign_all_attributes, signerinfo);
153
154 require_noerr(SecCmsSignedDataAddSignerInfo(sigd, signerinfo), out);
155
156 SecAsn1Item input = {};
157 if (data) {
158 input.Length = CFDataGetLength(data);
159 input.Data = (uint8_t*)CFDataGetBytePtr(data);
160 }
161
162 CSSM_DATA cssm_signed_data = {0, NULL};
163 // make an encoder context
164 if ((arena = PORT_NewArena(1024)) == NULL) {
165 goto out;
166 }
167 if (data_is_digest) {
168 require_noerr(SecCmsSignedDataSetDigestValue(sigd, sign_algorithm, &input), out);
169 require_noerr(SecCmsMessageEncode(cmsg, NULL, (SecArenaPoolRef)arena, &cssm_signed_data), out);
170 }
171 else
172 require_noerr(SecCmsMessageEncode(cmsg,(data && input.Length) ? &input : NULL,
173 (SecArenaPoolRef)arena, &cssm_signed_data), out);
174
175 if (signed_data && cssm_signed_data.Data) {
176 CFDataAppendBytes(signed_data, cssm_signed_data.Data, cssm_signed_data.Length);
177 }
178
179 status = errSecSuccess;
180 out:
181 if (arena) PORT_FreeArena(arena, PR_FALSE);
182 if (cmsg) SecCmsMessageDestroy(cmsg);
183 return status;
184 }
185
186 OSStatus SecCMSSignDataAndAttributes(SecIdentityRef identity, CFDataRef data, bool detached,
187 CFMutableDataRef signed_data, CFDictionaryRef signed_attributes)
188 {
189 return SecCMSSignDataOrDigestAndAttributes(identity, data, detached, false, SEC_OID_SHA1,
190 signed_data, signed_attributes, SecCmsCMCertChain, NULL);
191 }
192
193 OSStatus SecCMSSignDigestAndAttributes(SecIdentityRef identity, CFDataRef digest,
194 CFMutableDataRef signed_data, CFDictionaryRef signed_attributes)
195 {
196 return SecCMSSignDataOrDigestAndAttributes(identity, digest, true, true, SEC_OID_SHA1,
197 signed_data, signed_attributes, SecCmsCMCertChain, NULL);
198 }
199
200 OSStatus SecCMSCreateSignedData(SecIdentityRef identity, CFDataRef data,
201 CFDictionaryRef parameters, CFDictionaryRef signed_attributes,
202 CFMutableDataRef signed_data)
203 {
204 bool is_digest = false, is_detached = false;
205 CFStringRef algorithm_name = NULL;
206 SecCmsCertChainMode chain_mode = SecCmsCMCertChain;
207 CFArrayRef additional_certs = NULL;
208
209 if (parameters) {
210 is_digest = CFDictionaryGetValueIfPresent(parameters,
211 kSecCMSSignDigest, NULL);
212 is_detached = CFDictionaryGetValueIfPresent(parameters,
213 kSecCMSSignDetached, NULL);
214 algorithm_name = CFDictionaryGetValue(parameters,
215 kSecCMSSignHashAlgorithm);
216
217 CFTypeRef chain_mode_param = CFDictionaryGetValue(parameters, kSecCMSCertChainMode);
218 if (chain_mode_param && (CFGetTypeID(chain_mode_param) == CFStringGetTypeID()))
219 chain_mode = CFStringGetIntValue(chain_mode_param);
220
221 CFTypeRef additional_certs_param = CFDictionaryGetValue(parameters, kSecCMSAdditionalCerts);
222 if (additional_certs_param && (CFGetTypeID(additional_certs_param) == CFArrayGetTypeID()))
223 additional_certs = (CFArrayRef)additional_certs_param;
224 }
225
226 SECOidTag algorithm = SEC_OID_SHA1;
227 if (algorithm_name) {
228 if (CFEqual(kSecCMSHashingAlgorithmSHA1, algorithm_name)) {
229 algorithm = SEC_OID_SHA1;
230 } else if (CFEqual(kSecCMSHashingAlgorithmSHA256, algorithm_name)) {
231 algorithm = SEC_OID_SHA256;
232 } else if (CFEqual(kSecCMSHashingAlgorithmSHA384, algorithm_name)) {
233 algorithm = SEC_OID_SHA384;
234 } else if (CFEqual(kSecCMSHashingAlgorithmSHA512, algorithm_name)) {
235 algorithm = SEC_OID_SHA512;
236 } else {
237 // signing with MD5 is no longer allowed
238 algorithm = SEC_OID_UNKNOWN;
239 }
240 }
241
242 return SecCMSSignDataOrDigestAndAttributes(identity, data,
243 is_detached, is_digest, algorithm,
244 signed_data, signed_attributes, chain_mode, additional_certs);
245 }
246
247 static OSStatus
248 SecCmsSignedDataSetDigestContext(SecCmsSignedDataRef sigd,
249 SecCmsDigestContextRef digestContext)
250 {
251 SecAsn1Item * *digests;
252
253 PLArenaPool *arena = NULL;
254
255 if ((arena = PORT_NewArena(1024)) == NULL)
256 goto loser;
257
258 if (SecCmsDigestContextFinishMultiple(digestContext, (SecArenaPoolRef)arena, &digests) != SECSuccess)
259 goto loser;
260
261 SECAlgorithmID **digestAlgorithms = SecCmsSignedDataGetDigestAlgs(sigd);
262 if(digestAlgorithms == NULL) {
263 goto loser;
264 }
265
266 if (SecCmsSignedDataSetDigests(sigd, digestAlgorithms, digests) != SECSuccess)
267 goto loser;
268
269 if (arena) {
270 PORT_FreeArena(arena, PR_FALSE);
271 }
272 return 0;
273 loser:
274 if (arena)
275 PORT_FreeArena(arena, PR_FALSE);
276 return PORT_GetError();
277 }
278
279 static CFMutableArrayRef copy_signed_attribute_values(SecCmsAttribute *attr)
280 {
281 CFMutableArrayRef array = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
282 SecAsn1Item **item = attr->values;
283 if (item) while (*item) {
284 CFDataRef asn1data = CFDataCreate(kCFAllocatorDefault, (*item)->Data, (*item)->Length);
285 if (asn1data) {
286 CFArrayAppendValue(array, asn1data);
287 CFRelease(asn1data);
288 }
289 item++;
290 }
291 return array;
292 }
293
294 static OSStatus SecCMSVerifySignedData_internal(CFDataRef message, CFDataRef detached_contents,
295 CFTypeRef policy, SecTrustRef *trustref, CFArrayRef additional_certs,
296 CFDataRef *attached_contents, CFDictionaryRef *signed_attributes)
297 {
298 SecCmsMessageRef cmsg = NULL;
299 SecCmsContentInfoRef cinfo;
300 SecCmsSignedDataRef sigd = NULL;
301 OSStatus status = errSecParam;
302
303 require(message, out);
304 SecAsn1Item encoded_message = { CFDataGetLength(message), (uint8_t*)CFDataGetBytePtr(message) };
305 require_noerr_action_quiet(SecCmsMessageDecode(&encoded_message, NULL, NULL, NULL, NULL, NULL, NULL, &cmsg),
306 out, status = errSecDecode);
307 /* expected to be a signed data message at the top level */
308 require_quiet(cinfo = SecCmsMessageContentLevel(cmsg, 0), out);
309 require_quiet(SecCmsContentInfoGetContentTypeTag(cinfo) == SEC_OID_PKCS7_SIGNED_DATA, out);
310 require_quiet(sigd = (SecCmsSignedDataRef)SecCmsContentInfoGetContent(cinfo), out);
311
312 if (detached_contents)
313 {
314 require_quiet(!SecCmsSignedDataHasDigests(sigd), out);
315 SECAlgorithmID **digestalgs = SecCmsSignedDataGetDigestAlgs(sigd);
316 SecCmsDigestContextRef digcx = SecCmsDigestContextStartMultiple(digestalgs);
317 SecCmsDigestContextUpdate(digcx, CFDataGetBytePtr(detached_contents), CFDataGetLength(detached_contents));
318 SecCmsSignedDataSetDigestContext(sigd, digcx);
319 }
320
321 if (additional_certs)
322 require_noerr_quiet(SecCmsSignedDataAddCertList(sigd, additional_certs), out);
323
324 if (policy) { /* if no policy is given skip verification */
325 /* find out about signers */
326 int nsigners = SecCmsSignedDataSignerInfoCount(sigd);
327 require_quiet(nsigners == 1, out);
328 require_noerr_action_quiet(SecCmsSignedDataVerifySignerInfo(sigd, 0, NULL, policy, trustref),
329 out, status = errSecAuthFailed);
330 }
331
332 status = errSecSuccess;
333
334 if (attached_contents) {
335 const SecAsn1Item *content = SecCmsMessageGetContent(cmsg);
336 if (content)
337 *attached_contents = CFDataCreate(kCFAllocatorDefault, content->Data, content->Length);
338 else
339 *attached_contents = NULL;
340 }
341
342 if (signed_attributes) {
343 CFMutableDictionaryRef attrs = CFDictionaryCreateMutable(kCFAllocatorDefault,
344 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
345 require_quiet(attrs, out);
346 SecCmsAttribute **signed_attrs = sigd->signerInfos[0]->authAttr;
347 if (signed_attrs) while (*signed_attrs) {
348 CFDataRef type = CFDataCreate(kCFAllocatorDefault, (*signed_attrs)->type.Data, (*signed_attrs)->type.Length);
349 if (type) {
350 CFMutableArrayRef attr = copy_signed_attribute_values(*signed_attrs);
351 if (attr) {
352 CFMutableArrayRef existing_attrs = (CFMutableArrayRef)CFDictionaryGetValue(attrs, type);
353 if (existing_attrs) {
354 CFIndex count = CFArrayGetCount(attr);
355 if (count)
356 CFArrayAppendArray(existing_attrs, attr, CFRangeMake(0, count));
357 } else
358 CFDictionarySetValue(attrs, type, attr);
359 CFRelease(attr);
360 }
361 CFRelease(type);
362 }
363 signed_attrs++;
364 }
365 CFMutableArrayRef certs = NULL;
366
367 SecAsn1Item **cert_datas = SecCmsSignedDataGetCertificateList(sigd);
368 certs = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
369 SecAsn1Item *cert_data;
370 if (cert_datas) while ((cert_data = *cert_datas) != NULL) {
371 SecCertificateRef cert = SecCertificateCreateWithBytes(NULL, cert_data->Data, cert_data->Length);
372 if (cert) {
373 CFArrayAppendValue(certs, cert);
374 CFRelease(cert);
375 }
376 cert_datas++;
377 }
378
379 CFDictionaryAddValue(attrs, kSecCMSAllCerts, certs);
380
381 /* Add "cooked" values separately */
382 CFAbsoluteTime signing_time;
383 if (errSecSuccess == SecCmsSignerInfoGetSigningTime(sigd->signerInfos[0], &signing_time)) {
384 CFDateRef signing_date = CFDateCreate(kCFAllocatorDefault, signing_time);
385 if (signing_date){
386 CFDictionarySetValue(attrs, kSecCMSSignDate, signing_date);
387 if (signing_date) CFRelease(signing_date);
388 }
389 }
390
391 CFDataRef hash_agility_value = NULL;
392 if (errSecSuccess == SecCmsSignerInfoGetAppleCodesigningHashAgility(sigd->signerInfos[0], &hash_agility_value)) {
393 if (hash_agility_value) {
394 CFDictionarySetValue(attrs, kSecCMSHashAgility, hash_agility_value);
395 }
396 }
397
398 *signed_attributes = attrs;
399 if (certs) CFRelease(certs);
400 }
401
402
403 out:
404 if (cmsg) SecCmsMessageDestroy(cmsg);
405 return status;
406 }
407
408 OSStatus SecCMSVerifyCopyDataAndAttributes(CFDataRef message, CFDataRef detached_contents,
409 CFTypeRef policy, SecTrustRef *trustref,
410 CFDataRef *attached_contents, CFDictionaryRef *signed_attributes)
411 {
412 OSStatus status = SecCMSVerifySignedData_internal(message, detached_contents, policy, trustref, NULL, attached_contents, signed_attributes);
413
414 return status;
415 }
416
417 OSStatus SecCMSVerifySignedData(CFDataRef message, CFDataRef detached_contents,
418 CFTypeRef policy, SecTrustRef *trustref, CFArrayRef additional_certificates,
419 CFDataRef *attached_contents, CFDictionaryRef *message_attributes)
420 {
421 CFDictionaryRef signed_attributes = NULL;
422 OSStatus status = SecCMSVerifySignedData_internal(message, detached_contents, policy, trustref, additional_certificates, attached_contents, &signed_attributes);
423 if (!status && signed_attributes && message_attributes) {
424 *message_attributes = CFDictionaryCreate(kCFAllocatorDefault, &kSecCMSSignedAttributes, (const void **)&signed_attributes, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
425 }
426 if (signed_attributes) CFRelease(signed_attributes);
427
428 return status;
429 }
430
431 OSStatus SecCMSVerify(CFDataRef message, CFDataRef detached_contents,
432 CFTypeRef policy, SecTrustRef *trustref,
433 CFDataRef *attached_contents) {
434 return SecCMSVerifySignedData_internal(message, detached_contents, policy, trustref, NULL, attached_contents, NULL);
435 }
436
437 /* Designed to match the sec submodule implementation available for iOS */
438 CFArrayRef SecCMSCertificatesOnlyMessageCopyCertificates(CFDataRef message) {
439 SecCmsMessageRef cmsg = NULL;
440 SecCmsContentInfoRef cinfo;
441 SecCmsSignedDataRef sigd = NULL;
442 CFMutableArrayRef certs = NULL;
443
444 CSSM_DATA encoded_message = { CFDataGetLength(message), (uint8_t*)CFDataGetBytePtr(message) };
445 require_noerr_quiet(SecCmsMessageDecode(&encoded_message, NULL, NULL, NULL, NULL, NULL, NULL, &cmsg), out);
446 /* expected to be a signed data message at the top level */
447 require(cinfo = SecCmsMessageContentLevel(cmsg, 0), out);
448 require(SecCmsContentInfoGetContentTypeTag(cinfo) == SEC_OID_PKCS7_SIGNED_DATA, out);
449 require(sigd = (SecCmsSignedDataRef)SecCmsContentInfoGetContent(cinfo), out);
450
451 /* find out about signers */
452 int nsigners = SecCmsSignedDataSignerInfoCount(sigd);
453 require(nsigners == 0, out);
454
455 CSSM_DATA_PTR *cert_datas = SecCmsSignedDataGetCertificateList(sigd);
456 certs = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
457 CSSM_DATA_PTR cert_data;
458 if (cert_datas) while ((cert_data = *cert_datas) != NULL) {
459 SecCertificateRef cert = SecCertificateCreateWithBytes(NULL, cert_data->Data, cert_data->Length);
460 if (cert) {
461 CFArrayAppendValue(certs, cert);
462 CFRelease(cert);
463 }
464 cert_datas++;
465 }
466
467 out:
468 if (cmsg)
469 SecCmsMessageDestroy(cmsg);
470
471 return certs;
472 }
473
474
475 extern const SecAsn1Template SecCmsMessageTemplate[];
476
477 CFDataRef SecCMSCreateCertificatesOnlyMessage(CFTypeRef cert_or_array_thereof) {
478 OSStatus status = errSecParam;
479 SecCmsMessageRef cmsg = NULL;
480 SecCmsContentInfoRef cinfo;
481 SecCmsSignedDataRef sigd = NULL;
482 CFMutableDataRef cert_only_signed_data = NULL;
483 CFArrayRef cert_array = NULL;
484 CFIndex cert_array_count = 0;
485 SecCertificateRef cert = NULL;
486
487 require(cert_or_array_thereof, out);
488
489 require(cmsg = SecCmsMessageCreate(NULL), out);
490 require(sigd = SecCmsSignedDataCreate(cmsg), out);
491 require_noerr(SecCmsContentInfoSetContentData(cmsg, &(sigd->contentInfo), NULL, PR_TRUE), out);
492 require(cinfo = SecCmsMessageGetContentInfo(cmsg), out);
493 require_noerr(SecCmsContentInfoSetContentSignedData(cmsg, cinfo, sigd), out);
494 long version = SEC_CMS_SIGNED_DATA_VERSION_BASIC;
495 require(SEC_ASN1EncodeInteger(cmsg->poolp, &(sigd->version), version), out);
496
497 if (CFGetTypeID(cert_or_array_thereof) == SecCertificateGetTypeID()) {
498 cert_array = CFArrayCreate(kCFAllocatorDefault, &cert_or_array_thereof, 1, &kCFTypeArrayCallBacks);
499 } else if (CFGetTypeID(cert_or_array_thereof) == CFArrayGetTypeID()) {
500 cert_array = CFArrayCreateCopy(kCFAllocatorDefault, (CFArrayRef)cert_or_array_thereof);
501 }
502
503 require(cert_array, out);
504 cert_array_count = CFArrayGetCount(cert_array);
505 require(cert_array_count > 0, out);
506
507 sigd->rawCerts = (SecAsn1Item * *)PORT_ArenaAlloc(cmsg->poolp, (cert_array_count + 1) * sizeof(SecAsn1Item *));
508 require(sigd->rawCerts, out);
509 CFIndex ix;
510 for (ix = 0; ix < cert_array_count; ix++) {
511 cert = (SecCertificateRef)CFArrayGetValueAtIndex(cert_array, ix);
512 require(cert, out);
513
514 sigd->rawCerts[ix] = PORT_ArenaZAlloc(cmsg->poolp, sizeof(SecAsn1Item));
515 SecAsn1Item cert_data = { SecCertificateGetLength(cert),
516 (uint8_t *)SecCertificateGetBytePtr(cert) };
517 *(sigd->rawCerts[ix]) = cert_data;
518 }
519 sigd->rawCerts[ix] = NULL;
520
521 /* this is a SET OF, so we need to sort them guys - we have the DER already, though */
522 if (cert_array_count > 1)
523 SecCmsArraySort((void **)sigd->rawCerts, SecCmsUtilDERCompare, NULL, NULL);
524
525 cert_only_signed_data = CFDataCreateMutable(kCFAllocatorDefault, 0);
526 SecAsn1Item cert_only_signed_data_item = {};
527 require_quiet(SEC_ASN1EncodeItem(cmsg->poolp, &cert_only_signed_data_item,
528 cmsg, SecCmsMessageTemplate), out);
529 CFDataAppendBytes(cert_only_signed_data, cert_only_signed_data_item.Data,
530 cert_only_signed_data_item.Length);
531
532 status = errSecSuccess;
533 out:
534 if (cert_array) { CFRelease(cert_array); }
535 if (status && cert_only_signed_data) { CFRelease(cert_only_signed_data); }
536 if (cmsg) SecCmsMessageDestroy(cmsg);
537 return cert_only_signed_data;
538 }
539
540 CFDataRef SecCMSCreateCertificatesOnlyMessageIAP(SecCertificateRef cert)
541 {
542 static const uint8_t header[] = {
543 0x30, 0x82, 0x03, 0x6d, 0x06, 0x09, 0x2a, 0x86,
544 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x02, 0xa0,
545 0x82, 0x03, 0x5e, 0x30, 0x82, 0x03, 0x5a, 0x02,
546 0x01, 0x01, 0x31, 0x00, 0x30, 0x0b, 0x06, 0x09,
547 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07,
548 0x01, 0xa0, 0x82, 0x03, 0x40
549 };
550
551 static const uint8_t trailer[] = {
552 0xa1, 0x00, 0x31, 0x00
553 };
554
555 CFMutableDataRef message = NULL;
556 CFDataRef certdata;
557 const uint8_t *certbytes;
558 CFIndex certlen;
559 uint8_t *messagebytes;
560 uint16_t messagelen;
561
562 certdata = SecCertificateCopyData(cert);
563 require(certdata, out);
564
565 certbytes = CFDataGetBytePtr(certdata);
566 certlen = CFDataGetLength(certdata);
567 require(certlen > UINT8_MAX, out);
568 require(certlen < UINT16_MAX, out);
569
570 message = CFDataCreateMutable(kCFAllocatorDefault, 0);
571 require(message, out);
572
573 CFDataAppendBytes(message, header, sizeof(header));
574 CFDataAppendBytes(message, certbytes, certlen);
575 CFDataAppendBytes(message, trailer, sizeof(trailer));
576
577 messagebytes = CFDataGetMutableBytePtr(message);
578 messagelen = CFDataGetLength(message);
579
580 messagelen -= 4;
581 messagebytes[2] = messagelen >> 8;
582 messagebytes[3] = messagelen & 0xFF;
583
584 messagelen -= 15;
585 messagebytes[17] = messagelen >> 8;
586 messagebytes[18] = messagelen & 0xFF;
587
588 messagelen -= 4;
589 messagebytes[21] = messagelen >> 8;
590 messagebytes[22] = messagelen & 0xFF;
591
592 messagelen -= 26;
593 messagebytes[43] = messagelen >> 8;
594 messagebytes[44] = messagelen & 0xFF;
595
596 out:
597 if (certdata != NULL)
598 {
599 CFRelease(certdata);
600 }
601 return message;
602 }
603
604 OSStatus SecCMSCreateEnvelopedData(CFTypeRef recipient_or_cfarray_thereof,
605 CFDictionaryRef params, CFDataRef data, CFMutableDataRef enveloped_data)
606 {
607 SecCmsMessageRef cmsg = NULL;
608 SecCmsContentInfoRef cinfo;
609 SecCmsEnvelopedDataRef envd = NULL;
610 SECOidTag algorithmTag = SEC_OID_DES_EDE3_CBC;
611 int keySize = 192;
612 OSStatus status = errSecParam;
613 PLArenaPool *arena = NULL;
614
615 if (params) {
616 CFStringRef algorithm_name = CFDictionaryGetValue(params, kSecCMSBulkEncryptionAlgorithm);
617 if (algorithm_name) {
618 if (CFEqual(kSecCMSEncryptionAlgorithmDESCBC, algorithm_name)) {
619 algorithmTag = SEC_OID_DES_CBC;
620 keySize = 64;
621 } else if (CFEqual(kSecCMSEncryptionAlgorithmAESCBC, algorithm_name)) {
622 algorithmTag = SEC_OID_AES_128_CBC;
623 keySize = 128;
624 }
625 }
626 }
627
628 require(cmsg = SecCmsMessageCreate(NULL), out);
629 require(envd = SecCmsEnvelopedDataCreate(cmsg, algorithmTag, keySize), out);
630 require(cinfo = SecCmsMessageGetContentInfo(cmsg), out);
631 require_noerr(SecCmsContentInfoSetContentEnvelopedData(cmsg, cinfo, envd), out);
632 require(cinfo = SecCmsEnvelopedDataGetContentInfo(envd), out);
633 require_noerr(SecCmsContentInfoSetContentData(cmsg, cinfo, NULL, false), out);
634 // == wrapper of: require(SECSuccess == SecCmsContentInfoSetContent(cinfo, SEC_OID_PKCS7_DATA, NULL), out);
635
636 if (CFGetTypeID(recipient_or_cfarray_thereof) == CFArrayGetTypeID()) {
637 CFIndex dex, numCerts = CFArrayGetCount(recipient_or_cfarray_thereof);
638 for(dex=0; dex<numCerts; dex++) {
639 SecCertificateRef recip =
640 (SecCertificateRef)CFArrayGetValueAtIndex(recipient_or_cfarray_thereof, dex);
641 SecCmsRecipientInfoRef rinfo;
642 require(rinfo = SecCmsRecipientInfoCreate(cmsg, recip), out);
643 require_noerr(SecCmsEnvelopedDataAddRecipient(envd, rinfo), out);
644 }
645 } else if (CFGetTypeID(recipient_or_cfarray_thereof) == SecCertificateGetTypeID()) {
646 SecCmsRecipientInfoRef rinfo;
647 require(rinfo = SecCmsRecipientInfoCreate(cmsg, (SecCertificateRef)recipient_or_cfarray_thereof), out);
648 require_noerr(SecCmsEnvelopedDataAddRecipient(envd, rinfo), out);
649 } else
650 goto out;
651
652 SecAsn1Item input = {};
653 if (data) {
654 input.Length = CFDataGetLength(data);
655 input.Data = (uint8_t*)CFDataGetBytePtr(data);
656 }
657
658 CSSM_DATA cssm_enveloped_data = {0, NULL};
659 // make an encoder context
660 if ((arena = PORT_NewArena(1024)) == NULL) {
661 goto out;
662 }
663 require_noerr(SecCmsMessageEncode(cmsg, (data && input.Length) ? &input : NULL, (SecArenaPoolRef)arena, &cssm_enveloped_data), out);
664 if (enveloped_data && cssm_enveloped_data.Data) {
665 CFDataAppendBytes(enveloped_data, cssm_enveloped_data.Data, cssm_enveloped_data.Length);
666 }
667
668 status = errSecSuccess;
669 out:
670 if (arena) PORT_FreeArena(arena, PR_FALSE);
671 if (cmsg) SecCmsMessageDestroy(cmsg);
672 return status;
673 }
674
675 OSStatus SecCMSDecryptEnvelopedData(CFDataRef message,
676 CFMutableDataRef data, SecCertificateRef *recipient)
677 {
678 SecCmsMessageRef cmsg = NULL;
679 SecCmsContentInfoRef cinfo;
680 SecCmsEnvelopedDataRef envd = NULL;
681 SecCertificateRef used_recipient = NULL;
682 OSStatus status = errSecParam;
683
684 SecAsn1Item encoded_message = { CFDataGetLength(message), (uint8_t*)CFDataGetBytePtr(message) };
685 require_noerr_action_quiet(SecCmsMessageDecode(&encoded_message, NULL, NULL, NULL, NULL, NULL, NULL, &cmsg),
686 out, status = errSecDecode);
687 require_quiet(cinfo = SecCmsMessageContentLevel(cmsg, 0), out);
688 require_quiet(SecCmsContentInfoGetContentTypeTag(cinfo) == SEC_OID_PKCS7_ENVELOPED_DATA, out);
689 require_quiet(envd = (SecCmsEnvelopedDataRef)SecCmsContentInfoGetContent(cinfo), out);
690 SecCmsRecipientInfoRef *rinfo = envd->recipientInfos;
691 while (!used_recipient && *rinfo) {
692 used_recipient = (*rinfo)->cert;
693 rinfo++;
694 }
695 require_quiet(2 == SecCmsMessageContentLevelCount(cmsg), out);
696 require_quiet(cinfo = SecCmsMessageContentLevel(cmsg, 1), out);
697 require_quiet(SecCmsContentInfoGetContentTypeTag(cinfo) == SEC_OID_PKCS7_DATA, out);
698 const SecAsn1Item *content = SecCmsMessageGetContent(cmsg);
699 if (content)
700 CFDataAppendBytes(data, content->Data, content->Length);
701 if (recipient) {
702 CFRetainSafe(used_recipient);
703 *recipient = used_recipient;
704 }
705 status = errSecSuccess;
706 out:
707 if (cmsg) SecCmsMessageDestroy(cmsg);
708 return status;
709 }