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