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