]> git.saurik.com Git - apple/security.git/blob - OSX/sec/Security/SecTrust.c
Security-58286.1.32.tar.gz
[apple/security.git] / OSX / sec / Security / SecTrust.c
1 /*
2 * Copyright (c) 2006-2017 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 * SecTrust.c - CoreFoundation based certificate trust evaluator
24 *
25 */
26
27 #include <Security/SecTrustPriv.h>
28 #include <Security/SecTrustInternal.h>
29 #include <Security/SecTrustStatusCodes.h>
30 #include <Security/SecItemPriv.h>
31 #include <Security/SecCertificateInternal.h>
32 #include <Security/SecCertificatePath.h>
33 #include <Security/SecFramework.h>
34 #include <Security/SecPolicyCerts.h>
35 #include <Security/SecPolicyInternal.h>
36 #include <Security/SecPolicyPriv.h>
37 #include <Security/SecuritydXPC.h>
38 #include <Security/SecInternal.h>
39 #include <Security/SecBasePriv.h>
40 #include <CoreFoundation/CFRuntime.h>
41 #include <CoreFoundation/CFSet.h>
42 #include <CoreFoundation/CFString.h>
43 #include <CoreFoundation/CFNumber.h>
44 #include <CoreFoundation/CFArray.h>
45 #include <CoreFoundation/CFPropertyList.h>
46 #include <AssertMacros.h>
47 #include <stdbool.h>
48 #include <string.h>
49 #include <stdlib.h>
50 #include <syslog.h>
51 #include <pthread.h>
52 #include <os/activity.h>
53
54 #include <utilities/SecIOFormat.h>
55 #include <utilities/SecCFError.h>
56 #include <utilities/SecCFWrappers.h>
57 #include <utilities/debugging.h>
58 #include <utilities/der_plist.h>
59 #include <utilities/SecDispatchRelease.h>
60
61 #include "SecRSAKey.h"
62 #include <libDER/oids.h>
63
64 #include <ipc/securityd_client.h>
65
66 #include <securityd/SecTrustServer.h>
67
68 #define SEC_CONST_DECL(k,v) const CFStringRef k = CFSTR(v);
69
70 SEC_CONST_DECL (kSecCertificateDetailSHA1Digest, "SHA1Digest");
71 SEC_CONST_DECL (kSecCertificateDetailStatusCodes, "StatusCodes");
72
73 SEC_CONST_DECL (kSecTrustInfoExtendedValidationKey, "ExtendedValidation");
74 SEC_CONST_DECL (kSecTrustInfoCompanyNameKey, "CompanyName");
75 SEC_CONST_DECL (kSecTrustInfoRevocationKey, "Revocation");
76 SEC_CONST_DECL (kSecTrustInfoRevocationValidUntilKey, "RevocationValidUntil");
77 SEC_CONST_DECL (kSecTrustInfoCertificateTransparencyKey, "CertificateTransparency");
78
79 /* Public trust result constants */
80 SEC_CONST_DECL (kSecTrustEvaluationDate, "TrustEvaluationDate");
81 SEC_CONST_DECL (kSecTrustExtendedValidation, "TrustExtendedValidation");
82 SEC_CONST_DECL (kSecTrustOrganizationName, "Organization");
83 SEC_CONST_DECL (kSecTrustResultValue, "TrustResultValue");
84 SEC_CONST_DECL (kSecTrustRevocationChecked, "TrustRevocationChecked");
85 SEC_CONST_DECL (kSecTrustRevocationReason, "TrustRevocationReason");
86 SEC_CONST_DECL (kSecTrustRevocationValidUntilDate, "TrustExpirationDate");
87 SEC_CONST_DECL (kSecTrustResultDetails, "TrustResultDetails");
88 SEC_CONST_DECL (kSecTrustCertificateTransparency, "TrustCertificateTransparency");
89 SEC_CONST_DECL (kSecTrustCertificateTransparencyWhiteList, "TrustCertificateTransparencyWhiteList");
90
91 #pragma mark -
92 #pragma mark SecTrust
93
94 /********************************************************
95 ****************** SecTrust object *********************
96 ********************************************************/
97 struct __SecTrust {
98 CFRuntimeBase _base;
99 CFArrayRef _certificates;
100 CFArrayRef _anchors;
101 CFTypeRef _policies;
102 CFArrayRef _responses;
103 CFArrayRef _SCTs;
104 CFArrayRef _trustedLogs;
105 CFDateRef _verifyDate;
106 SecCertificatePathRef _chain;
107 SecKeyRef _publicKey;
108 CFArrayRef _details;
109 CFDictionaryRef _info;
110 CFArrayRef _exceptions;
111
112 /* Note that a value of kSecTrustResultInvalid (0)
113 * indicates the trust must be (re)evaluated; any
114 * functions which modify trust parameters in a way
115 * that would invalidate the current result must set
116 * this value back to kSecTrustResultInvalid.
117 */
118 SecTrustResultType _trustResult;
119
120 /* If true we don't trust any anchors other than the ones in _anchors. */
121 bool _anchorsOnly;
122 /* If false we shouldn't search keychains for parents or anchors. */
123 bool _keychainsAllowed;
124
125 /* Data blobs for legacy CSSM_TP_APPLE_EVIDENCE_INFO structure,
126 * to support callers of SecTrustGetResult on OS X. Since fields of
127 * one structure contain pointers into the other, these cannot be
128 * serialized; if a SecTrust is being serialized or copied, these values
129 * should just be initialized to NULL in the copy and built when needed. */
130 void* _legacy_info_array;
131 void* _legacy_status_array;
132
133 /* Dispatch queue for thread-safety */
134 dispatch_queue_t _trustQueue;
135
136 /* === IMPORTANT! ===
137 * Any change to this structure definition
138 * must also be made in the TSecTrust structure,
139 * located in SecTrust.cpp. To avoid problems,
140 * new fields should always be appended at the
141 * end of the structure.
142 */
143 };
144
145 /* Forward declarations of static functions. */
146 static OSStatus SecTrustEvaluateIfNecessary(SecTrustRef trust);
147
148 /* Static functions. */
149 static CFStringRef SecTrustCopyFormatDescription(CFTypeRef cf, CFDictionaryRef formatOptions) {
150 SecTrustRef trust = (SecTrustRef)cf;
151 return CFStringCreateWithFormat(kCFAllocatorDefault, NULL,
152 CFSTR("<SecTrustRef: %p>"), trust);
153 }
154
155 static void SecTrustDestroy(CFTypeRef cf) {
156 SecTrustRef trust = (SecTrustRef)cf;
157
158 dispatch_release_null(trust->_trustQueue);
159 CFReleaseNull(trust->_certificates);
160 CFReleaseNull(trust->_policies);
161 CFReleaseNull(trust->_responses);
162 CFReleaseNull(trust->_SCTs);
163 CFReleaseNull(trust->_trustedLogs);
164 CFReleaseNull(trust->_verifyDate);
165 CFReleaseNull(trust->_anchors);
166 CFReleaseNull(trust->_chain);
167 CFReleaseNull(trust->_publicKey);
168 CFReleaseNull(trust->_details);
169 CFReleaseNull(trust->_info);
170 CFReleaseNull(trust->_exceptions);
171
172 if (trust->_legacy_info_array) {
173 free(trust->_legacy_info_array);
174 }
175 if (trust->_legacy_status_array) {
176 free(trust->_legacy_status_array);
177 }
178 }
179
180 /* Public API functions. */
181 CFGiblisFor(SecTrust)
182
183 OSStatus SecTrustCreateWithCertificates(CFTypeRef certificates,
184 CFTypeRef policies, SecTrustRef *trust) {
185 OSStatus status = errSecParam;
186 CFAllocatorRef allocator = kCFAllocatorDefault;
187 CFArrayRef l_certs = NULL, l_policies = NULL;
188 SecTrustRef result = NULL;
189 dispatch_queue_t queue = NULL;
190
191 check(certificates);
192 check(trust);
193 CFTypeID certType = CFGetTypeID(certificates);
194 if (certType == CFArrayGetTypeID()) {
195 CFIndex idx, count = CFArrayGetCount(certificates);
196 /* We need at least 1 certificate. */
197 require_quiet(count > 0, errOut);
198 l_certs = (CFArrayRef) CFArrayCreateMutable(allocator, count,
199 &kCFTypeArrayCallBacks);
200 if (!l_certs) {
201 status = errSecAllocate;
202 goto errOut;
203 }
204 for (idx = 0; idx < count; idx++) {
205 CFTypeRef val = CFArrayGetValueAtIndex(certificates, idx);
206 if (val) { CFArrayAppendValue((CFMutableArrayRef)l_certs, val); }
207 }
208 require_quiet(count == CFArrayGetCount(l_certs), errOut);
209 } else if (certType == SecCertificateGetTypeID()) {
210 l_certs = CFArrayCreate(allocator, &certificates, 1,
211 &kCFTypeArrayCallBacks);
212 } else {
213 goto errOut;
214 }
215 if (!l_certs) {
216 status = errSecAllocate;
217 goto errOut;
218 }
219
220 if (!policies) {
221 CFTypeRef policy = SecPolicyCreateBasicX509();
222 l_policies = CFArrayCreate(allocator, &policy, 1,
223 &kCFTypeArrayCallBacks);
224 CFRelease(policy);
225 }
226 else if (CFGetTypeID(policies) == CFArrayGetTypeID()) {
227 CFIndex idx, count = CFArrayGetCount(policies);
228 /* We need at least 1 policy. */
229 require_quiet(count > 0, errOut);
230 l_policies = (CFArrayRef) CFArrayCreateMutable(allocator, count,
231 &kCFTypeArrayCallBacks);
232 if (!l_policies) {
233 status = errSecAllocate;
234 goto errOut;
235 }
236 for (idx = 0; idx < count; idx++) {
237 CFTypeRef val = CFArrayGetValueAtIndex(policies, idx);
238 if (val) { CFArrayAppendValue((CFMutableArrayRef)l_policies, val); }
239 }
240 require_quiet(count == CFArrayGetCount(l_policies), errOut);
241 }
242 else if (CFGetTypeID(policies) == SecPolicyGetTypeID()) {
243 l_policies = CFArrayCreate(allocator, &policies, 1,
244 &kCFTypeArrayCallBacks);
245 } else {
246 goto errOut;
247 }
248 if (!l_policies) {
249 status = errSecAllocate;
250 goto errOut;
251 }
252
253 queue = dispatch_queue_create("trust", DISPATCH_QUEUE_SERIAL);
254 if (!queue) {
255 status = errSecAllocate;
256 goto errOut;
257 }
258
259 CFIndex size = sizeof(struct __SecTrust);
260 require_quiet(result = (SecTrustRef)_CFRuntimeCreateInstance(allocator,
261 SecTrustGetTypeID(), size - sizeof(CFRuntimeBase), 0), errOut);
262 memset((char*)result + sizeof(result->_base), 0,
263 sizeof(*result) - sizeof(result->_base));
264 status = errSecSuccess;
265
266 errOut:
267 if (status) {
268 CFReleaseSafe(result);
269 CFReleaseSafe(l_certs);
270 CFReleaseSafe(l_policies);
271 dispatch_release_null(queue);
272 } else {
273 result->_certificates = l_certs;
274 result->_policies = l_policies;
275 result->_keychainsAllowed = true;
276 result->_trustQueue = queue;
277 if (trust)
278 *trust = result;
279 else
280 CFReleaseSafe(result);
281 }
282 return status;
283 }
284
285 OSStatus SecTrustCopyInputCertificates(SecTrustRef trust, CFArrayRef *certificates) {
286 if (!trust || !certificates) {
287 return errSecParam;
288 }
289 __block CFArrayRef certArray = NULL;
290 dispatch_sync(trust->_trustQueue, ^{
291 certArray = CFArrayCreateCopy(NULL, trust->_certificates);
292 });
293 if (!certArray) {
294 return errSecAllocate;
295 }
296 *certificates = certArray;
297 return errSecSuccess;
298 }
299
300 OSStatus SecTrustAddToInputCertificates(SecTrustRef trust, CFTypeRef certificates) {
301 if (!trust || !certificates) {
302 return errSecParam;
303 }
304 __block CFMutableArrayRef newCertificates = NULL;
305 dispatch_sync(trust->_trustQueue, ^{
306 newCertificates = CFArrayCreateMutableCopy(NULL, 0, trust->_certificates);
307 });
308
309 if (isArray(certificates)) {
310 CFArrayAppendArray(newCertificates, certificates,
311 CFRangeMake(0, CFArrayGetCount(certificates)));
312 } else if (CFGetTypeID(certificates) == SecCertificateGetTypeID()) {
313 CFArrayAppendValue(newCertificates, certificates);
314 } else {
315 CFReleaseNull(newCertificates);
316 return errSecParam;
317 }
318
319 dispatch_sync(trust->_trustQueue, ^{
320 CFReleaseNull(trust->_certificates);
321 trust->_certificates = (CFArrayRef)newCertificates;
322 });
323
324 return errSecSuccess;
325 }
326
327 static void SecTrustSetNeedsEvaluation(SecTrustRef trust) {
328 check(trust);
329 if (trust) {
330 dispatch_sync(trust->_trustQueue, ^{
331 trust->_trustResult = kSecTrustResultInvalid;
332 });
333 }
334 }
335
336 OSStatus SecTrustSetAnchorCertificatesOnly(SecTrustRef trust,
337 Boolean anchorCertificatesOnly) {
338 if (!trust) {
339 return errSecParam;
340 }
341 SecTrustSetNeedsEvaluation(trust);
342 trust->_anchorsOnly = anchorCertificatesOnly;
343
344 return errSecSuccess;
345 }
346
347 OSStatus SecTrustSetAnchorCertificates(SecTrustRef trust,
348 CFArrayRef anchorCertificates) {
349 if (!trust) {
350 return errSecParam;
351 }
352 SecTrustSetNeedsEvaluation(trust);
353 __block CFArrayRef anchorsArray = NULL;
354 if (anchorCertificates) {
355 if (CFGetTypeID(anchorCertificates) == CFArrayGetTypeID()) {
356 CFIndex idx, count = CFArrayGetCount(anchorCertificates);
357 anchorsArray = (CFArrayRef) CFArrayCreateMutable(NULL, count,
358 &kCFTypeArrayCallBacks);
359 if (!anchorsArray) {
360 return errSecAllocate;
361 }
362 for (idx = 0; idx < count; idx++) {
363 CFTypeRef val = CFArrayGetValueAtIndex(anchorCertificates, idx);
364 if (val) { CFArrayAppendValue((CFMutableArrayRef)anchorsArray, val); }
365 }
366 if (count != CFArrayGetCount(anchorsArray)) {
367 CFReleaseSafe(anchorsArray);
368 return errSecParam;
369 }
370 } else {
371 return errSecParam;
372 }
373 }
374
375 dispatch_sync(trust->_trustQueue, ^{
376 CFReleaseSafe(trust->_anchors);
377 trust->_anchors = anchorsArray;
378 });
379 trust->_anchorsOnly = (anchorCertificates != NULL);
380
381 return errSecSuccess;
382 }
383
384 OSStatus SecTrustCopyCustomAnchorCertificates(SecTrustRef trust,
385 CFArrayRef *anchors) {
386 if (!trust|| !anchors) {
387 return errSecParam;
388 }
389 __block CFArrayRef anchorsArray = NULL;
390 dispatch_sync(trust->_trustQueue, ^{
391 if (trust->_anchors) {
392 anchorsArray = CFArrayCreateCopy(kCFAllocatorDefault, trust->_anchors);
393 }
394 });
395
396 *anchors = anchorsArray;
397 return errSecSuccess;
398 }
399
400 OSStatus SecTrustSetOCSPResponse(SecTrustRef trust, CFTypeRef responseData) {
401 if (!trust) {
402 return errSecParam;
403 }
404 SecTrustSetNeedsEvaluation(trust);
405 __block CFArrayRef responseArray = NULL;
406 if (responseData) {
407 if (CFGetTypeID(responseData) == CFArrayGetTypeID()) {
408 CFIndex idx, count = CFArrayGetCount(responseData);
409 responseArray = (CFArrayRef) CFArrayCreateMutable(NULL, count,
410 &kCFTypeArrayCallBacks);
411 if (!responseArray) {
412 return errSecAllocate;
413 }
414 for (idx = 0; idx < count; idx++) {
415 CFTypeRef val = CFArrayGetValueAtIndex(responseData, idx);
416 if (val) { CFArrayAppendValue((CFMutableArrayRef)responseArray, val); }
417 }
418 if (count != CFArrayGetCount(responseArray)) {
419 CFReleaseSafe(responseArray);
420 return errSecParam;
421 }
422 } else if (CFGetTypeID(responseData) == CFDataGetTypeID()) {
423 responseArray = CFArrayCreate(kCFAllocatorDefault, &responseData, 1,
424 &kCFTypeArrayCallBacks);
425 } else {
426 return errSecParam;
427 }
428 }
429
430 dispatch_sync(trust->_trustQueue, ^{
431 CFReleaseSafe(trust->_responses);
432 trust->_responses = responseArray;
433 });
434
435 return errSecSuccess;
436 }
437
438 OSStatus SecTrustSetSignedCertificateTimestamps(SecTrustRef trust, CFArrayRef sctArray) {
439 if (!trust) {
440 return errSecParam;
441 }
442 SecTrustSetNeedsEvaluation(trust);
443 dispatch_sync(trust->_trustQueue, ^{
444 CFRetainAssign(trust->_SCTs, sctArray);
445 });
446 return errSecSuccess;
447 }
448
449 OSStatus SecTrustSetTrustedLogs(SecTrustRef trust, CFArrayRef trustedLogs) {
450 if (!trust) {
451 return errSecParam;
452 }
453 SecTrustSetNeedsEvaluation(trust);
454 dispatch_sync(trust->_trustQueue, ^{
455 CFRetainAssign(trust->_trustedLogs, trustedLogs);
456 });
457 return errSecSuccess;
458 }
459
460 OSStatus SecTrustSetVerifyDate(SecTrustRef trust, CFDateRef verifyDate) {
461 if (!trust) {
462 return errSecParam;
463 }
464 SecTrustSetNeedsEvaluation(trust);
465 check(verifyDate);
466 dispatch_sync(trust->_trustQueue, ^{
467 CFRetainAssign(trust->_verifyDate, verifyDate);
468 });
469 return errSecSuccess;
470 }
471
472 OSStatus SecTrustSetPolicies(SecTrustRef trust, CFTypeRef newPolicies) {
473 if (!trust || !newPolicies) {
474 return errSecParam;
475 }
476 SecTrustSetNeedsEvaluation(trust);
477 check(newPolicies);
478
479 __block CFArrayRef policyArray = NULL;
480 if (CFGetTypeID(newPolicies) == CFArrayGetTypeID()) {
481 CFIndex idx, count = CFArrayGetCount(newPolicies);
482 /* We need at least 1 policy. */
483 if (!(count > 0)) {
484 return errSecParam;
485 }
486 policyArray = (CFArrayRef) CFArrayCreateMutable(NULL, count,
487 &kCFTypeArrayCallBacks);
488 if (!policyArray) {
489 return errSecAllocate;
490 }
491 for (idx = 0; idx < count; idx++) {
492 CFTypeRef val = CFArrayGetValueAtIndex(newPolicies, idx);
493 if (val) { CFArrayAppendValue((CFMutableArrayRef)policyArray, val); }
494 }
495 if (count != CFArrayGetCount(policyArray)) {
496 CFReleaseSafe(policyArray);
497 return errSecParam;
498 }
499 } else if (CFGetTypeID(newPolicies) == SecPolicyGetTypeID()) {
500 policyArray = CFArrayCreate(kCFAllocatorDefault, &newPolicies, 1,
501 &kCFTypeArrayCallBacks);
502 } else {
503 return errSecParam;
504 }
505
506 dispatch_sync(trust->_trustQueue, ^{
507 CFReleaseSafe(trust->_policies);
508 trust->_policies = policyArray;
509 });
510
511 return errSecSuccess;
512 }
513
514 OSStatus SecTrustSetPinningPolicyName(SecTrustRef trust, CFStringRef policyName) {
515 if (!trust || !policyName) {
516 return errSecParam;
517 }
518
519 SecTrustSetNeedsEvaluation(trust);
520
521 dispatch_sync(trust->_trustQueue, ^{
522 CFArrayForEach(trust->_policies, ^(const void *value) {
523 SecPolicyRef policy = (SecPolicyRef)value;
524 SecPolicySetName(policy, policyName);
525 });
526 });
527 return errSecSuccess;
528 }
529
530 OSStatus SecTrustSetKeychainsAllowed(SecTrustRef trust, Boolean allowed) {
531 if (!trust) {
532 return errSecParam;
533 }
534 SecTrustSetNeedsEvaluation(trust);
535 trust->_keychainsAllowed = allowed;
536
537 return errSecSuccess;
538 }
539
540 OSStatus SecTrustGetKeychainsAllowed(SecTrustRef trust, Boolean *allowed) {
541 if (!trust || !allowed) {
542 return errSecParam;
543 }
544 *allowed = trust->_keychainsAllowed;
545
546 return errSecSuccess;
547 }
548
549 OSStatus SecTrustCopyPolicies(SecTrustRef trust, CFArrayRef *policies) {
550 if (!trust|| !policies) {
551 return errSecParam;
552 }
553 __block CFArrayRef policyArray = NULL;
554 dispatch_sync(trust->_trustQueue, ^{
555 policyArray = CFArrayCreateCopy(kCFAllocatorDefault, trust->_policies);
556 });
557 if (!policyArray) {
558 return errSecAllocate;
559 }
560 *policies = policyArray;
561 return errSecSuccess;
562 }
563
564 static OSStatus SecTrustSetOptionInPolicies(CFArrayRef policies, CFStringRef key, CFTypeRef value) {
565 OSStatus status = errSecSuccess;
566 require_action(policies && CFGetTypeID(policies) == CFArrayGetTypeID(), out, status = errSecInternal);
567 for (int i=0; i < CFArrayGetCount(policies); i++) {
568 SecPolicyRef policy = NULL;
569 require_action_quiet(policy = (SecPolicyRef)CFArrayGetValueAtIndex(policies, i), out, status = errSecInternal);
570 CFMutableDictionaryRef options = NULL;
571 require_action_quiet(options = CFDictionaryCreateMutableCopy(NULL, 0, policy->_options), out, status = errSecAllocate);
572 CFDictionaryAddValue(options, key, value);
573 CFReleaseNull(policy->_options);
574 policy->_options = options;
575 }
576 out:
577 return status;
578 }
579
580 static OSStatus SecTrustRemoveOptionInPolicies(CFArrayRef policies, CFStringRef key) {
581 OSStatus status = errSecSuccess;
582 require_action(policies && CFGetTypeID(policies) == CFArrayGetTypeID(), out, status = errSecInternal);
583 for (int i=0; i < CFArrayGetCount(policies); i++) {
584 SecPolicyRef policy = NULL;
585 require_action_quiet(policy = (SecPolicyRef)CFArrayGetValueAtIndex(policies, i), out, status = errSecInternal);
586 if (CFDictionaryGetValue(policy->_options, key)) {
587 CFMutableDictionaryRef options = NULL;
588 require_action_quiet(options = CFDictionaryCreateMutableCopy(NULL, 0, policy->_options), out, status = errSecAllocate);
589 CFDictionaryRemoveValue(options, key);
590 CFReleaseNull(policy->_options);
591 policy->_options = options;
592 }
593 }
594 out:
595 return status;
596 }
597
598 static CF_RETURNS_RETAINED CFArrayRef SecTrustCopyOptionsFromPolicies(CFArrayRef policies, CFStringRef key) {
599 CFMutableArrayRef foundValues = NULL;
600 foundValues = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
601 for (int i=0; i < CFArrayGetCount(policies); i++) {
602 SecPolicyRef policy = (SecPolicyRef)CFArrayGetValueAtIndex(policies, i);
603 CFTypeRef value = CFDictionaryGetValue(policy->_options, key);
604 if (value) {
605 CFArrayAppendValue(foundValues, value);
606 }
607 }
608 if (!CFArrayGetCount(foundValues)) {
609 CFReleaseNull(foundValues);
610 return NULL;
611 }
612 else {
613 return foundValues;
614 }
615 }
616
617 /* The only effective way to disable network fetch is within the policy options:
618 * presence of the kSecPolicyCheckNoNetworkAccess key in any of the policies
619 * will prevent network access for fetching.
620 * The current SecTrustServer implementation doesn't distinguish between network
621 * access for revocation and network access for fetching.
622 */
623 OSStatus SecTrustSetNetworkFetchAllowed(SecTrustRef trust, Boolean allowFetch) {
624 if (!trust) {
625 return errSecParam;
626 }
627 __block OSStatus status = errSecSuccess;
628 dispatch_sync(trust->_trustQueue, ^{
629 if (!allowFetch) {
630 status = SecTrustSetOptionInPolicies(trust->_policies, kSecPolicyCheckNoNetworkAccess, kCFBooleanTrue);
631 } else {
632 status = SecTrustRemoveOptionInPolicies(trust->_policies, kSecPolicyCheckNoNetworkAccess);
633 }
634 });
635 return status;
636 }
637
638 OSStatus SecTrustGetNetworkFetchAllowed(SecTrustRef trust, Boolean *allowFetch) {
639 if (!trust || !allowFetch) {
640 return errSecParam;
641 }
642 __block CFArrayRef foundValues = NULL;
643 dispatch_sync(trust->_trustQueue, ^{
644 foundValues = SecTrustCopyOptionsFromPolicies(trust->_policies, kSecPolicyCheckNoNetworkAccess);
645 });
646 if (foundValues) {
647 *allowFetch = false;
648 } else {
649 *allowFetch = true;
650 }
651 CFReleaseNull(foundValues);
652 return errSecSuccess;
653 }
654
655 OSStatus SecTrustSetPinningException(SecTrustRef trust) {
656 if (!trust) { return errSecParam; }
657 __block OSStatus status = errSecSuccess;
658 dispatch_sync(trust->_trustQueue, ^{
659 status = SecTrustRemoveOptionInPolicies(trust->_policies, kSecPolicyCheckPinningRequired);
660 });
661 return status;
662 }
663
664 CFAbsoluteTime SecTrustGetVerifyTime(SecTrustRef trust) {
665 __block CFAbsoluteTime verifyTime = CFAbsoluteTimeGetCurrent();
666 if (!trust) {
667 return verifyTime;
668 }
669 dispatch_sync(trust->_trustQueue, ^{
670 if (trust->_verifyDate) {
671 verifyTime = CFDateGetAbsoluteTime(trust->_verifyDate);
672 } else {
673 trust->_verifyDate = CFDateCreate(CFGetAllocator(trust), verifyTime);
674 }
675 });
676
677 return verifyTime;
678 }
679
680 CFArrayRef SecTrustGetDetails(SecTrustRef trust) {
681 if (!trust) {
682 return NULL;
683 }
684 SecTrustEvaluateIfNecessary(trust);
685 return trust->_details;
686 }
687
688 OSStatus SecTrustGetTrustResult(SecTrustRef trust,
689 SecTrustResultType *result) {
690 if (!trust || !result) {
691 return errSecParam;
692 }
693 SecTrustEvaluateIfNecessary(trust);
694 dispatch_sync(trust->_trustQueue, ^{
695 *result = trust->_trustResult;
696 });
697 return errSecSuccess;
698 }
699
700 static CFDictionaryRef SecTrustGetExceptionForCertificateAtIndex(SecTrustRef trust, CFIndex ix) {
701 CFDictionaryRef exception = NULL;
702 __block CFArrayRef exceptions = NULL;
703 dispatch_sync(trust->_trustQueue, ^{
704 exceptions = CFRetainSafe(trust->_exceptions);
705 });
706 if (!exceptions || ix >= CFArrayGetCount(exceptions)) {
707 goto out;
708 }
709
710 SecCertificateRef certificate = SecTrustGetCertificateAtIndex(trust, ix);
711 if (!certificate) {
712 goto out;
713 }
714
715 exception = (CFDictionaryRef)CFArrayGetValueAtIndex(exceptions, ix);
716 if (CFGetTypeID(exception) != CFDictionaryGetTypeID()) {
717 exception = NULL;
718 goto out;
719 }
720
721 /* If the exception contains the current certificates sha1Digest in the
722 kSecCertificateDetailSHA1Digest key then we use it otherwise we ignore it. */
723 CFDataRef sha1Digest = SecCertificateGetSHA1Digest(certificate);
724 CFTypeRef digestValue = CFDictionaryGetValue(exception, kSecCertificateDetailSHA1Digest);
725 if (!digestValue || !CFEqual(sha1Digest, digestValue))
726 exception = NULL;
727
728 out:
729 CFReleaseSafe(exceptions);
730 return exception;
731 }
732
733 CFArrayRef SecTrustCopyFilteredDetails(SecTrustRef trust) {
734 if (!trust) {
735 return NULL;
736 }
737 SecTrustEvaluateIfNecessary(trust);
738 __block CFArrayRef details = NULL;
739 dispatch_sync(trust->_trustQueue, ^{
740 details = CFRetainSafe(trust->_details);
741 });
742
743 /* Done automatically by the Policy Server with SecPVCIsExceptedError */
744 return details;
745 }
746
747 Boolean SecTrustIsExpiredOnly(SecTrustRef trust) {
748 /* Returns true if one or more certificates in the chain have expired,
749 * expiration is an error (i.e. is not covered by existing trust settings),
750 * and it is the only error encountered.
751 * Returns false if the certificate is valid, or if the trust chain has
752 * other errors beside expiration.
753 */
754 Boolean result = false;
755 Boolean foundExpired = false;
756 CFArrayRef details = SecTrustCopyFilteredDetails(trust);
757 require(details != NULL, out);
758
759 CFIndex ix, pathLength = CFArrayGetCount(details);
760 for (ix = 0; ix < pathLength; ++ix) {
761 CFDictionaryRef detail = (CFDictionaryRef)CFArrayGetValueAtIndex(details, ix);
762 CFIndex count = (detail) ? CFDictionaryGetCount(detail) : 0;
763 require(count <= 1, out);
764 if (count) {
765 CFStringRef key = CFSTR("ValidIntermediates");
766 if (ix == 0) {
767 key = CFSTR("ValidLeaf");
768 } else if (ix == pathLength-1) {
769 key = CFSTR("ValidRoot");
770 }
771 CFBooleanRef valid = (CFBooleanRef)CFDictionaryGetValue(detail, key);
772 require(isBoolean(valid) && CFEqual(valid, kCFBooleanFalse), out);
773 foundExpired = true;
774 }
775 }
776 result = foundExpired;
777 out:
778 CFReleaseSafe(details);
779 return result;
780 }
781
782 #if TARGET_OS_IPHONE
783 static CFArrayRef SecTrustCreatePolicyAnchorsArray(const UInt8* certData, CFIndex certLength)
784 {
785 CFArrayRef array = NULL;
786 CFAllocatorRef allocator = kCFAllocatorDefault;
787 SecCertificateRef cert = SecCertificateCreateWithBytes(allocator, certData, certLength);
788 if (cert) {
789 array = CFArrayCreate(allocator, (const void **)&cert, 1, &kCFTypeArrayCallBacks);
790 CFReleaseSafe(cert);
791 }
792 return array;
793 }
794 #endif
795
796 static void SecTrustAddPolicyAnchors(SecTrustRef trust)
797 {
798 /* Provide anchor certificates specifically required by certain policies.
799 This is used to evaluate test policies where the anchor is not provided
800 in the root store and may not be able to be supplied by the caller.
801 */
802 if (!trust) { return; }
803 __block CFArrayRef policies = NULL;
804 dispatch_sync(trust->_trustQueue, ^{
805 policies = CFRetain(trust->_policies);
806 });
807 CFIndex ix, count = CFArrayGetCount(policies);
808 for (ix = 0; ix < count; ++ix) {
809 SecPolicyRef policy = (SecPolicyRef) CFArrayGetValueAtIndex(policies, ix);
810 if (policy) {
811 #if TARGET_OS_IPHONE
812 if (CFEqual(policy->_oid, kSecPolicyAppleTestSMPEncryption)) {
813 __block CFArrayRef policyAnchors = SecTrustCreatePolicyAnchorsArray(_SEC_TestAppleRootCAECC, sizeof(_SEC_TestAppleRootCAECC));
814 dispatch_sync(trust->_trustQueue, ^{
815 CFReleaseSafe(trust->_anchors);
816 trust->_anchors = policyAnchors;
817 });
818 trust->_anchorsOnly = true;
819 break;
820 }
821 #endif
822 }
823 }
824 CFReleaseSafe(policies);
825 }
826
827 // uncomment for verbose debug logging (debug builds only)
828 //#define CERT_TRUST_DUMP 1
829
830 #if CERT_TRUST_DUMP
831 static void sectrustlog(int priority, const char *format, ...)
832 {
833 #ifndef NDEBUG
834 // log everything
835 #else
836 if (priority < LOG_NOTICE) // log warnings and errors
837 #endif
838 {
839 va_list list;
840 va_start(list, format);
841 vsyslog(priority, format, list);
842 va_end(list);
843 }
844 }
845
846 static void sectrustshow(CFTypeRef obj, const char *context)
847 {
848 #ifndef NDEBUG
849 CFStringRef desc = CFCopyDescription(obj);
850 if (!desc) return;
851
852 CFIndex length = CFStringGetMaximumSizeForEncoding(CFStringGetLength(desc), kCFStringEncodingUTF8) + 1;
853 char* buffer = (char*) malloc(length);
854 if (buffer) {
855 Boolean converted = CFStringGetCString(desc, buffer, length, kCFStringEncodingUTF8);
856 if (converted) {
857 const char *prefix = (context) ? context : "";
858 const char *separator = (context) ? " " : "";
859 sectrustlog(LOG_NOTICE, "%s%s%s", prefix, separator, buffer);
860 }
861 free(buffer);
862 }
863 CFRelease(desc);
864 #endif
865 }
866
867 static void cert_trust_dump(SecTrustRef trust) {
868 SecCertificateRef leaf = SecTrustGetCertificateAtIndex(trust, 0);
869 CFStringRef name = (leaf) ? SecCertificateCopySubjectSummary(leaf) : NULL;
870 secerror("leaf \"%@\"", name);
871 secerror(": result = %d", (int) trust->_trustResult);
872 if (trust->_chain) {
873 CFIndex ix, count = SecCertificatePathGetCount(trust->_chain);
874 CFMutableArrayRef chain = CFArrayCreateMutable(kCFAllocatorDefault, count, &kCFTypeArrayCallBacks);
875 for (ix = 0; ix < count; ix++) {
876 SecCertificateRef cert = SecCertificatePathGetCertificateAtIndex(trust->_chain, ix);
877 if (cert) {
878 CFArrayAppendValue(chain, cert);
879 }
880 }
881 sectrustshow(chain, "chain:");
882 CFReleaseSafe(chain);
883 }
884 secerror(": %ld certificates, %ld anchors, %ld policies, %ld details",
885 (trust->_certificates) ? (long)CFArrayGetCount(trust->_certificates) : 0,
886 (trust->_anchors) ? (long)CFArrayGetCount(trust->_anchors) : 0,
887 (trust->_policies) ? (long)CFArrayGetCount(trust->_policies) : 0,
888 (trust->_details) ? (long)CFArrayGetCount(trust->_details) : 0);
889
890 sectrustshow(trust->_verifyDate, "verify date:");
891 sectrustshow(trust->_certificates, "certificates:");
892 sectrustshow(trust->_anchors, "anchors:");
893 sectrustshow(trust->_policies, "policies:");
894 sectrustshow(trust->_details, "details:");
895 sectrustshow(trust->_info, "info:");
896
897 CFReleaseSafe(name);
898 }
899 #else
900 static void cert_trust_dump(SecTrustRef trust) {}
901 #endif
902
903
904 OSStatus SecTrustEvaluate(SecTrustRef trust, SecTrustResultType *result) {
905 if (result) {
906 *result = kSecTrustResultInvalid;
907 }
908 if (!trust) {
909 return errSecParam;
910 }
911 OSStatus status = SecTrustEvaluateIfNecessary(trust);
912 if (status) {
913 return status;
914 }
915 /* post-process trust result based on exceptions */
916 __block SecTrustResultType trustResult = kSecTrustResultInvalid;
917 dispatch_sync(trust->_trustQueue, ^{
918 trustResult = trust->_trustResult;
919 });
920
921 /* log to syslog when there is a trust failure */
922 if (trustResult != kSecTrustResultProceed &&
923 trustResult != kSecTrustResultUnspecified) {
924 CFStringRef failureDesc = SecTrustCopyFailureDescription(trust);
925 secerror("%{public}@", failureDesc);
926 CFRelease(failureDesc);
927 }
928
929
930 if (result) {
931 *result = trustResult;
932 }
933
934 return status;
935 }
936
937 OSStatus SecTrustEvaluateAsync(SecTrustRef trust,
938 dispatch_queue_t queue, SecTrustCallback result)
939 {
940 CFRetainSafe(trust);
941 dispatch_async(queue, ^{
942 SecTrustResultType trustResult;
943 if (errSecSuccess != SecTrustEvaluate(trust, &trustResult)) {
944 trustResult = kSecTrustResultInvalid;
945 }
946 result(trust, trustResult);
947 CFReleaseSafe(trust);
948 });
949 return errSecSuccess;
950 }
951
952 static bool append_certificate_to_xpc_array(SecCertificateRef certificate, xpc_object_t xpc_certificates);
953 static xpc_object_t copy_xpc_certificates_array(CFArrayRef certificates);
954 xpc_object_t copy_xpc_policies_array(CFArrayRef policies);
955 OSStatus validate_array_of_items(CFArrayRef array, CFStringRef arrayItemType, CFTypeID itemTypeID, bool required);
956
957 static bool append_certificate_to_xpc_array(SecCertificateRef certificate, xpc_object_t xpc_certificates) {
958 if (!certificate) {
959 return true; // NOOP
960 }
961 size_t length = SecCertificateGetLength(certificate);
962 const uint8_t *bytes = SecCertificateGetBytePtr(certificate);
963 if (!length || !bytes) {
964 return false;
965 }
966 xpc_array_set_data(xpc_certificates, XPC_ARRAY_APPEND, bytes, length);
967 return true;
968 }
969
970 static xpc_object_t copy_xpc_certificates_array(CFArrayRef certificates) {
971 xpc_object_t xpc_certificates = xpc_array_create(NULL, 0);
972 if (!xpc_certificates) {
973 return NULL;
974 }
975 CFIndex ix, count = CFArrayGetCount(certificates);
976 for (ix = 0; ix < count; ++ix) {
977 SecCertificateRef certificate = (SecCertificateRef) CFArrayGetValueAtIndex(certificates, ix);
978 #if SECTRUST_VERBOSE_DEBUG
979 size_t length = SecCertificateGetLength(certificate);
980 const uint8_t *bytes = SecCertificateGetBytePtr(certificate);
981 secerror("idx=%d of %d; cert=0x%lX length=%ld bytes=0x%lX", (int)ix, (int)count, (uintptr_t)certificate, (size_t)length, (uintptr_t)bytes);
982 #endif
983 if (!append_certificate_to_xpc_array(certificate, xpc_certificates)) {
984 xpc_release(xpc_certificates);
985 xpc_certificates = NULL;
986 break;
987 }
988 }
989 return xpc_certificates;
990 }
991
992 static bool SecXPCDictionarySetCertificates(xpc_object_t message, const char *key, CFArrayRef certificates, CFErrorRef *error) {
993 xpc_object_t xpc_certificates = copy_xpc_certificates_array(certificates);
994 if (!xpc_certificates) {
995 SecError(errSecAllocate, error, CFSTR("failed to create xpc_array of certificates"));
996 return false;
997 }
998 xpc_dictionary_set_value(message, key, xpc_certificates);
999 xpc_release(xpc_certificates);
1000 return true;
1001 }
1002
1003 static bool SecXPCDictionarySetPolicies(xpc_object_t message, const char *key, CFArrayRef policies, CFErrorRef *error) {
1004 xpc_object_t xpc_policies = copy_xpc_policies_array(policies);
1005 if (!xpc_policies) {
1006 SecError(errSecAllocate, error, CFSTR("failed to create xpc_array of policies"));
1007 return false;
1008 }
1009 xpc_dictionary_set_value(message, key, xpc_policies);
1010 xpc_release(xpc_policies);
1011 return true;
1012 }
1013
1014
1015 static bool CFDataAppendToXPCArray(CFDataRef data, xpc_object_t xpc_data_array, CFErrorRef *error) {
1016 if (!data)
1017 return true; // NOOP
1018
1019 size_t length = CFDataGetLength(data);
1020 const uint8_t *bytes = CFDataGetBytePtr(data);
1021 if (!length || !bytes)
1022 return SecError(errSecParam, error, CFSTR("invalid CFDataRef"));
1023
1024 xpc_array_set_data(xpc_data_array, XPC_ARRAY_APPEND, bytes, length);
1025 return true;
1026 }
1027
1028
1029 static xpc_object_t CFDataArrayCopyXPCArray(CFArrayRef data_array, CFErrorRef *error) {
1030 xpc_object_t xpc_data_array;
1031 require_action_quiet(xpc_data_array = xpc_array_create(NULL, 0), exit,
1032 SecError(errSecAllocate, error, CFSTR("failed to create xpc_array")));
1033 CFIndex ix, count = CFArrayGetCount(data_array);
1034 for (ix = 0; ix < count; ++ix) {
1035 if (!CFDataAppendToXPCArray((CFDataRef)CFArrayGetValueAtIndex(data_array, ix), xpc_data_array, error)) {
1036 xpc_release(xpc_data_array);
1037 return NULL;
1038 }
1039 }
1040
1041 exit:
1042 return xpc_data_array;
1043 }
1044
1045 static bool SecXPCDictionarySetDataArray(xpc_object_t message, const char *key, CFArrayRef data_array, CFErrorRef *error) {
1046 xpc_object_t xpc_data_array = CFDataArrayCopyXPCArray(data_array, error);
1047 if (!xpc_data_array)
1048 return false;
1049 xpc_dictionary_set_value(message, key, xpc_data_array);
1050 xpc_release(xpc_data_array);
1051 return true;
1052 }
1053
1054 static bool SecXPCDictionaryCopyChainOptional(xpc_object_t message, const char *key, SecCertificatePathRef *path, CFErrorRef *error) {
1055 xpc_object_t xpc_path = xpc_dictionary_get_value(message, key);
1056 if (!xpc_path) {
1057 *path = NULL;
1058 return true;
1059 }
1060 *path = SecCertificatePathCreateWithXPCArray(xpc_path, error);
1061 return *path;
1062 }
1063
1064 static int SecXPCDictionaryGetNonZeroInteger(xpc_object_t message, const char *key, CFErrorRef *error) {
1065 int64_t value = xpc_dictionary_get_int64(message, key);
1066 if (!value) {
1067 SecError(errSecInternal, error, CFSTR("object for key %s is 0"), key);
1068 }
1069 return (int)value;
1070 }
1071
1072 static SecTrustResultType handle_trust_evaluate_xpc(enum SecXPCOperation op, CFArrayRef certificates,
1073 CFArrayRef anchors, bool anchorsOnly,
1074 bool keychainsAllowed, CFArrayRef policies, CFArrayRef responses,
1075 CFArrayRef SCTs, CFArrayRef trustedLogs,
1076 CFAbsoluteTime verifyTime, __unused CFArrayRef accessGroups, CFArrayRef exceptions,
1077 CFArrayRef *details, CFDictionaryRef *info, SecCertificatePathRef *chain, CFErrorRef *error)
1078 {
1079 __block SecTrustResultType tr = kSecTrustResultInvalid;
1080 securityd_send_sync_and_do(op, error, ^bool(xpc_object_t message, CFErrorRef *error) {
1081 if (!SecXPCDictionarySetCertificates(message, kSecTrustCertificatesKey, certificates, error))
1082 return false;
1083 if (anchors && !SecXPCDictionarySetCertificates(message, kSecTrustAnchorsKey, anchors, error))
1084 return false;
1085 if (anchorsOnly)
1086 xpc_dictionary_set_bool(message, kSecTrustAnchorsOnlyKey, anchorsOnly);
1087 xpc_dictionary_set_bool(message, kSecTrustKeychainsAllowedKey, keychainsAllowed);
1088 if (!SecXPCDictionarySetPolicies(message, kSecTrustPoliciesKey, policies, error))
1089 return false;
1090 if (responses && !SecXPCDictionarySetDataArray(message, kSecTrustResponsesKey, responses, error))
1091 return false;
1092 if (SCTs && !SecXPCDictionarySetDataArray(message, kSecTrustSCTsKey, SCTs, error))
1093 return false;
1094 if (trustedLogs && !SecXPCDictionarySetPList(message, kSecTrustTrustedLogsKey, trustedLogs, error))
1095 return false;
1096 xpc_dictionary_set_double(message, kSecTrustVerifyDateKey, verifyTime);
1097 if (exceptions && !SecXPCDictionarySetPList(message, kSecTrustExceptionsKey, exceptions, error))
1098 return false;
1099 return true;
1100 }, ^bool(xpc_object_t response, CFErrorRef *error) {
1101 secdebug("trust", "response: %@", response);
1102 return SecXPCDictionaryCopyArrayOptional(response, kSecTrustDetailsKey, details, error) &&
1103 SecXPCDictionaryCopyDictionaryOptional(response, kSecTrustInfoKey, info, error) &&
1104 SecXPCDictionaryCopyChainOptional(response, kSecTrustChainKey, chain, error) &&
1105 ((tr = SecXPCDictionaryGetNonZeroInteger(response, kSecTrustResultKey, error)) != kSecTrustResultInvalid);
1106 });
1107 return tr;
1108 }
1109
1110 OSStatus validate_array_of_items(CFArrayRef array, CFStringRef arrayItemType, CFTypeID itemTypeID, bool required) {
1111 OSStatus result = errSecSuccess;
1112 CFIndex index, count;
1113 count = (array) ? CFArrayGetCount(array) : 0;
1114 if (!count && required) {
1115 secerror("no %@ in array!", arrayItemType);
1116 result = errSecParam;
1117 }
1118 for (index = 0; index < count; index++) {
1119 CFTypeRef item = (CFTypeRef) CFArrayGetValueAtIndex(array, index);
1120 if (!item) {
1121 secerror("%@ %@ (index %d)", arrayItemType, CFSTR("reference is nil"), (int)index);
1122 result = errSecParam;
1123 continue;
1124 }
1125 if (CFGetTypeID(item) != itemTypeID) {
1126 secerror("%@ %@ (index %d)", arrayItemType, CFSTR("is not the expected CF type"), (int)index);
1127 result = errSecParam;
1128 }
1129 // certificates
1130 if (CFGetTypeID(item) == SecCertificateGetTypeID()) {
1131 SecCertificateRef certificate = (SecCertificateRef) item;
1132 CFIndex length = SecCertificateGetLength(certificate);
1133 const UInt8 *bytes = SecCertificateGetBytePtr(certificate);
1134 if (!length) {
1135 secerror("%@ %@ (index %d)", arrayItemType, CFSTR("has zero length"), (int)index);
1136 result = errSecParam;
1137 }
1138 if (!bytes) {
1139 secerror("%@ %@ (index %d)", arrayItemType, CFSTR("has nil bytes"), (int)index);
1140 result = errSecParam;
1141 }
1142 #if SECTRUST_VERBOSE_DEBUG
1143 secerror("%@[%d] of %d = %ld bytes @ 0x%lX", arrayItemType, (int)index, (int)count, (size_t)length, (uintptr_t)bytes);
1144 #endif
1145 }
1146 // policies
1147 if (CFGetTypeID(item) == SecPolicyGetTypeID()) {
1148 SecPolicyRef policy = (SecPolicyRef) item;
1149 CFStringRef oidStr = policy->_oid;
1150 if (!oidStr || (CFGetTypeID(oidStr) != CFStringGetTypeID())) {
1151 oidStr = CFSTR("has invalid OID string!");
1152 secerror("%@ %@ (index %d)", arrayItemType, oidStr, (int)index);
1153 }
1154 #if SECTRUST_VERBOSE_DEBUG
1155 secerror("%@[%d] of %d = \"%@\" 0x%lX", arrayItemType, (int)index, (int)count, oidStr, (uintptr_t)policy);
1156 #endif
1157 }
1158 }
1159 return result;
1160 }
1161
1162 static OSStatus SecTrustValidateInput(SecTrustRef trust) {
1163 OSStatus status, result = errSecSuccess;
1164
1165 // certificates (required)
1166 status = validate_array_of_items(trust->_certificates, CFSTR("certificate"), SecCertificateGetTypeID(), true);
1167 if (status) result = status;
1168 // anchors (optional)
1169 status = validate_array_of_items(trust->_anchors, CFSTR("input anchor"), SecCertificateGetTypeID(), false);
1170 if (status) result = status;
1171 // policies (required??)
1172 status = validate_array_of_items(trust->_policies, CFSTR("policy"), SecPolicyGetTypeID(), true);
1173 if (status) result = status;
1174 // _responses, _SCTs, _trustedLogs, ...
1175 // verify time: SecTrustGetVerifyTime(trust)
1176 // access groups: SecAccessGroupsGetCurrent()
1177
1178 return result;
1179 }
1180
1181 static OSStatus SecTrustEvaluateIfNecessary(SecTrustRef trust) {
1182 __block OSStatus result;
1183 check(trust);
1184 if (!trust)
1185 return errSecParam;
1186
1187 __block CFAbsoluteTime verifyTime = SecTrustGetVerifyTime(trust);
1188 SecTrustAddPolicyAnchors(trust);
1189 dispatch_sync(trust->_trustQueue, ^{
1190 if (trust->_trustResult != kSecTrustResultInvalid) {
1191 result = errSecSuccess;
1192 return;
1193 }
1194
1195 trust->_trustResult = kSecTrustResultOtherError; /* to avoid potential recursion */
1196
1197 CFReleaseNull(trust->_chain);
1198 CFReleaseNull(trust->_details);
1199 CFReleaseNull(trust->_info);
1200 if (trust->_legacy_info_array) {
1201 free(trust->_legacy_info_array);
1202 trust->_legacy_info_array = NULL;
1203 }
1204 if (trust->_legacy_status_array) {
1205 free(trust->_legacy_status_array);
1206 trust->_legacy_status_array = NULL;
1207 }
1208
1209 os_activity_initiate("SecTrustEvaluateIfNecessary", OS_ACTIVITY_FLAG_DEFAULT, ^{
1210 SecTrustValidateInput(trust);
1211
1212 /* @@@ Consider an optimization where we keep a side dictionary with the SHA1 hash of ever SecCertificateRef we send, so we only send potential duplicates once, and have the server respond with either just the SHA1 hash of a certificate, or the complete certificate in the response depending on whether the client already sent it, so we don't send back certificates to the client it already has. */
1213 result = SecOSStatusWith(^bool (CFErrorRef *error) {
1214 trust->_trustResult = TRUSTD_XPC(sec_trust_evaluate,
1215 handle_trust_evaluate_xpc,
1216 trust->_certificates, trust->_anchors, trust->_anchorsOnly, trust->_keychainsAllowed,
1217 trust->_policies, trust->_responses, trust->_SCTs, trust->_trustedLogs,
1218 verifyTime, SecAccessGroupsGetCurrent(), trust->_exceptions,
1219 &trust->_details, &trust->_info, &trust->_chain, error);
1220 if (trust->_trustResult == kSecTrustResultInvalid /* TODO check domain */ &&
1221 SecErrorGetOSStatus(*error) == errSecNotAvailable &&
1222 CFArrayGetCount(trust->_certificates)) {
1223 /* We failed to talk to securityd. The only time this should
1224 happen is when we are running prior to launchd enabling
1225 registration of services. This currently happens when we
1226 are running from the ramdisk. To make ASR happy we initialize
1227 _chain and return success with a failure as the trustResult, to
1228 make it seem like we did a cert evaluation, so ASR can extract
1229 the public key from the leaf. */
1230 SecCertificateRef leafCert = (SecCertificateRef)CFArrayGetValueAtIndex(trust->_certificates, 0);
1231 CFArrayRef leafCertArray = CFArrayCreate(NULL, (const void**)&leafCert, 1, &kCFTypeArrayCallBacks);
1232 trust->_chain = SecCertificatePathCreateWithCertificates(leafCertArray, NULL);
1233 CFReleaseNull(leafCertArray);
1234 if (error)
1235 CFReleaseNull(*error);
1236 return true;
1237 }
1238 return trust->_trustResult != kSecTrustResultInvalid;
1239 });
1240 });
1241 });
1242 return result;
1243 }
1244
1245 /* Helper for the qsort below. */
1246 static int compare_strings(const void *a1, const void *a2) {
1247 CFStringRef s1 = *(CFStringRef *)a1;
1248 CFStringRef s2 = *(CFStringRef *)a2;
1249 return (int) CFStringCompare(s1, s2, kCFCompareForcedOrdering);
1250 }
1251
1252 CFStringRef SecTrustCopyFailureDescription(SecTrustRef trust) {
1253 if (!trust) {
1254 return NULL;
1255 }
1256 CFMutableStringRef reason = CFStringCreateMutable(NULL, 0);
1257 SecTrustEvaluateIfNecessary(trust);
1258 __block CFArrayRef details = NULL;
1259 dispatch_sync(trust->_trustQueue, ^{
1260 details = CFRetainSafe(trust->_details);
1261 });
1262 CFIndex pathLength = details ? CFArrayGetCount(details) : 0;
1263 for (CFIndex ix = 0; ix < pathLength; ++ix) {
1264 CFDictionaryRef detail = (CFDictionaryRef)CFArrayGetValueAtIndex(details, ix);
1265 CFIndex dCount = CFDictionaryGetCount(detail);
1266 if (dCount) {
1267 if (ix == 0)
1268 CFStringAppend(reason, CFSTR(" [leaf"));
1269 else if (ix == pathLength - 1)
1270 CFStringAppend(reason, CFSTR(" [root"));
1271 else
1272 CFStringAppendFormat(reason, NULL, CFSTR(" [ca%" PRIdCFIndex ), ix);
1273
1274 const void *keys[dCount];
1275 CFDictionaryGetKeysAndValues(detail, &keys[0], NULL);
1276 qsort(&keys[0], dCount, sizeof(keys[0]), compare_strings);
1277 for (CFIndex kix = 0; kix < dCount; ++kix) {
1278 CFStringRef key = keys[kix];
1279 const void *value = CFDictionaryGetValue(detail, key);
1280 CFStringAppendFormat(reason, NULL, CFSTR(" %@%@"), key,
1281 (CFGetTypeID(value) == CFBooleanGetTypeID()
1282 ? CFSTR("") : value));
1283 }
1284 CFStringAppend(reason, CFSTR("]"));
1285 }
1286 }
1287 CFReleaseSafe(details);
1288 return reason;
1289 }
1290
1291 #if TARGET_OS_OSX
1292 /* On OS X we need SecTrustCopyPublicKey to give us a CDSA-based SecKeyRef,
1293 so we will refer to this one internally as SecTrustCopyPublicKey_ios,
1294 and call it from SecTrustCopyPublicKey.
1295 */
1296 SecKeyRef SecTrustCopyPublicKey_ios(SecTrustRef trust)
1297 #else
1298 SecKeyRef SecTrustCopyPublicKey(SecTrustRef trust)
1299 #endif
1300 {
1301 if (!trust) {
1302 return NULL;
1303 }
1304 __block SecKeyRef publicKey = NULL;
1305 dispatch_sync(trust->_trustQueue, ^{
1306 if (trust->_publicKey) {
1307 publicKey = CFRetainSafe(trust->_publicKey);
1308 return;
1309 }
1310 SecCertificateRef leaf = (SecCertificateRef)CFArrayGetValueAtIndex(trust->_certificates, 0);
1311 #if TARGET_OS_OSX
1312 trust->_publicKey = SecCertificateCopyPublicKey_ios(leaf);
1313 #else
1314 trust->_publicKey = SecCertificateCopyPublicKey(leaf);
1315 #endif
1316 if (trust->_publicKey) {
1317 publicKey = CFRetainSafe(trust->_publicKey);
1318 }
1319 });
1320 /* If we couldn't get a public key from the leaf cert alone. */
1321 if (!publicKey) {
1322 SecTrustEvaluateIfNecessary(trust);
1323 dispatch_sync(trust->_trustQueue, ^{
1324 if (trust->_chain) {
1325 trust->_publicKey = SecCertificatePathCopyPublicKeyAtIndex(trust->_chain, 0);
1326 publicKey = CFRetainSafe(trust->_publicKey);
1327 }
1328 });
1329 }
1330 return publicKey;
1331 }
1332
1333 CFIndex SecTrustGetCertificateCount(SecTrustRef trust) {
1334 if (!trust) {
1335 return 0;
1336 }
1337 SecTrustEvaluateIfNecessary(trust);
1338 __block CFIndex certCount = 1;
1339 dispatch_sync(trust->_trustQueue, ^{
1340 if (trust->_chain) {
1341 certCount = SecCertificatePathGetCount(trust->_chain);
1342 }
1343 });
1344 return certCount;
1345 }
1346
1347 SecCertificateRef SecTrustGetCertificateAtIndex(SecTrustRef trust,
1348 CFIndex ix) {
1349 if (!trust) {
1350 return NULL;
1351 }
1352 __block SecCertificateRef cert = NULL;
1353 if (ix == 0) {
1354 dispatch_sync(trust->_trustQueue, ^{
1355 cert = (SecCertificateRef)CFArrayGetValueAtIndex(trust->_certificates, 0);
1356 });
1357 return cert;
1358 }
1359 SecTrustEvaluateIfNecessary(trust);
1360 dispatch_sync(trust->_trustQueue, ^{
1361 if (trust->_chain) {
1362 cert = SecCertificatePathGetCertificateAtIndex(trust->_chain, ix);
1363 }
1364 });
1365 return cert;
1366 }
1367
1368 CFDictionaryRef SecTrustCopyInfo(SecTrustRef trust) {
1369 if (!trust) {
1370 return NULL;
1371 }
1372 SecTrustEvaluateIfNecessary(trust);
1373 __block CFDictionaryRef info = NULL;
1374 dispatch_sync(trust->_trustQueue, ^{
1375 info = CFRetainSafe(trust->_info);
1376 });
1377 return info;
1378 }
1379
1380 CFArrayRef SecTrustGetTrustExceptionsArray(SecTrustRef trust) {
1381 if (!trust) {
1382 return NULL;
1383 }
1384 __block CFArrayRef exceptions = NULL;
1385 dispatch_sync(trust->_trustQueue, ^{
1386 exceptions = trust->_exceptions;
1387 });
1388 return exceptions;
1389 }
1390
1391 CFDataRef SecTrustCopyExceptions(SecTrustRef trust) {
1392 /* Stash the old exceptions and run an evaluation with no exceptions filtered. */
1393 __block CFArrayRef oldExceptions = NULL;
1394 dispatch_sync(trust->_trustQueue, ^{
1395 if (trust->_exceptions) {
1396 oldExceptions = trust->_exceptions;
1397 trust->_exceptions = NULL;
1398 }
1399 });
1400 SecTrustSetNeedsEvaluation(trust);
1401
1402 /* Create the new exceptions based on an unfiltered eval. */
1403 __block CFArrayRef details = NULL;
1404 SecTrustEvaluateIfNecessary(trust);
1405 dispatch_sync(trust->_trustQueue, ^{
1406 details = CFRetainSafe(trust->_details);
1407 });
1408 CFIndex pathLength = details ? CFArrayGetCount(details) : 0;
1409 CFMutableArrayRef exceptions = CFArrayCreateMutable(kCFAllocatorDefault, pathLength, &kCFTypeArrayCallBacks);
1410 CFIndex ix;
1411 for (ix = 0; ix < pathLength; ++ix) {
1412 CFDictionaryRef detail = (CFDictionaryRef)CFArrayGetValueAtIndex(details, ix);
1413 CFIndex detailCount = CFDictionaryGetCount(detail);
1414 CFMutableDictionaryRef exception;
1415 if (ix == 0 || detailCount > 0) {
1416 exception = CFDictionaryCreateMutableCopy(kCFAllocatorDefault, detailCount + 1, detail);
1417 SecCertificateRef certificate = SecTrustGetCertificateAtIndex(trust, ix);
1418 CFDataRef digest = SecCertificateGetSHA1Digest(certificate);
1419 CFDictionaryAddValue(exception, kSecCertificateDetailSHA1Digest, digest);
1420 } else {
1421 /* Add empty exception dictionaries for non leaf certs which have no exceptions to save space. */
1422 exception = (CFMutableDictionaryRef)CFDictionaryCreate(kCFAllocatorDefault, NULL, NULL, 0,
1423 &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
1424 }
1425 CFArrayAppendValue(exceptions, exception);
1426 CFReleaseNull(exception);
1427 }
1428
1429 /* Restore the stashed exceptions. */
1430 if (oldExceptions) {
1431 dispatch_sync(trust->_trustQueue, ^{
1432 trust->_exceptions = oldExceptions;
1433 });
1434 SecTrustSetNeedsEvaluation(trust);
1435 }
1436
1437 /* Remove any trailing empty dictionaries to save even more space (we skip the leaf
1438 since it will never be empty). */
1439 for (ix = pathLength; ix-- > 1;) {
1440 CFDictionaryRef exception = (CFDictionaryRef)CFArrayGetValueAtIndex(exceptions, ix);
1441 if (CFDictionaryGetCount(exception) == 0) {
1442 CFArrayRemoveValueAtIndex(exceptions, ix);
1443 } else {
1444 break;
1445 }
1446 }
1447
1448 CFDataRef encodedExceptions = CFPropertyListCreateData(kCFAllocatorDefault,
1449 exceptions, kCFPropertyListBinaryFormat_v1_0, 0, NULL);
1450 CFRelease(exceptions);
1451 CFReleaseSafe(details);
1452 return encodedExceptions;
1453 }
1454
1455 bool SecTrustSetExceptions(SecTrustRef trust, CFDataRef encodedExceptions) {
1456 if (!trust) {
1457 return false;
1458 }
1459 CFArrayRef exceptions = NULL;
1460
1461 if (NULL != encodedExceptions) {
1462 exceptions = (CFArrayRef)CFPropertyListCreateWithData(kCFAllocatorDefault,
1463 encodedExceptions, kCFPropertyListImmutable, NULL, NULL);
1464 }
1465
1466 if (exceptions && CFGetTypeID(exceptions) != CFArrayGetTypeID()) {
1467 CFRelease(exceptions);
1468 exceptions = NULL;
1469 }
1470
1471 dispatch_sync(trust->_trustQueue, ^{
1472 CFReleaseSafe(trust->_exceptions);
1473 trust->_exceptions = exceptions;
1474 });
1475
1476 /* We changed the exceptions -- so we need to re-evaluate */
1477 SecTrustSetNeedsEvaluation(trust);
1478
1479 /* If there is a valid exception entry for our current leaf we're golden. */
1480 if (SecTrustGetExceptionForCertificateAtIndex(trust, 0))
1481 return true;
1482
1483 /* The passed in exceptions didn't match our current leaf, so we discard it. */
1484 dispatch_sync(trust->_trustQueue, ^{
1485 CFReleaseNull(trust->_exceptions);
1486 });
1487 return false;
1488 }
1489
1490 #if TARGET_OS_OSX
1491 OSStatus
1492 SecTrustSetOptions(SecTrustRef trustRef, SecTrustOptionFlags options)
1493 {
1494 /* bridge to support API functionality for legacy callers */
1495 OSStatus status = errSecSuccess;
1496
1497 /* No options or none that trigger the exceptions behavior */
1498 if (!options ||
1499 0 == (options & (kSecTrustOptionAllowExpired |
1500 kSecTrustOptionImplicitAnchors |
1501 kSecTrustOptionAllowExpiredRoot))) {
1502 return status;
1503 }
1504
1505 __block CFMutableArrayRef exceptions = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
1506 if (!exceptions) { return errSecAllocate; }
1507
1508 /* Add the new options to the old_exceptions when those exceptions are tied to a particular cert.
1509 * If not tied to a particular cert, we reset the exceptions based on the input options. */
1510 CFArrayRef old_exceptions = SecTrustGetTrustExceptionsArray(trustRef);
1511 if (old_exceptions && SecTrustGetExceptionForCertificateAtIndex(trustRef, 0)) {
1512 CFIndex ix, count = CFArrayGetCount(old_exceptions);
1513 for (ix = 0; ix < count; ix++) {
1514 CFMutableDictionaryRef exception_dictionary = CFDictionaryCreateMutableCopy(NULL, 0, (CFDictionaryRef)CFArrayGetValueAtIndex(old_exceptions, ix));
1515 if (!exception_dictionary) { status = errSecAllocate; goto out; }
1516 if ((options & kSecTrustOptionAllowExpired) != 0) {
1517 if (ix == 0) { CFDictionaryAddValue(exception_dictionary, CFSTR("ValidLeaf"), kCFBooleanFalse); }
1518 if (ix == (count - 1)) { CFDictionaryAddValue(exception_dictionary, CFSTR("ValidRoot"), kCFBooleanFalse); }
1519 if (ix > 0 && ix < (count - 1)) {
1520 CFDictionaryAddValue(exception_dictionary, CFSTR("ValidIntermediates"), kCFBooleanFalse); }
1521 }
1522 if ((options & kSecTrustOptionAllowExpiredRoot) != 0) {
1523 if (ix == (count - 1)) { CFDictionaryAddValue(exception_dictionary, CFSTR("ValidRoot"), kCFBooleanFalse); }
1524 }
1525 if ((options & kSecTrustOptionImplicitAnchors) != 0) {
1526 /* Check that root is self-signed. (Done by trustd for other case.) */
1527 Boolean isSelfSigned = false;
1528 SecCertificateRef cert = SecTrustGetCertificateAtIndex(trustRef, ix);
1529 if (cert && (errSecSuccess == SecCertificateIsSelfSigned(cert, &isSelfSigned)) &&
1530 isSelfSigned) {
1531 CFDictionaryAddValue(exception_dictionary, CFSTR("AnchorTrusted"), kCFBooleanFalse);
1532 }
1533 }
1534 CFArrayAppendValue(exceptions, exception_dictionary);
1535 CFReleaseNull(exception_dictionary);
1536 }
1537 } else {
1538 /* Create a new exceptions array. Warning, this takes advantage of implementation details of the exceptions mechanism. */
1539 CFMutableDictionaryRef exception_dictionary = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks,
1540 &kCFTypeDictionaryValueCallBacks);
1541 if (!exception_dictionary) { status = errSecAllocate; goto out; }
1542 if ((options & kSecTrustOptionAllowExpired) != 0) {
1543 CFDictionaryAddValue(exception_dictionary, CFSTR("ValidLeaf"), kCFBooleanFalse);
1544 CFDictionaryAddValue(exception_dictionary, CFSTR("ValidIntermediates"), kCFBooleanFalse);
1545 CFDictionaryAddValue(exception_dictionary, CFSTR("ValidRoot"), kCFBooleanFalse);
1546 }
1547 if ((options & kSecTrustOptionAllowExpiredRoot) != 0) {
1548 CFDictionaryAddValue(exception_dictionary, CFSTR("ValidRoot"), kCFBooleanFalse);
1549 }
1550 if ((options & kSecTrustOptionImplicitAnchors) != 0) {
1551 CFDictionaryAddValue(exception_dictionary, CFSTR("AnchorTrusted"), kCFBooleanFalse);
1552 }
1553 CFArrayAppendValue(exceptions, exception_dictionary);
1554 CFReleaseNull(exception_dictionary);
1555 }
1556
1557 /* Set exceptions */
1558 dispatch_sync(trustRef->_trustQueue, ^{
1559 CFReleaseSafe(trustRef->_exceptions);
1560 trustRef->_exceptions = CFRetainSafe(exceptions);
1561 });
1562 /* We changed the exceptions -- so we need to re-evaluate */
1563 SecTrustSetNeedsEvaluation(trustRef);
1564
1565 out:
1566 CFReleaseNull(exceptions);
1567 return status;
1568 }
1569 #endif
1570
1571 CFArrayRef SecTrustCopySummaryPropertiesAtIndex(SecTrustRef trust, CFIndex ix) {
1572 CFMutableArrayRef summary;
1573 SecCertificateRef certificate = SecTrustGetCertificateAtIndex(trust, ix);
1574 summary = SecCertificateCopySummaryProperties(certificate,
1575 SecTrustGetVerifyTime(trust));
1576 /* FIXME Add more details in the failure case. */
1577
1578 return summary;
1579 }
1580
1581 CFArrayRef SecTrustCopyDetailedPropertiesAtIndex(SecTrustRef trust, CFIndex ix) {
1582 CFArrayRef summary;
1583 SecCertificateRef certificate = SecTrustGetCertificateAtIndex(trust, ix);
1584 summary = SecCertificateCopyProperties(certificate);
1585
1586 return summary;
1587 }
1588
1589 #if 0
1590
1591
1592
1593 /* Valid chain.
1594 Can be on any non root cert in the chain.
1595 Priority: Top down
1596 Short circuit: Yes (No other errors matter after this one)
1597 Non recoverable error
1598 Trust UI: Invalid certificate chain linkage
1599 Cert UI: Invalid linkage to parent certificate
1600 */
1601 CFStringRef kSecPolicyCheckIdLinkage = CFSTR("IdLinkage");
1602
1603 /* X.509 required checks.
1604 Can be on any cert in the chain
1605 Priority: Top down
1606 Short circuit: Yes (No other errors matter after this one)
1607 Non recoverable error
1608 Trust UI: (One or more) unsupported critical extensions found.
1609 */
1610 /* If we have no names for the extention oids use:
1611 Cert UI: One or more unsupported critical extensions found (Non recoverable error).
1612 Cert UI: Unsupported 'foo', 'bar', baz' critical extensions found.
1613 */
1614 CFStringRef kSecPolicyCheckCriticalExtensions = CFSTR("CriticalExtensions");
1615 /* Cert UI: Unsupported critical Qualified Certificate Statements extension found (Non recoverable error). */
1616 CFStringRef kSecPolicyCheckQualifiedCertStatements = CFSTR("QualifiedCertStatements");
1617 /* Cert UI: Certificate has an empty subject (and no critial subjectAltname). */
1618
1619 /* Trusted root.
1620 Only apply to the anchor.
1621 Priority: N/A
1622 Short circuit: No (Under discussion)
1623 Recoverable
1624 Trust UI: Root certificate is not trusted (for this policy/app/host/whatever?)
1625 Cert UI: Not a valid anchor
1626 */
1627 CFStringRef kSecPolicyCheckAnchorTrusted = CFSTR("AnchorTrusted");
1628 CFStringRef kSecPolicyCheckAnchorSHA1 = CFSTR("AnchorSHA1");
1629
1630 CFStringRef kSecPolicyCheckAnchorApple = CFSTR("AnchorApple");
1631 CFStringRef kSecPolicyAppleAnchorIncludeTestRoots = CFSTR("AnchorAppleTestRoots");
1632
1633 /* Binding.
1634 Only applies to leaf
1635 Priority: N/A
1636 Short Circuit: No
1637 Recoverable
1638 Trust UI: (Hostname|email address) mismatch
1639 */
1640 CFStringRef kSecPolicyCheckSSLHostname = CFSTR("SSLHostname");
1641
1642 /* Policy specific checks.
1643 Can be on any cert in the chain
1644 Priority: Top down
1645 Short Circuit: No
1646 Recoverable
1647 Trust UI: Certificate chain is not valid for the current policy.
1648 OR: (One or more) certificates in the chain are not valid for the current policy/application
1649 */
1650 CFStringRef kSecPolicyCheckNonEmptySubject = CFSTR("NonEmptySubject");
1651 /* Cert UI: Non CA certificate used as CA.
1652 Cert UI: CA certificate used as leaf.
1653 Cert UI: Cert chain length exceeded.
1654 Cert UI: Basic constraints extension not critical (non fatal).
1655 Cert UI: Leaf certificate has basic constraints extension (non fatal).
1656 */
1657 CFStringRef kSecPolicyCheckBasicConstraints = CFSTR("BasicConstraints");
1658 CFStringRef kSecPolicyCheckKeyUsage = CFSTR("KeyUsage");
1659 CFStringRef kSecPolicyCheckExtendedKeyUsage = CFSTR("ExtendedKeyUsage");
1660 /* Checks that the issuer of the leaf has exactly one Common Name and that it
1661 matches the specified string. */
1662 CFStringRef kSecPolicyCheckIssuerCommonName = CFSTR("IssuerCommonName");
1663 /* Checks that the leaf has exactly one Common Name and that it has the
1664 specified string as a prefix. */
1665 CFStringRef kSecPolicyCheckSubjectCommonNamePrefix = CFSTR("SubjectCommonNamePrefix");
1666 /* Check that the certificate chain length matches the specificed CFNumberRef
1667 length. */
1668 CFStringRef kSecPolicyCheckChainLength = CFSTR("ChainLength");
1669 CFStringRef kSecPolicyCheckNotValidBefore = CFSTR("NotValidBefore");
1670
1671 /* Expiration.
1672 Can be on any cert in the chain
1673 Priority: Top down
1674 Short Circuit: No
1675 Recoverable
1676 Trust UI: One or more certificates have expired or are not valid yet.
1677 OS: The (root|intermediate|leaf) certificate (expired on 'date'|is not valid until 'date')
1678 Cert UI: Certificate (expired on 'date'|is not valid until 'date')
1679 */
1680 CFStringRef kSecPolicyCheckValidIntermediates = CFSTR("ValidIntermediates");
1681 CFStringRef kSecPolicyCheckValidLeaf = CFSTR("ValidLeaf");
1682 CFStringRef kSecPolicyCheckValidRoot = CFSTR("ValidRoot");
1683
1684 #endif
1685
1686 struct TrustFailures {
1687 bool badLinkage;
1688 bool unknownCritExtn;
1689 bool untrustedAnchor;
1690 bool hostnameMismatch;
1691 bool policyFail;
1692 bool invalidCert;
1693 bool weakKey;
1694 bool revocation;
1695 };
1696
1697 static void applyDetailProperty(const void *_key, const void *_value,
1698 void *context) {
1699 CFStringRef key = (CFStringRef)_key;
1700 struct TrustFailures *tf = (struct TrustFailures *)context;
1701 if (CFGetTypeID(_value) != CFBooleanGetTypeID()) {
1702 /* Value isn't a CFBooleanRef, oh no! */
1703 return;
1704 }
1705 CFBooleanRef value = (CFBooleanRef)_value;
1706 if (CFBooleanGetValue(value)) {
1707 /* Not an actual failure so we don't report it. */
1708 return;
1709 }
1710
1711 /* @@@ FIXME: Report a different return value when something is in the
1712 details but masked out by an exception and use that below for display
1713 purposes. */
1714 if (CFEqual(key, kSecPolicyCheckIdLinkage)) {
1715 tf->badLinkage = true;
1716 } else if (CFEqual(key, kSecPolicyCheckCriticalExtensions)
1717 || CFEqual(key, kSecPolicyCheckQualifiedCertStatements)) {
1718 tf->unknownCritExtn = true;
1719 } else if (CFEqual(key, kSecPolicyCheckAnchorTrusted)
1720 || CFEqual(key, kSecPolicyCheckAnchorSHA1)
1721 || CFEqual(key, kSecPolicyCheckAnchorSHA256)
1722 || CFEqual(key, kSecPolicyCheckAnchorApple)) {
1723 tf->untrustedAnchor = true;
1724 } else if (CFEqual(key, kSecPolicyCheckSSLHostname)) {
1725 tf->hostnameMismatch = true;
1726 } else if (CFEqual(key, kSecPolicyCheckValidIntermediates)
1727 || CFEqual(key, kSecPolicyCheckValidLeaf)
1728 || CFEqual(key, kSecPolicyCheckValidRoot)) {
1729 tf->invalidCert = true;
1730 } else if (CFEqual(key, kSecPolicyCheckWeakIntermediates)
1731 || CFEqual(key, kSecPolicyCheckWeakLeaf)
1732 || CFEqual(key, kSecPolicyCheckWeakRoot)) {
1733 tf->weakKey = true;
1734 } else if (CFEqual(key, kSecPolicyCheckRevocation)) {
1735 tf->revocation = true;
1736 } else
1737 /* Anything else is a policy failure. */
1738 #if 0
1739 if (CFEqual(key, kSecPolicyCheckNonEmptySubject)
1740 || CFEqual(key, kSecPolicyCheckBasicConstraints)
1741 || CFEqual(key, kSecPolicyCheckKeyUsage)
1742 || CFEqual(key, kSecPolicyCheckExtendedKeyUsage)
1743 || CFEqual(key, kSecPolicyCheckIssuerCommonName)
1744 || CFEqual(key, kSecPolicyCheckSubjectCommonNamePrefix)
1745 || CFEqual(key, kSecPolicyCheckChainLength)
1746 || CFEqual(key, kSecPolicyCheckNotValidBefore))
1747 #endif
1748 {
1749 tf->policyFail = true;
1750 }
1751 }
1752
1753 static void appendError(CFMutableArrayRef properties, CFStringRef error) {
1754 CFStringRef localizedError = SecFrameworkCopyLocalizedString(error,
1755 CFSTR("SecCertificate"));
1756 if (!localizedError) {
1757 //secerror("WARNING: localized error string was not found in Security.framework");
1758 localizedError = CFRetain(error);
1759 }
1760 appendProperty(properties, kSecPropertyTypeError, NULL, NULL,
1761 localizedError);
1762 CFReleaseNull(localizedError);
1763 }
1764
1765 #if TARGET_OS_OSX
1766 /* OS X properties array has a different structure and is implemented SecTrust.cpp. */
1767 CFArrayRef SecTrustCopyProperties_ios(SecTrustRef trust)
1768 #else
1769 CFArrayRef SecTrustCopyProperties(SecTrustRef trust)
1770 #endif
1771 {
1772 if (!trust) {
1773 return NULL;
1774 }
1775 SecTrustEvaluateIfNecessary(trust);
1776 __block CFArrayRef details = NULL;
1777 dispatch_sync(trust->_trustQueue, ^{
1778 details = CFRetainSafe(trust->_details);
1779 });
1780 if (!details)
1781 return NULL;
1782
1783 struct TrustFailures tf = {};
1784
1785 CFIndex ix, count = CFArrayGetCount(details);
1786 for (ix = 0; ix < count; ++ix) {
1787 CFDictionaryRef detail = (CFDictionaryRef)
1788 CFArrayGetValueAtIndex(details, ix);
1789 /* We now have a detail dictionary for certificate at index ix, with
1790 a key value pair for each failed policy check. Let's convert it
1791 from Ro-Man form into something a Hu-Man can understand. */
1792 CFDictionaryApplyFunction(detail, applyDetailProperty, &tf);
1793 }
1794
1795 CFMutableArrayRef properties = CFArrayCreateMutable(kCFAllocatorDefault, 0,
1796 &kCFTypeArrayCallBacks);
1797 /* The badLinkage and unknownCritExtn failures are short circuited, since
1798 you can't recover from those errors. */
1799 if (tf.badLinkage) {
1800 appendError(properties, CFSTR("Invalid certificate chain linkage."));
1801 } else if (tf.unknownCritExtn) {
1802 appendError(properties, CFSTR("One or more unsupported critical extensions found."));
1803 } else {
1804 if (tf.untrustedAnchor) {
1805 appendError(properties, CFSTR("Root certificate is not trusted."));
1806 }
1807 if (tf.hostnameMismatch) {
1808 appendError(properties, CFSTR("Hostname mismatch."));
1809 }
1810 if (tf.policyFail) {
1811 appendError(properties, CFSTR("Policy requirements not met."));
1812 }
1813 if (tf.invalidCert) {
1814 appendError(properties, CFSTR("One or more certificates have expired or are not valid yet."));
1815 }
1816 if (tf.weakKey) {
1817 appendError(properties, CFSTR("One or more certificates is using a weak key size."));
1818 }
1819 if (tf.revocation) {
1820 appendError(properties, CFSTR("One or more certificates have been revoked."));
1821 }
1822 }
1823
1824 if (CFArrayGetCount(properties) == 0) {
1825 /* The certificate chain is trusted, return an empty plist */
1826 CFReleaseNull(properties);
1827 }
1828
1829 CFReleaseNull(details);
1830 return properties;
1831 }
1832
1833 #if TARGET_OS_OSX
1834 static void _AppendStatusCode(CFMutableArrayRef array, OSStatus statusCode) {
1835 if (!array) {
1836 return;
1837 }
1838 SInt32 num = statusCode;
1839 CFNumberRef numRef = CFNumberCreate(NULL, kCFNumberSInt32Type, &num);
1840 if (!numRef) {
1841 return;
1842 }
1843 CFArrayAppendValue(array, numRef);
1844 CFRelease(numRef);
1845 }
1846 #endif
1847
1848 static CFArrayRef _SecTrustCopyDetails(SecTrustRef trust) {
1849 if (!trust) {
1850 return NULL;
1851 }
1852 __block CFArrayRef details = NULL;
1853 dispatch_sync(trust->_trustQueue, ^{
1854 details = CFRetainSafe(trust->_details);
1855 });
1856 #if TARGET_OS_OSX
1857 // Include status codes in the per-certificate details (rdar://27930542)
1858 CFMutableArrayRef newDetails = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
1859 if (!newDetails) {
1860 CFReleaseSafe(details);
1861 return NULL;
1862 }
1863 CFIndex index, chainLen = (details) ? CFArrayGetCount(details) : 0;
1864 for (index = 0; index < chainLen; index++) {
1865 CFDictionaryRef detailDict = CFArrayGetValueAtIndex(details, index);
1866 CFMutableDictionaryRef newDict = CFDictionaryCreateMutableCopy(NULL, 0, detailDict);
1867 CFMutableArrayRef statusCodes = CFArrayCreateMutable(kCFAllocatorDefault,
1868 0, &kCFTypeArrayCallBacks);
1869 if (statusCodes) {
1870 CFIndex i, numCodes = 0;
1871 SInt32 *codes = SecTrustCopyStatusCodes(trust, index, &numCodes);
1872 if (codes) {
1873 for (i = 0; i < numCodes; i++) {
1874 OSStatus scode = (OSStatus)codes[i];
1875 _AppendStatusCode(statusCodes, scode);
1876 }
1877 free(codes);
1878 }
1879 if (CFArrayGetCount(statusCodes) > 0) {
1880 CFDictionarySetValue(newDict, kSecCertificateDetailStatusCodes, statusCodes);
1881 }
1882 CFRelease(statusCodes);
1883 }
1884 if (newDict) {
1885 CFArrayAppendValue(newDetails, newDict);
1886 CFRelease(newDict);
1887 }
1888 }
1889 CFReleaseSafe(details);
1890 return newDetails;
1891 #else
1892 return details;
1893 #endif
1894 }
1895
1896 CFDictionaryRef SecTrustCopyResult(SecTrustRef trust) {
1897 // Builds and returns a dictionary of evaluation results.
1898 if (!trust) {
1899 return NULL;
1900 }
1901 __block CFMutableDictionaryRef results = CFDictionaryCreateMutable(NULL, 0,
1902 &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
1903
1904 SecTrustEvaluateIfNecessary(trust);
1905 __block CFArrayRef details = _SecTrustCopyDetails(trust);
1906
1907 dispatch_sync(trust->_trustQueue, ^{
1908 // kSecTrustResultDetails (per-cert results)
1909 if (details) {
1910 CFDictionarySetValue(results, (const void *)kSecTrustResultDetails, (const void *)details);
1911 CFRelease(details);
1912 }
1913
1914 // kSecTrustResultValue (overall trust result)
1915 CFNumberRef numValue = CFNumberCreate(NULL, kCFNumberSInt32Type, &trust->_trustResult);
1916 if (numValue) {
1917 CFDictionarySetValue(results, (const void *)kSecTrustResultValue, (const void *)numValue);
1918 CFRelease(numValue);
1919 }
1920 CFDictionaryRef info = trust->_info;
1921 if (trust->_trustResult == kSecTrustResultInvalid || !info) {
1922 return; // we have nothing more to add
1923 }
1924
1925 // kSecTrustEvaluationDate
1926 CFDateRef evaluationDate = trust->_verifyDate;
1927 if (evaluationDate) {
1928 CFDictionarySetValue(results, (const void *)kSecTrustEvaluationDate, (const void *)evaluationDate);
1929 }
1930
1931 // kSecTrustCertificateTransparency
1932 CFBooleanRef ctValue;
1933 if (CFDictionaryGetValueIfPresent(info, kSecTrustInfoCertificateTransparencyKey, (const void **)&ctValue)) {
1934 CFDictionarySetValue(results, (const void *)kSecTrustCertificateTransparency, (const void *)ctValue);
1935 }
1936
1937 // kSecTrustExtendedValidation
1938 CFBooleanRef evValue;
1939 if (CFDictionaryGetValueIfPresent(info, kSecTrustInfoExtendedValidationKey, (const void **)&evValue)) {
1940 CFDictionarySetValue(results, (const void *)kSecTrustExtendedValidation, (const void *)evValue);
1941 }
1942
1943 // kSecTrustOrganizationName
1944 CFStringRef organizationName;
1945 if (CFDictionaryGetValueIfPresent(info, kSecTrustInfoCompanyNameKey, (const void **)&organizationName)) {
1946 CFDictionarySetValue(results, (const void *)kSecTrustOrganizationName, (const void *)organizationName);
1947 }
1948
1949 // kSecTrustRevocationChecked
1950 CFBooleanRef revocationChecked;
1951 if (CFDictionaryGetValueIfPresent(info, kSecTrustRevocationChecked, (const void **)&revocationChecked)) {
1952 CFDictionarySetValue(results, (const void *)kSecTrustRevocationChecked, (const void *)revocationChecked);
1953 }
1954
1955 // kSecTrustRevocationReason
1956 CFNumberRef revocationReason;
1957 if (CFDictionaryGetValueIfPresent(info, kSecTrustRevocationReason, (const void **)&revocationReason)) {
1958 CFDictionarySetValue(results, (const void *)kSecTrustRevocationReason, (const void *)revocationReason);
1959 }
1960
1961 // kSecTrustRevocationValidUntilDate
1962 CFDateRef validUntilDate;
1963 if (CFDictionaryGetValueIfPresent(info, kSecTrustRevocationValidUntilDate, (const void **)&validUntilDate)) {
1964 CFDictionarySetValue(results, (const void *)kSecTrustRevocationValidUntilDate, (const void *)validUntilDate);
1965 }
1966 });
1967
1968 return results;
1969 }
1970
1971 // Return 0 upon error.
1972 static int to_int_error_request(enum SecXPCOperation op, CFErrorRef *error) {
1973 __block int64_t result = 0;
1974 securityd_send_sync_and_do(op, error, NULL, ^bool(xpc_object_t response, CFErrorRef *error) {
1975 result = xpc_dictionary_get_int64(response, kSecXPCKeyResult);
1976 if (!result)
1977 return SecError(errSecInternal, error, CFSTR("int64 missing in response"));
1978 return true;
1979 });
1980 return (int)result;
1981 }
1982
1983 // version 0 -> error, so we need to start at version 1 or later.
1984 OSStatus SecTrustGetOTAPKIAssetVersionNumber(int* versionNumber)
1985 {
1986 OSStatus result;
1987 os_activity_t trace_activity = os_activity_start("SecTrustGetOTAPKIAssetVersionNumber", OS_ACTIVITY_FLAG_DEFAULT);
1988 result = SecOSStatusWith(^bool(CFErrorRef *error) {
1989 if (!versionNumber)
1990 return SecError(errSecParam, error, CFSTR("versionNumber is NULL"));
1991
1992 return (*versionNumber = TRUSTD_XPC(sec_ota_pki_asset_version, to_int_error_request, error)) != 0;
1993 });
1994
1995 os_activity_end(trace_activity);
1996 return result;
1997 }
1998
1999 #define do_if_registered(sdp, ...) if (gTrustd && gTrustd->sdp) { return gTrustd->sdp(__VA_ARGS__); }
2000
2001 static bool xpc_dictionary_entry_is_type(xpc_object_t dictionary, const char *key, xpc_type_t type)
2002 {
2003 xpc_object_t value = xpc_dictionary_get_value(dictionary, key);
2004
2005 return value && (xpc_get_type(value) == type);
2006 }
2007
2008 OSStatus SecTrustOTAPKIGetUpdatedAsset(int* didUpdateAsset)
2009 {
2010 CFErrorRef error = NULL;
2011 do_if_registered(sec_ota_pki_get_new_asset, &error);
2012
2013 int64_t num = 0;
2014 xpc_object_t message = securityd_create_message(kSecXPCOpOTAPKIGetNewAsset, &error);
2015 if (message)
2016 {
2017 xpc_object_t response = securityd_message_with_reply_sync(message, &error);
2018
2019 if (response && xpc_dictionary_entry_is_type(response, kSecXPCKeyResult, XPC_TYPE_INT64))
2020 {
2021 num = (int64_t) xpc_dictionary_get_int64(response, kSecXPCKeyResult);
2022 xpc_release(response);
2023 }
2024
2025 xpc_release(message);
2026 }
2027
2028 if (NULL != didUpdateAsset)
2029 {
2030 *didUpdateAsset = (int)num;
2031 }
2032 return noErr;
2033 }
2034
2035 /*
2036 * This function performs an evaluation of the leaf certificate only, and
2037 * does so in the process that called it. Its primary use is in SecItemCopyMatching
2038 * when kSecMatchPolicy is in the dictionary.
2039 */
2040 OSStatus SecTrustEvaluateLeafOnly(SecTrustRef trust, SecTrustResultType *result) {
2041 if (!trust) {
2042 return errSecParam;
2043 }
2044 OSStatus status = errSecSuccess;
2045 SecTrustResultType trustResult = kSecTrustResultInvalid;
2046 if((status = SecTrustValidateInput(trust))) {
2047 return status;
2048 }
2049
2050 struct OpaqueSecLeafPVC pvc;
2051 SecCertificateRef leaf = SecTrustGetCertificateAtIndex(trust, 0);
2052 __block CFArrayRef policies = NULL;
2053 dispatch_sync(trust->_trustQueue, ^{
2054 policies = CFRetainSafe(trust->_policies);
2055 });
2056 SecLeafPVCInit(&pvc, leaf, policies, SecTrustGetVerifyTime(trust));
2057
2058 if(!SecLeafPVCLeafChecks(&pvc)) {
2059 trustResult = kSecTrustResultRecoverableTrustFailure;
2060 } else {
2061 trustResult = kSecTrustResultUnspecified;
2062 }
2063
2064 /* Set other result context information */
2065 dispatch_sync(trust->_trustQueue, ^{
2066 trust->_trustResult = trustResult;
2067 trust->_details = CFRetainSafe(pvc.details);
2068 trust->_info = CFDictionaryCreateMutable(kCFAllocatorDefault, 0,
2069 &kCFTypeDictionaryKeyCallBacks,
2070 &kCFTypeDictionaryValueCallBacks);
2071 CFMutableArrayRef leafCert = CFArrayCreateMutableCopy(NULL, 1, trust->_certificates);
2072 trust->_chain = SecCertificatePathCreateWithCertificates(leafCert, NULL);
2073 CFReleaseNull(leafCert);
2074 });
2075
2076 SecLeafPVCDelete(&pvc);
2077
2078 /* log to syslog when there is a trust failure */
2079 if (trustResult != kSecTrustResultUnspecified) {
2080 CFStringRef failureDesc = SecTrustCopyFailureDescription(trust);
2081 secerror("%@", failureDesc);
2082 CFRelease(failureDesc);
2083 }
2084
2085 if (result) {
2086 *result = trustResult;
2087 }
2088
2089 CFReleaseSafe(policies);
2090 return status;
2091 }
2092
2093 static void deserializeCert(const void *value, void *context) {
2094 CFDataRef certData = (CFDataRef)value;
2095 if (isData(certData)) {
2096 SecCertificateRef cert = SecCertificateCreateWithData(NULL, certData);
2097 if (cert) {
2098 CFArrayAppendValue((CFMutableArrayRef)context, cert);
2099 CFRelease(cert);
2100 }
2101 }
2102 }
2103
2104 static CF_RETURNS_RETAINED CFArrayRef SecCertificateArrayDeserialize(CFArrayRef serializedCertificates) {
2105 CFMutableArrayRef result = NULL;
2106 require_quiet(isArray(serializedCertificates), errOut);
2107 CFIndex count = CFArrayGetCount(serializedCertificates);
2108 result = CFArrayCreateMutable(kCFAllocatorDefault, count, &kCFTypeArrayCallBacks);
2109 CFRange all_certs = { 0, count };
2110 CFArrayApplyFunction(serializedCertificates, all_certs, deserializeCert, result);
2111 errOut:
2112 return result;
2113 }
2114
2115 static void serializeCertificate(const void *value, void *context) {
2116 SecCertificateRef cert = (SecCertificateRef)value;
2117 if (cert && SecCertificateGetTypeID() == CFGetTypeID(cert)) {
2118 CFDataRef certData = SecCertificateCopyData(cert);
2119 if (certData) {
2120 CFArrayAppendValue((CFMutableArrayRef)context, certData);
2121 CFRelease(certData);
2122 }
2123 }
2124 }
2125
2126 static CFArrayRef SecCertificateArraySerialize(CFArrayRef certificates) {
2127 CFMutableArrayRef result = NULL;
2128 require_quiet(isArray(certificates), errOut);
2129 CFIndex count = CFArrayGetCount(certificates);
2130 result = CFArrayCreateMutable(NULL, count, &kCFTypeArrayCallBacks);
2131 CFRange all_certificates = { 0, count};
2132 CFArrayApplyFunction(certificates, all_certificates, serializeCertificate, result);
2133 errOut:
2134 return result;
2135 }
2136
2137 static CFPropertyListRef SecTrustCopyPlist(SecTrustRef trust) {
2138 __block CFMutableDictionaryRef output = NULL;
2139 output = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks,
2140 &kCFTypeDictionaryValueCallBacks);
2141
2142 dispatch_sync(trust->_trustQueue, ^{
2143 if (trust->_certificates) {
2144 CFArrayRef serializedCerts = SecCertificateArraySerialize(trust->_certificates);
2145 if (serializedCerts) {
2146 CFDictionaryAddValue(output, CFSTR(kSecTrustCertificatesKey), serializedCerts);
2147 CFRelease(serializedCerts);
2148 }
2149 }
2150 if (trust->_anchors) {
2151 CFArrayRef serializedAnchors = SecCertificateArraySerialize(trust->_anchors);
2152 if (serializedAnchors) {
2153 CFDictionaryAddValue(output, CFSTR(kSecTrustAnchorsKey), serializedAnchors);
2154 CFRelease(serializedAnchors);
2155 }
2156 }
2157 if (trust->_policies) {
2158 CFArrayRef serializedPolicies = SecPolicyArrayCreateSerialized(trust->_policies);
2159 if (serializedPolicies) {
2160 CFDictionaryAddValue(output, CFSTR(kSecTrustPoliciesKey), serializedPolicies);
2161 CFRelease(serializedPolicies);
2162 }
2163 }
2164 if (trust->_responses) {
2165 CFDictionaryAddValue(output, CFSTR(kSecTrustResponsesKey), trust->_responses);
2166 }
2167 if (trust->_SCTs) {
2168 CFDictionaryAddValue(output, CFSTR(kSecTrustSCTsKey), trust->_SCTs);
2169 }
2170 if (trust->_trustedLogs) {
2171 CFDictionaryAddValue(output, CFSTR(kSecTrustTrustedLogsKey), trust->_trustedLogs);
2172 }
2173 if (trust->_verifyDate) {
2174 CFDictionaryAddValue(output, CFSTR(kSecTrustVerifyDateKey), trust->_verifyDate);
2175 }
2176 if (trust->_chain) {
2177 CFArrayRef serializedChain = SecCertificatePathCreateSerialized(trust->_chain, NULL);
2178 if (serializedChain) {
2179 CFDictionaryAddValue(output, CFSTR(kSecTrustChainKey), serializedChain);
2180 CFRelease(serializedChain);
2181 }
2182 }
2183 if (trust->_details) {
2184 CFDictionaryAddValue(output, CFSTR(kSecTrustDetailsKey), trust->_details);
2185 }
2186 if (trust->_info) {
2187 CFDictionaryAddValue(output, CFSTR(kSecTrustInfoKey), trust->_info);
2188 }
2189 if (trust->_exceptions) {
2190 CFDictionaryAddValue(output, CFSTR(kSecTrustExceptionsKey), trust->_exceptions);
2191 }
2192 CFNumberRef trustResult = CFNumberCreate(NULL, kCFNumberSInt32Type, &trust->_trustResult);
2193 if (trustResult) {
2194 CFDictionaryAddValue(output, CFSTR(kSecTrustResultKey), trustResult);
2195 }
2196 CFReleaseNull(trustResult);
2197 if (trust->_anchorsOnly) {
2198 CFDictionaryAddValue(output, CFSTR(kSecTrustAnchorsOnlyKey), kCFBooleanTrue);
2199 } else {
2200 CFDictionaryAddValue(output, CFSTR(kSecTrustAnchorsOnlyKey), kCFBooleanFalse);
2201 }
2202 if (trust->_keychainsAllowed) {
2203 CFDictionaryAddValue(output, CFSTR(kSecTrustKeychainsAllowedKey), kCFBooleanTrue);
2204 } else {
2205 CFDictionaryAddValue(output, CFSTR(kSecTrustKeychainsAllowedKey), kCFBooleanFalse);
2206 }
2207 });
2208
2209 return output;
2210 }
2211
2212 CFDataRef SecTrustSerialize(SecTrustRef trust, CFErrorRef *error) {
2213 CFPropertyListRef plist = NULL;
2214 CFDataRef derTrust = NULL;
2215 require_action_quiet(trust, out,
2216 SecError(errSecParam, error, CFSTR("null trust input")));
2217 require_action_quiet(plist = SecTrustCopyPlist(trust), out,
2218 SecError(errSecDecode, error, CFSTR("unable to create trust plist")));
2219 require_quiet(derTrust = CFPropertyListCreateDERData(NULL, plist, error), out);
2220
2221 out:
2222 CFReleaseNull(plist);
2223 return derTrust;
2224 }
2225
2226 static OSStatus SecTrustCreateFromPlist(CFPropertyListRef plist, SecTrustRef CF_RETURNS_RETAINED *trust) {
2227 OSStatus status = errSecParam;
2228 SecTrustRef output = NULL;
2229 CFTypeRef serializedCertificates = NULL, serializedPolicies = NULL, serializedAnchors = NULL,
2230 serializedChain = NULL;
2231 CFNumberRef trustResultNum = NULL;
2232 CFArrayRef certificates = NULL, policies = NULL, anchors = NULL, responses = NULL,
2233 SCTs = NULL, trustedLogs = NULL, details = NULL, exceptions = NULL;
2234 CFDateRef verifyDate = NULL;
2235 CFDictionaryRef info = NULL;
2236 SecCertificatePathRef chain = NULL;
2237
2238 require_quiet(CFDictionaryGetTypeID() == CFGetTypeID(plist), out);
2239 require_quiet(serializedCertificates = CFDictionaryGetValue(plist, CFSTR(kSecTrustCertificatesKey)), out);
2240 require_quiet(certificates = SecCertificateArrayDeserialize(serializedCertificates), out);
2241 require_quiet(serializedPolicies = CFDictionaryGetValue(plist, CFSTR(kSecTrustPoliciesKey)), out);
2242 require_quiet(policies = SecPolicyArrayCreateDeserialized(serializedPolicies), out);
2243 require_noerr_quiet(status = SecTrustCreateWithCertificates(certificates, policies, &output), out);
2244
2245 serializedAnchors = CFDictionaryGetValue(plist, CFSTR(kSecTrustAnchorsKey));
2246 if (isArray(serializedAnchors)) {
2247 anchors = SecCertificateArrayDeserialize(serializedAnchors);
2248 output->_anchors = anchors;
2249 }
2250 responses = CFDictionaryGetValue(plist, CFSTR(kSecTrustResponsesKey));
2251 if (isArray(responses)) {
2252 output->_responses = CFRetainSafe(responses);
2253 }
2254 SCTs = CFDictionaryGetValue(plist, CFSTR(kSecTrustSCTsKey));
2255 if (isArray(responses)) {
2256 output->_SCTs = CFRetainSafe(SCTs);
2257 }
2258 trustedLogs = CFDictionaryGetValue(plist, CFSTR(kSecTrustTrustedLogsKey));
2259 if (isArray(trustedLogs)) {
2260 output->_trustedLogs = CFRetainSafe(trustedLogs);
2261 }
2262 verifyDate = CFDictionaryGetValue(plist, CFSTR(kSecTrustVerifyDateKey));
2263 if (isDate(verifyDate)) {
2264 output->_verifyDate = CFRetainSafe(verifyDate);
2265 }
2266 serializedChain = CFDictionaryGetValue(plist, CFSTR(kSecTrustChainKey));
2267 if (isArray(serializedChain)) {
2268 chain = SecCertificatePathCreateDeserialized(serializedChain, NULL);
2269 output->_chain = chain;
2270 }
2271 details = CFDictionaryGetValue(plist, CFSTR(kSecTrustDetailsKey));
2272 if (isArray(details)) {
2273 output->_details = CFRetainSafe(details);
2274 }
2275 info = CFDictionaryGetValue(plist, CFSTR(kSecTrustInfoKey));
2276 if (isDictionary(info)) {
2277 output->_info = CFRetainSafe(info);
2278 }
2279 exceptions = CFDictionaryGetValue(plist, CFSTR(kSecTrustExceptionsKey));
2280 if (isArray(exceptions)) {
2281 output->_exceptions = CFRetainSafe(exceptions);
2282 }
2283 int32_t trustResult = -1;
2284 trustResultNum = CFDictionaryGetValue(plist, CFSTR(kSecTrustResultKey));
2285 if (isNumber(trustResultNum) && CFNumberGetValue(trustResultNum, kCFNumberSInt32Type, &trustResult) &&
2286 (trustResult >= 0)) {
2287 output->_trustResult = trustResult;
2288 } else {
2289 status = errSecParam;
2290 }
2291 if (CFDictionaryGetValue(plist, CFSTR(kSecTrustAnchorsOnlyKey)) == kCFBooleanTrue) {
2292 output->_anchorsOnly = true;
2293 } /* false is set by default */
2294 if (CFDictionaryGetValue(plist, CFSTR(kSecTrustKeychainsAllowedKey)) == kCFBooleanFalse) {
2295 output->_keychainsAllowed = false;
2296 } /* true is set by default */
2297
2298 out:
2299 if (errSecSuccess == status && trust) {
2300 *trust = output;
2301 }
2302 CFReleaseNull(policies);
2303 CFReleaseNull(certificates);
2304 return status;
2305 }
2306
2307 SecTrustRef SecTrustDeserialize(CFDataRef serializedTrust, CFErrorRef *error) {
2308 SecTrustRef trust = NULL;
2309 CFPropertyListRef plist = NULL;
2310 OSStatus status = errSecSuccess;
2311 require_action_quiet(serializedTrust, out,
2312 SecError(errSecParam, error, CFSTR("null serialized trust input")));
2313 require_quiet(plist = CFPropertyListCreateWithDERData(NULL, serializedTrust,
2314 kCFPropertyListImmutable, NULL, error), out);
2315 require_noerr_action_quiet(status = SecTrustCreateFromPlist(plist, &trust), out,
2316 SecError(status, error, CFSTR("unable to create trust ref")));
2317
2318 out:
2319 CFReleaseNull(plist);
2320 return trust;
2321 }