]> git.saurik.com Git - apple/security.git/blob - sec/Security/SecCMS.c
Security-55471.14.18.tar.gz
[apple/security.git] / sec / Security / SecCMS.c
1 /*
2 * Copyright (c) 2008-2010 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 * Created by Conrad Sauerwald on 2/11/08.
30 *
31 */
32 #include <AssertMacros.h>
33
34 #include <TargetConditionals.h>
35 #if (TARGET_OS_MAC && !(TARGET_OS_EMBEDDED || TARGET_OS_IPHONE))
36 #define ENABLE_CMS 0
37 #else
38 #define ENABLE_CMS 1
39 #endif
40
41 #if ENABLE_CMS
42 #include <Security/SecBase.h>
43 #include <Security/SecCmsMessage.h>
44 #include <Security/SecCmsSignedData.h>
45 #include <Security/SecCmsEnvelopedData.h>
46 #include <Security/SecCmsContentInfo.h>
47 #include <Security/SecCmsSignerInfo.h>
48 #include <Security/SecCmsRecipientInfo.h>
49 #include <Security/SecCmsEncoder.h>
50 #include <Security/SecCmsDecoder.h>
51 #include <Security/SecCmsDigestContext.h>
52 #include <Security/cmstpriv.h>
53
54 #include <CoreFoundation/CFData.h>
55
56 #include <Security/SecInternal.h>
57 #include <Security/SecBasePriv.h>
58 #include <Security/SecCertificatePriv.h>
59
60 #include "SecCMS.h"
61 #include <Security/SecTrustPriv.h>
62
63
64 #include <security_asn1/secasn1.h>
65 #include <security_asn1/secerr.h>
66 #include <security_asn1/secport.h>
67 #include <Security/SecAsn1Item.h>
68 #include <security_smime/secoid.h>
69 #include <security_smime/cmslocal.h>
70
71 CFTypeRef kSecCMSBulkEncryptionAlgorithm = CFSTR("kSecCMSBulkEncryptionAlgorithm");
72 CFTypeRef kSecCMSSignDigest = CFSTR("kSecCMSSignDigest");
73 CFTypeRef kSecCMSSignDetached = CFSTR("kSecCMSSignDetached");
74 CFTypeRef kSecCMSSignHashAlgorithm = CFSTR("kSecCMSSignHashAlgorithm");
75 CFTypeRef kSecCMSEncryptionAlgorithmDESCBC = CFSTR("kSecCMSEncryptionAlgorithmDESCBC");
76 CFTypeRef kSecCMSEncryptionAlgorithmAESCBC = CFSTR("kSecCMSEncryptionAlgorithmAESCBC");
77 CFTypeRef kSecCMSHashingAlgorithmMD5 = CFSTR("kSecCMSHashingAlgorithmMD5");
78 CFTypeRef kSecCMSCertChainMode = CFSTR("kSecCMSCertChainMode");
79 CFTypeRef kSecCMSCertChainModeNone = CFSTR("0");
80 CFTypeRef kSecCMSAdditionalCerts = CFSTR("kSecCMSAdditionalCerts");
81 CFTypeRef kSecCMSSignedAttributes = CFSTR("kSecCMSSignedAttributes");
82 CFTypeRef kSecCMSSignDate = CFSTR("kSecCMSSignDate");
83 CFTypeRef kSecCMSAllCerts = CFSTR("kSecCMSAllCerts");
84
85 OSStatus SecCMSCreateEnvelopedData(CFTypeRef recipient_or_cfarray_thereof,
86 CFDictionaryRef params, CFDataRef data, CFMutableDataRef enveloped_data)
87 {
88 SecCmsMessageRef cmsg = NULL;
89 SecCmsContentInfoRef cinfo;
90 SecCmsEnvelopedDataRef envd = NULL;
91 SECOidTag algorithmTag = SEC_OID_DES_EDE3_CBC;
92 int keySize = 192;
93 OSStatus status = errSecParam;
94
95 if (params) {
96 CFStringRef algorithm_name = CFDictionaryGetValue(params, kSecCMSBulkEncryptionAlgorithm);
97 if (algorithm_name) {
98 if (CFEqual(kSecCMSEncryptionAlgorithmDESCBC, algorithm_name)) {
99 algorithmTag = SEC_OID_DES_CBC;
100 keySize = 64;
101 } else if (CFEqual(kSecCMSEncryptionAlgorithmAESCBC, algorithm_name)) {
102 algorithmTag = SEC_OID_AES_128_CBC;
103 keySize = 128;
104 }
105 }
106 }
107
108 require(cmsg = SecCmsMessageCreate(), out);
109 require(envd = SecCmsEnvelopedDataCreate(cmsg, algorithmTag, keySize), out);
110 require(cinfo = SecCmsMessageGetContentInfo(cmsg), out);
111 require_noerr(SecCmsContentInfoSetContentEnvelopedData(cinfo, envd), out);
112 require(cinfo = SecCmsEnvelopedDataGetContentInfo(envd), out);
113 require_noerr(SecCmsContentInfoSetContentData(cinfo, NULL, false), out);
114 // == wrapper of: require(SECSuccess == SecCmsContentInfoSetContent(cinfo, SEC_OID_PKCS7_DATA, NULL), out);
115
116 if (CFGetTypeID(recipient_or_cfarray_thereof) == CFArrayGetTypeID()) {
117 CFIndex dex, numCerts = CFArrayGetCount(recipient_or_cfarray_thereof);
118 for(dex=0; dex<numCerts; dex++) {
119 SecCertificateRef recip =
120 (SecCertificateRef)CFArrayGetValueAtIndex(recipient_or_cfarray_thereof, dex);
121 SecCmsRecipientInfoRef rinfo;
122 require(rinfo = SecCmsRecipientInfoCreate(envd, recip), out);
123 }
124 } else if (CFGetTypeID(recipient_or_cfarray_thereof) == SecCertificateGetTypeID()) {
125 require(SecCmsRecipientInfoCreate(envd, (SecCertificateRef)recipient_or_cfarray_thereof), out);
126 } else
127 goto out;
128
129 SecAsn1Item input = {};
130 if (data) {
131 input.Length = CFDataGetLength(data);
132 input.Data = (uint8_t*)CFDataGetBytePtr(data);
133 }
134 require_noerr(SecCmsMessageEncode(cmsg, (data && input.Length) ? &input : NULL, enveloped_data), out);
135
136 status = errSecSuccess;
137 out:
138 if (cmsg) SecCmsMessageDestroy(cmsg);
139 return status;
140 }
141
142 OSStatus SecCMSDecryptEnvelopedData(CFDataRef message,
143 CFMutableDataRef data, SecCertificateRef *recipient)
144 {
145 SecCmsMessageRef cmsg = NULL;
146 SecCmsContentInfoRef cinfo;
147 SecCmsEnvelopedDataRef envd = NULL;
148 SecCertificateRef used_recipient = NULL;
149 OSStatus status = errSecParam;
150
151 SecAsn1Item encoded_message = { CFDataGetLength(message), (uint8_t*)CFDataGetBytePtr(message) };
152 require_noerr_action_quiet(SecCmsMessageDecode(&encoded_message, NULL, NULL, NULL, NULL, NULL, NULL, &cmsg),
153 out, status = errSecDecode);
154 require_quiet(cinfo = SecCmsMessageContentLevel(cmsg, 0), out);
155 require_quiet(SecCmsContentInfoGetContentTypeTag(cinfo) == SEC_OID_PKCS7_ENVELOPED_DATA, out);
156 require_quiet(envd = (SecCmsEnvelopedDataRef)SecCmsContentInfoGetContent(cinfo), out);
157 SecCmsRecipientInfoRef *rinfo = envd->recipientInfos;
158 while (!used_recipient && *rinfo) {
159 used_recipient = (*rinfo)->cert;
160 rinfo++;
161 }
162 require_quiet(2 == SecCmsMessageContentLevelCount(cmsg), out);
163 require_quiet(cinfo = SecCmsMessageContentLevel(cmsg, 1), out);
164 require_quiet(SecCmsContentInfoGetContentTypeTag(cinfo) == SEC_OID_PKCS7_DATA, out);
165 const SecAsn1Item *content = SecCmsMessageGetContent(cmsg);
166 if (content)
167 CFDataAppendBytes(data, content->Data, content->Length);
168 if (recipient) {
169 CFRetainSafe(used_recipient);
170 *recipient = used_recipient;
171 }
172 status = errSecSuccess;
173 out:
174 if (cmsg) SecCmsMessageDestroy(cmsg);
175 return status;
176 }
177
178 static SecCmsAttribute *
179 make_attr(PLArenaPool *poolp, SecAsn1Item *type, SecAsn1Item *value, bool encoded)
180 {
181 SecAsn1Item * copiedvalue;
182 SecCmsAttribute *attr = (SecCmsAttribute *)PORT_ArenaZAlloc(poolp, sizeof(SecCmsAttribute));
183 if (attr == NULL)
184 goto loser;
185
186 if (SECITEM_CopyItem(poolp, &(attr->type), type) != SECSuccess)
187 goto loser;
188
189 if (value != NULL) {
190 if ((copiedvalue = SECITEM_AllocItem(poolp, NULL, value->Length)) == NULL)
191 goto loser;
192
193 if (SECITEM_CopyItem(poolp, copiedvalue, value) != SECSuccess)
194 goto loser;
195
196 SecCmsArrayAdd(poolp, (void ***)&(attr->values), (void *)copiedvalue);
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 }
496
497
498 out:
499 if (cmsg) SecCmsMessageDestroy(cmsg);
500 return status;
501 }
502
503 OSStatus SecCMSVerifyCopyDataAndAttributes(CFDataRef message, CFDataRef detached_contents,
504 CFTypeRef policy, SecTrustRef *trustref,
505 CFDataRef *attached_contents, CFDictionaryRef *signed_attributes)
506 {
507 OSStatus status = SecCMSVerifySignedData_internal(message, detached_contents, policy, trustref, NULL, attached_contents, signed_attributes);
508
509 return status;
510 }
511
512 OSStatus SecCMSVerifySignedData(CFDataRef message, CFDataRef detached_contents,
513 CFTypeRef policy, SecTrustRef *trustref, CFArrayRef additional_certificates,
514 CFDataRef *attached_contents, CFDictionaryRef *message_attributes)
515 {
516 CFDictionaryRef signed_attributes = NULL;
517 OSStatus status = SecCMSVerifySignedData_internal(message, detached_contents, policy, trustref, additional_certificates, attached_contents, &signed_attributes);
518 if (!status && signed_attributes && message_attributes) {
519 *message_attributes = CFDictionaryCreate(kCFAllocatorDefault, &kSecCMSSignedAttributes, (const void **)&signed_attributes, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
520 }
521 CFReleaseSafe(signed_attributes);
522
523 return status;
524 }
525
526 OSStatus SecCMSVerify(CFDataRef message, CFDataRef detached_contents,
527 CFTypeRef policy, SecTrustRef *trustref,
528 CFDataRef *attached_contents) {
529 return SecCMSVerifySignedData_internal(message, detached_contents, policy, trustref, NULL, attached_contents, NULL);
530 }
531
532 CFArrayRef SecCMSCertificatesOnlyMessageCopyCertificates(CFDataRef message) {
533 SecCmsMessageRef cmsg = NULL;
534 SecCmsContentInfoRef cinfo;
535 SecCmsSignedDataRef sigd = NULL;
536 CFMutableArrayRef certs = NULL;
537
538 SecAsn1Item encoded_message = { CFDataGetLength(message), (uint8_t*)CFDataGetBytePtr(message) };
539 require_noerr_quiet(SecCmsMessageDecode(&encoded_message, NULL, NULL, NULL, NULL, NULL, NULL, &cmsg), out);
540 /* expected to be a signed data message at the top level */
541 require(cinfo = SecCmsMessageContentLevel(cmsg, 0), out);
542 require(SecCmsContentInfoGetContentTypeTag(cinfo) == SEC_OID_PKCS7_SIGNED_DATA, out);
543 require(sigd = (SecCmsSignedDataRef)SecCmsContentInfoGetContent(cinfo), out);
544
545 /* find out about signers */
546 int nsigners = SecCmsSignedDataSignerInfoCount(sigd);
547 require(nsigners == 0, out);
548
549 SecAsn1Item **cert_datas = SecCmsSignedDataGetCertificateList(sigd);
550 certs = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
551 SecAsn1Item *cert_data;
552 if (cert_datas) while ((cert_data = *cert_datas) != NULL) {
553 SecCertificateRef cert = SecCertificateCreateWithBytes(NULL, cert_data->Data, cert_data->Length);
554 if (cert) {
555 CFArrayAppendValue(certs, cert);
556 CFRelease(cert);
557 }
558 cert_datas++;
559 }
560
561 out:
562 if (cmsg)
563 SecCmsMessageDestroy(cmsg);
564
565 return certs;
566 }
567
568
569 extern const SecAsn1Template SecCmsMessageTemplate[];
570
571 CFDataRef SecCMSCreateCertificatesOnlyMessage(CFTypeRef cert_or_array_thereof) {
572 OSStatus status = errSecParam;
573 SecCmsMessageRef cmsg = NULL;
574 SecCmsContentInfoRef cinfo;
575 SecCmsSignedDataRef sigd = NULL;
576 CFMutableDataRef cert_only_signed_data = NULL;
577 CFArrayRef cert_array = NULL;
578 CFIndex cert_array_count = 0;
579 SecCertificateRef cert = NULL;
580
581 require(cert_or_array_thereof, out);
582
583 require(cmsg = SecCmsMessageCreate(), out);
584 require(sigd = SecCmsSignedDataCreate(cmsg), out);
585 require_noerr(SecCmsContentInfoSetContentData(&(sigd->contentInfo), NULL, PR_TRUE), out);
586 require(cinfo = SecCmsMessageGetContentInfo(cmsg), out);
587 require_noerr(SecCmsContentInfoSetContentSignedData(cinfo, sigd), out);
588 long version = SEC_CMS_SIGNED_DATA_VERSION_BASIC;
589 require(SEC_ASN1EncodeInteger(cmsg->poolp, &(sigd->version), version), out);
590
591 if (CFGetTypeID(cert_or_array_thereof) == SecCertificateGetTypeID()) {
592 cert_array = CFArrayCreate(kCFAllocatorDefault, &cert_or_array_thereof, 1, &kCFTypeArrayCallBacks);
593 } else if (CFGetTypeID(cert_or_array_thereof) == CFArrayGetTypeID()) {
594 cert_array = CFArrayCreateCopy(kCFAllocatorDefault, (CFArrayRef)cert_or_array_thereof);
595 }
596
597 require(cert_array, out);
598 cert_array_count = CFArrayGetCount(cert_array);
599 require(cert_array_count > 0, out);
600
601 sigd->rawCerts = (SecAsn1Item * *)PORT_ArenaAlloc(cmsg->poolp, (cert_array_count + 1) * sizeof(SecAsn1Item *));
602 require(sigd->rawCerts, out);
603 CFIndex ix;
604 for (ix = 0; ix < cert_array_count; ix++) {
605 cert = (SecCertificateRef)CFArrayGetValueAtIndex(cert_array, ix);
606 require(cert, out);
607
608 sigd->rawCerts[ix] = PORT_ArenaZAlloc(cmsg->poolp, sizeof(SecAsn1Item));
609 SecAsn1Item cert_data = { SecCertificateGetLength(cert),
610 (uint8_t *)SecCertificateGetBytePtr(cert) };
611 *(sigd->rawCerts[ix]) = cert_data;
612 }
613 sigd->rawCerts[ix] = NULL;
614
615 /* this is a SET OF, so we need to sort them guys - we have the DER already, though */
616 if (cert_array_count > 1)
617 SecCmsArraySort((void **)sigd->rawCerts, SecCmsUtilDERCompare, NULL, NULL);
618
619 cert_only_signed_data = CFDataCreateMutable(kCFAllocatorDefault, 0);
620 SecAsn1Item cert_only_signed_data_item = {};
621 require_quiet(SEC_ASN1EncodeItem(cmsg->poolp, &cert_only_signed_data_item,
622 cmsg, SecCmsMessageTemplate), out);
623 CFDataAppendBytes(cert_only_signed_data, cert_only_signed_data_item.Data,
624 cert_only_signed_data_item.Length);
625
626 status = errSecSuccess;
627 out:
628 CFReleaseSafe(cert_array);
629 if (status) CFReleaseSafe(cert_only_signed_data);
630 if (cmsg) SecCmsMessageDestroy(cmsg);
631 return cert_only_signed_data;
632 }
633
634 CFDataRef SecCMSCreateCertificatesOnlyMessageIAP(SecCertificateRef cert)
635 {
636 static const uint8_t header[] = {
637 0x30, 0x82, 0x03, 0x6d, 0x06, 0x09, 0x2a, 0x86,
638 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x02, 0xa0,
639 0x82, 0x03, 0x5e, 0x30, 0x82, 0x03, 0x5a, 0x02,
640 0x01, 0x01, 0x31, 0x00, 0x30, 0x0b, 0x06, 0x09,
641 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07,
642 0x01, 0xa0, 0x82, 0x03, 0x40
643 };
644
645 static const uint8_t trailer[] = {
646 0xa1, 0x00, 0x31, 0x00
647 };
648
649 CFMutableDataRef message = NULL;
650 CFDataRef certdata;
651 const uint8_t *certbytes;
652 CFIndex certlen;
653 uint8_t *messagebytes;
654 uint16_t messagelen;
655
656 certdata = SecCertificateCopyData(cert);
657 require(certdata, out);
658
659 certbytes = CFDataGetBytePtr(certdata);
660 certlen = CFDataGetLength(certdata);
661 require(certlen > UINT8_MAX, out);
662 require(certlen < UINT16_MAX, out);
663
664 message = CFDataCreateMutable(kCFAllocatorDefault, 0);
665 require(message, out);
666
667 CFDataAppendBytes(message, header, sizeof(header));
668 CFDataAppendBytes(message, certbytes, certlen);
669 CFDataAppendBytes(message, trailer, sizeof(trailer));
670
671 messagebytes = CFDataGetMutableBytePtr(message);
672 messagelen = CFDataGetLength(message);
673
674 messagelen -= 4;
675 messagebytes[2] = messagelen >> 8;
676 messagebytes[3] = messagelen & 0xFF;
677
678 messagelen -= 15;
679 messagebytes[17] = messagelen >> 8;
680 messagebytes[18] = messagelen & 0xFF;
681
682 messagelen -= 4;
683 messagebytes[21] = messagelen >> 8;
684 messagebytes[22] = messagelen & 0xFF;
685
686 messagelen -= 26;
687 messagebytes[43] = messagelen >> 8;
688 messagebytes[44] = messagelen & 0xFF;
689
690 out:
691 CFReleaseSafe(certdata);
692 return message;
693 }
694
695 #endif /* ENABLE_CMS */
696