]> git.saurik.com Git - apple/security.git/blob - OSX/sec/Security/SecCMS.c
Security-58286.1.32.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
81 CFTypeRef kSecCMSBulkEncryptionAlgorithm = CFSTR("kSecCMSBulkEncryptionAlgorithm");
82 CFTypeRef kSecCMSEncryptionAlgorithmDESCBC = CFSTR("kSecCMSEncryptionAlgorithmDESCBC");
83 CFTypeRef kSecCMSEncryptionAlgorithmAESCBC = CFSTR("kSecCMSEncryptionAlgorithmAESCBC");
84
85 CFTypeRef kSecCMSSignHashAlgorithm = CFSTR("kSecCMSSignHashAlgorithm");
86 CFTypeRef kSecCMSHashingAlgorithmMD5 = CFSTR("kSecCMSHashingAlgorithmMD5");
87 CFTypeRef kSecCMSHashingAlgorithmSHA1 = CFSTR("kSecCMSHashingAlgorithmSHA1");
88 CFTypeRef kSecCMSHashingAlgorithmSHA256 = CFSTR("kSecCMSHashingAlgorithmSHA256");
89 CFTypeRef kSecCMSHashingAlgorithmSHA384 = CFSTR("kSecCMSHashingAlgorithmSHA384");
90 CFTypeRef kSecCMSHashingAlgorithmSHA512 = CFSTR("kSecCMSHashingAlgorithmSHA512");
91
92 OSStatus SecCMSCreateEnvelopedData(CFTypeRef recipient_or_cfarray_thereof,
93 CFDictionaryRef params, CFDataRef data, CFMutableDataRef enveloped_data)
94 {
95 SecCmsMessageRef cmsg = NULL;
96 SecCmsContentInfoRef cinfo;
97 SecCmsEnvelopedDataRef envd = NULL;
98 SECOidTag algorithmTag = SEC_OID_DES_EDE3_CBC;
99 int keySize = 192;
100 OSStatus status = errSecParam;
101
102 if (params) {
103 CFStringRef algorithm_name = CFDictionaryGetValue(params, kSecCMSBulkEncryptionAlgorithm);
104 if (algorithm_name) {
105 if (CFEqual(kSecCMSEncryptionAlgorithmDESCBC, algorithm_name)) {
106 algorithmTag = SEC_OID_DES_CBC;
107 keySize = 64;
108 } else if (CFEqual(kSecCMSEncryptionAlgorithmAESCBC, algorithm_name)) {
109 algorithmTag = SEC_OID_AES_128_CBC;
110 keySize = 128;
111 }
112 }
113 }
114
115 require(cmsg = SecCmsMessageCreate(), out);
116 require(envd = SecCmsEnvelopedDataCreate(cmsg, algorithmTag, keySize), out);
117 require(cinfo = SecCmsMessageGetContentInfo(cmsg), out);
118 require_noerr(SecCmsContentInfoSetContentEnvelopedData(cinfo, envd), out);
119 require(cinfo = SecCmsEnvelopedDataGetContentInfo(envd), out);
120 require_noerr(SecCmsContentInfoSetContentData(cinfo, NULL, false), out);
121 // == wrapper of: require(SECSuccess == SecCmsContentInfoSetContent(cinfo, SEC_OID_PKCS7_DATA, NULL), out);
122
123 if (CFGetTypeID(recipient_or_cfarray_thereof) == CFArrayGetTypeID()) {
124 CFIndex dex, numCerts = CFArrayGetCount(recipient_or_cfarray_thereof);
125 for(dex=0; dex<numCerts; dex++) {
126 SecCertificateRef recip =
127 (SecCertificateRef)CFArrayGetValueAtIndex(recipient_or_cfarray_thereof, dex);
128 SecCmsRecipientInfoRef rinfo;
129 require(rinfo = SecCmsRecipientInfoCreate(envd, recip), out);
130 }
131 } else if (CFGetTypeID(recipient_or_cfarray_thereof) == SecCertificateGetTypeID()) {
132 require(SecCmsRecipientInfoCreate(envd, (SecCertificateRef)recipient_or_cfarray_thereof), out);
133 } else
134 goto out;
135
136 SecAsn1Item input = {};
137 if (data) {
138 input.Length = CFDataGetLength(data);
139 input.Data = (uint8_t*)CFDataGetBytePtr(data);
140 }
141 require_noerr(SecCmsMessageEncode(cmsg, (data && input.Length) ? &input : NULL, enveloped_data), out);
142
143 status = errSecSuccess;
144 out:
145 if (cmsg) SecCmsMessageDestroy(cmsg);
146 return status;
147 }
148
149 OSStatus SecCMSDecryptEnvelopedData(CFDataRef message,
150 CFMutableDataRef data, SecCertificateRef *recipient)
151 {
152 SecCmsMessageRef cmsg = NULL;
153 SecCmsContentInfoRef cinfo;
154 SecCmsEnvelopedDataRef envd = NULL;
155 SecCertificateRef used_recipient = NULL;
156 OSStatus status = errSecParam;
157
158 SecAsn1Item encoded_message = { CFDataGetLength(message), (uint8_t*)CFDataGetBytePtr(message) };
159 require_noerr_action_quiet(SecCmsMessageDecode(&encoded_message, NULL, NULL, NULL, NULL, NULL, NULL, &cmsg),
160 out, status = errSecDecode);
161 require_quiet(cinfo = SecCmsMessageContentLevel(cmsg, 0), out);
162 require_quiet(SecCmsContentInfoGetContentTypeTag(cinfo) == SEC_OID_PKCS7_ENVELOPED_DATA, out);
163 require_quiet(envd = (SecCmsEnvelopedDataRef)SecCmsContentInfoGetContent(cinfo), out);
164 SecCmsRecipientInfoRef *rinfo = envd->recipientInfos;
165 while (!used_recipient && *rinfo) {
166 used_recipient = (*rinfo)->cert;
167 rinfo++;
168 }
169 require_quiet(2 == SecCmsMessageContentLevelCount(cmsg), out);
170 require_quiet(cinfo = SecCmsMessageContentLevel(cmsg, 1), out);
171 require_quiet(SecCmsContentInfoGetContentTypeTag(cinfo) == SEC_OID_PKCS7_DATA, out);
172 const SecAsn1Item *content = SecCmsMessageGetContent(cmsg);
173 if (content)
174 CFDataAppendBytes(data, content->Data, content->Length);
175 if (recipient) {
176 CFRetainSafe(used_recipient);
177 *recipient = used_recipient;
178 }
179 status = errSecSuccess;
180 out:
181 if (cmsg) SecCmsMessageDestroy(cmsg);
182 return status;
183 }
184
185 static SecCmsAttribute *
186 make_attr(PLArenaPool *poolp, SecAsn1Item *type, SecAsn1Item *value, bool encoded)
187 {
188 SecAsn1Item * copiedvalue;
189 SecCmsAttribute *attr = (SecCmsAttribute *)PORT_ArenaZAlloc(poolp, sizeof(SecCmsAttribute));
190 if (attr == NULL)
191 goto loser;
192
193 if (SECITEM_CopyItem(poolp, &(attr->type), type) != SECSuccess)
194 goto loser;
195
196 if (value != NULL) {
197 if ((copiedvalue = SECITEM_AllocItem(poolp, NULL, value->Length)) == NULL)
198 goto loser;
199
200 if (SECITEM_CopyItem(poolp, copiedvalue, value) != SECSuccess)
201 goto loser;
202
203 if (SecCmsArrayAdd(poolp, (void ***)&(attr->values), (void *)copiedvalue) != SECSuccess)
204 goto loser;
205 }
206
207 attr->encoded = encoded;
208
209 loser:
210 return attr;
211 }
212
213 static void
214 signerinfo_add_auth_attr(SecCmsSignerInfoRef signerinfo, /*SECOidTag oidtag*/
215 SecAsn1Item *oid, SecAsn1Item *value, bool encoded)
216 {
217 PLArenaPool *poolp = signerinfo->signedData->contentInfo.cmsg->poolp;
218 PORT_Assert (poolp != NULL);
219 void *mark = PORT_ArenaMark (poolp);
220
221 SecCmsAttribute *attr = make_attr(poolp, oid, value, encoded);
222 if (!attr || SecCmsAttributeArrayAddAttr(poolp, &(signerinfo->authAttr), attr) != SECSuccess)
223 goto loser;
224
225 PORT_ArenaUnmark (poolp, mark);
226 return;
227
228 loser:
229 PORT_Assert (mark != NULL);
230 PORT_ArenaRelease (poolp, mark);
231 return;
232 }
233
234 static void sign_all_attributes(const void *key, const void *value, void *context)
235 {
236 SecAsn1Item oid = { CFDataGetLength(key), (uint8_t*)CFDataGetBytePtr(key) },
237 oid_value = { CFDataGetLength(value), (uint8_t*)CFDataGetBytePtr(value) };
238
239 signerinfo_add_auth_attr((SecCmsSignerInfoRef)context, &oid, &oid_value, true);
240 }
241
242 #if 0
243 static void enveloped_data_add_unprotected_attr(SecCmsEnvelopedDataRef envd,
244 SecAsn1Item *oid, SecAsn1Item *value, bool encoded)
245 {
246 PLArenaPool *poolp = envd->contentInfo.cmsg->poolp;
247 PORT_Assert (poolp != NULL);
248 void *mark = PORT_ArenaMark (poolp);
249 SecCmsAttribute *attr = make_attr(poolp, oid, value, encoded);
250
251 if (!attr || SecCmsAttributeArrayAddAttr(
252 poolp,
253 &(envd->unprotectedAttr), attr) != SECSuccess)
254 goto loser;
255
256 PORT_ArenaUnmark (poolp, mark);
257 return;
258
259 loser:
260 PORT_Assert (mark != NULL);
261 PORT_ArenaRelease (poolp, mark);
262 return;
263
264 }
265 #endif
266
267 static OSStatus SecCMSSignDataOrDigestAndAttributes(SecIdentityRef identity,
268 CFDataRef data, bool detached, bool data_is_digest, SECOidTag sign_algorithm,
269 CFMutableDataRef signed_data, CFDictionaryRef signed_attributes, SecCmsCertChainMode chainMode, CFArrayRef additional_certs)
270 {
271 SecCmsMessageRef cmsg = NULL;
272 SecCmsContentInfoRef cinfo;
273 SecCmsSignedDataRef sigd = NULL;
274 SecCmsSignerInfoRef signerinfo;
275 OSStatus status = errSecParam;
276
277 require(!data_is_digest || detached /* if digest, must be detached */, out);
278
279 require(cmsg = SecCmsMessageCreate(), out);
280 require(sigd = SecCmsSignedDataCreate(cmsg), out);
281 require(cinfo = SecCmsMessageGetContentInfo(cmsg), out);
282 require_noerr(SecCmsContentInfoSetContentSignedData(cinfo, sigd), out);
283 require(cinfo = SecCmsSignedDataGetContentInfo(sigd), out);
284 require_noerr(SecCmsContentInfoSetContentData(cinfo, NULL, detached), out);
285 require(signerinfo = SecCmsSignerInfoCreate(sigd, identity, sign_algorithm), out);
286 if (additional_certs)
287 require_noerr(SecCmsSignedDataAddCertList(sigd, additional_certs), out);
288 require_noerr(SecCmsSignerInfoIncludeCerts(signerinfo, chainMode, certUsageAnyCA), out);
289 require_noerr(SecCmsSignerInfoAddSigningTime(signerinfo, CFAbsoluteTimeGetCurrent()), out);
290
291 if (signed_attributes)
292 CFDictionaryApplyFunction(signed_attributes, sign_all_attributes, signerinfo);
293
294 SecAsn1Item input = {};
295 if (data) {
296 input.Length = CFDataGetLength(data);
297 input.Data = (uint8_t*)CFDataGetBytePtr(data);
298 }
299 if (data_is_digest) {
300 require_noerr(SecCmsSignedDataSetDigestValue(sigd, sign_algorithm, &input), out);
301 require_noerr(SecCmsMessageEncode(cmsg, NULL, signed_data), out);
302 }
303 else
304 require_noerr(SecCmsMessageEncode(cmsg, (data && input.Length) ? &input : NULL, signed_data), out);
305
306 status = errSecSuccess;
307 out:
308 if (cmsg) SecCmsMessageDestroy(cmsg);
309 return status;
310 }
311
312 OSStatus SecCMSSignDataAndAttributes(SecIdentityRef identity, CFDataRef data, bool detached,
313 CFMutableDataRef signed_data, CFDictionaryRef signed_attributes)
314 {
315 return SecCMSSignDataOrDigestAndAttributes(identity, data, detached, false, SEC_OID_SHA1,
316 signed_data, signed_attributes, SecCmsCMCertChain, NULL);
317 }
318
319 OSStatus SecCMSSignDigestAndAttributes(SecIdentityRef identity, CFDataRef digest,
320 CFMutableDataRef signed_data, CFDictionaryRef signed_attributes)
321 {
322 return SecCMSSignDataOrDigestAndAttributes(identity, digest, true, true, SEC_OID_SHA1,
323 signed_data, signed_attributes, SecCmsCMCertChain, NULL);
324 }
325
326
327 OSStatus SecCMSCreateSignedData(SecIdentityRef identity, CFDataRef data,
328 CFDictionaryRef parameters, CFDictionaryRef signed_attributes,
329 CFMutableDataRef signed_data)
330 {
331 bool is_digest = false, is_detached = false;
332 CFStringRef algorithm_name = NULL;
333 SecCmsCertChainMode chain_mode = SecCmsCMCertChain;
334 CFArrayRef additional_certs = NULL;
335
336 if (parameters) {
337 is_digest = CFDictionaryGetValueIfPresent(parameters,
338 kSecCMSSignDigest, NULL);
339 is_detached = CFDictionaryGetValueIfPresent(parameters,
340 kSecCMSSignDetached, NULL);
341 algorithm_name = CFDictionaryGetValue(parameters,
342 kSecCMSSignHashAlgorithm);
343
344 CFTypeRef chain_mode_param = CFDictionaryGetValue(parameters, kSecCMSCertChainMode);
345 if (chain_mode_param && (CFGetTypeID(chain_mode_param) == CFStringGetTypeID()))
346 chain_mode = CFStringGetIntValue(chain_mode_param);
347
348 CFTypeRef additional_certs_param = CFDictionaryGetValue(parameters, kSecCMSAdditionalCerts);
349 if (additional_certs_param && (CFGetTypeID(additional_certs_param) == CFArrayGetTypeID()))
350 additional_certs = (CFArrayRef)additional_certs_param;
351 }
352
353 SECOidTag algorithm = SEC_OID_SHA1;
354 if (algorithm_name) {
355 if (CFEqual(kSecCMSHashingAlgorithmSHA1, algorithm_name)) {
356 algorithm = SEC_OID_SHA1;
357 } else if (CFEqual(kSecCMSHashingAlgorithmSHA256, algorithm_name)) {
358 algorithm = SEC_OID_SHA256;
359 } else if (CFEqual(kSecCMSHashingAlgorithmSHA384, algorithm_name)) {
360 algorithm = SEC_OID_SHA384;
361 } else if (CFEqual(kSecCMSHashingAlgorithmSHA512, algorithm_name)) {
362 algorithm = SEC_OID_SHA512;
363 } else {
364 // signing with MD5 is no longer allowed
365 algorithm = SEC_OID_UNKNOWN;
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 *signed_attributes = attrs;
517 CFReleaseSafe(certs);
518 }
519
520
521 out:
522 if (cmsg) SecCmsMessageDestroy(cmsg);
523 return status;
524 }
525
526 OSStatus SecCMSVerifyCopyDataAndAttributes(CFDataRef message, CFDataRef detached_contents,
527 CFTypeRef policy, SecTrustRef *trustref,
528 CFDataRef *attached_contents, CFDictionaryRef *signed_attributes)
529 {
530 OSStatus status = SecCMSVerifySignedData_internal(message, detached_contents, policy, trustref, NULL, attached_contents, signed_attributes);
531
532 return status;
533 }
534
535 OSStatus SecCMSVerifySignedData(CFDataRef message, CFDataRef detached_contents,
536 CFTypeRef policy, SecTrustRef *trustref, CFArrayRef additional_certificates,
537 CFDataRef *attached_contents, CFDictionaryRef *message_attributes)
538 {
539 CFDictionaryRef signed_attributes = NULL;
540 OSStatus status = SecCMSVerifySignedData_internal(message, detached_contents, policy, trustref, additional_certificates, attached_contents, &signed_attributes);
541 if (!status && signed_attributes && message_attributes) {
542 *message_attributes = CFDictionaryCreate(kCFAllocatorDefault, &kSecCMSSignedAttributes, (const void **)&signed_attributes, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
543 }
544 CFReleaseSafe(signed_attributes);
545
546 return status;
547 }
548
549 OSStatus SecCMSVerify(CFDataRef message, CFDataRef detached_contents,
550 CFTypeRef policy, SecTrustRef *trustref,
551 CFDataRef *attached_contents) {
552 return SecCMSVerifySignedData_internal(message, detached_contents, policy, trustref, NULL, attached_contents, NULL);
553 }
554
555 CFArrayRef SecCMSCertificatesOnlyMessageCopyCertificates(CFDataRef message) {
556 SecCmsMessageRef cmsg = NULL;
557 SecCmsContentInfoRef cinfo;
558 SecCmsSignedDataRef sigd = NULL;
559 CFMutableArrayRef certs = NULL;
560
561 SecAsn1Item encoded_message = { CFDataGetLength(message), (uint8_t*)CFDataGetBytePtr(message) };
562 require_noerr_quiet(SecCmsMessageDecode(&encoded_message, NULL, NULL, NULL, NULL, NULL, NULL, &cmsg), out);
563 /* expected to be a signed data message at the top level */
564 require(cinfo = SecCmsMessageContentLevel(cmsg, 0), out);
565 require(SecCmsContentInfoGetContentTypeTag(cinfo) == SEC_OID_PKCS7_SIGNED_DATA, out);
566 require(sigd = (SecCmsSignedDataRef)SecCmsContentInfoGetContent(cinfo), out);
567
568 /* find out about signers */
569 int nsigners = SecCmsSignedDataSignerInfoCount(sigd);
570 require(nsigners == 0, out);
571
572 SecAsn1Item **cert_datas = SecCmsSignedDataGetCertificateList(sigd);
573 certs = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
574 SecAsn1Item *cert_data;
575 if (cert_datas) while ((cert_data = *cert_datas) != NULL) {
576 SecCertificateRef cert = SecCertificateCreateWithBytes(NULL, cert_data->Data, cert_data->Length);
577 if (cert) {
578 CFArrayAppendValue(certs, cert);
579 CFRelease(cert);
580 }
581 cert_datas++;
582 }
583
584 out:
585 if (cmsg)
586 SecCmsMessageDestroy(cmsg);
587
588 return certs;
589 }
590
591
592 extern const SecAsn1Template SecCmsMessageTemplate[];
593
594 CFDataRef SecCMSCreateCertificatesOnlyMessage(CFTypeRef cert_or_array_thereof) {
595 OSStatus status = errSecParam;
596 SecCmsMessageRef cmsg = NULL;
597 SecCmsContentInfoRef cinfo;
598 SecCmsSignedDataRef sigd = NULL;
599 CFMutableDataRef cert_only_signed_data = NULL;
600 CFArrayRef cert_array = NULL;
601 CFIndex cert_array_count = 0;
602 SecCertificateRef cert = NULL;
603
604 require(cert_or_array_thereof, out);
605
606 require(cmsg = SecCmsMessageCreate(), out);
607 require(sigd = SecCmsSignedDataCreate(cmsg), out);
608 require_noerr(SecCmsContentInfoSetContentData(&(sigd->contentInfo), NULL, PR_TRUE), out);
609 require(cinfo = SecCmsMessageGetContentInfo(cmsg), out);
610 require_noerr(SecCmsContentInfoSetContentSignedData(cinfo, sigd), out);
611 long version = SEC_CMS_SIGNED_DATA_VERSION_BASIC;
612 require(SEC_ASN1EncodeInteger(cmsg->poolp, &(sigd->version), version), out);
613
614 if (CFGetTypeID(cert_or_array_thereof) == SecCertificateGetTypeID()) {
615 cert_array = CFArrayCreate(kCFAllocatorDefault, &cert_or_array_thereof, 1, &kCFTypeArrayCallBacks);
616 } else if (CFGetTypeID(cert_or_array_thereof) == CFArrayGetTypeID()) {
617 cert_array = CFArrayCreateCopy(kCFAllocatorDefault, (CFArrayRef)cert_or_array_thereof);
618 }
619
620 require(cert_array, out);
621 cert_array_count = CFArrayGetCount(cert_array);
622 require(cert_array_count > 0, out);
623
624 sigd->rawCerts = (SecAsn1Item * *)PORT_ArenaAlloc(cmsg->poolp, (cert_array_count + 1) * sizeof(SecAsn1Item *));
625 require(sigd->rawCerts, out);
626 CFIndex ix;
627 for (ix = 0; ix < cert_array_count; ix++) {
628 cert = (SecCertificateRef)CFArrayGetValueAtIndex(cert_array, ix);
629 require(cert, out);
630
631 sigd->rawCerts[ix] = PORT_ArenaZAlloc(cmsg->poolp, sizeof(SecAsn1Item));
632 SecAsn1Item cert_data = { SecCertificateGetLength(cert),
633 (uint8_t *)SecCertificateGetBytePtr(cert) };
634 *(sigd->rawCerts[ix]) = cert_data;
635 }
636 sigd->rawCerts[ix] = NULL;
637
638 /* this is a SET OF, so we need to sort them guys - we have the DER already, though */
639 if (cert_array_count > 1)
640 SecCmsArraySort((void **)sigd->rawCerts, SecCmsUtilDERCompare, NULL, NULL);
641
642 cert_only_signed_data = CFDataCreateMutable(kCFAllocatorDefault, 0);
643 SecAsn1Item cert_only_signed_data_item = {};
644 require_quiet(SEC_ASN1EncodeItem(cmsg->poolp, &cert_only_signed_data_item,
645 cmsg, SecCmsMessageTemplate), out);
646 CFDataAppendBytes(cert_only_signed_data, cert_only_signed_data_item.Data,
647 cert_only_signed_data_item.Length);
648
649 status = errSecSuccess;
650 out:
651 CFReleaseSafe(cert_array);
652 if (status) CFReleaseSafe(cert_only_signed_data);
653 if (cmsg) SecCmsMessageDestroy(cmsg);
654 return cert_only_signed_data;
655 }
656
657 CFDataRef SecCMSCreateCertificatesOnlyMessageIAP(SecCertificateRef cert)
658 {
659 static const uint8_t header[] = {
660 0x30, 0x82, 0x03, 0x6d, 0x06, 0x09, 0x2a, 0x86,
661 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x02, 0xa0,
662 0x82, 0x03, 0x5e, 0x30, 0x82, 0x03, 0x5a, 0x02,
663 0x01, 0x01, 0x31, 0x00, 0x30, 0x0b, 0x06, 0x09,
664 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07,
665 0x01, 0xa0, 0x82, 0x03, 0x40
666 };
667
668 static const uint8_t trailer[] = {
669 0xa1, 0x00, 0x31, 0x00
670 };
671
672 CFMutableDataRef message = NULL;
673 CFDataRef certdata;
674 const uint8_t *certbytes;
675 CFIndex certlen;
676 uint8_t *messagebytes;
677 uint16_t messagelen;
678
679 certdata = SecCertificateCopyData(cert);
680 require(certdata, out);
681
682 certbytes = CFDataGetBytePtr(certdata);
683 certlen = CFDataGetLength(certdata);
684 require(certlen > UINT8_MAX, out);
685 require(certlen < UINT16_MAX, out);
686
687 message = CFDataCreateMutable(kCFAllocatorDefault, 0);
688 require(message, out);
689
690 CFDataAppendBytes(message, header, sizeof(header));
691 CFDataAppendBytes(message, certbytes, certlen);
692 CFDataAppendBytes(message, trailer, sizeof(trailer));
693
694 messagebytes = CFDataGetMutableBytePtr(message);
695 messagelen = CFDataGetLength(message);
696
697 messagelen -= 4;
698 messagebytes[2] = messagelen >> 8;
699 messagebytes[3] = messagelen & 0xFF;
700
701 messagelen -= 15;
702 messagebytes[17] = messagelen >> 8;
703 messagebytes[18] = messagelen & 0xFF;
704
705 messagelen -= 4;
706 messagebytes[21] = messagelen >> 8;
707 messagebytes[22] = messagelen & 0xFF;
708
709 messagelen -= 26;
710 messagebytes[43] = messagelen >> 8;
711 messagebytes[44] = messagelen & 0xFF;
712
713 out:
714 CFReleaseSafe(certdata);
715 return message;
716 }
717
718 #endif /* ENABLE_CMS */
719