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