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