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