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