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