]> git.saurik.com Git - apple/security.git/blob - OSX/sec/Security/SecTrust.c
Security-59306.41.2.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 typedef enum {
1043 kSecTrustErrorSubTypeBlocked,
1044 kSecTrustErrorSubTypeRevoked,
1045 kSecTrustErrorSubTypeKeySize,
1046 kSecTrustErrorSubTypeWeakHash,
1047 kSecTrustErrorSubTypeDenied,
1048 kSecTrustErrorSubTypeCompliance,
1049 kSecTrustErrorSubTypePinning,
1050 kSecTrustErrorSubTypeTrust,
1051 kSecTrustErrorSubTypeUsage,
1052 kSecTrustErrorSubTypeName,
1053 kSecTrustErrorSubTypeExpired,
1054 kSecTrustErrorSubTypeInvalid,
1055 } SecTrustErrorSubType;
1056
1057 #define SecCopyTrustString(KEY) SecFrameworkCopyLocalizedString(KEY, CFSTR("Trust"))
1058
1059 struct checkmap_entry_s {
1060 SecTrustErrorSubType type;
1061 OSStatus status;
1062 const CFStringRef errorKey;
1063 };
1064 typedef struct checkmap_entry_s checkmap_entry_t;
1065
1066 const checkmap_entry_t checkmap[] = {
1067 #undef POLICYCHECKMACRO
1068 #define __PC_SUBTYPE_ kSecTrustErrorSubTypeInvalid
1069 #define __PC_SUBTYPE_N kSecTrustErrorSubTypeName
1070 #define __PC_SUBTYPE_E kSecTrustErrorSubTypeExpired
1071 #define __PC_SUBTYPE_S kSecTrustErrorSubTypeKeySize
1072 #define __PC_SUBTYPE_H kSecTrustErrorSubTypeWeakHash
1073 #define __PC_SUBTYPE_U kSecTrustErrorSubTypeUsage
1074 #define __PC_SUBTYPE_P kSecTrustErrorSubTypePinning
1075 #define __PC_SUBTYPE_V kSecTrustErrorSubTypeRevoked
1076 #define __PC_SUBTYPE_T kSecTrustErrorSubTypeTrust
1077 #define __PC_SUBTYPE_C kSecTrustErrorSubTypeCompliance
1078 #define __PC_SUBTYPE_D kSecTrustErrorSubTypeDenied
1079 #define __PC_SUBTYPE_B kSecTrustErrorSubTypeBlocked
1080 #define POLICYCHECKMACRO(NAME, TRUSTRESULT, SUBTYPE, LEAFCHECK, PATHCHECK, LEAFONLY, CSSMERR, OSSTATUS) \
1081 { __PC_SUBTYPE_##SUBTYPE , OSSTATUS, SEC_TRUST_ERROR_##NAME },
1082 #include "SecPolicyChecks.list"
1083 };
1084
1085 static OSStatus SecTrustCopyErrorStrings(SecTrustRef trust,
1086 CFStringRef * CF_RETURNS_RETAINED simpleError,
1087 CFStringRef * CF_RETURNS_RETAINED fullError) {
1088 if (!simpleError || !fullError) {
1089 return errSecParam;
1090 }
1091 __block CFArrayRef details = NULL;
1092 dispatch_sync(trust->_trustQueue, ^{
1093 details = CFRetainSafe(trust->_details);
1094 });
1095 if (!details)
1096 return errSecInternal;
1097
1098 /* We need to map the policy check constants to indexes into our checkmap table. */
1099 static dispatch_once_t onceToken;
1100 static CFArrayRef policyChecks = NULL;
1101 dispatch_once(&onceToken, ^{
1102 CFMutableArrayRef _policyChecks = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
1103 #undef POLICYCHECKMACRO
1104 #define POLICYCHECKMACRO(NAME, TRUSTRESULT, SUBTYPE, LEAFCHECK, PATHCHECK, LEAFONLY, CSSMERR, ERRORSTRING) \
1105 CFArrayAppendValue(_policyChecks, kSecPolicyCheck##NAME);
1106 #include "SecPolicyChecks.list"
1107 policyChecks = _policyChecks;
1108 });
1109
1110 /* Build the errors for each cert in the detailed results array */
1111 __block CFMutableStringRef fullMutableError = CFStringCreateMutable(NULL, 0);
1112 __block SecTrustErrorSubType simpleErrorSubType = kSecTrustErrorSubTypeInvalid;
1113 __block OSStatus simpleErrorStatus = errSecInternalError;
1114 __block CFIndex simpleErrorCertIndex = kCFNotFound;
1115 __block CFIndex ix;
1116 CFIndex count = CFArrayGetCount(details);
1117 for (ix = 0; ix < count; ix++) {
1118 CFDictionaryRef perCertDetails = (CFDictionaryRef)CFArrayGetValueAtIndex(details, ix);
1119 if (CFDictionaryGetCount(perCertDetails) == 0) { continue; } // no errors on this cert
1120
1121 /* Get the cert summary and start the full error details string for this cert */
1122 CFStringRef certSummary = SecCertificateCopySubjectSummary(SecTrustGetCertificateAtIndex(trust, ix));
1123 CFStringRef format = SecCopyTrustString(SEC_TRUST_CERTIFICATE_ERROR);
1124 CFStringAppendFormat(fullMutableError, NULL, format,
1125 ix, certSummary);
1126 CFReleaseNull(certSummary);
1127 CFReleaseNull(format);
1128
1129 /* Figure out the errors */
1130 __block bool firstError = true;
1131 CFDictionaryForEach(perCertDetails, ^(const void *key, const void * __unused value) {
1132 CFIndex policyCheckIndex = CFArrayGetFirstIndexOfValue(policyChecks, CFRangeMake(0, CFArrayGetCount(policyChecks)), key);
1133 if ((policyCheckIndex < 0) || ((size_t)policyCheckIndex >= sizeof(checkmap)/sizeof(checkmap[0]))) {
1134 secwarning("unknown failure key in details dictionary: %@", key);
1135 return;
1136 }
1137 /* Keep track of the highest priority error encountered during this evaluation.
1138 * If multiple certs have errors of the same subtype we keep the lowest indexed cert. */
1139 if (simpleErrorSubType > checkmap[policyCheckIndex].type) {
1140 simpleErrorSubType = checkmap[policyCheckIndex].type;
1141 simpleErrorCertIndex = ix;
1142 simpleErrorStatus = checkmap[policyCheckIndex].status;
1143 }
1144 /* Add this error to the full error */
1145 if (!firstError) { CFStringAppend(fullMutableError, CFSTR(", ")); }
1146 CFStringRef errorString = SecCopyTrustString(checkmap[policyCheckIndex].errorKey);
1147 CFStringAppend(fullMutableError, errorString);
1148 CFReleaseNull(errorString);
1149 firstError = false;
1150 });
1151 CFStringAppend(fullMutableError, CFSTR(";"));
1152 }
1153 CFReleaseNull(details);
1154
1155 /* Build the simple error */
1156 if (simpleErrorCertIndex == kCFNotFound) { simpleErrorCertIndex = 0; }
1157 CFStringRef format = NULL;
1158 CFStringRef certSummary = SecCertificateCopySubjectSummary(SecTrustGetCertificateAtIndex(trust, simpleErrorCertIndex));
1159 switch (simpleErrorSubType) {
1160 case kSecTrustErrorSubTypeBlocked: {
1161 format = SecCopyTrustString(SEC_TRUST_ERROR_SUBTYPE_BLOCKED);
1162 break;
1163 }
1164 case kSecTrustErrorSubTypeRevoked: {
1165 format = SecCopyTrustString(SEC_TRUST_ERROR_SUBTYPE_REVOKED);
1166 break;
1167 }
1168 case kSecTrustErrorSubTypeKeySize: {
1169 format = SecCopyTrustString(SEC_TRUST_ERROR_SUBTYPE_KEYSIZE);
1170 break;
1171 }
1172 case kSecTrustErrorSubTypeWeakHash: {
1173 format = SecCopyTrustString(SEC_TRUST_ERROR_SUBTYPE_WEAKHASH);
1174 break;
1175 }
1176 case kSecTrustErrorSubTypeDenied: {
1177 format = SecCopyTrustString(SEC_TRUST_ERROR_SUBTYPE_DENIED);
1178 break;
1179 }
1180 case kSecTrustErrorSubTypeCompliance: {
1181 format = SecCopyTrustString(SEC_TRUST_ERROR_SUBTYPE_COMPLIANCE);
1182 break;
1183 }
1184 case kSecTrustErrorSubTypeExpired: {
1185 format = SecCopyTrustString(SEC_TRUST_ERROR_SUBTYPE_EXPIRED);
1186 break;
1187 }
1188 case kSecTrustErrorSubTypeTrust: {
1189 format = SecCopyTrustString(SEC_TRUST_ERROR_SUBTYPE_TRUST);
1190 break;
1191 }
1192 case kSecTrustErrorSubTypeName: {
1193 format = SecCopyTrustString(SEC_TRUST_ERROR_SUBTYPE_NAME);
1194 break;
1195 }
1196 case kSecTrustErrorSubTypeUsage: {
1197 format = SecCopyTrustString(SEC_TRUST_ERROR_SUBTYPE_USAGE);
1198 break;
1199 }
1200 case kSecTrustErrorSubTypePinning: {
1201 format = SecCopyTrustString(SEC_TRUST_ERROR_SUBTYPE_PINNING);
1202 CFAssignRetained(certSummary, SecTrustCopyChainSummary(trust));
1203 break;
1204 }
1205 default: {
1206 format = SecCopyTrustString(SEC_TRUST_ERROR_SUBTYPE_INVALID);
1207 break;
1208 }
1209 }
1210 if (format && certSummary) {
1211 *simpleError = CFStringCreateWithFormat(NULL, NULL, format, certSummary);
1212 }
1213 CFReleaseNull(format);
1214 CFReleaseNull(certSummary);
1215 *fullError = fullMutableError;
1216 return simpleErrorStatus;
1217 }
1218
1219 static CF_RETURNS_RETAINED CFErrorRef SecTrustCopyError(SecTrustRef trust) {
1220 if (!trust) { return NULL; }
1221 OSStatus status = errSecSuccess;
1222 __block SecTrustResultType trustResult = kSecTrustResultInvalid;
1223 dispatch_sync(trust->_trustQueue, ^{
1224 trustResult = trust->_trustResult;
1225 });
1226 if (trustResult == kSecTrustResultProceed || trustResult == kSecTrustResultUnspecified) {
1227 return NULL;
1228 }
1229
1230 CFStringRef detailedError = NULL;
1231 CFStringRef simpleError = NULL;
1232 status = SecTrustCopyErrorStrings(trust, &simpleError, &detailedError);
1233 /* failure to obtain either string must not cause a failure to create the CFErrorRef */
1234 if (!simpleError) {
1235 simpleError = SecCopyErrorMessageString(status, NULL);
1236 }
1237 if (!detailedError) {
1238 detailedError = SecCopyErrorMessageString(status, NULL);
1239 }
1240 CFDictionaryRef userInfo = CFDictionaryCreate(NULL, (const void **)&kCFErrorLocalizedDescriptionKey,
1241 (const void **)&detailedError, 1,
1242 &kCFTypeDictionaryKeyCallBacks,
1243 &kCFTypeDictionaryValueCallBacks);
1244 CFErrorRef underlyingError = CFErrorCreate(NULL, kCFErrorDomainOSStatus, status, userInfo);
1245 CFReleaseNull(userInfo);
1246 CFReleaseNull(detailedError);
1247
1248 const void *keys[] = { kCFErrorLocalizedDescriptionKey, kCFErrorUnderlyingErrorKey };
1249 const void *values[] = { simpleError, underlyingError };
1250 userInfo = CFDictionaryCreate(NULL, keys, values, 2,
1251 &kCFTypeDictionaryKeyCallBacks,
1252 &kCFTypeDictionaryValueCallBacks);
1253 CFErrorRef error = CFErrorCreate(NULL, kCFErrorDomainOSStatus, status, userInfo);
1254 CFReleaseNull(userInfo);
1255 CFReleaseNull(simpleError);
1256 CFReleaseNull(underlyingError);
1257 return error;
1258 }
1259
1260 bool SecTrustEvaluateWithError(SecTrustRef trust, CFErrorRef *error) {
1261 SecTrustResultType trustResult = kSecTrustResultInvalid;
1262 OSStatus status = SecTrustEvaluateInternal(trust, &trustResult);
1263 if (status == errSecSuccess && (trustResult == kSecTrustResultProceed || trustResult == kSecTrustResultUnspecified)) {
1264 if (error) {
1265 *error = NULL;
1266 }
1267 return true;
1268 }
1269 if (error) {
1270 if (status != errSecSuccess) {
1271 *error = SecCopyLastError(status);
1272 } else {
1273 *error = SecTrustCopyError(trust);
1274 }
1275 }
1276 return false;
1277 }
1278
1279 OSStatus SecTrustEvaluateAsync(SecTrustRef trust,
1280 dispatch_queue_t queue, SecTrustCallback result)
1281 {
1282 CFRetainSafe(trust);
1283 dispatch_async(queue, ^{
1284 SecTrustResultType trustResult;
1285 if (errSecSuccess != SecTrustEvaluateInternal(trust, &trustResult)) {
1286 trustResult = kSecTrustResultInvalid;
1287 }
1288 result(trust, trustResult);
1289 CFReleaseSafe(trust);
1290 });
1291 return errSecSuccess;
1292 }
1293
1294
1295 OSStatus SecTrustEvaluateFastAsync(SecTrustRef trust,
1296 dispatch_queue_t queue, SecTrustCallback result)
1297 {
1298 if (trust == NULL || queue == NULL || result == NULL) {
1299 return errSecParam;
1300 }
1301
1302 dispatch_assert_queue(queue);
1303 SecTrustEvaluateIfNecessaryFastAsync(trust, queue, ^(OSStatus status) {
1304 if (status != noErr) {
1305 result(trust, kSecTrustResultInvalid);
1306 return;
1307 }
1308 __block SecTrustResultType trustResult = kSecTrustResultInvalid;
1309 dispatch_sync(trust->_trustQueue, ^{
1310 trustResult = trust->_trustResult;
1311 });
1312 SecTrustLogFailureDescription(trust, trustResult);
1313
1314
1315 result(trust, trustResult);
1316 });
1317 return errSecSuccess;
1318 }
1319
1320 OSStatus SecTrustEvaluateAsyncWithError(SecTrustRef trust, dispatch_queue_t queue, SecTrustWithErrorCallback callback)
1321 {
1322 if (trust == NULL || queue == NULL || callback == NULL) {
1323 return errSecParam;
1324 }
1325
1326 dispatch_assert_queue(queue);
1327 SecTrustEvaluateIfNecessaryFastAsync(trust, queue, ^(OSStatus status) {
1328 if (status != noErr) {
1329 CFErrorRef error = SecCopyLastError(status);
1330 callback(trust, false, error);
1331 CFReleaseNull(error);
1332 return;
1333 }
1334
1335 __block SecTrustResultType trustResult = kSecTrustResultInvalid;
1336 dispatch_sync(trust->_trustQueue, ^{
1337 trustResult = trust->_trustResult;
1338 });
1339 SecTrustLogFailureDescription(trust, trustResult);
1340
1341
1342 CFErrorRef error = SecTrustCopyError(trust);
1343 bool result = (trustResult == kSecTrustResultProceed || trustResult == kSecTrustResultUnspecified);
1344 callback(trust, result, error);
1345 CFReleaseNull(error);
1346 });
1347
1348 return errSecSuccess;
1349 }
1350
1351 static bool append_certificate_to_xpc_array(SecCertificateRef certificate, xpc_object_t xpc_certificates);
1352 static xpc_object_t copy_xpc_certificates_array(CFArrayRef certificates);
1353 xpc_object_t copy_xpc_policies_array(CFArrayRef policies);
1354 OSStatus validate_array_of_items(CFArrayRef array, CFStringRef arrayItemType, CFTypeID itemTypeID, bool required);
1355
1356 static bool append_certificate_to_xpc_array(SecCertificateRef certificate, xpc_object_t xpc_certificates) {
1357 if (!certificate) {
1358 return true; // NOOP
1359 }
1360 size_t length = SecCertificateGetLength(certificate);
1361 const uint8_t *bytes = SecCertificateGetBytePtr(certificate);
1362 if (!length || !bytes) {
1363 return false;
1364 }
1365 xpc_array_set_data(xpc_certificates, XPC_ARRAY_APPEND, bytes, length);
1366 return true;
1367 }
1368
1369 static xpc_object_t copy_xpc_certificates_array(CFArrayRef certificates) {
1370 xpc_object_t xpc_certificates = xpc_array_create(NULL, 0);
1371 if (!xpc_certificates) {
1372 return NULL;
1373 }
1374 CFIndex ix, count = CFArrayGetCount(certificates);
1375 for (ix = 0; ix < count; ++ix) {
1376 SecCertificateRef certificate = (SecCertificateRef) CFArrayGetValueAtIndex(certificates, ix);
1377 #if SECTRUST_VERBOSE_DEBUG
1378 size_t length = SecCertificateGetLength(certificate);
1379 const uint8_t *bytes = SecCertificateGetBytePtr(certificate);
1380 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);
1381 #endif
1382 if (!append_certificate_to_xpc_array(certificate, xpc_certificates)) {
1383 xpc_release(xpc_certificates);
1384 xpc_certificates = NULL;
1385 break;
1386 }
1387 }
1388 return xpc_certificates;
1389 }
1390
1391 static bool SecXPCDictionarySetCertificates(xpc_object_t message, const char *key, CFArrayRef certificates, CFErrorRef *error) {
1392 xpc_object_t xpc_certificates = copy_xpc_certificates_array(certificates);
1393 if (!xpc_certificates) {
1394 SecError(errSecAllocate, error, CFSTR("failed to create xpc_array of certificates"));
1395 return false;
1396 }
1397 xpc_dictionary_set_value(message, key, xpc_certificates);
1398 xpc_release(xpc_certificates);
1399 return true;
1400 }
1401
1402 static bool SecXPCDictionarySetPolicies(xpc_object_t message, const char *key, CFArrayRef policies, CFErrorRef *error) {
1403 xpc_object_t xpc_policies = copy_xpc_policies_array(policies);
1404 if (!xpc_policies) {
1405 SecError(errSecAllocate, error, CFSTR("failed to create xpc_array of policies"));
1406 return false;
1407 }
1408 xpc_dictionary_set_value(message, key, xpc_policies);
1409 xpc_release(xpc_policies);
1410 return true;
1411 }
1412
1413
1414 static bool CFDataAppendToXPCArray(CFDataRef data, xpc_object_t xpc_data_array, CFErrorRef *error) {
1415 if (!data)
1416 return true; // NOOP
1417
1418 size_t length = CFDataGetLength(data);
1419 const uint8_t *bytes = CFDataGetBytePtr(data);
1420 if (!length || !bytes)
1421 return SecError(errSecParam, error, CFSTR("invalid CFDataRef"));
1422
1423 xpc_array_set_data(xpc_data_array, XPC_ARRAY_APPEND, bytes, length);
1424 return true;
1425 }
1426
1427
1428 static xpc_object_t CFDataArrayCopyXPCArray(CFArrayRef data_array, CFErrorRef *error) {
1429 xpc_object_t xpc_data_array;
1430 require_action_quiet(xpc_data_array = xpc_array_create(NULL, 0), exit,
1431 SecError(errSecAllocate, error, CFSTR("failed to create xpc_array")));
1432 CFIndex ix, count = CFArrayGetCount(data_array);
1433 for (ix = 0; ix < count; ++ix) {
1434 if (!CFDataAppendToXPCArray((CFDataRef)CFArrayGetValueAtIndex(data_array, ix), xpc_data_array, error)) {
1435 xpc_release(xpc_data_array);
1436 return NULL;
1437 }
1438 }
1439
1440 exit:
1441 return xpc_data_array;
1442 }
1443
1444 static bool SecXPCDictionarySetDataArray(xpc_object_t message, const char *key, CFArrayRef data_array, CFErrorRef *error) {
1445 xpc_object_t xpc_data_array = CFDataArrayCopyXPCArray(data_array, error);
1446 if (!xpc_data_array)
1447 return false;
1448 xpc_dictionary_set_value(message, key, xpc_data_array);
1449 xpc_release(xpc_data_array);
1450 return true;
1451 }
1452
1453 static bool SecXPCDictionaryCopyChainOptional(xpc_object_t message, const char *key, CFArrayRef *path, CFErrorRef *error) {
1454 xpc_object_t xpc_path = xpc_dictionary_get_value(message, key);
1455 CFMutableArrayRef output = NULL;
1456 size_t count = 0;
1457 if (!xpc_path) {
1458 *path = NULL;
1459 return true;
1460 }
1461 require_action_quiet(xpc_get_type(xpc_path) == XPC_TYPE_ARRAY, exit, SecError(errSecDecode, error, CFSTR("xpc_path value is not an array")));
1462 require_action_quiet(count = xpc_array_get_count(xpc_path), exit, SecError(errSecDecode, error, CFSTR("xpc_path array count == 0")));
1463 output = CFArrayCreateMutable(NULL, count, &kCFTypeArrayCallBacks);
1464
1465 size_t ix;
1466 for (ix = 0; ix < count; ++ix) {
1467 SecCertificateRef certificate = SecCertificateCreateWithXPCArrayAtIndex(xpc_path, ix, error);
1468 if (certificate) {
1469 CFArrayAppendValue(output, certificate);
1470 CFReleaseNull(certificate);
1471 } else {
1472 CFReleaseNull(output);
1473 break;
1474 }
1475 }
1476
1477 exit:
1478 if (output) {
1479 *path = output;
1480 return true;
1481 }
1482 return false;
1483 }
1484
1485 static int SecXPCDictionaryGetNonZeroInteger(xpc_object_t message, const char *key, CFErrorRef *error) {
1486 int64_t value = xpc_dictionary_get_int64(message, key);
1487 if (!value) {
1488 SecError(errSecInternal, error, CFSTR("object for key %s is 0"), key);
1489 }
1490 return (int)value;
1491 }
1492
1493 static SecTrustResultType handle_trust_evaluate_xpc(enum SecXPCOperation op, CFArrayRef certificates,
1494 CFArrayRef anchors, bool anchorsOnly,
1495 bool keychainsAllowed, CFArrayRef policies, CFArrayRef responses,
1496 CFArrayRef SCTs, CFArrayRef trustedLogs,
1497 CFAbsoluteTime verifyTime, __unused CFArrayRef accessGroups, CFArrayRef exceptions,
1498 CFArrayRef *details, CFDictionaryRef *info, CFArrayRef *chain, CFErrorRef *error)
1499 {
1500 __block SecTrustResultType tr = kSecTrustResultInvalid;
1501 securityd_send_sync_and_do(op, error, ^bool(xpc_object_t message, CFErrorRef *blockError) {
1502 if (!SecXPCDictionarySetCertificates(message, kSecTrustCertificatesKey, certificates, blockError))
1503 return false;
1504 if (anchors && !SecXPCDictionarySetCertificates(message, kSecTrustAnchorsKey, anchors, blockError))
1505 return false;
1506 if (anchorsOnly)
1507 xpc_dictionary_set_bool(message, kSecTrustAnchorsOnlyKey, anchorsOnly);
1508 xpc_dictionary_set_bool(message, kSecTrustKeychainsAllowedKey, keychainsAllowed);
1509 if (!SecXPCDictionarySetPolicies(message, kSecTrustPoliciesKey, policies, blockError))
1510 return false;
1511 if (responses && !SecXPCDictionarySetDataArray(message, kSecTrustResponsesKey, responses, blockError))
1512 return false;
1513 if (SCTs && !SecXPCDictionarySetDataArray(message, kSecTrustSCTsKey, SCTs, blockError))
1514 return false;
1515 if (trustedLogs && !SecXPCDictionarySetPList(message, kSecTrustTrustedLogsKey, trustedLogs, blockError))
1516 return false;
1517 xpc_dictionary_set_double(message, kSecTrustVerifyDateKey, verifyTime);
1518 if (exceptions && !SecXPCDictionarySetPList(message, kSecTrustExceptionsKey, exceptions, blockError))
1519 return false;
1520 return true;
1521 }, ^bool(xpc_object_t response, CFErrorRef *blockError) {
1522 secdebug("trust", "response: %@", response);
1523 return SecXPCDictionaryCopyArrayOptional(response, kSecTrustDetailsKey, details, blockError) &&
1524 SecXPCDictionaryCopyDictionaryOptional(response, kSecTrustInfoKey, info, blockError) &&
1525 SecXPCDictionaryCopyChainOptional(response, kSecTrustChainKey, chain, blockError) &&
1526 ((tr = SecXPCDictionaryGetNonZeroInteger(response, kSecTrustResultKey, blockError)) != kSecTrustResultInvalid);
1527 });
1528 return tr;
1529 }
1530
1531 typedef void (^trust_handler_t)(SecTrustResultType tr, CFErrorRef error);
1532
1533 static void handle_trust_evaluate_xpc_async(dispatch_queue_t replyq, trust_handler_t trustHandler,
1534 enum SecXPCOperation op, CFArrayRef certificates,
1535 CFArrayRef anchors, bool anchorsOnly,
1536 bool keychainsAllowed, CFArrayRef policies,
1537 CFArrayRef responses, CFArrayRef SCTs, CFArrayRef trustedLogs,
1538 CFAbsoluteTime verifyTime, __unused CFArrayRef accessGroups,
1539 CFArrayRef exceptions, CFArrayRef *details,
1540 CFDictionaryRef *info, CFArrayRef *chain)
1541 {
1542 securityd_send_async_and_do(op, replyq, ^bool(xpc_object_t message, CFErrorRef *error) {
1543 if (!SecXPCDictionarySetCertificates(message, kSecTrustCertificatesKey, certificates, error))
1544 return false;
1545 if (anchors && !SecXPCDictionarySetCertificates(message, kSecTrustAnchorsKey, anchors, error))
1546 return false;
1547 if (anchorsOnly)
1548 xpc_dictionary_set_bool(message, kSecTrustAnchorsOnlyKey, anchorsOnly);
1549 xpc_dictionary_set_bool(message, kSecTrustKeychainsAllowedKey, keychainsAllowed);
1550 if (!SecXPCDictionarySetPolicies(message, kSecTrustPoliciesKey, policies, error))
1551 return false;
1552 if (responses && !SecXPCDictionarySetDataArray(message, kSecTrustResponsesKey, responses, error))
1553 return false;
1554 if (SCTs && !SecXPCDictionarySetDataArray(message, kSecTrustSCTsKey, SCTs, error))
1555 return false;
1556 if (trustedLogs && !SecXPCDictionarySetPList(message, kSecTrustTrustedLogsKey, trustedLogs, error))
1557 return false;
1558 xpc_dictionary_set_double(message, kSecTrustVerifyDateKey, verifyTime);
1559 if (exceptions && !SecXPCDictionarySetPList(message, kSecTrustExceptionsKey, exceptions, error))
1560 return false;
1561 return true;
1562 }, ^(xpc_object_t response, CFErrorRef error) {
1563 secdebug("trust", "response: %@", response);
1564 if (response == NULL || error != NULL) {
1565 trustHandler(kSecTrustResultInvalid, error);
1566 return;
1567 }
1568 SecTrustResultType tr = kSecTrustResultInvalid;
1569 CFErrorRef error2 = NULL;
1570 if (SecXPCDictionaryCopyArrayOptional(response, kSecTrustDetailsKey, details, &error2) &&
1571 SecXPCDictionaryCopyDictionaryOptional(response, kSecTrustInfoKey, info, &error2) &&
1572 SecXPCDictionaryCopyChainOptional(response, kSecTrustChainKey, chain, &error2)) {
1573 tr = SecXPCDictionaryGetNonZeroInteger(response, kSecTrustResultKey, &error2);
1574 }
1575 trustHandler(tr, error2);
1576 CFReleaseNull(error2);
1577 });
1578 }
1579
1580 OSStatus validate_array_of_items(CFArrayRef array, CFStringRef arrayItemType, CFTypeID itemTypeID, bool required) {
1581 OSStatus result = errSecSuccess;
1582 CFIndex index, count;
1583 count = (array) ? CFArrayGetCount(array) : 0;
1584 if (!count && required) {
1585 secerror("no %@ in array!", arrayItemType);
1586 result = errSecParam;
1587 }
1588 for (index = 0; index < count; index++) {
1589 CFTypeRef item = (CFTypeRef) CFArrayGetValueAtIndex(array, index);
1590 if (!item) {
1591 secerror("%@ %@ (index %d)", arrayItemType, CFSTR("reference is nil"), (int)index);
1592 result = errSecParam;
1593 continue;
1594 }
1595 if (CFGetTypeID(item) != itemTypeID) {
1596 secerror("%@ %@ (index %d)", arrayItemType, CFSTR("is not the expected CF type"), (int)index);
1597 result = errSecParam;
1598 }
1599 // certificates
1600 if (CFGetTypeID(item) == SecCertificateGetTypeID()) {
1601 SecCertificateRef certificate = (SecCertificateRef) item;
1602 CFIndex length = SecCertificateGetLength(certificate);
1603 const UInt8 *bytes = SecCertificateGetBytePtr(certificate);
1604 if (!length) {
1605 secerror("%@ %@ (index %d)", arrayItemType, CFSTR("has zero length"), (int)index);
1606 result = errSecParam;
1607 }
1608 if (!bytes) {
1609 secerror("%@ %@ (index %d)", arrayItemType, CFSTR("has nil bytes"), (int)index);
1610 result = errSecParam;
1611 }
1612 #if SECTRUST_VERBOSE_DEBUG
1613 secerror("%@[%d] of %d = %ld bytes @ 0x%lX", arrayItemType, (int)index, (int)count, (size_t)length, (uintptr_t)bytes);
1614 #endif
1615 }
1616 // policies
1617 if (CFGetTypeID(item) == SecPolicyGetTypeID()) {
1618 SecPolicyRef policy = (SecPolicyRef) item;
1619 CFStringRef oidStr = policy->_oid;
1620 if (!oidStr || (CFGetTypeID(oidStr) != CFStringGetTypeID())) {
1621 oidStr = CFSTR("has invalid OID string!");
1622 secerror("%@ %@ (index %d)", arrayItemType, oidStr, (int)index);
1623 }
1624 #if SECTRUST_VERBOSE_DEBUG
1625 secerror("%@[%d] of %d = \"%@\" 0x%lX", arrayItemType, (int)index, (int)count, oidStr, (uintptr_t)policy);
1626 #endif
1627 }
1628 }
1629 return result;
1630 }
1631
1632 static OSStatus SecTrustValidateInput(SecTrustRef trust) {
1633 OSStatus status, result = errSecSuccess;
1634
1635 // certificates (required)
1636 status = validate_array_of_items(trust->_certificates, CFSTR("certificate"), SecCertificateGetTypeID(), true);
1637 if (status) result = status;
1638 // anchors (optional)
1639 status = validate_array_of_items(trust->_anchors, CFSTR("input anchor"), SecCertificateGetTypeID(), false);
1640 if (status) result = status;
1641 // policies (required??)
1642 status = validate_array_of_items(trust->_policies, CFSTR("policy"), SecPolicyGetTypeID(), true);
1643 if (status) result = status;
1644 // _responses, _SCTs, _trustedLogs, ...
1645 // verify time: SecTrustGetVerifyTime(trust)
1646 // access groups: SecAccessGroupsGetCurrent()
1647
1648 return result;
1649 }
1650
1651 static CFArrayRef SecTrustGetCurrentAccessGroups(void) {
1652 static CFArrayRef accessGroups = NULL;
1653 static dispatch_once_t onceToken;
1654 dispatch_once(&onceToken, ^{
1655 accessGroups = CFArrayCreateForCFTypes(kCFAllocatorDefault,
1656 CFSTR("com.apple.trustd"),
1657 CFSTR("com.apple.trusttests"),
1658 NULL);
1659 });
1660 return accessGroups;
1661 }
1662
1663 static OSStatus SecTrustEvaluateIfNecessary(SecTrustRef trust) {
1664 __block OSStatus result;
1665 check(trust);
1666 if (!trust)
1667 return errSecParam;
1668
1669 __block CFAbsoluteTime verifyTime = SecTrustGetVerifyTime(trust);
1670 SecTrustAddPolicyAnchors(trust);
1671 dispatch_sync(trust->_trustQueue, ^{
1672 if (trust->_trustResult != kSecTrustResultInvalid) {
1673 result = errSecSuccess;
1674 return;
1675 }
1676
1677 trust->_trustResult = kSecTrustResultOtherError; /* to avoid potential recursion */
1678
1679 CFReleaseNull(trust->_chain);
1680 CFReleaseNull(trust->_details);
1681 CFReleaseNull(trust->_info);
1682 if (trust->_legacy_info_array) {
1683 free(trust->_legacy_info_array);
1684 trust->_legacy_info_array = NULL;
1685 }
1686 if (trust->_legacy_status_array) {
1687 free(trust->_legacy_status_array);
1688 trust->_legacy_status_array = NULL;
1689 }
1690
1691 os_activity_initiate("SecTrustEvaluateIfNecessary", OS_ACTIVITY_FLAG_DEFAULT, ^{
1692 SecTrustValidateInput(trust);
1693
1694 /* @@@ 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. */
1695 result = SecOSStatusWith(^bool (CFErrorRef *error) {
1696 trust->_trustResult = TRUSTD_XPC(sec_trust_evaluate,
1697 handle_trust_evaluate_xpc,
1698 trust->_certificates, trust->_anchors, trust->_anchorsOnly, trust->_keychainsAllowed,
1699 trust->_policies, trust->_responses, trust->_SCTs, trust->_trustedLogs,
1700 verifyTime, SecTrustGetCurrentAccessGroups(), trust->_exceptions,
1701 &trust->_details, &trust->_info, &trust->_chain, error);
1702 if (trust->_trustResult == kSecTrustResultInvalid /* TODO check domain */ &&
1703 SecErrorGetOSStatus(*error) == errSecNotAvailable &&
1704 CFArrayGetCount(trust->_certificates)) {
1705 /* We failed to talk to securityd. The only time this should
1706 happen is when we are running prior to launchd enabling
1707 registration of services. This currently happens when we
1708 are running from the ramdisk. To make ASR happy we initialize
1709 _chain and return success with a failure as the trustResult, to
1710 make it seem like we did a cert evaluation, so ASR can extract
1711 the public key from the leaf. */
1712 SecCertificateRef leafCert = (SecCertificateRef)CFArrayGetValueAtIndex(trust->_certificates, 0);
1713 CFArrayRef leafCertArray = CFArrayCreate(NULL, (const void**)&leafCert, 1, &kCFTypeArrayCallBacks);
1714 trust->_chain = leafCertArray;
1715 if (error)
1716 CFReleaseNull(*error);
1717 return true;
1718 }
1719 return trust->_trustResult != kSecTrustResultInvalid;
1720 });
1721 });
1722 });
1723 return result;
1724 }
1725
1726 // IMPORTANT: this MUST be called on the provided queue as it will call the handler synchronously
1727 // if no asynchronous work is needed
1728 static void SecTrustEvaluateIfNecessaryFastAsync(SecTrustRef trust,
1729 dispatch_queue_t queue,
1730 void (^handler)(OSStatus status)) {
1731 check(trust);
1732 check(queue);
1733 check(handler);
1734 if (handler == NULL) {
1735 return;
1736 }
1737 if (trust == NULL || queue == NULL) {
1738 handler(errSecParam);
1739 return;
1740 }
1741
1742 __block bool shouldReturnSuccess = false;
1743 __block CFAbsoluteTime verifyTime = SecTrustGetVerifyTime(trust);
1744 SecTrustAddPolicyAnchors(trust);
1745 dispatch_sync(trust->_trustQueue, ^{
1746 if (trust->_trustResult != kSecTrustResultInvalid) {
1747 shouldReturnSuccess = true;
1748 return;
1749 }
1750
1751 trust->_trustResult = kSecTrustResultOtherError; /* to avoid potential recursion */
1752
1753 CFReleaseNull(trust->_chain);
1754 CFReleaseNull(trust->_details);
1755 CFReleaseNull(trust->_info);
1756 if (trust->_legacy_info_array) {
1757 free(trust->_legacy_info_array);
1758 trust->_legacy_info_array = NULL;
1759 }
1760 if (trust->_legacy_status_array) {
1761 free(trust->_legacy_status_array);
1762 trust->_legacy_status_array = NULL;
1763 }
1764
1765 os_activity_t activity = os_activity_create("SecTrustEvaluateIfNecessaryFastAsync",
1766 OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_DEFAULT);
1767 __block struct os_activity_scope_state_s activityState;
1768 os_activity_scope_enter(activity, &activityState);
1769 os_release(activity);
1770
1771 SecTrustValidateInput(trust);
1772
1773 CFRetainSafe(trust);
1774 TRUSTD_XPC_ASYNC(sec_trust_evaluate,
1775 handle_trust_evaluate_xpc_async,
1776 queue,
1777 ^(SecTrustResultType tr, CFErrorRef error) {
1778 __block OSStatus result = errSecInternalError;
1779 dispatch_sync(trust->_trustQueue, ^{
1780 trust->_trustResult = tr;
1781 if (trust->_trustResult == kSecTrustResultInvalid /* TODO check domain */ &&
1782 SecErrorGetOSStatus(error) == errSecNotAvailable &&
1783 CFArrayGetCount(trust->_certificates)) {
1784 /* We failed to talk to securityd. The only time this should
1785 happen is when we are running prior to launchd enabling
1786 registration of services. This currently happens when we
1787 are running from the ramdisk. To make ASR happy we initialize
1788 _chain and return success with a failure as the trustResult, to
1789 make it seem like we did a cert evaluation, so ASR can extract
1790 the public key from the leaf. */
1791 SecCertificateRef leafCert = (SecCertificateRef)CFArrayGetValueAtIndex(trust->_certificates, 0);
1792 CFArrayRef leafCertArray = CFArrayCreate(NULL, (const void**)&leafCert, 1, &kCFTypeArrayCallBacks);
1793 trust->_chain = leafCertArray;
1794 result = errSecSuccess;
1795 return;
1796 }
1797 result = SecOSStatusWith(^bool (CFErrorRef *error2) {
1798 if (error2 != NULL) {
1799 *error2 = error;
1800 }
1801 return trust->_trustResult != kSecTrustResultInvalid;
1802 });
1803 });
1804 os_activity_scope_leave(&activityState);
1805 handler(result);
1806 CFReleaseSafe(trust);
1807 },
1808 trust->_certificates, trust->_anchors, trust->_anchorsOnly, trust->_keychainsAllowed,
1809 trust->_policies, trust->_responses, trust->_SCTs, trust->_trustedLogs,
1810 verifyTime, SecTrustGetCurrentAccessGroups(), trust->_exceptions,
1811 &trust->_details, &trust->_info, &trust->_chain);
1812 });
1813 if (shouldReturnSuccess) {
1814 handler(errSecSuccess);
1815 }
1816 }
1817
1818 /* Helper for the qsort below. */
1819 static int compare_strings(const void *a1, const void *a2) {
1820 CFStringRef s1 = *(CFStringRef *)a1;
1821 CFStringRef s2 = *(CFStringRef *)a2;
1822 return (int) CFStringCompare(s1, s2, kCFCompareForcedOrdering);
1823 }
1824
1825 CFStringRef SecTrustCopyFailureDescription(SecTrustRef trust) {
1826 if (!trust) {
1827 return NULL;
1828 }
1829 CFMutableStringRef reason = CFStringCreateMutable(NULL, 0);
1830 SecTrustEvaluateIfNecessary(trust);
1831 __block CFArrayRef details = NULL;
1832 dispatch_sync(trust->_trustQueue, ^{
1833 details = CFRetainSafe(trust->_details);
1834 });
1835 CFIndex pathLength = details ? CFArrayGetCount(details) : 0;
1836 for (CFIndex ix = 0; ix < pathLength; ++ix) {
1837 CFDictionaryRef detail = (CFDictionaryRef)CFArrayGetValueAtIndex(details, ix);
1838 CFIndex dCount = CFDictionaryGetCount(detail);
1839 if (dCount) {
1840 if (ix == 0)
1841 CFStringAppend(reason, CFSTR(" [leaf"));
1842 else if (ix == pathLength - 1)
1843 CFStringAppend(reason, CFSTR(" [root"));
1844 else
1845 CFStringAppendFormat(reason, NULL, CFSTR(" [ca%" PRIdCFIndex ), ix);
1846
1847 const void *keys[dCount];
1848 CFDictionaryGetKeysAndValues(detail, &keys[0], NULL);
1849 qsort(&keys[0], dCount, sizeof(keys[0]), compare_strings);
1850 for (CFIndex kix = 0; kix < dCount; ++kix) {
1851 CFStringRef key = keys[kix];
1852 const void *value = CFDictionaryGetValue(detail, key);
1853 CFStringAppendFormat(reason, NULL, CFSTR(" %@%@"), key,
1854 (CFGetTypeID(value) == CFBooleanGetTypeID()
1855 ? CFSTR("") : value));
1856 }
1857 CFStringAppend(reason, CFSTR("]"));
1858 }
1859 }
1860 CFReleaseSafe(details);
1861 return reason;
1862 }
1863
1864 #if TARGET_OS_OSX
1865 /* On OS X we need SecTrustCopyPublicKey to give us a CDSA-based SecKeyRef,
1866 so we will refer to this one internally as SecTrustCopyPublicKey_ios,
1867 and call it from SecTrustCopyPublicKey.
1868 */
1869 SecKeyRef SecTrustCopyPublicKey_ios(SecTrustRef trust)
1870 #else
1871 SecKeyRef SecTrustCopyPublicKey(SecTrustRef trust)
1872 #endif
1873 {
1874 if (!trust) {
1875 return NULL;
1876 }
1877 __block SecKeyRef publicKey = NULL;
1878 dispatch_sync(trust->_trustQueue, ^{
1879 if (trust->_publicKey) {
1880 publicKey = CFRetainSafe(trust->_publicKey);
1881 return;
1882 }
1883 SecCertificateRef leaf = (SecCertificateRef)CFArrayGetValueAtIndex(trust->_certificates, 0);
1884 trust->_publicKey = SecCertificateCopyKey(leaf);
1885 if (trust->_publicKey) {
1886 publicKey = CFRetainSafe(trust->_publicKey);
1887 }
1888 });
1889 /* If we couldn't get a public key from the leaf cert alone. */
1890 if (!publicKey) {
1891 SecTrustEvaluateIfNecessary(trust);
1892 dispatch_sync(trust->_trustQueue, ^{
1893 if (trust->_chain) {
1894 SecCertificateRef cert = (SecCertificateRef)CFArrayGetValueAtIndex(trust->_chain, 0);
1895 trust->_publicKey = SecCertificateCopyKey(cert);
1896 publicKey = CFRetainSafe(trust->_publicKey);
1897 }
1898 });
1899 }
1900 return publicKey;
1901 }
1902
1903 CFIndex SecTrustGetCertificateCount(SecTrustRef trust) {
1904 if (!trust) {
1905 return 0;
1906 }
1907 SecTrustEvaluateIfNecessary(trust);
1908 __block CFIndex certCount = 1;
1909 dispatch_sync(trust->_trustQueue, ^{
1910 if (trust->_chain) {
1911 certCount = CFArrayGetCount(trust->_chain);
1912 }
1913 });
1914 return certCount;
1915 }
1916
1917 SecCertificateRef SecTrustGetCertificateAtIndex(SecTrustRef trust,
1918 CFIndex ix) {
1919 if (!trust) {
1920 return NULL;
1921 }
1922 __block SecCertificateRef cert = NULL;
1923 if (ix == 0) {
1924 dispatch_sync(trust->_trustQueue, ^{
1925 cert = (SecCertificateRef)CFArrayGetValueAtIndex(trust->_certificates, 0);
1926 });
1927 return cert;
1928 }
1929 SecTrustEvaluateIfNecessary(trust);
1930 dispatch_sync(trust->_trustQueue, ^{
1931 if (trust->_chain) {
1932 cert = (SecCertificateRef)CFArrayGetValueAtIndex(trust->_chain, ix);
1933 }
1934 });
1935 return cert;
1936 }
1937
1938 CFDictionaryRef SecTrustCopyInfo(SecTrustRef trust) {
1939 if (!trust) {
1940 return NULL;
1941 }
1942 SecTrustEvaluateIfNecessary(trust);
1943 __block CFDictionaryRef info = NULL;
1944 dispatch_sync(trust->_trustQueue, ^{
1945 info = CFRetainSafe(trust->_info);
1946 });
1947 return info;
1948 }
1949
1950 CFArrayRef SecTrustGetTrustExceptionsArray(SecTrustRef trust) {
1951 if (!trust) {
1952 return NULL;
1953 }
1954 __block CFArrayRef exceptions = NULL;
1955 dispatch_sync(trust->_trustQueue, ^{
1956 exceptions = trust->_exceptions;
1957 });
1958 return exceptions;
1959 }
1960
1961 CFDataRef SecTrustCopyExceptions(SecTrustRef trust) {
1962 /* Stash the old exceptions and run an evaluation with no exceptions filtered. */
1963 __block CFArrayRef oldExceptions = NULL;
1964 dispatch_sync(trust->_trustQueue, ^{
1965 if (trust->_exceptions) {
1966 oldExceptions = trust->_exceptions;
1967 trust->_exceptions = NULL;
1968 }
1969 });
1970 SecTrustSetNeedsEvaluation(trust);
1971
1972 /* Create the new exceptions based on an unfiltered eval. */
1973 __block CFArrayRef details = NULL;
1974 SecTrustEvaluateIfNecessary(trust);
1975 dispatch_sync(trust->_trustQueue, ^{
1976 details = CFRetainSafe(trust->_details);
1977 });
1978 CFIndex pathLength = details ? CFArrayGetCount(details) : 0;
1979 CFMutableArrayRef exceptions = CFArrayCreateMutable(kCFAllocatorDefault, pathLength, &kCFTypeArrayCallBacks);
1980 #if TARGET_OS_IPHONE
1981 /* Fetch the current exceptions epoch and tag each exception with it. */
1982 CFErrorRef exceptionResetCountError = NULL;
1983 uint64_t exceptionResetCount = SecTrustGetExceptionResetCount(&exceptionResetCountError);
1984 secinfo("trust", "The current exceptions epoch is %llu. (%{public}s)", exceptionResetCount, exceptionResetCountError ? "Error" : "OK");
1985 CFNumberRef exceptionResetCountRef = CFNumberCreate(NULL, kCFNumberSInt64Type, &exceptionResetCount);
1986 #endif
1987 CFIndex ix;
1988 for (ix = 0; ix < pathLength; ++ix) {
1989 CFDictionaryRef detail = (CFDictionaryRef)CFArrayGetValueAtIndex(details, ix);
1990 CFIndex detailCount = CFDictionaryGetCount(detail);
1991 CFMutableDictionaryRef exception;
1992 if (ix == 0 || detailCount > 0) {
1993 exception = CFDictionaryCreateMutableCopy(kCFAllocatorDefault, detailCount + 1, detail);
1994 SecCertificateRef certificate = SecTrustGetCertificateAtIndex(trust, ix);
1995 CFDataRef digest = SecCertificateGetSHA1Digest(certificate);
1996 CFDictionaryAddValue(exception, kSecCertificateDetailSHA1Digest, digest);
1997 #if TARGET_OS_IPHONE
1998 if (exceptionResetCount && !exceptionResetCountError && exceptionResetCountRef) {
1999 CFDictionaryAddValue(exception, kSecCertificateExceptionResetCount, exceptionResetCountRef);
2000 }
2001 #endif
2002 } else {
2003 /* Add empty exception dictionaries for non leaf certs which have no exceptions to save space. */
2004 exception = (CFMutableDictionaryRef)CFDictionaryCreate(kCFAllocatorDefault, NULL, NULL, 0,
2005 &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
2006 }
2007 CFArrayAppendValue(exceptions, exception);
2008 CFReleaseNull(exception);
2009 }
2010
2011 /* Restore the stashed exceptions. */
2012 if (oldExceptions) {
2013 dispatch_sync(trust->_trustQueue, ^{
2014 trust->_exceptions = oldExceptions;
2015 });
2016 SecTrustSetNeedsEvaluation(trust);
2017 }
2018
2019 /* Remove any trailing empty dictionaries to save even more space (we skip the leaf
2020 since it will never be empty). */
2021 for (ix = pathLength; ix-- > 1;) {
2022 CFDictionaryRef exception = (CFDictionaryRef)CFArrayGetValueAtIndex(exceptions, ix);
2023 if (CFDictionaryGetCount(exception) == 0) {
2024 CFArrayRemoveValueAtIndex(exceptions, ix);
2025 } else {
2026 break;
2027 }
2028 }
2029
2030 CFDataRef encodedExceptions = CFPropertyListCreateData(kCFAllocatorDefault,
2031 exceptions, kCFPropertyListBinaryFormat_v1_0, 0, NULL);
2032 CFRelease(exceptions);
2033 CFReleaseSafe(details);
2034 #if TARGET_OS_IPHONE
2035 CFReleaseSafe(exceptionResetCountRef);
2036 #endif
2037 return encodedExceptions;
2038 }
2039
2040 #if TARGET_OS_IPHONE
2041 static bool SecTrustExceptionsValidForThisEpoch(CFArrayRef exceptions) {
2042 if (!exceptions) {
2043 return false;
2044 }
2045 CFDictionaryRef exception = (CFDictionaryRef)CFArrayGetValueAtIndex(exceptions, 0);
2046
2047 CFErrorRef currentExceptionResetCountError = NULL;
2048 uint64_t currentExceptionResetCount = SecTrustGetExceptionResetCount(&currentExceptionResetCountError);
2049 secinfo("trust", "The current exceptions epoch is %llu. (%{public}s)", currentExceptionResetCount, currentExceptionResetCountError ? "Error" : "OK");
2050 /* Fail closed: if we were unable to get the current exceptions epoch consider the exceptions invalid. */
2051 if (currentExceptionResetCountError) {
2052 secerror("Failed to get the current exceptions epoch.");
2053 return false;
2054 }
2055 /* If this is the first epoch ever there is no point in checking whether any exceptions belong in the past. */
2056 if (currentExceptionResetCount == 0) {
2057 return true;
2058 }
2059
2060 CFNumberRef resetCountRef = CFDictionaryGetValue(exception, kSecCertificateExceptionResetCount);
2061 if (!resetCountRef) {
2062 secerror("Failed to get the exception's epoch.");
2063 return false;
2064 }
2065
2066 uint64_t exceptionResetCount;
2067 if (!CFNumberGetValue(resetCountRef, kCFNumberSInt64Type, &exceptionResetCount)) {
2068 secerror("Failed to parse the current exceptions epoch as a uint64.");
2069 return false;
2070 }
2071
2072 if (exceptionResetCount != currentExceptionResetCount) {
2073 secerror("The current exception's epoch (%llu) is not the current epoch. (%llu)", exceptionResetCount, currentExceptionResetCount);
2074 return false;
2075 }
2076
2077 secinfo("trust", "Exceptions are valid for the current exceptions epoch. (%llu)", currentExceptionResetCount);
2078 return true;
2079 }
2080 #endif
2081
2082 bool SecTrustSetExceptions(SecTrustRef trust, CFDataRef encodedExceptions) {
2083 if (!trust) {
2084 return false;
2085 }
2086 CFArrayRef exceptions = NULL;
2087
2088 if (NULL != encodedExceptions) {
2089 exceptions = (CFArrayRef)CFPropertyListCreateWithData(kCFAllocatorDefault,
2090 encodedExceptions, kCFPropertyListImmutable, NULL, NULL);
2091 }
2092
2093 if (exceptions && CFGetTypeID(exceptions) != CFArrayGetTypeID()) {
2094 CFRelease(exceptions);
2095 exceptions = NULL;
2096 }
2097
2098 dispatch_sync(trust->_trustQueue, ^{
2099 CFReleaseSafe(trust->_exceptions);
2100 trust->_exceptions = exceptions;
2101 });
2102
2103 /* We changed the exceptions -- so we need to re-evaluate */
2104 SecTrustSetNeedsEvaluation(trust);
2105
2106 /* If there is a valid exception entry for our current leaf we're golden. */
2107 #if TARGET_OS_IPHONE
2108 if (SecTrustGetExceptionForCertificateAtIndex(trust, 0) && SecTrustExceptionsValidForThisEpoch(exceptions)) {
2109 #else
2110 if (SecTrustGetExceptionForCertificateAtIndex(trust, 0)) {
2111 #endif
2112 return true;
2113 }
2114
2115 /* The passed in exceptions didn't match our current leaf, so we discard it. */
2116 dispatch_sync(trust->_trustQueue, ^{
2117 CFReleaseNull(trust->_exceptions);
2118 });
2119 return false;
2120 }
2121
2122 #if TARGET_OS_OSX
2123 OSStatus
2124 SecTrustSetOptions(SecTrustRef trustRef, SecTrustOptionFlags options)
2125 {
2126 /* bridge to support API functionality for legacy callers */
2127 OSStatus status = errSecSuccess;
2128
2129 /* No options or none that trigger the exceptions behavior */
2130 if (!options ||
2131 0 == (options & (kSecTrustOptionAllowExpired |
2132 kSecTrustOptionImplicitAnchors |
2133 kSecTrustOptionAllowExpiredRoot))) {
2134 return status;
2135 }
2136
2137 __block CFMutableArrayRef exceptions = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
2138 if (!exceptions) { return errSecAllocate; }
2139
2140 /* Add the new options to the old_exceptions when those exceptions are tied to a particular cert.
2141 * If not tied to a particular cert, we reset the exceptions based on the input options. */
2142 CFArrayRef old_exceptions = SecTrustGetTrustExceptionsArray(trustRef);
2143 if (old_exceptions && SecTrustGetExceptionForCertificateAtIndex(trustRef, 0)) {
2144 CFIndex ix, count = CFArrayGetCount(old_exceptions);
2145 for (ix = 0; ix < count; ix++) {
2146 CFMutableDictionaryRef exception_dictionary = CFDictionaryCreateMutableCopy(NULL, 0, (CFDictionaryRef)CFArrayGetValueAtIndex(old_exceptions, ix));
2147 if (!exception_dictionary) { status = errSecAllocate; goto out; }
2148 if ((options & kSecTrustOptionAllowExpired) != 0) {
2149 CFDictionaryAddValue(exception_dictionary, kSecPolicyCheckTemporalValidity, kCFBooleanFalse);
2150 }
2151 if ((options & (kSecTrustOptionImplicitAnchors | kSecTrustOptionAllowExpiredRoot)) != 0) {
2152 /* Check that root is self-signed. */
2153 Boolean isSelfSigned = false;
2154 SecCertificateRef cert = SecTrustGetCertificateAtIndex(trustRef, ix);
2155 if (cert && (errSecSuccess == SecCertificateIsSelfSigned(cert, &isSelfSigned)) &&
2156 isSelfSigned) {
2157 if ((options & kSecTrustOptionImplicitAnchors) != 0) {
2158 CFDictionaryAddValue(exception_dictionary, kSecPolicyCheckAnchorTrusted, kCFBooleanFalse);
2159 } else if ((options & kSecTrustOptionAllowExpiredRoot) != 0) {
2160 CFDictionaryAddValue(exception_dictionary, kSecPolicyCheckTemporalValidity, kCFBooleanFalse);
2161 }
2162 }
2163 }
2164 CFArrayAppendValue(exceptions, exception_dictionary);
2165 CFReleaseNull(exception_dictionary);
2166 }
2167 } else {
2168 /* Create a new exceptions array. Warning, this takes advantage of implementation details of the exceptions mechanism. */
2169 CFMutableDictionaryRef exception_dictionary = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks,
2170 &kCFTypeDictionaryValueCallBacks);
2171 if (!exception_dictionary) { status = errSecAllocate; goto out; }
2172 if ((options & kSecTrustOptionAllowExpired) != 0) {
2173 CFDictionaryAddValue(exception_dictionary, kSecPolicyCheckTemporalValidity, kCFBooleanFalse);
2174 }
2175 if ((options & kSecTrustOptionAllowExpiredRoot) != 0) {
2176 CFDictionaryAddValue(exception_dictionary, kSecPolicyCheckValidRoot, kCFBooleanFalse);
2177 }
2178 if ((options & kSecTrustOptionImplicitAnchors) != 0) {
2179 CFDictionaryAddValue(exception_dictionary, kSecPolicyCheckAnchorTrusted, kCFBooleanFalse);
2180 }
2181 CFArrayAppendValue(exceptions, exception_dictionary);
2182 CFReleaseNull(exception_dictionary);
2183 }
2184
2185 /* Set exceptions */
2186 dispatch_sync(trustRef->_trustQueue, ^{
2187 CFReleaseSafe(trustRef->_exceptions);
2188 trustRef->_exceptions = CFRetainSafe(exceptions);
2189 });
2190 /* We changed the exceptions -- so we need to re-evaluate */
2191 SecTrustSetNeedsEvaluation(trustRef);
2192
2193 out:
2194 CFReleaseNull(exceptions);
2195 return status;
2196 }
2197 #endif
2198
2199 CFArrayRef SecTrustCopySummaryPropertiesAtIndex(SecTrustRef trust, CFIndex ix) {
2200 CFMutableArrayRef summary;
2201 SecCertificateRef certificate = SecTrustGetCertificateAtIndex(trust, ix);
2202 summary = SecCertificateCopySummaryProperties(certificate,
2203 SecTrustGetVerifyTime(trust));
2204 /* FIXME Add more details in the failure case. */
2205
2206 return summary;
2207 }
2208
2209 CFArrayRef SecTrustCopyDetailedPropertiesAtIndex(SecTrustRef trust, CFIndex ix) {
2210 CFArrayRef summary;
2211 SecCertificateRef certificate = SecTrustGetCertificateAtIndex(trust, ix);
2212 summary = SecCertificateCopyProperties(certificate);
2213
2214 return summary;
2215 }
2216
2217 struct TrustFailures {
2218 bool badLinkage;
2219 bool unknownCritExtn;
2220 bool untrustedAnchor;
2221 bool missingIntermediate;
2222 bool hostnameMismatch;
2223 bool policyFail;
2224 bool invalidCert;
2225 bool weakKey;
2226 bool weakHash;
2227 bool revocation;
2228 };
2229
2230 static void applyDetailProperty(const void *_key, const void *_value,
2231 void *context) {
2232 CFStringRef key = (CFStringRef)_key;
2233 struct TrustFailures *tf = (struct TrustFailures *)context;
2234 if (CFGetTypeID(_value) != CFBooleanGetTypeID()) {
2235 /* Value isn't a CFBooleanRef, oh no! */
2236 return;
2237 }
2238 CFBooleanRef value = (CFBooleanRef)_value;
2239 if (CFBooleanGetValue(value)) {
2240 /* Not an actual failure so we don't report it. */
2241 return;
2242 }
2243
2244 /* @@@ FIXME: Report a different return value when something is in the
2245 details but masked out by an exception and use that below for display
2246 purposes. */
2247 if (CFEqual(key, kSecPolicyCheckIdLinkage)) {
2248 tf->badLinkage = true;
2249 } else if (CFEqual(key, kSecPolicyCheckCriticalExtensions)) {
2250 tf->unknownCritExtn = true;
2251 } else if (CFEqual(key, kSecPolicyCheckAnchorTrusted)
2252 || CFEqual(key, kSecPolicyCheckAnchorSHA1)
2253 || CFEqual(key, kSecPolicyCheckAnchorSHA256)
2254 || CFEqual(key, kSecPolicyCheckAnchorApple)) {
2255 tf->untrustedAnchor = true;
2256 } else if (CFEqual(key, kSecPolicyCheckMissingIntermediate)) {
2257 tf->missingIntermediate = true;
2258 } else if (CFEqual(key, kSecPolicyCheckSSLHostname)) {
2259 tf->hostnameMismatch = true;
2260 } else if (CFEqual(key, kSecPolicyCheckTemporalValidity)) {
2261 tf->invalidCert = true;
2262 } else if (CFEqual(key, kSecPolicyCheckWeakKeySize)
2263 || CFEqualSafe(key, kSecPolicyCheckKeySize)
2264 || CFEqualSafe(key, kSecPolicyCheckSystemTrustedWeakKey)) {
2265 tf->weakKey = true;
2266 } else if (CFEqual(key, kSecPolicyCheckWeakSignature)
2267 || CFEqualSafe(key, kSecPolicyCheckSignatureHashAlgorithms)
2268 || CFEqualSafe(key, kSecPolicyCheckSystemTrustedWeakHash)) {
2269 tf->weakHash = true;
2270 } else if (CFEqual(key, kSecPolicyCheckRevocation)) {
2271 tf->revocation = true;
2272 } else {
2273 /* Anything else is a policy failure. */
2274 tf->policyFail = true;
2275 }
2276 }
2277
2278 static void appendError(CFMutableArrayRef properties, CFStringRef error, bool localized) {
2279 CFStringRef localizedError = NULL;
2280 if (!error) {
2281 return;
2282 } else if (localized) {
2283 //%%% "SecCertificate" should be changed to "Certificate": rdar://37517120
2284 localizedError = SecFrameworkCopyLocalizedString(error, CFSTR("SecCertificate"));
2285 } else {
2286 localizedError = (CFStringRef) CFRetainSafe(error);
2287 }
2288 appendProperty(properties, kSecPropertyTypeError, NULL, NULL,
2289 localizedError, localized);
2290 CFReleaseNull(localizedError);
2291 }
2292
2293 #if TARGET_OS_OSX
2294 /* OS X properties array has a different structure and is implemented SecTrust.cpp. */
2295 CFArrayRef SecTrustCopyProperties_ios(SecTrustRef trust)
2296 #else
2297 CFArrayRef SecTrustCopyProperties(SecTrustRef trust)
2298 #endif
2299 {
2300 if (!trust) {
2301 return NULL;
2302 }
2303 SecTrustEvaluateIfNecessary(trust);
2304 bool localized = true;
2305 __block CFArrayRef details = NULL;
2306 dispatch_sync(trust->_trustQueue, ^{
2307 details = CFRetainSafe(trust->_details);
2308 });
2309 if (!details) {
2310 return NULL;
2311 }
2312
2313 struct TrustFailures tf = {};
2314
2315 CFIndex ix, count = CFArrayGetCount(details);
2316 for (ix = 0; ix < count; ++ix) {
2317 CFDictionaryRef detail = (CFDictionaryRef)
2318 CFArrayGetValueAtIndex(details, ix);
2319 /* We now have a detail dictionary for certificate at index ix, with
2320 a key value pair for each failed policy check. Let's convert it
2321 from Ro-Man form into something a Hu-Man can understand. */
2322 CFDictionaryApplyFunction(detail, applyDetailProperty, &tf);
2323 }
2324
2325 CFMutableArrayRef properties = CFArrayCreateMutable(kCFAllocatorDefault, 0,
2326 &kCFTypeArrayCallBacks);
2327 /* The badLinkage and unknownCritExtn failures are short circuited, since
2328 you can't recover from those errors. */
2329 if (tf.badLinkage) {
2330 appendError(properties, CFSTR("Invalid certificate chain linkage."), localized);
2331 } else if (tf.unknownCritExtn) {
2332 appendError(properties, CFSTR("One or more unsupported critical extensions found."), localized);
2333 } else {
2334 if (tf.untrustedAnchor) {
2335 appendError(properties, CFSTR("Root certificate is not trusted."), localized);
2336 }
2337 if (tf.missingIntermediate) {
2338 appendError(properties, CFSTR("Unable to build chain to root certificate."), localized);
2339 }
2340 if (tf.hostnameMismatch) {
2341 appendError(properties, CFSTR("Hostname mismatch."), localized);
2342 }
2343 if (tf.policyFail) {
2344 appendError(properties, CFSTR("Policy requirements not met."), localized);
2345 }
2346 if (tf.invalidCert) {
2347 appendError(properties, CFSTR("One or more certificates have expired or are not valid yet."), localized);
2348 }
2349 if (tf.weakKey) {
2350 appendError(properties, CFSTR("One or more certificates is using a weak key size."), localized);
2351 }
2352 if (tf.weakHash) {
2353 appendError(properties, CFSTR("One or more certificates is using a weak signature algorithm."), localized);
2354 }
2355 if (tf.revocation) {
2356 appendError(properties, CFSTR("One or more certificates have been revoked."), localized);
2357 }
2358 }
2359
2360 if (CFArrayGetCount(properties) == 0) {
2361 /* The certificate chain is trusted, return an empty plist */
2362 CFReleaseNull(properties);
2363 }
2364
2365 CFReleaseNull(details);
2366 return properties;
2367 }
2368
2369 #if TARGET_OS_OSX
2370 static void _AppendStatusCode(CFMutableArrayRef array, OSStatus statusCode) {
2371 if (!array) {
2372 return;
2373 }
2374 SInt32 num = statusCode;
2375 CFNumberRef numRef = CFNumberCreate(NULL, kCFNumberSInt32Type, &num);
2376 if (!numRef) {
2377 return;
2378 }
2379 CFArrayAppendValue(array, numRef);
2380 CFRelease(numRef);
2381 }
2382 #endif
2383
2384 static CFArrayRef _SecTrustCopyDetails(SecTrustRef trust) {
2385 if (!trust) {
2386 return NULL;
2387 }
2388 __block CFArrayRef details = NULL;
2389 dispatch_sync(trust->_trustQueue, ^{
2390 details = CFRetainSafe(trust->_details);
2391 });
2392 #if TARGET_OS_OSX
2393 // Include status codes in the per-certificate details (rdar://27930542)
2394 CFMutableArrayRef newDetails = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
2395 if (!newDetails) {
2396 CFReleaseSafe(details);
2397 return NULL;
2398 }
2399 CFIndex index, chainLen = (details) ? CFArrayGetCount(details) : 0;
2400 for (index = 0; index < chainLen; index++) {
2401 CFDictionaryRef detailDict = CFArrayGetValueAtIndex(details, index);
2402 CFMutableDictionaryRef newDict = CFDictionaryCreateMutableCopy(NULL, 0, detailDict);
2403 CFMutableArrayRef statusCodes = CFArrayCreateMutable(kCFAllocatorDefault,
2404 0, &kCFTypeArrayCallBacks);
2405 if (statusCodes) {
2406 CFIndex i, numCodes = 0;
2407 SInt32 *codes = SecTrustCopyStatusCodes(trust, index, &numCodes);
2408 if (codes) {
2409 for (i = 0; i < numCodes; i++) {
2410 OSStatus scode = (OSStatus)codes[i];
2411 _AppendStatusCode(statusCodes, scode);
2412 }
2413 free(codes);
2414 }
2415 if (CFArrayGetCount(statusCodes) > 0) {
2416 CFDictionarySetValue(newDict, kSecCertificateDetailStatusCodes, statusCodes);
2417 }
2418 CFRelease(statusCodes);
2419 }
2420 if (newDict) {
2421 CFArrayAppendValue(newDetails, newDict);
2422 CFRelease(newDict);
2423 }
2424 }
2425 CFReleaseSafe(details);
2426 return newDetails;
2427 #else
2428 return details;
2429 #endif
2430 }
2431
2432 CFDictionaryRef SecTrustCopyResult(SecTrustRef trust) {
2433 // Builds and returns a dictionary of evaluation results.
2434 if (!trust) {
2435 return NULL;
2436 }
2437 __block CFMutableDictionaryRef results = CFDictionaryCreateMutable(NULL, 0,
2438 &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
2439
2440 SecTrustEvaluateIfNecessary(trust);
2441 __block CFArrayRef details = _SecTrustCopyDetails(trust);
2442
2443 dispatch_sync(trust->_trustQueue, ^{
2444 // kSecTrustResultDetails (per-cert results)
2445 if (details) {
2446 CFDictionarySetValue(results, (const void *)kSecTrustResultDetails, (const void *)details);
2447 CFRelease(details);
2448 }
2449
2450 // kSecTrustResultValue (overall trust result)
2451 CFNumberRef numValue = CFNumberCreate(NULL, kCFNumberSInt32Type, &trust->_trustResult);
2452 if (numValue) {
2453 CFDictionarySetValue(results, (const void *)kSecTrustResultValue, (const void *)numValue);
2454 CFRelease(numValue);
2455 }
2456 CFDictionaryRef info = trust->_info;
2457 if (trust->_trustResult == kSecTrustResultInvalid || !info) {
2458 return; // we have nothing more to add
2459 }
2460
2461 // kSecTrustEvaluationDate
2462 CFDateRef evaluationDate = trust->_verifyDate;
2463 if (evaluationDate) {
2464 CFDictionarySetValue(results, (const void *)kSecTrustEvaluationDate, (const void *)evaluationDate);
2465 }
2466
2467 // kSecTrustCertificateTransparency
2468 CFBooleanRef ctValue;
2469 if (CFDictionaryGetValueIfPresent(info, kSecTrustInfoCertificateTransparencyKey, (const void **)&ctValue)) {
2470 CFDictionarySetValue(results, (const void *)kSecTrustCertificateTransparency, (const void *)ctValue);
2471 }
2472
2473 // kSecTrustExtendedValidation
2474 CFBooleanRef evValue;
2475 if (CFDictionaryGetValueIfPresent(info, kSecTrustInfoExtendedValidationKey, (const void **)&evValue)) {
2476 CFDictionarySetValue(results, (const void *)kSecTrustExtendedValidation, (const void *)evValue);
2477 }
2478
2479 // kSecTrustOrganizationName
2480 CFStringRef organizationName;
2481 if (CFDictionaryGetValueIfPresent(info, kSecTrustInfoCompanyNameKey, (const void **)&organizationName)) {
2482 CFDictionarySetValue(results, (const void *)kSecTrustOrganizationName, (const void *)organizationName);
2483 }
2484
2485 // kSecTrustRevocationChecked
2486 CFBooleanRef revocationChecked;
2487 if (CFDictionaryGetValueIfPresent(info, kSecTrustRevocationChecked, (const void **)&revocationChecked)) {
2488 CFDictionarySetValue(results, (const void *)kSecTrustRevocationChecked, (const void *)revocationChecked);
2489 }
2490
2491 // kSecTrustRevocationReason
2492 CFNumberRef revocationReason;
2493 if (CFDictionaryGetValueIfPresent(info, kSecTrustRevocationReason, (const void **)&revocationReason)) {
2494 CFDictionarySetValue(results, (const void *)kSecTrustRevocationReason, (const void *)revocationReason);
2495 }
2496
2497 // kSecTrustRevocationValidUntilDate
2498 CFDateRef validUntilDate;
2499 if (CFDictionaryGetValueIfPresent(info, kSecTrustRevocationValidUntilDate, (const void **)&validUntilDate)) {
2500 CFDictionarySetValue(results, (const void *)kSecTrustRevocationValidUntilDate, (const void *)validUntilDate);
2501 }
2502 });
2503
2504 return results;
2505 }
2506
2507 #define do_if_registered(sdp, ...) if (gTrustd && gTrustd->sdp) { return gTrustd->sdp(__VA_ARGS__); }
2508
2509 static bool xpc_dictionary_entry_is_type(xpc_object_t dictionary, const char *key, xpc_type_t type) {
2510 xpc_object_t value = xpc_dictionary_get_value(dictionary, key);
2511 return value && (xpc_get_type(value) == type);
2512 }
2513
2514 static uint64_t do_ota_pki_op (enum SecXPCOperation op, CFErrorRef *error) {
2515 uint64_t num = 0;
2516 xpc_object_t message = securityd_create_message(op, error);
2517 if (message) {
2518 xpc_object_t response = securityd_message_with_reply_sync(message, error);
2519 if (response && xpc_dictionary_entry_is_type(response, kSecXPCKeyResult, XPC_TYPE_UINT64)) {
2520 num = (int64_t) xpc_dictionary_get_uint64(response, kSecXPCKeyResult);
2521 }
2522 if (response && error && xpc_dictionary_entry_is_type(response, kSecXPCKeyError, XPC_TYPE_DICTIONARY)) {
2523 xpc_object_t xpc_error = xpc_dictionary_get_value(response, kSecXPCKeyError);
2524 if (xpc_error) {
2525 *error = SecCreateCFErrorWithXPCObject(xpc_error);
2526 }
2527 }
2528 xpc_release_safe(message);
2529 xpc_release_safe(response);
2530 }
2531 return num;
2532 }
2533
2534 // version 0 -> error, so we need to start at version 1 or later.
2535 uint64_t SecTrustGetTrustStoreVersionNumber(CFErrorRef *error) {
2536 do_if_registered(sec_ota_pki_trust_store_version, error);
2537
2538 os_activity_t activity = os_activity_create("SecTrustGetTrustStoreVersionNumber", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_DEFAULT);
2539 os_activity_scope(activity);
2540
2541 uint64_t num = do_ota_pki_op(sec_ota_pki_trust_store_version_id, error);
2542
2543 os_release(activity);
2544 return num;
2545 }
2546
2547 uint64_t SecTrustGetAssetVersionNumber(CFErrorRef *error) {
2548 do_if_registered(sec_ota_pki_asset_version, error);
2549
2550 os_activity_t activity = os_activity_create("SecTrustGetAssetVersionNumber", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_DEFAULT);
2551 os_activity_scope(activity);
2552
2553 uint64_t num = do_ota_pki_op(sec_ota_pki_asset_version_id, error);
2554
2555 os_release(activity);
2556 return num;
2557 }
2558
2559 uint64_t SecTrustOTAPKIGetUpdatedAsset(CFErrorRef *error) {
2560 do_if_registered(sec_ota_pki_get_new_asset, error);
2561
2562 os_activity_t activity = os_activity_create("SecTrustOTAPKIGetUpdatedAsset", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_DEFAULT);
2563 os_activity_scope(activity);
2564
2565 uint64_t num = do_ota_pki_op(kSecXPCOpOTAPKIGetNewAsset, error);
2566
2567 os_release(activity);
2568 return num;
2569 }
2570
2571 uint64_t SecTrustOTASecExperimentGetUpdatedAsset(CFErrorRef *error) {
2572 do_if_registered(sec_ota_secexperiment_get_new_asset, error);
2573
2574 os_activity_t activity = os_activity_create("SecTrustOTASecExperimentGetUpdatedAsset", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_DEFAULT);
2575 os_activity_scope(activity);
2576
2577 uint64_t num = do_ota_pki_op(kSecXPCOpOTASecExperimentGetNewAsset, error);
2578
2579 os_release(activity);
2580 return num;
2581 }
2582
2583 CFDictionaryRef SecTrustOTASecExperimentCopyAsset(CFErrorRef *error) {
2584 __block CFDictionaryRef result = NULL;
2585 do_if_registered(sec_ota_secexperiment_get_asset, error);
2586
2587 securityd_send_sync_and_do(kSecXPCOpOTASecExperimentGetAsset, error, ^bool(xpc_object_t message, CFErrorRef *blockError) {
2588 // input: set message parameters here
2589 return true;
2590 }, ^bool(xpc_object_t response, CFErrorRef *blockError) {
2591 // output: get array from response object
2592 xpc_object_t xpc_dict = NULL;
2593 if (response) {
2594 xpc_dict = xpc_dictionary_get_value(response, kSecXPCKeyResult);
2595 }
2596 if (xpc_dict && (xpc_get_type(xpc_dict) == XPC_TYPE_DICTIONARY)) {
2597 result = (CFDictionaryRef)_CFXPCCreateCFObjectFromXPCObject(xpc_dict);
2598 } else {
2599 return SecError(errSecInternal, blockError, CFSTR("Unable to get SecExperiment Assets"));
2600 }
2601 return result != NULL;
2602 });
2603 return result;
2604 }
2605
2606 bool SecTrustReportTLSAnalytics(CFStringRef eventName, xpc_object_t eventAttributes, CFErrorRef *error) {
2607 if (!eventName || !eventAttributes) {
2608 return false;
2609 }
2610 do_if_registered(sec_networking_analytics_report, eventName, eventAttributes, error);
2611
2612 os_activity_t activity = os_activity_create("SecTrustReportTLSAnalytics", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_DEFAULT);
2613 os_activity_scope(activity);
2614
2615 __block bool result = false;
2616 securityd_send_sync_and_do(kSecXPCOpNetworkingAnalyticsReport, error, ^bool(xpc_object_t message, CFErrorRef *block_error) {
2617 if (!SecXPCDictionarySetString(message, kSecTrustEventNameKey, eventName, block_error)) {
2618 return false;
2619 }
2620 xpc_dictionary_set_value(message, kSecTrustEventAttributesKey, eventAttributes);
2621 return true;
2622 }, ^bool(xpc_object_t response, CFErrorRef *block_error) {
2623 result = SecXPCDictionaryGetBool(response, kSecXPCKeyResult, block_error);
2624 return true;
2625 });
2626
2627 os_release(activity);
2628 return result;
2629 }
2630
2631 bool SecTrustReportNetworkingAnalytics(const char *eventNameString, xpc_object_t eventAttributes) {
2632 if (!eventNameString || !eventAttributes) {
2633 return false;
2634 }
2635
2636 CFStringRef eventName = CFStringCreateWithCString(kCFAllocatorDefault, eventNameString, kCFStringEncodingUTF8);
2637 if (!eventName) {
2638 secerror("CFStringCreateWithCString failed");
2639 return false;
2640 }
2641
2642 CFErrorRef error = NULL;
2643 if (gTrustd && gTrustd->sec_networking_analytics_report) {
2644 bool result = gTrustd->sec_networking_analytics_report(eventName, eventAttributes, &error);
2645 if (error != NULL) {
2646 secerror("SecTrustReportNetworkingAnalytics failed with error: %d", (int)CFErrorGetCode(error));
2647 }
2648 CFReleaseNull(eventName);
2649 CFReleaseNull(error);
2650 return result;
2651 }
2652
2653 os_activity_t activity = os_activity_create("SecTrustReportNetworkingAnalytics", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_DEFAULT);
2654 os_activity_scope(activity);
2655
2656 __block bool result = false;
2657 securityd_send_sync_and_do(kSecXPCOpNetworkingAnalyticsReport, &error, ^bool(xpc_object_t message, CFErrorRef *block_error) {
2658 if (!SecXPCDictionarySetString(message, kSecTrustEventNameKey, eventName, block_error)) {
2659 return false;
2660 }
2661 xpc_dictionary_set_value(message, kSecTrustEventAttributesKey, eventAttributes);
2662 return true;
2663 }, ^bool(xpc_object_t response, CFErrorRef *block_error) {
2664 result = SecXPCDictionaryGetBool(response, kSecXPCKeyResult, block_error);
2665 return true;
2666 });
2667
2668 if (error != NULL) {
2669 secerror("SecTrustReportNetworkingAnalytics failed with error: %d", (int)CFErrorGetCode(error));
2670 }
2671 CFReleaseNull(error);
2672 CFReleaseNull(eventName);
2673
2674 os_release(activity);
2675 return result;
2676 }
2677
2678
2679 /*
2680 * This function performs an evaluation of the leaf certificate only, and
2681 * does so in the process that called it. Its primary use is in SecItemCopyMatching
2682 * when kSecMatchPolicy is in the dictionary.
2683 */
2684 OSStatus SecTrustEvaluateLeafOnly(SecTrustRef trust, SecTrustResultType *result) {
2685 if (!trust) {
2686 return errSecParam;
2687 }
2688 OSStatus status = errSecSuccess;
2689 SecTrustResultType trustResult = kSecTrustResultInvalid;
2690 if((status = SecTrustValidateInput(trust))) {
2691 return status;
2692 }
2693
2694 struct OpaqueSecLeafPVC pvc;
2695 SecCertificateRef leaf = SecTrustGetCertificateAtIndex(trust, 0);
2696 __block CFArrayRef policies = NULL;
2697 dispatch_sync(trust->_trustQueue, ^{
2698 policies = CFRetainSafe(trust->_policies);
2699 });
2700 SecLeafPVCInit(&pvc, leaf, policies, SecTrustGetVerifyTime(trust));
2701
2702 if(!SecLeafPVCLeafChecks(&pvc)) {
2703 trustResult = kSecTrustResultRecoverableTrustFailure;
2704 } else {
2705 trustResult = kSecTrustResultUnspecified;
2706 }
2707
2708 /* Set other result context information */
2709 dispatch_sync(trust->_trustQueue, ^{
2710 trust->_trustResult = trustResult;
2711 trust->_details = CFRetainSafe(pvc.details);
2712 trust->_info = CFDictionaryCreateMutable(kCFAllocatorDefault, 0,
2713 &kCFTypeDictionaryKeyCallBacks,
2714 &kCFTypeDictionaryValueCallBacks);
2715 CFMutableArrayRef leafCert = CFArrayCreateMutableCopy(NULL, 1, trust->_certificates);
2716 trust->_chain = leafCert;
2717 });
2718
2719 SecLeafPVCDelete(&pvc);
2720
2721 /* log to syslog when there is a trust failure */
2722 if (trustResult != kSecTrustResultUnspecified) {
2723 CFStringRef failureDesc = SecTrustCopyFailureDescription(trust);
2724 secerror("%@", failureDesc);
2725 CFRelease(failureDesc);
2726 }
2727
2728 if (result) {
2729 *result = trustResult;
2730 }
2731
2732 CFReleaseSafe(policies);
2733 return status;
2734 }
2735
2736 static void deserializeCert(const void *value, void *context) {
2737 CFDataRef certData = (CFDataRef)value;
2738 if (isData(certData)) {
2739 SecCertificateRef cert = SecCertificateCreateWithData(NULL, certData);
2740 if (cert) {
2741 CFArrayAppendValue((CFMutableArrayRef)context, cert);
2742 CFRelease(cert);
2743 }
2744 }
2745 }
2746
2747 static CF_RETURNS_RETAINED CFArrayRef SecCertificateArrayDeserialize(CFArrayRef serializedCertificates) {
2748 CFMutableArrayRef result = NULL;
2749 require_quiet(isArray(serializedCertificates), errOut);
2750 CFIndex count = CFArrayGetCount(serializedCertificates);
2751 result = CFArrayCreateMutable(kCFAllocatorDefault, count, &kCFTypeArrayCallBacks);
2752 CFRange all_certs = { 0, count };
2753 CFArrayApplyFunction(serializedCertificates, all_certs, deserializeCert, result);
2754 errOut:
2755 return result;
2756 }
2757
2758 static void serializeCertificate(const void *value, void *context) {
2759 SecCertificateRef cert = (SecCertificateRef)value;
2760 if (cert && SecCertificateGetTypeID() == CFGetTypeID(cert)) {
2761 CFDataRef certData = SecCertificateCopyData(cert);
2762 if (certData) {
2763 CFArrayAppendValue((CFMutableArrayRef)context, certData);
2764 CFRelease(certData);
2765 }
2766 }
2767 }
2768
2769 static CF_RETURNS_RETAINED CFArrayRef SecCertificateArraySerialize(CFArrayRef certificates) {
2770 CFMutableArrayRef result = NULL;
2771 require_quiet(isArray(certificates), errOut);
2772 CFIndex count = CFArrayGetCount(certificates);
2773 result = CFArrayCreateMutable(NULL, count, &kCFTypeArrayCallBacks);
2774 CFRange all_certificates = { 0, count};
2775 CFArrayApplyFunction(certificates, all_certificates, serializeCertificate, result);
2776 errOut:
2777 return result;
2778 }
2779
2780 static CFPropertyListRef SecTrustCopyPlist(SecTrustRef trust) {
2781 __block CFMutableDictionaryRef output = NULL;
2782 output = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks,
2783 &kCFTypeDictionaryValueCallBacks);
2784
2785 dispatch_sync(trust->_trustQueue, ^{
2786 if (trust->_certificates) {
2787 CFArrayRef serializedCerts = SecCertificateArraySerialize(trust->_certificates);
2788 if (serializedCerts) {
2789 CFDictionaryAddValue(output, CFSTR(kSecTrustCertificatesKey), serializedCerts);
2790 CFRelease(serializedCerts);
2791 }
2792 }
2793 if (trust->_anchors) {
2794 CFArrayRef serializedAnchors = SecCertificateArraySerialize(trust->_anchors);
2795 if (serializedAnchors) {
2796 CFDictionaryAddValue(output, CFSTR(kSecTrustAnchorsKey), serializedAnchors);
2797 CFRelease(serializedAnchors);
2798 }
2799 }
2800 if (trust->_policies) {
2801 CFArrayRef serializedPolicies = SecPolicyArrayCreateSerialized(trust->_policies);
2802 if (serializedPolicies) {
2803 CFDictionaryAddValue(output, CFSTR(kSecTrustPoliciesKey), serializedPolicies);
2804 CFRelease(serializedPolicies);
2805 }
2806 }
2807 if (trust->_responses) {
2808 CFDictionaryAddValue(output, CFSTR(kSecTrustResponsesKey), trust->_responses);
2809 }
2810 if (trust->_SCTs) {
2811 CFDictionaryAddValue(output, CFSTR(kSecTrustSCTsKey), trust->_SCTs);
2812 }
2813 if (trust->_trustedLogs) {
2814 CFDictionaryAddValue(output, CFSTR(kSecTrustTrustedLogsKey), trust->_trustedLogs);
2815 }
2816 if (trust->_verifyDate) {
2817 CFDictionaryAddValue(output, CFSTR(kSecTrustVerifyDateKey), trust->_verifyDate);
2818 }
2819 if (trust->_chain) {
2820 CFArrayRef serializedCerts = SecCertificateArraySerialize(trust->_chain);
2821 if (serializedCerts) {
2822 CFDictionaryAddValue(output, CFSTR(kSecTrustChainKey), serializedCerts);
2823 CFRelease(serializedCerts);
2824 }
2825 }
2826 if (trust->_details) {
2827 CFDictionaryAddValue(output, CFSTR(kSecTrustDetailsKey), trust->_details);
2828 }
2829 if (trust->_info) {
2830 CFDictionaryAddValue(output, CFSTR(kSecTrustInfoKey), trust->_info);
2831 }
2832 if (trust->_exceptions) {
2833 CFDictionaryAddValue(output, CFSTR(kSecTrustExceptionsKey), trust->_exceptions);
2834 }
2835 CFNumberRef trustResult = CFNumberCreate(NULL, kCFNumberSInt32Type, &trust->_trustResult);
2836 if (trustResult) {
2837 CFDictionaryAddValue(output, CFSTR(kSecTrustResultKey), trustResult);
2838 }
2839 CFReleaseNull(trustResult);
2840 if (trust->_anchorsOnly) {
2841 CFDictionaryAddValue(output, CFSTR(kSecTrustAnchorsOnlyKey), kCFBooleanTrue);
2842 } else {
2843 CFDictionaryAddValue(output, CFSTR(kSecTrustAnchorsOnlyKey), kCFBooleanFalse);
2844 }
2845 if (trust->_keychainsAllowed) {
2846 CFDictionaryAddValue(output, CFSTR(kSecTrustKeychainsAllowedKey), kCFBooleanTrue);
2847 } else {
2848 CFDictionaryAddValue(output, CFSTR(kSecTrustKeychainsAllowedKey), kCFBooleanFalse);
2849 }
2850 });
2851
2852 return output;
2853 }
2854
2855 CFDataRef SecTrustSerialize(SecTrustRef trust, CFErrorRef *error) {
2856 CFPropertyListRef plist = NULL;
2857 CFDataRef derTrust = NULL;
2858 require_action_quiet(trust, out,
2859 SecError(errSecParam, error, CFSTR("null trust input")));
2860 require_action_quiet(plist = SecTrustCopyPlist(trust), out,
2861 SecError(errSecDecode, error, CFSTR("unable to create trust plist")));
2862 require_quiet(derTrust = CFPropertyListCreateDERData(NULL, plist, error), out);
2863
2864 out:
2865 CFReleaseNull(plist);
2866 return derTrust;
2867 }
2868
2869 static OSStatus SecTrustCreateFromPlist(CFPropertyListRef plist, SecTrustRef CF_RETURNS_RETAINED *trust) {
2870 OSStatus status = errSecParam;
2871 SecTrustRef output = NULL;
2872 CFTypeRef serializedCertificates = NULL, serializedPolicies = NULL, serializedAnchors = NULL;
2873 CFNumberRef trustResultNum = NULL;
2874 CFArrayRef certificates = NULL, policies = NULL, anchors = NULL, responses = NULL,
2875 SCTs = NULL, trustedLogs = NULL, details = NULL, exceptions = NULL, chain = NULL;
2876 CFDateRef verifyDate = NULL;
2877 CFDictionaryRef info = NULL;
2878
2879 require_quiet(CFDictionaryGetTypeID() == CFGetTypeID(plist), out);
2880 require_quiet(serializedCertificates = CFDictionaryGetValue(plist, CFSTR(kSecTrustCertificatesKey)), out);
2881 require_quiet(certificates = SecCertificateArrayDeserialize(serializedCertificates), out);
2882 require_quiet(serializedPolicies = CFDictionaryGetValue(plist, CFSTR(kSecTrustPoliciesKey)), out);
2883 require_quiet(policies = SecPolicyArrayCreateDeserialized(serializedPolicies), out);
2884 require_noerr_quiet(status = SecTrustCreateWithCertificates(certificates, policies, &output), out);
2885
2886 serializedAnchors = CFDictionaryGetValue(plist, CFSTR(kSecTrustAnchorsKey));
2887 if (isArray(serializedAnchors)) {
2888 anchors = SecCertificateArrayDeserialize(serializedAnchors);
2889 output->_anchors = anchors;
2890 }
2891 responses = CFDictionaryGetValue(plist, CFSTR(kSecTrustResponsesKey));
2892 if (isArray(responses)) {
2893 output->_responses = CFRetainSafe(responses);
2894 }
2895 SCTs = CFDictionaryGetValue(plist, CFSTR(kSecTrustSCTsKey));
2896 if (isArray(SCTs)) {
2897 output->_SCTs = CFRetainSafe(SCTs);
2898 }
2899 trustedLogs = CFDictionaryGetValue(plist, CFSTR(kSecTrustTrustedLogsKey));
2900 if (isArray(trustedLogs)) {
2901 output->_trustedLogs = CFRetainSafe(trustedLogs);
2902 }
2903 verifyDate = CFDictionaryGetValue(plist, CFSTR(kSecTrustVerifyDateKey));
2904 if (isDate(verifyDate)) {
2905 output->_verifyDate = CFRetainSafe(verifyDate);
2906 }
2907 chain = CFDictionaryGetValue(plist, CFSTR(kSecTrustChainKey));
2908 if (isArray(chain)) {
2909 output->_chain = SecCertificateArrayDeserialize(chain);
2910 }
2911 details = CFDictionaryGetValue(plist, CFSTR(kSecTrustDetailsKey));
2912 if (isArray(details)) {
2913 output->_details = CFRetainSafe(details);
2914 }
2915 info = CFDictionaryGetValue(plist, CFSTR(kSecTrustInfoKey));
2916 if (isDictionary(info)) {
2917 output->_info = CFRetainSafe(info);
2918 }
2919 exceptions = CFDictionaryGetValue(plist, CFSTR(kSecTrustExceptionsKey));
2920 if (isArray(exceptions)) {
2921 output->_exceptions = CFRetainSafe(exceptions);
2922 }
2923 int32_t trustResult = -1;
2924 trustResultNum = CFDictionaryGetValue(plist, CFSTR(kSecTrustResultKey));
2925 if (isNumber(trustResultNum) && CFNumberGetValue(trustResultNum, kCFNumberSInt32Type, &trustResult) &&
2926 (trustResult >= 0)) {
2927 output->_trustResult = trustResult;
2928 } else {
2929 status = errSecParam;
2930 }
2931 if (CFDictionaryGetValue(plist, CFSTR(kSecTrustAnchorsOnlyKey)) == kCFBooleanTrue) {
2932 output->_anchorsOnly = true;
2933 } /* false is set by default */
2934 if (CFDictionaryGetValue(plist, CFSTR(kSecTrustKeychainsAllowedKey)) == kCFBooleanFalse) {
2935 output->_keychainsAllowed = false;
2936 } /* true is set by default */
2937
2938 out:
2939 if (errSecSuccess == status && trust) {
2940 *trust = output;
2941 }
2942 CFReleaseNull(policies);
2943 CFReleaseNull(certificates);
2944 return status;
2945 }
2946
2947 SecTrustRef SecTrustDeserialize(CFDataRef serializedTrust, CFErrorRef *error) {
2948 SecTrustRef trust = NULL;
2949 CFPropertyListRef plist = NULL;
2950 OSStatus status = errSecSuccess;
2951 require_action_quiet(serializedTrust, out,
2952 SecError(errSecParam, error, CFSTR("null serialized trust input")));
2953 require_quiet(plist = CFPropertyListCreateWithDERData(NULL, serializedTrust,
2954 kCFPropertyListImmutable, NULL, error), out);
2955 require_noerr_action_quiet(status = SecTrustCreateFromPlist(plist, &trust), out,
2956 SecError(status, error, CFSTR("unable to create trust ref")));
2957
2958 out:
2959 CFReleaseNull(plist);
2960 return trust;
2961 }
2962
2963 #if TARGET_OS_IPHONE
2964 static uint64_t to_uint_error_request(enum SecXPCOperation op, CFErrorRef *error) {
2965 __block uint64_t result = 0;
2966
2967 securityd_send_sync_and_do(op, error, NULL, ^bool(xpc_object_t response, CFErrorRef *localError) {
2968 uint64_t temp_result = xpc_dictionary_get_uint64(response, kSecXPCKeyResult);
2969 /* plists do not support unsigned integers. */
2970 if (temp_result <= INT64_MAX) {
2971 result = temp_result;
2972 } else {
2973 secerror("Invalid exceptions epoch.");
2974 if (error) {
2975 *error = CFErrorCreate(NULL, kCFErrorDomainPOSIX, ERANGE, NULL);
2976 }
2977 }
2978 if (error && localError && *localError) {
2979 *error = *localError;
2980 }
2981 return result;
2982 });
2983
2984 return result;
2985 }
2986
2987 uint64_t SecTrustGetExceptionResetCount(CFErrorRef *error) {
2988 os_activity_t activity = os_activity_create("SecTrustExceptionGetResetCount", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_DEFAULT);
2989 os_activity_scope(activity);
2990 uint64_t exceptionResetCount = TRUSTD_XPC(sec_trust_get_exception_reset_count, to_uint_error_request, error);
2991 os_release(activity);
2992 if (error && *error) {
2993 secerror("Failed to get the exceptions epoch.");
2994 }
2995 secinfo("trust", "The exceptions epoch is %lld.", exceptionResetCount);
2996
2997 return exceptionResetCount;
2998 }
2999
3000 OSStatus SecTrustIncrementExceptionResetCount(CFErrorRef *error) {
3001 OSStatus status = errSecInternal;
3002
3003 os_activity_t activity = os_activity_create("SecTrustIncrementExceptionResetCount", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_DEFAULT);
3004 os_activity_scope(activity);
3005 bool success = TRUSTD_XPC(sec_trust_increment_exception_reset_count, to_bool_error_request, error);
3006 os_release(activity);
3007 if ((error && *error) || !success) {
3008 secerror("Failed to increment the exceptions epoch.");
3009 return status;
3010 }
3011 status = errSecSuccess;
3012
3013 return status;
3014 }
3015 #endif