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