]> git.saurik.com Git - apple/security.git/blob - OSX/sec/Security/SecCMS.c
Security-57740.1.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 SecAsn1Item encoded_message = { CFDataGetLength(message), (uint8_t*)CFDataGetBytePtr(message) };
399 require_noerr_action_quiet(SecCmsMessageDecode(&encoded_message, NULL, NULL, NULL, NULL, NULL, NULL, &cmsg),
400 out, status = errSecDecode);
401 /* expected to be a signed data message at the top level */
402 require_quiet(cinfo = SecCmsMessageContentLevel(cmsg, 0), out);
403 require_quiet(SecCmsContentInfoGetContentTypeTag(cinfo) == SEC_OID_PKCS7_SIGNED_DATA, out);
404 require_quiet(sigd = (SecCmsSignedDataRef)SecCmsContentInfoGetContent(cinfo), out);
405
406 if (detached_contents)
407 {
408 require_quiet(!SecCmsSignedDataHasDigests(sigd), out);
409 SECAlgorithmID **digestalgs = SecCmsSignedDataGetDigestAlgs(sigd);
410 SecCmsDigestContextRef digcx = SecCmsDigestContextStartMultiple(digestalgs);
411 SecCmsDigestContextUpdate(digcx, CFDataGetBytePtr(detached_contents), CFDataGetLength(detached_contents));
412 SecCmsSignedDataSetDigestContext(sigd, digcx);
413 SecCmsDigestContextDestroy(digcx);
414 }
415
416 if (additional_certs)
417 require_noerr_quiet(SecCmsSignedDataAddCertList(sigd, additional_certs), out);
418
419 if (policy) { /* if no policy is given skip verification */
420 /* find out about signers */
421 int nsigners = SecCmsSignedDataSignerInfoCount(sigd);
422 require_quiet(nsigners == 1, out);
423 require_noerr_action_quiet(SecCmsSignedDataVerifySignerInfo(sigd, 0, NULL, policy, trustref),
424 out, status = errSecAuthFailed);
425 }
426
427 #if 0
428 if (nsigners > 1)
429 trustrefs = CFArrayCreateMutable(kCFAllocatorDefault, nsigners, &kCFTypeArrayCallBacks);
430
431 int j;
432 for (j = 0; j < nsigners; j++)
433 {
434 SecTrustRef trustRef;
435 require_noerr_action_quiet(SecCmsSignedDataVerifySignerInfo(sigd, j, NULL, policy, &trustRef),
436 out, status = errSecAuthFailed);
437 if ((j == 0) && (nsigners == 1))
438 *trustref_or_cfarray_thereof = trustRef;
439 else {
440 CFArrayAppendValue(trustrefs, trustRef);
441 CFRelease(trustRef);
442 }
443 }
444 *trustref_or_cfarray_thereof = trustrefs;
445 trustrefs = NULL;
446 #endif
447
448 status = errSecSuccess;
449
450 if (attached_contents) {
451 const SecAsn1Item *content = SecCmsMessageGetContent(cmsg);
452 if (content)
453 *attached_contents = CFDataCreate(kCFAllocatorDefault, content->Data, content->Length);
454 else
455 *attached_contents = NULL;
456 }
457
458 if (signed_attributes) {
459 CFMutableDictionaryRef attrs = CFDictionaryCreateMutable(kCFAllocatorDefault,
460 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
461 require_quiet(attrs, out);
462 SecCmsAttribute **signed_attrs = sigd->signerInfos[0]->authAttr;
463 if (signed_attrs) while (*signed_attrs) {
464 CFDataRef type = CFDataCreate(kCFAllocatorDefault, (*signed_attrs)->type.Data, (*signed_attrs)->type.Length);
465 if (type) {
466 CFMutableArrayRef attr = copy_signed_attribute_values(*signed_attrs);
467 if (attr) {
468 CFMutableArrayRef existing_attrs = (CFMutableArrayRef)CFDictionaryGetValue(attrs, type);
469 if (existing_attrs) {
470 CFIndex count = CFArrayGetCount(attr);
471 if (count)
472 CFArrayAppendArray(existing_attrs, attr, CFRangeMake(0, count));
473 } else
474 CFDictionarySetValue(attrs, type, attr);
475 CFRelease(attr);
476 }
477 CFRelease(type);
478 }
479 signed_attrs++;
480 }
481 CFMutableArrayRef certs = NULL;
482
483 SecAsn1Item **cert_datas = SecCmsSignedDataGetCertificateList(sigd);
484 certs = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
485 SecAsn1Item *cert_data;
486 if (cert_datas) while ((cert_data = *cert_datas) != NULL) {
487 SecCertificateRef cert = SecCertificateCreateWithBytes(NULL, cert_data->Data, cert_data->Length);
488 if (cert) {
489 CFArrayAppendValue(certs, cert);
490 CFRelease(cert);
491 }
492 cert_datas++;
493 }
494
495 CFDictionaryAddValue(attrs, kSecCMSAllCerts, certs);
496
497 /* Add "cooked" values separately */
498 CFAbsoluteTime signing_time;
499 if (errSecSuccess == SecCmsSignerInfoGetSigningTime(sigd->signerInfos[0], &signing_time)) {
500 CFDateRef signing_date = CFDateCreate(kCFAllocatorDefault, signing_time);
501 if (signing_date){
502 CFDictionarySetValue(attrs, kSecCMSSignDate, signing_date);
503 CFReleaseSafe(signing_date);
504 }
505 }
506
507 *signed_attributes = attrs;
508 CFReleaseSafe(certs);
509 }
510
511
512 out:
513 if (cmsg) SecCmsMessageDestroy(cmsg);
514 return status;
515 }
516
517 OSStatus SecCMSVerifyCopyDataAndAttributes(CFDataRef message, CFDataRef detached_contents,
518 CFTypeRef policy, SecTrustRef *trustref,
519 CFDataRef *attached_contents, CFDictionaryRef *signed_attributes)
520 {
521 OSStatus status = SecCMSVerifySignedData_internal(message, detached_contents, policy, trustref, NULL, attached_contents, signed_attributes);
522
523 return status;
524 }
525
526 OSStatus SecCMSVerifySignedData(CFDataRef message, CFDataRef detached_contents,
527 CFTypeRef policy, SecTrustRef *trustref, CFArrayRef additional_certificates,
528 CFDataRef *attached_contents, CFDictionaryRef *message_attributes)
529 {
530 CFDictionaryRef signed_attributes = NULL;
531 OSStatus status = SecCMSVerifySignedData_internal(message, detached_contents, policy, trustref, additional_certificates, attached_contents, &signed_attributes);
532 if (!status && signed_attributes && message_attributes) {
533 *message_attributes = CFDictionaryCreate(kCFAllocatorDefault, &kSecCMSSignedAttributes, (const void **)&signed_attributes, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
534 }
535 CFReleaseSafe(signed_attributes);
536
537 return status;
538 }
539
540 OSStatus SecCMSVerify(CFDataRef message, CFDataRef detached_contents,
541 CFTypeRef policy, SecTrustRef *trustref,
542 CFDataRef *attached_contents) {
543 return SecCMSVerifySignedData_internal(message, detached_contents, policy, trustref, NULL, attached_contents, NULL);
544 }
545
546 CFArrayRef SecCMSCertificatesOnlyMessageCopyCertificates(CFDataRef message) {
547 SecCmsMessageRef cmsg = NULL;
548 SecCmsContentInfoRef cinfo;
549 SecCmsSignedDataRef sigd = NULL;
550 CFMutableArrayRef certs = NULL;
551
552 SecAsn1Item encoded_message = { CFDataGetLength(message), (uint8_t*)CFDataGetBytePtr(message) };
553 require_noerr_quiet(SecCmsMessageDecode(&encoded_message, NULL, NULL, NULL, NULL, NULL, NULL, &cmsg), out);
554 /* expected to be a signed data message at the top level */
555 require(cinfo = SecCmsMessageContentLevel(cmsg, 0), out);
556 require(SecCmsContentInfoGetContentTypeTag(cinfo) == SEC_OID_PKCS7_SIGNED_DATA, out);
557 require(sigd = (SecCmsSignedDataRef)SecCmsContentInfoGetContent(cinfo), out);
558
559 /* find out about signers */
560 int nsigners = SecCmsSignedDataSignerInfoCount(sigd);
561 require(nsigners == 0, out);
562
563 SecAsn1Item **cert_datas = SecCmsSignedDataGetCertificateList(sigd);
564 certs = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
565 SecAsn1Item *cert_data;
566 if (cert_datas) while ((cert_data = *cert_datas) != NULL) {
567 SecCertificateRef cert = SecCertificateCreateWithBytes(NULL, cert_data->Data, cert_data->Length);
568 if (cert) {
569 CFArrayAppendValue(certs, cert);
570 CFRelease(cert);
571 }
572 cert_datas++;
573 }
574
575 out:
576 if (cmsg)
577 SecCmsMessageDestroy(cmsg);
578
579 return certs;
580 }
581
582
583 extern const SecAsn1Template SecCmsMessageTemplate[];
584
585 CFDataRef SecCMSCreateCertificatesOnlyMessage(CFTypeRef cert_or_array_thereof) {
586 OSStatus status = errSecParam;
587 SecCmsMessageRef cmsg = NULL;
588 SecCmsContentInfoRef cinfo;
589 SecCmsSignedDataRef sigd = NULL;
590 CFMutableDataRef cert_only_signed_data = NULL;
591 CFArrayRef cert_array = NULL;
592 CFIndex cert_array_count = 0;
593 SecCertificateRef cert = NULL;
594
595 require(cert_or_array_thereof, out);
596
597 require(cmsg = SecCmsMessageCreate(), out);
598 require(sigd = SecCmsSignedDataCreate(cmsg), out);
599 require_noerr(SecCmsContentInfoSetContentData(&(sigd->contentInfo), NULL, PR_TRUE), out);
600 require(cinfo = SecCmsMessageGetContentInfo(cmsg), out);
601 require_noerr(SecCmsContentInfoSetContentSignedData(cinfo, sigd), out);
602 long version = SEC_CMS_SIGNED_DATA_VERSION_BASIC;
603 require(SEC_ASN1EncodeInteger(cmsg->poolp, &(sigd->version), version), out);
604
605 if (CFGetTypeID(cert_or_array_thereof) == SecCertificateGetTypeID()) {
606 cert_array = CFArrayCreate(kCFAllocatorDefault, &cert_or_array_thereof, 1, &kCFTypeArrayCallBacks);
607 } else if (CFGetTypeID(cert_or_array_thereof) == CFArrayGetTypeID()) {
608 cert_array = CFArrayCreateCopy(kCFAllocatorDefault, (CFArrayRef)cert_or_array_thereof);
609 }
610
611 require(cert_array, out);
612 cert_array_count = CFArrayGetCount(cert_array);
613 require(cert_array_count > 0, out);
614
615 sigd->rawCerts = (SecAsn1Item * *)PORT_ArenaAlloc(cmsg->poolp, (cert_array_count + 1) * sizeof(SecAsn1Item *));
616 require(sigd->rawCerts, out);
617 CFIndex ix;
618 for (ix = 0; ix < cert_array_count; ix++) {
619 cert = (SecCertificateRef)CFArrayGetValueAtIndex(cert_array, ix);
620 require(cert, out);
621
622 sigd->rawCerts[ix] = PORT_ArenaZAlloc(cmsg->poolp, sizeof(SecAsn1Item));
623 SecAsn1Item cert_data = { SecCertificateGetLength(cert),
624 (uint8_t *)SecCertificateGetBytePtr(cert) };
625 *(sigd->rawCerts[ix]) = cert_data;
626 }
627 sigd->rawCerts[ix] = NULL;
628
629 /* this is a SET OF, so we need to sort them guys - we have the DER already, though */
630 if (cert_array_count > 1)
631 SecCmsArraySort((void **)sigd->rawCerts, SecCmsUtilDERCompare, NULL, NULL);
632
633 cert_only_signed_data = CFDataCreateMutable(kCFAllocatorDefault, 0);
634 SecAsn1Item cert_only_signed_data_item = {};
635 require_quiet(SEC_ASN1EncodeItem(cmsg->poolp, &cert_only_signed_data_item,
636 cmsg, SecCmsMessageTemplate), out);
637 CFDataAppendBytes(cert_only_signed_data, cert_only_signed_data_item.Data,
638 cert_only_signed_data_item.Length);
639
640 status = errSecSuccess;
641 out:
642 CFReleaseSafe(cert_array);
643 if (status) CFReleaseSafe(cert_only_signed_data);
644 if (cmsg) SecCmsMessageDestroy(cmsg);
645 return cert_only_signed_data;
646 }
647
648 CFDataRef SecCMSCreateCertificatesOnlyMessageIAP(SecCertificateRef cert)
649 {
650 static const uint8_t header[] = {
651 0x30, 0x82, 0x03, 0x6d, 0x06, 0x09, 0x2a, 0x86,
652 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x02, 0xa0,
653 0x82, 0x03, 0x5e, 0x30, 0x82, 0x03, 0x5a, 0x02,
654 0x01, 0x01, 0x31, 0x00, 0x30, 0x0b, 0x06, 0x09,
655 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07,
656 0x01, 0xa0, 0x82, 0x03, 0x40
657 };
658
659 static const uint8_t trailer[] = {
660 0xa1, 0x00, 0x31, 0x00
661 };
662
663 CFMutableDataRef message = NULL;
664 CFDataRef certdata;
665 const uint8_t *certbytes;
666 CFIndex certlen;
667 uint8_t *messagebytes;
668 uint16_t messagelen;
669
670 certdata = SecCertificateCopyData(cert);
671 require(certdata, out);
672
673 certbytes = CFDataGetBytePtr(certdata);
674 certlen = CFDataGetLength(certdata);
675 require(certlen > UINT8_MAX, out);
676 require(certlen < UINT16_MAX, out);
677
678 message = CFDataCreateMutable(kCFAllocatorDefault, 0);
679 require(message, out);
680
681 CFDataAppendBytes(message, header, sizeof(header));
682 CFDataAppendBytes(message, certbytes, certlen);
683 CFDataAppendBytes(message, trailer, sizeof(trailer));
684
685 messagebytes = CFDataGetMutableBytePtr(message);
686 messagelen = CFDataGetLength(message);
687
688 messagelen -= 4;
689 messagebytes[2] = messagelen >> 8;
690 messagebytes[3] = messagelen & 0xFF;
691
692 messagelen -= 15;
693 messagebytes[17] = messagelen >> 8;
694 messagebytes[18] = messagelen & 0xFF;
695
696 messagelen -= 4;
697 messagebytes[21] = messagelen >> 8;
698 messagebytes[22] = messagelen & 0xFF;
699
700 messagelen -= 26;
701 messagebytes[43] = messagelen >> 8;
702 messagebytes[44] = messagelen & 0xFF;
703
704 out:
705 CFReleaseSafe(certdata);
706 return message;
707 }
708
709 #endif /* ENABLE_CMS */
710