]> git.saurik.com Git - apple/security.git/blob - OSX/sec/Security/SecTrust.c
Security-59306.61.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 #if TARGET_OS_OSX
1838 /* On OS X we need SecTrustCopyPublicKey to give us a CDSA-based SecKeyRef,
1839 so we will refer to this one internally as SecTrustCopyPublicKey_ios,
1840 and call it from SecTrustCopyPublicKey.
1841 */
1842 SecKeyRef SecTrustCopyPublicKey_ios(SecTrustRef trust)
1843 #else
1844 SecKeyRef SecTrustCopyPublicKey(SecTrustRef trust)
1845 #endif
1846 {
1847 if (!trust) {
1848 return NULL;
1849 }
1850 __block SecKeyRef publicKey = NULL;
1851 dispatch_sync(trust->_trustQueue, ^{
1852 if (trust->_publicKey) {
1853 publicKey = CFRetainSafe(trust->_publicKey);
1854 return;
1855 }
1856 SecCertificateRef leaf = (SecCertificateRef)CFArrayGetValueAtIndex(trust->_certificates, 0);
1857 trust->_publicKey = SecCertificateCopyKey(leaf);
1858 if (trust->_publicKey) {
1859 publicKey = CFRetainSafe(trust->_publicKey);
1860 }
1861 });
1862 /* If we couldn't get a public key from the leaf cert alone. */
1863 if (!publicKey) {
1864 SecTrustEvaluateIfNecessary(trust);
1865 dispatch_sync(trust->_trustQueue, ^{
1866 if (trust->_chain) {
1867 SecCertificateRef cert = (SecCertificateRef)CFArrayGetValueAtIndex(trust->_chain, 0);
1868 trust->_publicKey = SecCertificateCopyKey(cert);
1869 publicKey = CFRetainSafe(trust->_publicKey);
1870 }
1871 });
1872 }
1873 return publicKey;
1874 }
1875
1876 CFIndex SecTrustGetCertificateCount(SecTrustRef trust) {
1877 if (!trust) {
1878 return 0;
1879 }
1880 SecTrustEvaluateIfNecessary(trust);
1881 __block CFIndex certCount = 1;
1882 dispatch_sync(trust->_trustQueue, ^{
1883 if (trust->_chain) {
1884 certCount = CFArrayGetCount(trust->_chain);
1885 }
1886 });
1887 return certCount;
1888 }
1889
1890 SecCertificateRef SecTrustGetCertificateAtIndex(SecTrustRef trust,
1891 CFIndex ix) {
1892 if (!trust) {
1893 return NULL;
1894 }
1895 __block SecCertificateRef cert = NULL;
1896 if (ix == 0) {
1897 dispatch_sync(trust->_trustQueue, ^{
1898 cert = (SecCertificateRef)CFArrayGetValueAtIndex(trust->_certificates, 0);
1899 });
1900 return cert;
1901 }
1902 SecTrustEvaluateIfNecessary(trust);
1903 dispatch_sync(trust->_trustQueue, ^{
1904 if (trust->_chain) {
1905 cert = (SecCertificateRef)CFArrayGetValueAtIndex(trust->_chain, ix);
1906 }
1907 });
1908 return cert;
1909 }
1910
1911 CFDictionaryRef SecTrustCopyInfo(SecTrustRef trust) {
1912 if (!trust) {
1913 return NULL;
1914 }
1915 SecTrustEvaluateIfNecessary(trust);
1916 __block CFDictionaryRef info = NULL;
1917 dispatch_sync(trust->_trustQueue, ^{
1918 info = CFRetainSafe(trust->_info);
1919 });
1920 return info;
1921 }
1922
1923 CFArrayRef SecTrustGetTrustExceptionsArray(SecTrustRef trust) {
1924 if (!trust) {
1925 return NULL;
1926 }
1927 __block CFArrayRef exceptions = NULL;
1928 dispatch_sync(trust->_trustQueue, ^{
1929 exceptions = trust->_exceptions;
1930 });
1931 return exceptions;
1932 }
1933
1934 CFDataRef SecTrustCopyExceptions(SecTrustRef trust) {
1935 /* Stash the old exceptions and run an evaluation with no exceptions filtered. */
1936 __block CFArrayRef oldExceptions = NULL;
1937 dispatch_sync(trust->_trustQueue, ^{
1938 if (trust->_exceptions) {
1939 oldExceptions = trust->_exceptions;
1940 trust->_exceptions = NULL;
1941 }
1942 });
1943 SecTrustSetNeedsEvaluation(trust);
1944
1945 /* Create the new exceptions based on an unfiltered eval. */
1946 __block CFArrayRef details = NULL;
1947 SecTrustEvaluateIfNecessary(trust);
1948 dispatch_sync(trust->_trustQueue, ^{
1949 details = CFRetainSafe(trust->_details);
1950 });
1951 CFIndex pathLength = details ? CFArrayGetCount(details) : 0;
1952 CFMutableArrayRef exceptions = CFArrayCreateMutable(kCFAllocatorDefault, pathLength, &kCFTypeArrayCallBacks);
1953 #if TARGET_OS_IPHONE
1954 /* Fetch the current exceptions epoch and tag each exception with it. */
1955 CFErrorRef exceptionResetCountError = NULL;
1956 uint64_t exceptionResetCount = SecTrustGetExceptionResetCount(&exceptionResetCountError);
1957 secinfo("trust", "The current exceptions epoch is %llu. (%{public}s)", exceptionResetCount, exceptionResetCountError ? "Error" : "OK");
1958 CFNumberRef exceptionResetCountRef = CFNumberCreate(NULL, kCFNumberSInt64Type, &exceptionResetCount);
1959 #endif
1960 CFIndex ix;
1961 for (ix = 0; ix < pathLength; ++ix) {
1962 CFDictionaryRef detail = (CFDictionaryRef)CFArrayGetValueAtIndex(details, ix);
1963 CFIndex detailCount = CFDictionaryGetCount(detail);
1964 CFMutableDictionaryRef exception;
1965 if (ix == 0 || detailCount > 0) {
1966 exception = CFDictionaryCreateMutableCopy(kCFAllocatorDefault, detailCount + 1, detail);
1967 SecCertificateRef certificate = SecTrustGetCertificateAtIndex(trust, ix);
1968 CFDataRef digest = SecCertificateGetSHA1Digest(certificate);
1969 CFDictionaryAddValue(exception, kSecCertificateDetailSHA1Digest, digest);
1970 #if TARGET_OS_IPHONE
1971 if (exceptionResetCount && !exceptionResetCountError && exceptionResetCountRef) {
1972 CFDictionaryAddValue(exception, kSecCertificateExceptionResetCount, exceptionResetCountRef);
1973 }
1974 #endif
1975 } else {
1976 /* Add empty exception dictionaries for non leaf certs which have no exceptions to save space. */
1977 exception = (CFMutableDictionaryRef)CFDictionaryCreate(kCFAllocatorDefault, NULL, NULL, 0,
1978 &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
1979 }
1980 CFArrayAppendValue(exceptions, exception);
1981 CFReleaseNull(exception);
1982 }
1983
1984 /* Restore the stashed exceptions. */
1985 if (oldExceptions) {
1986 dispatch_sync(trust->_trustQueue, ^{
1987 trust->_exceptions = oldExceptions;
1988 });
1989 SecTrustSetNeedsEvaluation(trust);
1990 }
1991
1992 /* Remove any trailing empty dictionaries to save even more space (we skip the leaf
1993 since it will never be empty). */
1994 for (ix = pathLength; ix-- > 1;) {
1995 CFDictionaryRef exception = (CFDictionaryRef)CFArrayGetValueAtIndex(exceptions, ix);
1996 if (CFDictionaryGetCount(exception) == 0) {
1997 CFArrayRemoveValueAtIndex(exceptions, ix);
1998 } else {
1999 break;
2000 }
2001 }
2002
2003 CFDataRef encodedExceptions = CFPropertyListCreateData(kCFAllocatorDefault,
2004 exceptions, kCFPropertyListBinaryFormat_v1_0, 0, NULL);
2005 CFRelease(exceptions);
2006 CFReleaseSafe(details);
2007 #if TARGET_OS_IPHONE
2008 CFReleaseSafe(exceptionResetCountRef);
2009 #endif
2010 return encodedExceptions;
2011 }
2012
2013 #if TARGET_OS_IPHONE
2014 static bool SecTrustExceptionsValidForThisEpoch(CFArrayRef exceptions) {
2015 if (!exceptions) {
2016 return false;
2017 }
2018 CFDictionaryRef exception = (CFDictionaryRef)CFArrayGetValueAtIndex(exceptions, 0);
2019
2020 CFErrorRef currentExceptionResetCountError = NULL;
2021 uint64_t currentExceptionResetCount = SecTrustGetExceptionResetCount(&currentExceptionResetCountError);
2022 secinfo("trust", "The current exceptions epoch is %llu. (%{public}s)", currentExceptionResetCount, currentExceptionResetCountError ? "Error" : "OK");
2023 /* Fail closed: if we were unable to get the current exceptions epoch consider the exceptions invalid. */
2024 if (currentExceptionResetCountError) {
2025 secerror("Failed to get the current exceptions epoch.");
2026 return false;
2027 }
2028 /* If this is the first epoch ever there is no point in checking whether any exceptions belong in the past. */
2029 if (currentExceptionResetCount == 0) {
2030 return true;
2031 }
2032
2033 CFNumberRef resetCountRef = CFDictionaryGetValue(exception, kSecCertificateExceptionResetCount);
2034 if (!resetCountRef) {
2035 secerror("Failed to get the exception's epoch.");
2036 return false;
2037 }
2038
2039 uint64_t exceptionResetCount;
2040 if (!CFNumberGetValue(resetCountRef, kCFNumberSInt64Type, &exceptionResetCount)) {
2041 secerror("Failed to parse the current exceptions epoch as a uint64.");
2042 return false;
2043 }
2044
2045 if (exceptionResetCount != currentExceptionResetCount) {
2046 secerror("The current exception's epoch (%llu) is not the current epoch. (%llu)", exceptionResetCount, currentExceptionResetCount);
2047 return false;
2048 }
2049
2050 secinfo("trust", "Exceptions are valid for the current exceptions epoch. (%llu)", currentExceptionResetCount);
2051 return true;
2052 }
2053 #endif
2054
2055 bool SecTrustSetExceptions(SecTrustRef trust, CFDataRef encodedExceptions) {
2056 if (!trust) {
2057 return false;
2058 }
2059 CFArrayRef exceptions = NULL;
2060
2061 if (NULL != encodedExceptions) {
2062 exceptions = (CFArrayRef)CFPropertyListCreateWithData(kCFAllocatorDefault,
2063 encodedExceptions, kCFPropertyListImmutable, NULL, NULL);
2064 }
2065
2066 if (exceptions && CFGetTypeID(exceptions) != CFArrayGetTypeID()) {
2067 CFRelease(exceptions);
2068 exceptions = NULL;
2069 }
2070
2071 dispatch_sync(trust->_trustQueue, ^{
2072 CFReleaseSafe(trust->_exceptions);
2073 trust->_exceptions = exceptions;
2074 });
2075
2076 /* We changed the exceptions -- so we need to re-evaluate */
2077 SecTrustSetNeedsEvaluation(trust);
2078
2079 /* If there is a valid exception entry for our current leaf we're golden. */
2080 #if TARGET_OS_IPHONE
2081 if (SecTrustGetExceptionForCertificateAtIndex(trust, 0) && SecTrustExceptionsValidForThisEpoch(exceptions)) {
2082 #else
2083 if (SecTrustGetExceptionForCertificateAtIndex(trust, 0)) {
2084 #endif
2085 return true;
2086 }
2087
2088 /* The passed in exceptions didn't match our current leaf, so we discard it. */
2089 dispatch_sync(trust->_trustQueue, ^{
2090 CFReleaseNull(trust->_exceptions);
2091 });
2092 return false;
2093 }
2094
2095 #if TARGET_OS_OSX
2096 OSStatus
2097 SecTrustSetOptions(SecTrustRef trustRef, SecTrustOptionFlags options)
2098 {
2099 /* bridge to support API functionality for legacy callers */
2100 OSStatus status = errSecSuccess;
2101
2102 /* No options or none that trigger the exceptions behavior */
2103 if (!options ||
2104 0 == (options & (kSecTrustOptionAllowExpired |
2105 kSecTrustOptionImplicitAnchors |
2106 kSecTrustOptionAllowExpiredRoot))) {
2107 return status;
2108 }
2109
2110 __block CFMutableArrayRef exceptions = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
2111 if (!exceptions) { return errSecAllocate; }
2112
2113 /* Add the new options to the old_exceptions when those exceptions are tied to a particular cert.
2114 * If not tied to a particular cert, we reset the exceptions based on the input options. */
2115 CFArrayRef old_exceptions = SecTrustGetTrustExceptionsArray(trustRef);
2116 if (old_exceptions && SecTrustGetExceptionForCertificateAtIndex(trustRef, 0)) {
2117 CFIndex ix, count = CFArrayGetCount(old_exceptions);
2118 for (ix = 0; ix < count; ix++) {
2119 CFMutableDictionaryRef exception_dictionary = CFDictionaryCreateMutableCopy(NULL, 0, (CFDictionaryRef)CFArrayGetValueAtIndex(old_exceptions, ix));
2120 if (!exception_dictionary) { status = errSecAllocate; goto out; }
2121 if ((options & kSecTrustOptionAllowExpired) != 0) {
2122 CFDictionaryAddValue(exception_dictionary, kSecPolicyCheckTemporalValidity, kCFBooleanFalse);
2123 }
2124 if ((options & (kSecTrustOptionImplicitAnchors | kSecTrustOptionAllowExpiredRoot)) != 0) {
2125 /* Check that root is self-signed. */
2126 Boolean isSelfSigned = false;
2127 SecCertificateRef cert = SecTrustGetCertificateAtIndex(trustRef, ix);
2128 if (cert && (errSecSuccess == SecCertificateIsSelfSigned(cert, &isSelfSigned)) &&
2129 isSelfSigned) {
2130 if ((options & kSecTrustOptionImplicitAnchors) != 0) {
2131 CFDictionaryAddValue(exception_dictionary, kSecPolicyCheckAnchorTrusted, kCFBooleanFalse);
2132 } else if ((options & kSecTrustOptionAllowExpiredRoot) != 0) {
2133 CFDictionaryAddValue(exception_dictionary, kSecPolicyCheckTemporalValidity, kCFBooleanFalse);
2134 }
2135 }
2136 }
2137 CFArrayAppendValue(exceptions, exception_dictionary);
2138 CFReleaseNull(exception_dictionary);
2139 }
2140 } else {
2141 /* Create a new exceptions array. Warning, this takes advantage of implementation details of the exceptions mechanism. */
2142 CFMutableDictionaryRef exception_dictionary = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks,
2143 &kCFTypeDictionaryValueCallBacks);
2144 if (!exception_dictionary) { status = errSecAllocate; goto out; }
2145 if ((options & kSecTrustOptionAllowExpired) != 0) {
2146 CFDictionaryAddValue(exception_dictionary, kSecPolicyCheckTemporalValidity, kCFBooleanFalse);
2147 }
2148 if ((options & kSecTrustOptionAllowExpiredRoot) != 0) {
2149 CFDictionaryAddValue(exception_dictionary, kSecPolicyCheckValidRoot, kCFBooleanFalse);
2150 }
2151 if ((options & kSecTrustOptionImplicitAnchors) != 0) {
2152 CFDictionaryAddValue(exception_dictionary, kSecPolicyCheckAnchorTrusted, kCFBooleanFalse);
2153 }
2154 CFArrayAppendValue(exceptions, exception_dictionary);
2155 CFReleaseNull(exception_dictionary);
2156 }
2157
2158 /* Set exceptions */
2159 dispatch_sync(trustRef->_trustQueue, ^{
2160 CFReleaseSafe(trustRef->_exceptions);
2161 trustRef->_exceptions = CFRetainSafe(exceptions);
2162 });
2163 /* We changed the exceptions -- so we need to re-evaluate */
2164 SecTrustSetNeedsEvaluation(trustRef);
2165
2166 out:
2167 CFReleaseNull(exceptions);
2168 return status;
2169 }
2170 #endif
2171
2172 CFArrayRef SecTrustCopySummaryPropertiesAtIndex(SecTrustRef trust, CFIndex ix) {
2173 CFMutableArrayRef summary;
2174 SecCertificateRef certificate = SecTrustGetCertificateAtIndex(trust, ix);
2175 summary = SecCertificateCopySummaryProperties(certificate,
2176 SecTrustGetVerifyTime(trust));
2177 /* FIXME Add more details in the failure case. */
2178
2179 return summary;
2180 }
2181
2182 CFArrayRef SecTrustCopyDetailedPropertiesAtIndex(SecTrustRef trust, CFIndex ix) {
2183 CFArrayRef summary;
2184 SecCertificateRef certificate = SecTrustGetCertificateAtIndex(trust, ix);
2185 summary = SecCertificateCopyProperties(certificate);
2186
2187 return summary;
2188 }
2189
2190 struct TrustFailures {
2191 bool badLinkage;
2192 bool unknownCritExtn;
2193 bool untrustedAnchor;
2194 bool missingIntermediate;
2195 bool hostnameMismatch;
2196 bool policyFail;
2197 bool invalidCert;
2198 bool weakKey;
2199 bool weakHash;
2200 bool revocation;
2201 };
2202
2203 static void applyDetailProperty(const void *_key, const void *_value,
2204 void *context) {
2205 CFStringRef key = (CFStringRef)_key;
2206 struct TrustFailures *tf = (struct TrustFailures *)context;
2207 if (CFGetTypeID(_value) != CFBooleanGetTypeID()) {
2208 /* Value isn't a CFBooleanRef, oh no! */
2209 return;
2210 }
2211 CFBooleanRef value = (CFBooleanRef)_value;
2212 if (CFBooleanGetValue(value)) {
2213 /* Not an actual failure so we don't report it. */
2214 return;
2215 }
2216
2217 /* @@@ FIXME: Report a different return value when something is in the
2218 details but masked out by an exception and use that below for display
2219 purposes. */
2220 if (CFEqual(key, kSecPolicyCheckIdLinkage)) {
2221 tf->badLinkage = true;
2222 } else if (CFEqual(key, kSecPolicyCheckCriticalExtensions)) {
2223 tf->unknownCritExtn = true;
2224 } else if (CFEqual(key, kSecPolicyCheckAnchorTrusted)
2225 || CFEqual(key, kSecPolicyCheckAnchorSHA1)
2226 || CFEqual(key, kSecPolicyCheckAnchorSHA256)
2227 || CFEqual(key, kSecPolicyCheckAnchorApple)) {
2228 tf->untrustedAnchor = true;
2229 } else if (CFEqual(key, kSecPolicyCheckMissingIntermediate)) {
2230 tf->missingIntermediate = true;
2231 } else if (CFEqual(key, kSecPolicyCheckSSLHostname)) {
2232 tf->hostnameMismatch = true;
2233 } else if (CFEqual(key, kSecPolicyCheckTemporalValidity)) {
2234 tf->invalidCert = true;
2235 } else if (CFEqual(key, kSecPolicyCheckWeakKeySize)
2236 || CFEqualSafe(key, kSecPolicyCheckKeySize)
2237 || CFEqualSafe(key, kSecPolicyCheckSystemTrustedWeakKey)) {
2238 tf->weakKey = true;
2239 } else if (CFEqual(key, kSecPolicyCheckWeakSignature)
2240 || CFEqualSafe(key, kSecPolicyCheckSignatureHashAlgorithms)
2241 || CFEqualSafe(key, kSecPolicyCheckSystemTrustedWeakHash)) {
2242 tf->weakHash = true;
2243 } else if (CFEqual(key, kSecPolicyCheckRevocation)) {
2244 tf->revocation = true;
2245 } else {
2246 /* Anything else is a policy failure. */
2247 tf->policyFail = true;
2248 }
2249 }
2250
2251 static void appendError(CFMutableArrayRef properties, CFStringRef error, bool localized) {
2252 CFStringRef localizedError = NULL;
2253 if (!error) {
2254 return;
2255 } else if (localized) {
2256 //%%% "SecCertificate" should be changed to "Certificate": rdar://37517120
2257 localizedError = SecFrameworkCopyLocalizedString(error, CFSTR("SecCertificate"));
2258 } else {
2259 localizedError = (CFStringRef) CFRetainSafe(error);
2260 }
2261 appendProperty(properties, kSecPropertyTypeError, NULL, NULL,
2262 localizedError, localized);
2263 CFReleaseNull(localizedError);
2264 }
2265
2266 #if TARGET_OS_OSX
2267 /* OS X properties array has a different structure and is implemented SecTrust.cpp. */
2268 CFArrayRef SecTrustCopyProperties_ios(SecTrustRef trust)
2269 #else
2270 CFArrayRef SecTrustCopyProperties(SecTrustRef trust)
2271 #endif
2272 {
2273 if (!trust) {
2274 return NULL;
2275 }
2276 SecTrustEvaluateIfNecessary(trust);
2277 bool localized = true;
2278 __block CFArrayRef details = NULL;
2279 dispatch_sync(trust->_trustQueue, ^{
2280 details = CFRetainSafe(trust->_details);
2281 });
2282 if (!details) {
2283 return NULL;
2284 }
2285
2286 struct TrustFailures tf = {};
2287
2288 CFIndex ix, count = CFArrayGetCount(details);
2289 for (ix = 0; ix < count; ++ix) {
2290 CFDictionaryRef detail = (CFDictionaryRef)
2291 CFArrayGetValueAtIndex(details, ix);
2292 /* We now have a detail dictionary for certificate at index ix, with
2293 a key value pair for each failed policy check. Let's convert it
2294 from Ro-Man form into something a Hu-Man can understand. */
2295 CFDictionaryApplyFunction(detail, applyDetailProperty, &tf);
2296 }
2297
2298 CFMutableArrayRef properties = CFArrayCreateMutable(kCFAllocatorDefault, 0,
2299 &kCFTypeArrayCallBacks);
2300 /* The badLinkage and unknownCritExtn failures are short circuited, since
2301 you can't recover from those errors. */
2302 if (tf.badLinkage) {
2303 appendError(properties, CFSTR("Invalid certificate chain linkage."), localized);
2304 } else if (tf.unknownCritExtn) {
2305 appendError(properties, CFSTR("One or more unsupported critical extensions found."), localized);
2306 } else {
2307 if (tf.untrustedAnchor) {
2308 appendError(properties, CFSTR("Root certificate is not trusted."), localized);
2309 }
2310 if (tf.missingIntermediate) {
2311 appendError(properties, CFSTR("Unable to build chain to root certificate."), localized);
2312 }
2313 if (tf.hostnameMismatch) {
2314 appendError(properties, CFSTR("Hostname mismatch."), localized);
2315 }
2316 if (tf.policyFail) {
2317 appendError(properties, CFSTR("Policy requirements not met."), localized);
2318 }
2319 if (tf.invalidCert) {
2320 appendError(properties, CFSTR("One or more certificates have expired or are not valid yet."), localized);
2321 }
2322 if (tf.weakKey) {
2323 appendError(properties, CFSTR("One or more certificates is using a weak key size."), localized);
2324 }
2325 if (tf.weakHash) {
2326 appendError(properties, CFSTR("One or more certificates is using a weak signature algorithm."), localized);
2327 }
2328 if (tf.revocation) {
2329 appendError(properties, CFSTR("One or more certificates have been revoked."), localized);
2330 }
2331 }
2332
2333 if (CFArrayGetCount(properties) == 0) {
2334 /* The certificate chain is trusted, return an empty plist */
2335 CFReleaseNull(properties);
2336 }
2337
2338 CFReleaseNull(details);
2339 return properties;
2340 }
2341
2342 #if TARGET_OS_OSX
2343 static void _AppendStatusCode(CFMutableArrayRef array, OSStatus statusCode) {
2344 if (!array) {
2345 return;
2346 }
2347 SInt32 num = statusCode;
2348 CFNumberRef numRef = CFNumberCreate(NULL, kCFNumberSInt32Type, &num);
2349 if (!numRef) {
2350 return;
2351 }
2352 CFArrayAppendValue(array, numRef);
2353 CFRelease(numRef);
2354 }
2355 #endif
2356
2357 static CFArrayRef _SecTrustCopyDetails(SecTrustRef trust) {
2358 if (!trust) {
2359 return NULL;
2360 }
2361 __block CFArrayRef details = NULL;
2362 dispatch_sync(trust->_trustQueue, ^{
2363 details = CFRetainSafe(trust->_details);
2364 });
2365 #if TARGET_OS_OSX
2366 // Include status codes in the per-certificate details (rdar://27930542)
2367 CFMutableArrayRef newDetails = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
2368 if (!newDetails) {
2369 CFReleaseSafe(details);
2370 return NULL;
2371 }
2372 CFIndex index, chainLen = (details) ? CFArrayGetCount(details) : 0;
2373 for (index = 0; index < chainLen; index++) {
2374 CFDictionaryRef detailDict = CFArrayGetValueAtIndex(details, index);
2375 CFMutableDictionaryRef newDict = CFDictionaryCreateMutableCopy(NULL, 0, detailDict);
2376 CFMutableArrayRef statusCodes = CFArrayCreateMutable(kCFAllocatorDefault,
2377 0, &kCFTypeArrayCallBacks);
2378 if (statusCodes) {
2379 CFIndex i, numCodes = 0;
2380 SInt32 *codes = SecTrustCopyStatusCodes(trust, index, &numCodes);
2381 if (codes) {
2382 for (i = 0; i < numCodes; i++) {
2383 OSStatus scode = (OSStatus)codes[i];
2384 _AppendStatusCode(statusCodes, scode);
2385 }
2386 free(codes);
2387 }
2388 if (CFArrayGetCount(statusCodes) > 0) {
2389 CFDictionarySetValue(newDict, kSecCertificateDetailStatusCodes, statusCodes);
2390 }
2391 CFRelease(statusCodes);
2392 }
2393 if (newDict) {
2394 CFArrayAppendValue(newDetails, newDict);
2395 CFRelease(newDict);
2396 }
2397 }
2398 CFReleaseSafe(details);
2399 return newDetails;
2400 #else
2401 return details;
2402 #endif
2403 }
2404
2405 CFDictionaryRef SecTrustCopyResult(SecTrustRef trust) {
2406 // Builds and returns a dictionary of evaluation results.
2407 if (!trust) {
2408 return NULL;
2409 }
2410 __block CFMutableDictionaryRef results = CFDictionaryCreateMutable(NULL, 0,
2411 &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
2412
2413 SecTrustEvaluateIfNecessary(trust);
2414 __block CFArrayRef details = _SecTrustCopyDetails(trust);
2415
2416 dispatch_sync(trust->_trustQueue, ^{
2417 // kSecTrustResultDetails (per-cert results)
2418 if (details) {
2419 CFDictionarySetValue(results, (const void *)kSecTrustResultDetails, (const void *)details);
2420 CFRelease(details);
2421 }
2422
2423 // kSecTrustResultValue (overall trust result)
2424 CFNumberRef numValue = CFNumberCreate(NULL, kCFNumberSInt32Type, &trust->_trustResult);
2425 if (numValue) {
2426 CFDictionarySetValue(results, (const void *)kSecTrustResultValue, (const void *)numValue);
2427 CFRelease(numValue);
2428 }
2429 CFDictionaryRef info = trust->_info;
2430 if (trust->_trustResult == kSecTrustResultInvalid || !info) {
2431 return; // we have nothing more to add
2432 }
2433
2434 // kSecTrustEvaluationDate
2435 CFDateRef evaluationDate = trust->_verifyDate;
2436 if (evaluationDate) {
2437 CFDictionarySetValue(results, (const void *)kSecTrustEvaluationDate, (const void *)evaluationDate);
2438 }
2439
2440 // kSecTrustCertificateTransparency
2441 CFBooleanRef ctValue;
2442 if (CFDictionaryGetValueIfPresent(info, kSecTrustInfoCertificateTransparencyKey, (const void **)&ctValue)) {
2443 CFDictionarySetValue(results, (const void *)kSecTrustCertificateTransparency, (const void *)ctValue);
2444 }
2445
2446 // kSecTrustExtendedValidation
2447 CFBooleanRef evValue;
2448 if (CFDictionaryGetValueIfPresent(info, kSecTrustInfoExtendedValidationKey, (const void **)&evValue)) {
2449 CFDictionarySetValue(results, (const void *)kSecTrustExtendedValidation, (const void *)evValue);
2450 }
2451
2452 // kSecTrustOrganizationName
2453 CFStringRef organizationName;
2454 if (CFDictionaryGetValueIfPresent(info, kSecTrustInfoCompanyNameKey, (const void **)&organizationName)) {
2455 CFDictionarySetValue(results, (const void *)kSecTrustOrganizationName, (const void *)organizationName);
2456 }
2457
2458 // kSecTrustRevocationChecked
2459 CFBooleanRef revocationChecked;
2460 if (CFDictionaryGetValueIfPresent(info, kSecTrustRevocationChecked, (const void **)&revocationChecked)) {
2461 CFDictionarySetValue(results, (const void *)kSecTrustRevocationChecked, (const void *)revocationChecked);
2462 }
2463
2464 // kSecTrustRevocationReason
2465 CFNumberRef revocationReason;
2466 if (CFDictionaryGetValueIfPresent(info, kSecTrustRevocationReason, (const void **)&revocationReason)) {
2467 CFDictionarySetValue(results, (const void *)kSecTrustRevocationReason, (const void *)revocationReason);
2468 }
2469
2470 // kSecTrustRevocationValidUntilDate
2471 CFDateRef validUntilDate;
2472 if (CFDictionaryGetValueIfPresent(info, kSecTrustRevocationValidUntilDate, (const void **)&validUntilDate)) {
2473 CFDictionarySetValue(results, (const void *)kSecTrustRevocationValidUntilDate, (const void *)validUntilDate);
2474 }
2475 });
2476
2477 return results;
2478 }
2479
2480 #define do_if_registered(sdp, ...) if (gTrustd && gTrustd->sdp) { return gTrustd->sdp(__VA_ARGS__); }
2481
2482 static bool xpc_dictionary_entry_is_type(xpc_object_t dictionary, const char *key, xpc_type_t type) {
2483 xpc_object_t value = xpc_dictionary_get_value(dictionary, key);
2484 return value && (xpc_get_type(value) == type);
2485 }
2486
2487 static uint64_t do_ota_pki_op (enum SecXPCOperation op, CFErrorRef *error) {
2488 uint64_t num = 0;
2489 xpc_object_t message = securityd_create_message(op, error);
2490 if (message) {
2491 xpc_object_t response = securityd_message_with_reply_sync(message, error);
2492 if (response && xpc_dictionary_entry_is_type(response, kSecXPCKeyResult, XPC_TYPE_UINT64)) {
2493 num = (int64_t) xpc_dictionary_get_uint64(response, kSecXPCKeyResult);
2494 }
2495 if (response && error && xpc_dictionary_entry_is_type(response, kSecXPCKeyError, XPC_TYPE_DICTIONARY)) {
2496 xpc_object_t xpc_error = xpc_dictionary_get_value(response, kSecXPCKeyError);
2497 if (xpc_error) {
2498 *error = SecCreateCFErrorWithXPCObject(xpc_error);
2499 }
2500 }
2501 xpc_release_safe(message);
2502 xpc_release_safe(response);
2503 }
2504 return num;
2505 }
2506
2507 // version 0 -> error, so we need to start at version 1 or later.
2508 uint64_t SecTrustGetTrustStoreVersionNumber(CFErrorRef *error) {
2509 do_if_registered(sec_ota_pki_trust_store_version, error);
2510
2511 os_activity_t activity = os_activity_create("SecTrustGetTrustStoreVersionNumber", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_DEFAULT);
2512 os_activity_scope(activity);
2513
2514 uint64_t num = do_ota_pki_op(sec_ota_pki_trust_store_version_id, error);
2515
2516 os_release(activity);
2517 return num;
2518 }
2519
2520 uint64_t SecTrustGetAssetVersionNumber(CFErrorRef *error) {
2521 do_if_registered(sec_ota_pki_asset_version, error);
2522
2523 os_activity_t activity = os_activity_create("SecTrustGetAssetVersionNumber", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_DEFAULT);
2524 os_activity_scope(activity);
2525
2526 uint64_t num = do_ota_pki_op(sec_ota_pki_asset_version_id, error);
2527
2528 os_release(activity);
2529 return num;
2530 }
2531
2532 uint64_t SecTrustOTAPKIGetUpdatedAsset(CFErrorRef *error) {
2533 do_if_registered(sec_ota_pki_get_new_asset, error);
2534
2535 os_activity_t activity = os_activity_create("SecTrustOTAPKIGetUpdatedAsset", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_DEFAULT);
2536 os_activity_scope(activity);
2537
2538 uint64_t num = do_ota_pki_op(kSecXPCOpOTAPKIGetNewAsset, error);
2539
2540 os_release(activity);
2541 return num;
2542 }
2543
2544 uint64_t SecTrustOTASecExperimentGetUpdatedAsset(CFErrorRef *error) {
2545 do_if_registered(sec_ota_secexperiment_get_new_asset, error);
2546
2547 os_activity_t activity = os_activity_create("SecTrustOTASecExperimentGetUpdatedAsset", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_DEFAULT);
2548 os_activity_scope(activity);
2549
2550 uint64_t num = do_ota_pki_op(kSecXPCOpOTASecExperimentGetNewAsset, error);
2551
2552 os_release(activity);
2553 return num;
2554 }
2555
2556 CFDictionaryRef SecTrustOTASecExperimentCopyAsset(CFErrorRef *error) {
2557 __block CFDictionaryRef result = NULL;
2558 do_if_registered(sec_ota_secexperiment_get_asset, error);
2559
2560 securityd_send_sync_and_do(kSecXPCOpOTASecExperimentGetAsset, error, ^bool(xpc_object_t message, CFErrorRef *blockError) {
2561 // input: set message parameters here
2562 return true;
2563 }, ^bool(xpc_object_t response, CFErrorRef *blockError) {
2564 // output: get array from response object
2565 xpc_object_t xpc_dict = NULL;
2566 if (response) {
2567 xpc_dict = xpc_dictionary_get_value(response, kSecXPCKeyResult);
2568 }
2569 if (xpc_dict && (xpc_get_type(xpc_dict) == XPC_TYPE_DICTIONARY)) {
2570 result = (CFDictionaryRef)_CFXPCCreateCFObjectFromXPCObject(xpc_dict);
2571 } else {
2572 return SecError(errSecInternal, blockError, CFSTR("Unable to get SecExperiment Assets"));
2573 }
2574 return result != NULL;
2575 });
2576 return result;
2577 }
2578
2579 bool SecTrustReportTLSAnalytics(CFStringRef eventName, xpc_object_t eventAttributes, CFErrorRef *error) {
2580 if (!eventName || !eventAttributes) {
2581 return false;
2582 }
2583 do_if_registered(sec_networking_analytics_report, eventName, eventAttributes, error);
2584
2585 os_activity_t activity = os_activity_create("SecTrustReportTLSAnalytics", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_DEFAULT);
2586 os_activity_scope(activity);
2587
2588 __block bool result = false;
2589 securityd_send_sync_and_do(kSecXPCOpNetworkingAnalyticsReport, error, ^bool(xpc_object_t message, CFErrorRef *block_error) {
2590 if (!SecXPCDictionarySetString(message, kSecTrustEventNameKey, eventName, block_error)) {
2591 return false;
2592 }
2593 xpc_dictionary_set_value(message, kSecTrustEventAttributesKey, eventAttributes);
2594 return true;
2595 }, ^bool(xpc_object_t response, CFErrorRef *block_error) {
2596 result = SecXPCDictionaryGetBool(response, kSecXPCKeyResult, block_error);
2597 return true;
2598 });
2599
2600 os_release(activity);
2601 return result;
2602 }
2603
2604 bool SecTrustReportNetworkingAnalytics(const char *eventNameString, xpc_object_t eventAttributes) {
2605 if (!eventNameString || !eventAttributes) {
2606 return false;
2607 }
2608
2609 CFStringRef eventName = CFStringCreateWithCString(kCFAllocatorDefault, eventNameString, kCFStringEncodingUTF8);
2610 if (!eventName) {
2611 secerror("CFStringCreateWithCString failed");
2612 return false;
2613 }
2614
2615 CFErrorRef error = NULL;
2616 if (gTrustd && gTrustd->sec_networking_analytics_report) {
2617 bool result = gTrustd->sec_networking_analytics_report(eventName, eventAttributes, &error);
2618 if (error != NULL) {
2619 secerror("SecTrustReportNetworkingAnalytics failed with error: %d", (int)CFErrorGetCode(error));
2620 }
2621 CFReleaseNull(eventName);
2622 CFReleaseNull(error);
2623 return result;
2624 }
2625
2626 os_activity_t activity = os_activity_create("SecTrustReportNetworkingAnalytics", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_DEFAULT);
2627 os_activity_scope(activity);
2628
2629 __block bool result = false;
2630 securityd_send_sync_and_do(kSecXPCOpNetworkingAnalyticsReport, &error, ^bool(xpc_object_t message, CFErrorRef *block_error) {
2631 if (!SecXPCDictionarySetString(message, kSecTrustEventNameKey, eventName, block_error)) {
2632 return false;
2633 }
2634 xpc_dictionary_set_value(message, kSecTrustEventAttributesKey, eventAttributes);
2635 return true;
2636 }, ^bool(xpc_object_t response, CFErrorRef *block_error) {
2637 result = SecXPCDictionaryGetBool(response, kSecXPCKeyResult, block_error);
2638 return true;
2639 });
2640
2641 if (error != NULL) {
2642 secerror("SecTrustReportNetworkingAnalytics failed with error: %d", (int)CFErrorGetCode(error));
2643 }
2644 CFReleaseNull(error);
2645 CFReleaseNull(eventName);
2646
2647 os_release(activity);
2648 return result;
2649 }
2650
2651
2652 /*
2653 * This function performs an evaluation of the leaf certificate only, and
2654 * does so in the process that called it. Its primary use is in SecItemCopyMatching
2655 * when kSecMatchPolicy is in the dictionary.
2656 */
2657 OSStatus SecTrustEvaluateLeafOnly(SecTrustRef trust, SecTrustResultType *result) {
2658 if (!trust) {
2659 return errSecParam;
2660 }
2661 OSStatus status = errSecSuccess;
2662 SecTrustResultType trustResult = kSecTrustResultInvalid;
2663 if((status = SecTrustValidateInput(trust))) {
2664 return status;
2665 }
2666
2667 struct OpaqueSecLeafPVC pvc;
2668 SecCertificateRef leaf = SecTrustGetCertificateAtIndex(trust, 0);
2669 __block CFArrayRef policies = NULL;
2670 dispatch_sync(trust->_trustQueue, ^{
2671 policies = CFRetainSafe(trust->_policies);
2672 });
2673 SecLeafPVCInit(&pvc, leaf, policies, SecTrustGetVerifyTime(trust));
2674
2675 if(!SecLeafPVCLeafChecks(&pvc)) {
2676 trustResult = kSecTrustResultRecoverableTrustFailure;
2677 } else {
2678 trustResult = kSecTrustResultUnspecified;
2679 }
2680
2681 /* Set other result context information */
2682 dispatch_sync(trust->_trustQueue, ^{
2683 trust->_trustResult = trustResult;
2684 trust->_details = CFRetainSafe(pvc.details);
2685 trust->_info = CFDictionaryCreateMutable(kCFAllocatorDefault, 0,
2686 &kCFTypeDictionaryKeyCallBacks,
2687 &kCFTypeDictionaryValueCallBacks);
2688 CFMutableArrayRef leafCert = CFArrayCreateMutableCopy(NULL, 1, trust->_certificates);
2689 trust->_chain = leafCert;
2690 });
2691
2692 SecLeafPVCDelete(&pvc);
2693
2694 /* log to syslog when there is a trust failure */
2695 if (trustResult != kSecTrustResultUnspecified) {
2696 CFStringRef failureDesc = SecTrustCopyFailureDescription(trust);
2697 secerror("%@", failureDesc);
2698 CFRelease(failureDesc);
2699 }
2700
2701 if (result) {
2702 *result = trustResult;
2703 }
2704
2705 CFReleaseSafe(policies);
2706 return status;
2707 }
2708
2709 static void deserializeCert(const void *value, void *context) {
2710 CFDataRef certData = (CFDataRef)value;
2711 if (isData(certData)) {
2712 SecCertificateRef cert = SecCertificateCreateWithData(NULL, certData);
2713 if (cert) {
2714 CFArrayAppendValue((CFMutableArrayRef)context, cert);
2715 CFRelease(cert);
2716 }
2717 }
2718 }
2719
2720 static CF_RETURNS_RETAINED CFArrayRef SecCertificateArrayDeserialize(CFArrayRef serializedCertificates) {
2721 CFMutableArrayRef result = NULL;
2722 require_quiet(isArray(serializedCertificates), errOut);
2723 CFIndex count = CFArrayGetCount(serializedCertificates);
2724 result = CFArrayCreateMutable(kCFAllocatorDefault, count, &kCFTypeArrayCallBacks);
2725 CFRange all_certs = { 0, count };
2726 CFArrayApplyFunction(serializedCertificates, all_certs, deserializeCert, result);
2727 errOut:
2728 return result;
2729 }
2730
2731 static void serializeCertificate(const void *value, void *context) {
2732 SecCertificateRef cert = (SecCertificateRef)value;
2733 if (cert && SecCertificateGetTypeID() == CFGetTypeID(cert)) {
2734 CFDataRef certData = SecCertificateCopyData(cert);
2735 if (certData) {
2736 CFArrayAppendValue((CFMutableArrayRef)context, certData);
2737 CFRelease(certData);
2738 }
2739 }
2740 }
2741
2742 static CF_RETURNS_RETAINED CFArrayRef SecCertificateArraySerialize(CFArrayRef certificates) {
2743 CFMutableArrayRef result = NULL;
2744 require_quiet(isArray(certificates), errOut);
2745 CFIndex count = CFArrayGetCount(certificates);
2746 result = CFArrayCreateMutable(NULL, count, &kCFTypeArrayCallBacks);
2747 CFRange all_certificates = { 0, count};
2748 CFArrayApplyFunction(certificates, all_certificates, serializeCertificate, result);
2749 errOut:
2750 return result;
2751 }
2752
2753 static CFPropertyListRef SecTrustCopyPlist(SecTrustRef trust) {
2754 __block CFMutableDictionaryRef output = NULL;
2755 output = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks,
2756 &kCFTypeDictionaryValueCallBacks);
2757
2758 dispatch_sync(trust->_trustQueue, ^{
2759 if (trust->_certificates) {
2760 CFArrayRef serializedCerts = SecCertificateArraySerialize(trust->_certificates);
2761 if (serializedCerts) {
2762 CFDictionaryAddValue(output, CFSTR(kSecTrustCertificatesKey), serializedCerts);
2763 CFRelease(serializedCerts);
2764 }
2765 }
2766 if (trust->_anchors) {
2767 CFArrayRef serializedAnchors = SecCertificateArraySerialize(trust->_anchors);
2768 if (serializedAnchors) {
2769 CFDictionaryAddValue(output, CFSTR(kSecTrustAnchorsKey), serializedAnchors);
2770 CFRelease(serializedAnchors);
2771 }
2772 }
2773 if (trust->_policies) {
2774 CFArrayRef serializedPolicies = SecPolicyArrayCreateSerialized(trust->_policies);
2775 if (serializedPolicies) {
2776 CFDictionaryAddValue(output, CFSTR(kSecTrustPoliciesKey), serializedPolicies);
2777 CFRelease(serializedPolicies);
2778 }
2779 }
2780 if (trust->_responses) {
2781 CFDictionaryAddValue(output, CFSTR(kSecTrustResponsesKey), trust->_responses);
2782 }
2783 if (trust->_SCTs) {
2784 CFDictionaryAddValue(output, CFSTR(kSecTrustSCTsKey), trust->_SCTs);
2785 }
2786 if (trust->_trustedLogs) {
2787 CFDictionaryAddValue(output, CFSTR(kSecTrustTrustedLogsKey), trust->_trustedLogs);
2788 }
2789 if (trust->_verifyDate) {
2790 CFDictionaryAddValue(output, CFSTR(kSecTrustVerifyDateKey), trust->_verifyDate);
2791 }
2792 if (trust->_chain) {
2793 CFArrayRef serializedCerts = SecCertificateArraySerialize(trust->_chain);
2794 if (serializedCerts) {
2795 CFDictionaryAddValue(output, CFSTR(kSecTrustChainKey), serializedCerts);
2796 CFRelease(serializedCerts);
2797 }
2798 }
2799 if (trust->_details) {
2800 CFDictionaryAddValue(output, CFSTR(kSecTrustDetailsKey), trust->_details);
2801 }
2802 if (trust->_info) {
2803 CFDictionaryAddValue(output, CFSTR(kSecTrustInfoKey), trust->_info);
2804 }
2805 if (trust->_exceptions) {
2806 CFDictionaryAddValue(output, CFSTR(kSecTrustExceptionsKey), trust->_exceptions);
2807 }
2808 CFNumberRef trustResult = CFNumberCreate(NULL, kCFNumberSInt32Type, &trust->_trustResult);
2809 if (trustResult) {
2810 CFDictionaryAddValue(output, CFSTR(kSecTrustResultKey), trustResult);
2811 }
2812 CFReleaseNull(trustResult);
2813 if (trust->_anchorsOnly) {
2814 CFDictionaryAddValue(output, CFSTR(kSecTrustAnchorsOnlyKey), kCFBooleanTrue);
2815 } else {
2816 CFDictionaryAddValue(output, CFSTR(kSecTrustAnchorsOnlyKey), kCFBooleanFalse);
2817 }
2818 if (trust->_keychainsAllowed) {
2819 CFDictionaryAddValue(output, CFSTR(kSecTrustKeychainsAllowedKey), kCFBooleanTrue);
2820 } else {
2821 CFDictionaryAddValue(output, CFSTR(kSecTrustKeychainsAllowedKey), kCFBooleanFalse);
2822 }
2823 });
2824
2825 return output;
2826 }
2827
2828 CFDataRef SecTrustSerialize(SecTrustRef trust, CFErrorRef *error) {
2829 CFPropertyListRef plist = NULL;
2830 CFDataRef derTrust = NULL;
2831 require_action_quiet(trust, out,
2832 SecError(errSecParam, error, CFSTR("null trust input")));
2833 require_action_quiet(plist = SecTrustCopyPlist(trust), out,
2834 SecError(errSecDecode, error, CFSTR("unable to create trust plist")));
2835 require_quiet(derTrust = CFPropertyListCreateDERData(NULL, plist, error), out);
2836
2837 out:
2838 CFReleaseNull(plist);
2839 return derTrust;
2840 }
2841
2842 static OSStatus SecTrustCreateFromPlist(CFPropertyListRef plist, SecTrustRef CF_RETURNS_RETAINED *trust) {
2843 OSStatus status = errSecParam;
2844 SecTrustRef output = NULL;
2845 CFTypeRef serializedCertificates = NULL, serializedPolicies = NULL, serializedAnchors = NULL;
2846 CFNumberRef trustResultNum = NULL;
2847 CFArrayRef certificates = NULL, policies = NULL, anchors = NULL, responses = NULL,
2848 SCTs = NULL, trustedLogs = NULL, details = NULL, exceptions = NULL, chain = NULL;
2849 CFDateRef verifyDate = NULL;
2850 CFDictionaryRef info = NULL;
2851
2852 require_quiet(CFDictionaryGetTypeID() == CFGetTypeID(plist), out);
2853 require_quiet(serializedCertificates = CFDictionaryGetValue(plist, CFSTR(kSecTrustCertificatesKey)), out);
2854 require_quiet(certificates = SecCertificateArrayDeserialize(serializedCertificates), out);
2855 require_quiet(serializedPolicies = CFDictionaryGetValue(plist, CFSTR(kSecTrustPoliciesKey)), out);
2856 require_quiet(policies = SecPolicyArrayCreateDeserialized(serializedPolicies), out);
2857 require_noerr_quiet(status = SecTrustCreateWithCertificates(certificates, policies, &output), out);
2858
2859 serializedAnchors = CFDictionaryGetValue(plist, CFSTR(kSecTrustAnchorsKey));
2860 if (isArray(serializedAnchors)) {
2861 anchors = SecCertificateArrayDeserialize(serializedAnchors);
2862 output->_anchors = anchors;
2863 }
2864 responses = CFDictionaryGetValue(plist, CFSTR(kSecTrustResponsesKey));
2865 if (isArray(responses)) {
2866 output->_responses = CFRetainSafe(responses);
2867 }
2868 SCTs = CFDictionaryGetValue(plist, CFSTR(kSecTrustSCTsKey));
2869 if (isArray(SCTs)) {
2870 output->_SCTs = CFRetainSafe(SCTs);
2871 }
2872 trustedLogs = CFDictionaryGetValue(plist, CFSTR(kSecTrustTrustedLogsKey));
2873 if (isArray(trustedLogs)) {
2874 output->_trustedLogs = CFRetainSafe(trustedLogs);
2875 }
2876 verifyDate = CFDictionaryGetValue(plist, CFSTR(kSecTrustVerifyDateKey));
2877 if (isDate(verifyDate)) {
2878 output->_verifyDate = CFRetainSafe(verifyDate);
2879 }
2880 chain = CFDictionaryGetValue(plist, CFSTR(kSecTrustChainKey));
2881 if (isArray(chain)) {
2882 output->_chain = SecCertificateArrayDeserialize(chain);
2883 }
2884 details = CFDictionaryGetValue(plist, CFSTR(kSecTrustDetailsKey));
2885 if (isArray(details)) {
2886 output->_details = CFRetainSafe(details);
2887 }
2888 info = CFDictionaryGetValue(plist, CFSTR(kSecTrustInfoKey));
2889 if (isDictionary(info)) {
2890 output->_info = CFRetainSafe(info);
2891 }
2892 exceptions = CFDictionaryGetValue(plist, CFSTR(kSecTrustExceptionsKey));
2893 if (isArray(exceptions)) {
2894 output->_exceptions = CFRetainSafe(exceptions);
2895 }
2896 int32_t trustResult = -1;
2897 trustResultNum = CFDictionaryGetValue(plist, CFSTR(kSecTrustResultKey));
2898 if (isNumber(trustResultNum) && CFNumberGetValue(trustResultNum, kCFNumberSInt32Type, &trustResult) &&
2899 (trustResult >= 0)) {
2900 output->_trustResult = trustResult;
2901 } else {
2902 status = errSecParam;
2903 }
2904 if (CFDictionaryGetValue(plist, CFSTR(kSecTrustAnchorsOnlyKey)) == kCFBooleanTrue) {
2905 output->_anchorsOnly = true;
2906 } /* false is set by default */
2907 if (CFDictionaryGetValue(plist, CFSTR(kSecTrustKeychainsAllowedKey)) == kCFBooleanFalse) {
2908 output->_keychainsAllowed = false;
2909 } /* true is set by default */
2910
2911 out:
2912 if (errSecSuccess == status && trust) {
2913 *trust = output;
2914 }
2915 CFReleaseNull(policies);
2916 CFReleaseNull(certificates);
2917 return status;
2918 }
2919
2920 SecTrustRef SecTrustDeserialize(CFDataRef serializedTrust, CFErrorRef *error) {
2921 SecTrustRef trust = NULL;
2922 CFPropertyListRef plist = NULL;
2923 OSStatus status = errSecSuccess;
2924 require_action_quiet(serializedTrust, out,
2925 SecError(errSecParam, error, CFSTR("null serialized trust input")));
2926 require_quiet(plist = CFPropertyListCreateWithDERData(NULL, serializedTrust,
2927 kCFPropertyListImmutable, NULL, error), out);
2928 require_noerr_action_quiet(status = SecTrustCreateFromPlist(plist, &trust), out,
2929 SecError(status, error, CFSTR("unable to create trust ref")));
2930
2931 out:
2932 CFReleaseNull(plist);
2933 return trust;
2934 }
2935
2936 #if TARGET_OS_IPHONE
2937 static uint64_t to_uint_error_request(enum SecXPCOperation op, CFErrorRef *error) {
2938 __block uint64_t result = 0;
2939
2940 securityd_send_sync_and_do(op, error, NULL, ^bool(xpc_object_t response, CFErrorRef *localError) {
2941 uint64_t temp_result = xpc_dictionary_get_uint64(response, kSecXPCKeyResult);
2942 /* plists do not support unsigned integers. */
2943 if (temp_result <= INT64_MAX) {
2944 result = temp_result;
2945 } else {
2946 secerror("Invalid exceptions epoch.");
2947 if (error) {
2948 *error = CFErrorCreate(NULL, kCFErrorDomainPOSIX, ERANGE, NULL);
2949 }
2950 }
2951 if (error && localError && *localError) {
2952 *error = *localError;
2953 }
2954 return result;
2955 });
2956
2957 return result;
2958 }
2959
2960 uint64_t SecTrustGetExceptionResetCount(CFErrorRef *error) {
2961 os_activity_t activity = os_activity_create("SecTrustExceptionGetResetCount", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_DEFAULT);
2962 os_activity_scope(activity);
2963 uint64_t exceptionResetCount = TRUSTD_XPC(sec_trust_get_exception_reset_count, to_uint_error_request, error);
2964 os_release(activity);
2965 if (error && *error) {
2966 secerror("Failed to get the exceptions epoch.");
2967 }
2968 secinfo("trust", "The exceptions epoch is %lld.", exceptionResetCount);
2969
2970 return exceptionResetCount;
2971 }
2972
2973 OSStatus SecTrustIncrementExceptionResetCount(CFErrorRef *error) {
2974 OSStatus status = errSecInternal;
2975
2976 os_activity_t activity = os_activity_create("SecTrustIncrementExceptionResetCount", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_DEFAULT);
2977 os_activity_scope(activity);
2978 bool success = TRUSTD_XPC(sec_trust_increment_exception_reset_count, to_bool_error_request, error);
2979 os_release(activity);
2980 if ((error && *error) || !success) {
2981 secerror("Failed to increment the exceptions epoch.");
2982 return status;
2983 }
2984 status = errSecSuccess;
2985
2986 return status;
2987 }
2988 #endif