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