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