]> git.saurik.com Git - apple/security.git/blob - OSX/sec/Security/SecTrust.c
618d0941fd56c086fd89952a02976902ebba55a9
[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 CFDictionaryAddValue(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 dispatch_sync(trust->_trustQueue, ^{
658 if (!allowFetch) {
659 status = SecTrustSetOptionInPolicies(trust->_policies, kSecPolicyCheckNoNetworkAccess, kCFBooleanTrue);
660 } else {
661 status = SecTrustRemoveOptionInPolicies(trust->_policies, kSecPolicyCheckNoNetworkAccess);
662 }
663 });
664 return status;
665 }
666
667 OSStatus SecTrustGetNetworkFetchAllowed(SecTrustRef trust, Boolean *allowFetch) {
668 if (!trust || !allowFetch) {
669 return errSecParam;
670 }
671 __block CFArrayRef foundValues = NULL;
672 dispatch_sync(trust->_trustQueue, ^{
673 foundValues = SecTrustCopyOptionsFromPolicies(trust->_policies, kSecPolicyCheckNoNetworkAccess);
674 });
675 if (foundValues) {
676 *allowFetch = false;
677 } else {
678 *allowFetch = true;
679 }
680 CFReleaseNull(foundValues);
681 return errSecSuccess;
682 }
683
684 OSStatus SecTrustSetPinningException(SecTrustRef trust) {
685 if (!trust) { return errSecParam; }
686 __block OSStatus status = errSecSuccess;
687 dispatch_sync(trust->_trustQueue, ^{
688 status = SecTrustRemoveOptionInPolicies(trust->_policies, kSecPolicyCheckPinningRequired);
689 });
690 return status;
691 }
692
693 CFAbsoluteTime SecTrustGetVerifyTime(SecTrustRef trust) {
694 __block CFAbsoluteTime verifyTime = CFAbsoluteTimeGetCurrent();
695 if (!trust) {
696 return verifyTime;
697 }
698 dispatch_sync(trust->_trustQueue, ^{
699 if (trust->_verifyDate) {
700 verifyTime = CFDateGetAbsoluteTime(trust->_verifyDate);
701 } else {
702 trust->_verifyDate = CFDateCreate(CFGetAllocator(trust), verifyTime);
703 }
704 });
705
706 return verifyTime;
707 }
708
709 CFArrayRef SecTrustGetDetails(SecTrustRef trust) {
710 if (!trust) {
711 return NULL;
712 }
713 SecTrustEvaluateIfNecessary(trust);
714 return trust->_details;
715 }
716
717 OSStatus SecTrustGetTrustResult(SecTrustRef trust,
718 SecTrustResultType *result) {
719 if (!trust || !result) {
720 return errSecParam;
721 }
722 SecTrustEvaluateIfNecessary(trust);
723 dispatch_sync(trust->_trustQueue, ^{
724 *result = trust->_trustResult;
725 });
726 return errSecSuccess;
727 }
728
729 static CFDictionaryRef SecTrustGetExceptionForCertificateAtIndex(SecTrustRef trust, CFIndex ix) {
730 CFDictionaryRef exception = NULL;
731 __block CFArrayRef exceptions = NULL;
732 dispatch_sync(trust->_trustQueue, ^{
733 exceptions = CFRetainSafe(trust->_exceptions);
734 });
735 if (!exceptions || ix >= CFArrayGetCount(exceptions)) {
736 goto out;
737 }
738
739 SecCertificateRef certificate = SecTrustGetCertificateAtIndex(trust, ix);
740 if (!certificate) {
741 goto out;
742 }
743
744 exception = (CFDictionaryRef)CFArrayGetValueAtIndex(exceptions, ix);
745 if (CFGetTypeID(exception) != CFDictionaryGetTypeID()) {
746 exception = NULL;
747 goto out;
748 }
749
750 /* If the exception contains the current certificates sha1Digest in the
751 kSecCertificateDetailSHA1Digest key then we use it otherwise we ignore it. */
752 CFDataRef sha1Digest = SecCertificateGetSHA1Digest(certificate);
753 CFTypeRef digestValue = CFDictionaryGetValue(exception, kSecCertificateDetailSHA1Digest);
754 if (!digestValue || !CFEqual(sha1Digest, digestValue))
755 exception = NULL;
756
757 out:
758 CFReleaseSafe(exceptions);
759 return exception;
760 }
761
762 CFArrayRef SecTrustCopyFilteredDetails(SecTrustRef trust) {
763 if (!trust) {
764 return NULL;
765 }
766 SecTrustEvaluateIfNecessary(trust);
767 __block CFArrayRef details = NULL;
768 dispatch_sync(trust->_trustQueue, ^{
769 details = CFRetainSafe(trust->_details);
770 });
771
772 /* Done automatically by the Policy Server with SecPVCIsExceptedError */
773 return details;
774 }
775
776 Boolean SecTrustIsExpiredOnly(SecTrustRef trust) {
777 /* Returns true if one or more certificates in the chain have expired,
778 * expiration is an error (i.e. is not covered by existing trust settings),
779 * and it is the only error encountered.
780 * Returns false if the certificate is valid, or if the trust chain has
781 * other errors beside expiration.
782 */
783 Boolean result = false;
784 Boolean foundExpired = false;
785 CFArrayRef details = SecTrustCopyFilteredDetails(trust);
786 require(details != NULL, out);
787
788 CFIndex ix, pathLength = CFArrayGetCount(details);
789 for (ix = 0; ix < pathLength; ++ix) {
790 CFDictionaryRef detail = (CFDictionaryRef)CFArrayGetValueAtIndex(details, ix);
791 CFIndex count = (detail) ? CFDictionaryGetCount(detail) : 0;
792 require(count <= 1, out);
793 if (count) {
794 CFBooleanRef valid = (CFBooleanRef)CFDictionaryGetValue(detail, kSecPolicyCheckTemporalValidity);
795 require(isBoolean(valid) && CFEqual(valid, kCFBooleanFalse), out);
796 foundExpired = true;
797 }
798 }
799 result = foundExpired;
800 out:
801 CFReleaseSafe(details);
802 return result;
803 }
804
805 #if TARGET_OS_IPHONE
806 static CFArrayRef SecTrustCreatePolicyAnchorsArray(const UInt8* certData, CFIndex certLength)
807 {
808 CFArrayRef array = NULL;
809 CFAllocatorRef allocator = kCFAllocatorDefault;
810 SecCertificateRef cert = SecCertificateCreateWithBytes(allocator, certData, certLength);
811 if (cert) {
812 array = CFArrayCreate(allocator, (const void **)&cert, 1, &kCFTypeArrayCallBacks);
813 CFReleaseSafe(cert);
814 }
815 return array;
816 }
817 #endif
818
819 static void SecTrustAddPolicyAnchors(SecTrustRef trust)
820 {
821 /* Provide anchor certificates specifically required by certain policies.
822 This is used to evaluate test policies where the anchor is not provided
823 in the root store and may not be able to be supplied by the caller.
824 */
825 if (!trust) { return; }
826 __block CFArrayRef policies = NULL;
827 dispatch_sync(trust->_trustQueue, ^{
828 policies = CFRetain(trust->_policies);
829 });
830 CFIndex ix, count = CFArrayGetCount(policies);
831 for (ix = 0; ix < count; ++ix) {
832 SecPolicyRef policy = (SecPolicyRef) CFArrayGetValueAtIndex(policies, ix);
833 if (policy) {
834 #if TARGET_OS_IPHONE
835 if (CFEqual(policy->_oid, kSecPolicyAppleTestSMPEncryption)) {
836 __block CFArrayRef policyAnchors = SecTrustCreatePolicyAnchorsArray(_SEC_TestAppleRootCAECC, sizeof(_SEC_TestAppleRootCAECC));
837 dispatch_sync(trust->_trustQueue, ^{
838 CFReleaseSafe(trust->_anchors);
839 trust->_anchors = policyAnchors;
840 });
841 trust->_anchorsOnly = true;
842 break;
843 }
844 #endif
845 }
846 }
847 CFReleaseSafe(policies);
848 }
849
850 // uncomment for verbose debug logging (debug builds only)
851 //#define CERT_TRUST_DUMP 1
852
853 #if CERT_TRUST_DUMP
854 static void sectrustlog(int priority, const char *format, ...)
855 {
856 #ifndef NDEBUG
857 // log everything
858 #else
859 if (priority < LOG_NOTICE) // log warnings and errors
860 #endif
861 {
862 va_list list;
863 va_start(list, format);
864 vsyslog(priority, format, list);
865 va_end(list);
866 }
867 }
868
869 static void sectrustshow(CFTypeRef obj, const char *context)
870 {
871 #ifndef NDEBUG
872 CFStringRef desc = CFCopyDescription(obj);
873 if (!desc) return;
874
875 CFIndex length = CFStringGetMaximumSizeForEncoding(CFStringGetLength(desc), kCFStringEncodingUTF8) + 1;
876 char* buffer = (char*) malloc(length);
877 if (buffer) {
878 Boolean converted = CFStringGetCString(desc, buffer, length, kCFStringEncodingUTF8);
879 if (converted) {
880 const char *prefix = (context) ? context : "";
881 const char *separator = (context) ? " " : "";
882 sectrustlog(LOG_NOTICE, "%s%s%s", prefix, separator, buffer);
883 }
884 free(buffer);
885 }
886 CFRelease(desc);
887 #endif
888 }
889
890 static void cert_trust_dump(SecTrustRef trust) {
891 SecCertificateRef leaf = SecTrustGetCertificateAtIndex(trust, 0);
892 CFStringRef name = (leaf) ? SecCertificateCopySubjectSummary(leaf) : NULL;
893 secerror("leaf \"%@\"", name);
894 secerror(": result = %d", (int) trust->_trustResult);
895 if (trust->_chain) {
896 CFIndex ix, count = CFArrayGetCount(trust->_chain);
897 CFMutableArrayRef chain = CFArrayCreateMutable(kCFAllocatorDefault, count, &kCFTypeArrayCallBacks);
898 for (ix = 0; ix < count; ix++) {
899 SecCertificateRef cert = (SecCertificateRef)CFArrayGetValueAtIndex(trust->_chain, ix);
900 if (cert) {
901 CFArrayAppendValue(chain, cert);
902 }
903 }
904 sectrustshow(chain, "chain:");
905 CFReleaseSafe(chain);
906 }
907 secerror(": %ld certificates, %ld anchors, %ld policies, %ld details",
908 (trust->_certificates) ? (long)CFArrayGetCount(trust->_certificates) : 0,
909 (trust->_anchors) ? (long)CFArrayGetCount(trust->_anchors) : 0,
910 (trust->_policies) ? (long)CFArrayGetCount(trust->_policies) : 0,
911 (trust->_details) ? (long)CFArrayGetCount(trust->_details) : 0);
912
913 sectrustshow(trust->_verifyDate, "verify date:");
914 sectrustshow(trust->_certificates, "certificates:");
915 sectrustshow(trust->_anchors, "anchors:");
916 sectrustshow(trust->_policies, "policies:");
917 sectrustshow(trust->_details, "details:");
918 sectrustshow(trust->_info, "info:");
919
920 CFReleaseSafe(name);
921 }
922 #else
923 static void cert_trust_dump(SecTrustRef trust) {}
924 #endif
925
926
927 OSStatus SecTrustEvaluate(SecTrustRef trust, SecTrustResultType *result) {
928 if (result) {
929 *result = kSecTrustResultInvalid;
930 }
931 if (!trust) {
932 return errSecParam;
933 }
934 OSStatus status = SecTrustEvaluateIfNecessary(trust);
935 if (status) {
936 return status;
937 }
938 /* post-process trust result based on exceptions */
939 __block SecTrustResultType trustResult = kSecTrustResultInvalid;
940 dispatch_sync(trust->_trustQueue, ^{
941 trustResult = trust->_trustResult;
942 });
943
944 /* log to syslog when there is a trust failure */
945 if (trustResult != kSecTrustResultProceed &&
946 trustResult != kSecTrustResultUnspecified) {
947 CFStringRef failureDesc = SecTrustCopyFailureDescription(trust);
948 secerror("Trust evaluate failure:%{public}@", failureDesc);
949 CFRelease(failureDesc);
950 }
951
952
953 if (result) {
954 *result = trustResult;
955 }
956
957 return status;
958 }
959
960 static CFStringRef SecTrustCopyChainSummary(SecTrustRef trust) {
961 CFMutableStringRef summary = CFStringCreateMutable(NULL, 0);
962 __block CFArrayRef chain = NULL;
963 dispatch_sync(trust->_trustQueue, ^{
964 chain = trust->_chain;
965 });
966 CFIndex ix, count = CFArrayGetCount(chain);
967 for (ix = 0; ix < count; ix++) {
968 if (ix != 0) { CFStringAppend(summary, CFSTR(",")); }
969 CFStringRef certSummary = SecCertificateCopySubjectSummary((SecCertificateRef)CFArrayGetValueAtIndex(chain, ix));
970 CFStringAppendFormat(summary, NULL, CFSTR("\"%@\""), certSummary);
971 CFReleaseNull(certSummary);
972 }
973 return summary;
974 }
975
976 typedef enum {
977 kSecTrustErrorSubTypeRevoked,
978 kSecTrustErrorSubTypeKeySize,
979 kSecTrustErrorSubTypeWeakHash,
980 kSecTrustErrorSubTypeDenied,
981 kSecTrustErrorSubTypeCompliance,
982 kSecTrustErrorSubTypePinning,
983 kSecTrustErrorSubTypeTrust,
984 kSecTrustErrorSubTypeUsage,
985 kSecTrustErrorSubTypeName,
986 kSecTrustErrorSubTypeExpired,
987 kSecTrustErrorSubTypeInvalid,
988 } SecTrustErrorSubType;
989
990 #define SecCopyTrustString(KEY) SecFrameworkCopyLocalizedString(KEY, CFSTR("Trust"))
991
992 struct checkmap_entry_s {
993 SecTrustErrorSubType type;
994 OSStatus status;
995 const CFStringRef errorKey;
996
997 };
998 typedef struct checkmap_entry_s checkmap_entry_t;
999
1000 const checkmap_entry_t checkmap[] = {
1001 #undef POLICYCHECKMACRO
1002 #define __PC_SUBTYPE_ kSecTrustErrorSubTypeInvalid
1003 #define __PC_SUBTYPE_N kSecTrustErrorSubTypeName
1004 #define __PC_SUBTYPE_E kSecTrustErrorSubTypeExpired
1005 #define __PC_SUBTYPE_S kSecTrustErrorSubTypeKeySize
1006 #define __PC_SUBTYPE_H kSecTrustErrorSubTypeWeakHash
1007 #define __PC_SUBTYPE_U kSecTrustErrorSubTypeUsage
1008 #define __PC_SUBTYPE_P kSecTrustErrorSubTypePinning
1009 #define __PC_SUBTYPE_V kSecTrustErrorSubTypeRevoked
1010 #define __PC_SUBTYPE_T kSecTrustErrorSubTypeTrust
1011 #define __PC_SUBTYPE_C kSecTrustErrorSubTypeCompliance
1012 #define __PC_SUBTYPE_D kSecTrustErrorSubTypeDenied
1013 #define POLICYCHECKMACRO(NAME, TRUSTRESULT, SUBTYPE, LEAFCHECK, PATHCHECK, LEAFONLY, CSSMERR, OSSTATUS) \
1014 { __PC_SUBTYPE_##SUBTYPE , OSSTATUS, SEC_TRUST_ERROR_##NAME },
1015 #include "SecPolicyChecks.list"
1016 };
1017
1018 static OSStatus SecTrustCopyErrorStrings(SecTrustRef trust,
1019 CFStringRef * CF_RETURNS_RETAINED simpleError,
1020 CFStringRef * CF_RETURNS_RETAINED fullError) {
1021 if (!simpleError || !fullError) {
1022 return errSecParam;
1023 }
1024 __block CFArrayRef details = NULL;
1025 dispatch_sync(trust->_trustQueue, ^{
1026 details = CFRetainSafe(trust->_details);
1027 });
1028 if (!details)
1029 return errSecInternal;
1030
1031 /* We need to map the policy check constants to indexes into our checkmap table. */
1032 static dispatch_once_t onceToken;
1033 static CFArrayRef policyChecks = NULL;
1034 dispatch_once(&onceToken, ^{
1035 CFMutableArrayRef _policyChecks = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
1036 #undef POLICYCHECKMACRO
1037 #define POLICYCHECKMACRO(NAME, TRUSTRESULT, SUBTYPE, LEAFCHECK, PATHCHECK, LEAFONLY, CSSMERR, ERRORSTRING) \
1038 CFArrayAppendValue(_policyChecks, kSecPolicyCheck##NAME);
1039 #include "SecPolicyChecks.list"
1040 policyChecks = _policyChecks;
1041 });
1042
1043 /* Build the errors for each cert in the detailed results array */
1044 __block CFMutableStringRef fullMutableError = CFStringCreateMutable(NULL, 0);
1045 __block SecTrustErrorSubType simpleErrorSubType = kSecTrustErrorSubTypeInvalid;
1046 __block OSStatus simpleErrorStatus = errSecInternalError;
1047 __block CFIndex simpleErrorCertIndex = kCFNotFound;
1048 __block CFIndex ix;
1049 CFIndex count = CFArrayGetCount(details);
1050 for (ix = 0; ix < count; ix++) {
1051 CFDictionaryRef perCertDetails = (CFDictionaryRef)CFArrayGetValueAtIndex(details, ix);
1052 if (CFDictionaryGetCount(perCertDetails) == 0) { continue; } // no errors on this cert
1053
1054 /* Get the cert summary and start the full error details string for this cert */
1055 CFStringRef certSummary = SecCertificateCopySubjectSummary(SecTrustGetCertificateAtIndex(trust, ix));
1056 CFStringRef format = SecCopyTrustString(SEC_TRUST_CERTIFICATE_ERROR);
1057 CFStringAppendFormat(fullMutableError, NULL, format,
1058 ix, certSummary);
1059 CFReleaseNull(certSummary);
1060 CFReleaseNull(format);
1061
1062 /* Figure out the errors */
1063 __block bool firstError = true;
1064 CFDictionaryForEach(perCertDetails, ^(const void *key, const void * __unused value) {
1065 CFIndex policyCheckIndex = CFArrayGetFirstIndexOfValue(policyChecks, CFRangeMake(0, CFArrayGetCount(policyChecks)), key);
1066 if (policyCheckIndex == kCFNotFound) { return; }
1067 /* Keep track of the highest priority error encountered during this evaluation.
1068 * If multiple certs have errors of the same subtype we keep the lowest indexed cert. */
1069 if (simpleErrorSubType > checkmap[policyCheckIndex].type) {
1070 simpleErrorSubType = checkmap[policyCheckIndex].type;
1071 simpleErrorCertIndex = ix;
1072 simpleErrorStatus = checkmap[policyCheckIndex].status;
1073 }
1074 /* Add this error to the full error */
1075 if (!firstError) { CFStringAppend(fullMutableError, CFSTR(", ")); }
1076 CFStringRef errorString = SecCopyTrustString(checkmap[policyCheckIndex].errorKey);
1077 CFStringAppend(fullMutableError, errorString);
1078 CFReleaseNull(errorString);
1079 firstError = false;
1080 });
1081 CFStringAppend(fullMutableError, CFSTR(";"));
1082 }
1083 CFReleaseNull(details);
1084
1085 /* Build the simple error */
1086 if (simpleErrorCertIndex == kCFNotFound) { simpleErrorCertIndex = 0; }
1087 CFStringRef format = NULL;
1088 CFStringRef certSummary = SecCertificateCopySubjectSummary(SecTrustGetCertificateAtIndex(trust, simpleErrorCertIndex));
1089 switch (simpleErrorSubType) {
1090 case kSecTrustErrorSubTypeRevoked: {
1091 format = SecCopyTrustString(SEC_TRUST_ERROR_SUBTYPE_REVOKED);
1092 break;
1093 }
1094 case kSecTrustErrorSubTypeKeySize: {
1095 format = SecCopyTrustString(SEC_TRUST_ERROR_SUBTYPE_KEYSIZE);
1096 break;
1097 }
1098 case kSecTrustErrorSubTypeWeakHash: {
1099 format = SecCopyTrustString(SEC_TRUST_ERROR_SUBTYPE_WEAKHASH);
1100 break;
1101 }
1102 case kSecTrustErrorSubTypeDenied: {
1103 format = SecCopyTrustString(SEC_TRUST_ERROR_SUBTYPE_DENIED);
1104 break;
1105 }
1106 case kSecTrustErrorSubTypeCompliance: {
1107 format = SecCopyTrustString(SEC_TRUST_ERROR_SUBTYPE_COMPLIANCE);
1108 break;
1109 }
1110 case kSecTrustErrorSubTypeExpired: {
1111 format = SecCopyTrustString(SEC_TRUST_ERROR_SUBTYPE_EXPIRED);
1112 break;
1113 }
1114 case kSecTrustErrorSubTypeTrust: {
1115 format = SecCopyTrustString(SEC_TRUST_ERROR_SUBTYPE_TRUST);
1116 break;
1117 }
1118 case kSecTrustErrorSubTypeName: {
1119 format = SecCopyTrustString(SEC_TRUST_ERROR_SUBTYPE_NAME);
1120 break;
1121 }
1122 case kSecTrustErrorSubTypeUsage: {
1123 format = SecCopyTrustString(SEC_TRUST_ERROR_SUBTYPE_USAGE);
1124 break;
1125 }
1126 case kSecTrustErrorSubTypePinning: {
1127 format = SecCopyTrustString(SEC_TRUST_ERROR_SUBTYPE_PINNING);
1128 CFAssignRetained(certSummary, SecTrustCopyChainSummary(trust));
1129 break;
1130 }
1131 default: {
1132 format = SecCopyTrustString(SEC_TRUST_ERROR_SUBTYPE_INVALID);
1133 break;
1134 }
1135 }
1136 if (format && certSummary) {
1137 *simpleError = CFStringCreateWithFormat(NULL, NULL, format, certSummary);
1138 }
1139 CFReleaseNull(format);
1140 CFReleaseNull(certSummary);
1141 *fullError = fullMutableError;
1142 return simpleErrorStatus;
1143 }
1144
1145 static CFErrorRef SecTrustCopyError(SecTrustRef trust) {
1146 if (!trust) { return NULL; }
1147 (void)SecTrustEvaluateIfNecessary(trust);
1148 OSStatus status = errSecSuccess;
1149 __block SecTrustResultType trustResult = kSecTrustResultInvalid;
1150 dispatch_sync(trust->_trustQueue, ^{
1151 trustResult = trust->_trustResult;
1152 });
1153 if (trustResult == kSecTrustResultProceed || trustResult == kSecTrustResultUnspecified) {
1154 return NULL;
1155 }
1156
1157 CFStringRef detailedError = NULL;
1158 CFStringRef simpleError = NULL;
1159 status = SecTrustCopyErrorStrings(trust, &simpleError, &detailedError);
1160 CFDictionaryRef userInfo = CFDictionaryCreate(NULL, (const void **)&kCFErrorLocalizedDescriptionKey,
1161 (const void **)&detailedError, 1,
1162 &kCFTypeDictionaryKeyCallBacks,
1163 &kCFTypeDictionaryValueCallBacks);
1164 CFErrorRef underlyingError = CFErrorCreate(NULL, kCFErrorDomainOSStatus, status, userInfo);
1165 CFReleaseNull(userInfo);
1166 CFReleaseNull(detailedError);
1167
1168 const void *keys[] = { kCFErrorLocalizedDescriptionKey, kCFErrorUnderlyingErrorKey };
1169 const void *values[] = { simpleError, underlyingError };
1170 userInfo = CFDictionaryCreate(NULL, keys, values, 2,
1171 &kCFTypeDictionaryKeyCallBacks,
1172 &kCFTypeDictionaryValueCallBacks);
1173 CFErrorRef error = CFErrorCreate(NULL, kCFErrorDomainOSStatus, status, userInfo);
1174 CFReleaseNull(userInfo);
1175 CFReleaseNull(simpleError);
1176 return error;
1177 }
1178
1179 bool SecTrustEvaluateWithError(SecTrustRef trust, CFErrorRef *error) {
1180 SecTrustResultType trustResult = kSecTrustResultInvalid;
1181 OSStatus status = SecTrustEvaluate(trust, &trustResult);
1182 if (status == errSecSuccess && (trustResult == kSecTrustResultProceed || trustResult == kSecTrustResultUnspecified)) {
1183 if (error) {
1184 *error = NULL;
1185 }
1186 return true;
1187 }
1188 if (error) {
1189 if (status != errSecSuccess) {
1190 *error = SecCopyLastError(status);
1191 } else {
1192 *error = SecTrustCopyError(trust);
1193 }
1194 }
1195 return false;
1196 }
1197
1198 OSStatus SecTrustEvaluateAsync(SecTrustRef trust,
1199 dispatch_queue_t queue, SecTrustCallback result)
1200 {
1201 CFRetainSafe(trust);
1202 dispatch_async(queue, ^{
1203 SecTrustResultType trustResult;
1204 if (errSecSuccess != SecTrustEvaluate(trust, &trustResult)) {
1205 trustResult = kSecTrustResultInvalid;
1206 }
1207 result(trust, trustResult);
1208 CFReleaseSafe(trust);
1209 });
1210 return errSecSuccess;
1211 }
1212
1213 static bool append_certificate_to_xpc_array(SecCertificateRef certificate, xpc_object_t xpc_certificates);
1214 static xpc_object_t copy_xpc_certificates_array(CFArrayRef certificates);
1215 xpc_object_t copy_xpc_policies_array(CFArrayRef policies);
1216 OSStatus validate_array_of_items(CFArrayRef array, CFStringRef arrayItemType, CFTypeID itemTypeID, bool required);
1217
1218 static bool append_certificate_to_xpc_array(SecCertificateRef certificate, xpc_object_t xpc_certificates) {
1219 if (!certificate) {
1220 return true; // NOOP
1221 }
1222 size_t length = SecCertificateGetLength(certificate);
1223 const uint8_t *bytes = SecCertificateGetBytePtr(certificate);
1224 if (!length || !bytes) {
1225 return false;
1226 }
1227 xpc_array_set_data(xpc_certificates, XPC_ARRAY_APPEND, bytes, length);
1228 return true;
1229 }
1230
1231 static xpc_object_t copy_xpc_certificates_array(CFArrayRef certificates) {
1232 xpc_object_t xpc_certificates = xpc_array_create(NULL, 0);
1233 if (!xpc_certificates) {
1234 return NULL;
1235 }
1236 CFIndex ix, count = CFArrayGetCount(certificates);
1237 for (ix = 0; ix < count; ++ix) {
1238 SecCertificateRef certificate = (SecCertificateRef) CFArrayGetValueAtIndex(certificates, ix);
1239 #if SECTRUST_VERBOSE_DEBUG
1240 size_t length = SecCertificateGetLength(certificate);
1241 const uint8_t *bytes = SecCertificateGetBytePtr(certificate);
1242 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);
1243 #endif
1244 if (!append_certificate_to_xpc_array(certificate, xpc_certificates)) {
1245 xpc_release(xpc_certificates);
1246 xpc_certificates = NULL;
1247 break;
1248 }
1249 }
1250 return xpc_certificates;
1251 }
1252
1253 static bool SecXPCDictionarySetCertificates(xpc_object_t message, const char *key, CFArrayRef certificates, CFErrorRef *error) {
1254 xpc_object_t xpc_certificates = copy_xpc_certificates_array(certificates);
1255 if (!xpc_certificates) {
1256 SecError(errSecAllocate, error, CFSTR("failed to create xpc_array of certificates"));
1257 return false;
1258 }
1259 xpc_dictionary_set_value(message, key, xpc_certificates);
1260 xpc_release(xpc_certificates);
1261 return true;
1262 }
1263
1264 static bool SecXPCDictionarySetPolicies(xpc_object_t message, const char *key, CFArrayRef policies, CFErrorRef *error) {
1265 xpc_object_t xpc_policies = copy_xpc_policies_array(policies);
1266 if (!xpc_policies) {
1267 SecError(errSecAllocate, error, CFSTR("failed to create xpc_array of policies"));
1268 return false;
1269 }
1270 xpc_dictionary_set_value(message, key, xpc_policies);
1271 xpc_release(xpc_policies);
1272 return true;
1273 }
1274
1275
1276 static bool CFDataAppendToXPCArray(CFDataRef data, xpc_object_t xpc_data_array, CFErrorRef *error) {
1277 if (!data)
1278 return true; // NOOP
1279
1280 size_t length = CFDataGetLength(data);
1281 const uint8_t *bytes = CFDataGetBytePtr(data);
1282 if (!length || !bytes)
1283 return SecError(errSecParam, error, CFSTR("invalid CFDataRef"));
1284
1285 xpc_array_set_data(xpc_data_array, XPC_ARRAY_APPEND, bytes, length);
1286 return true;
1287 }
1288
1289
1290 static xpc_object_t CFDataArrayCopyXPCArray(CFArrayRef data_array, CFErrorRef *error) {
1291 xpc_object_t xpc_data_array;
1292 require_action_quiet(xpc_data_array = xpc_array_create(NULL, 0), exit,
1293 SecError(errSecAllocate, error, CFSTR("failed to create xpc_array")));
1294 CFIndex ix, count = CFArrayGetCount(data_array);
1295 for (ix = 0; ix < count; ++ix) {
1296 if (!CFDataAppendToXPCArray((CFDataRef)CFArrayGetValueAtIndex(data_array, ix), xpc_data_array, error)) {
1297 xpc_release(xpc_data_array);
1298 return NULL;
1299 }
1300 }
1301
1302 exit:
1303 return xpc_data_array;
1304 }
1305
1306 static bool SecXPCDictionarySetDataArray(xpc_object_t message, const char *key, CFArrayRef data_array, CFErrorRef *error) {
1307 xpc_object_t xpc_data_array = CFDataArrayCopyXPCArray(data_array, error);
1308 if (!xpc_data_array)
1309 return false;
1310 xpc_dictionary_set_value(message, key, xpc_data_array);
1311 xpc_release(xpc_data_array);
1312 return true;
1313 }
1314
1315 static bool SecXPCDictionaryCopyChainOptional(xpc_object_t message, const char *key, CFArrayRef *path, CFErrorRef *error) {
1316 xpc_object_t xpc_path = xpc_dictionary_get_value(message, key);
1317 CFMutableArrayRef output = NULL;
1318 size_t count = 0;
1319 if (!xpc_path) {
1320 *path = NULL;
1321 return true;
1322 }
1323 require_action_quiet(xpc_get_type(xpc_path) == XPC_TYPE_ARRAY, exit, SecError(errSecDecode, error, CFSTR("xpc_path value is not an array")));
1324 require_action_quiet(count = xpc_array_get_count(xpc_path), exit, SecError(errSecDecode, error, CFSTR("xpc_path array count == 0")));
1325 output = CFArrayCreateMutable(NULL, count, &kCFTypeArrayCallBacks);
1326
1327 size_t ix;
1328 for (ix = 0; ix < count; ++ix) {
1329 SecCertificateRef certificate = SecCertificateCreateWithXPCArrayAtIndex(xpc_path, ix, error);
1330 if (certificate) {
1331 CFArrayAppendValue(output, certificate);
1332 CFReleaseNull(certificate);
1333 } else {
1334 CFReleaseNull(output);
1335 break;
1336 }
1337 }
1338
1339 exit:
1340 if (output) {
1341 *path = output;
1342 return true;
1343 }
1344 return false;
1345 }
1346
1347 static int SecXPCDictionaryGetNonZeroInteger(xpc_object_t message, const char *key, CFErrorRef *error) {
1348 int64_t value = xpc_dictionary_get_int64(message, key);
1349 if (!value) {
1350 SecError(errSecInternal, error, CFSTR("object for key %s is 0"), key);
1351 }
1352 return (int)value;
1353 }
1354
1355 static SecTrustResultType handle_trust_evaluate_xpc(enum SecXPCOperation op, CFArrayRef certificates,
1356 CFArrayRef anchors, bool anchorsOnly,
1357 bool keychainsAllowed, CFArrayRef policies, CFArrayRef responses,
1358 CFArrayRef SCTs, CFArrayRef trustedLogs,
1359 CFAbsoluteTime verifyTime, __unused CFArrayRef accessGroups, CFArrayRef exceptions,
1360 CFArrayRef *details, CFDictionaryRef *info, CFArrayRef *chain, CFErrorRef *error)
1361 {
1362 __block SecTrustResultType tr = kSecTrustResultInvalid;
1363 securityd_send_sync_and_do(op, error, ^bool(xpc_object_t message, CFErrorRef *error) {
1364 if (!SecXPCDictionarySetCertificates(message, kSecTrustCertificatesKey, certificates, error))
1365 return false;
1366 if (anchors && !SecXPCDictionarySetCertificates(message, kSecTrustAnchorsKey, anchors, error))
1367 return false;
1368 if (anchorsOnly)
1369 xpc_dictionary_set_bool(message, kSecTrustAnchorsOnlyKey, anchorsOnly);
1370 xpc_dictionary_set_bool(message, kSecTrustKeychainsAllowedKey, keychainsAllowed);
1371 if (!SecXPCDictionarySetPolicies(message, kSecTrustPoliciesKey, policies, error))
1372 return false;
1373 if (responses && !SecXPCDictionarySetDataArray(message, kSecTrustResponsesKey, responses, error))
1374 return false;
1375 if (SCTs && !SecXPCDictionarySetDataArray(message, kSecTrustSCTsKey, SCTs, error))
1376 return false;
1377 if (trustedLogs && !SecXPCDictionarySetPList(message, kSecTrustTrustedLogsKey, trustedLogs, error))
1378 return false;
1379 xpc_dictionary_set_double(message, kSecTrustVerifyDateKey, verifyTime);
1380 if (exceptions && !SecXPCDictionarySetPList(message, kSecTrustExceptionsKey, exceptions, error))
1381 return false;
1382 return true;
1383 }, ^bool(xpc_object_t response, CFErrorRef *error) {
1384 secdebug("trust", "response: %@", response);
1385 return SecXPCDictionaryCopyArrayOptional(response, kSecTrustDetailsKey, details, error) &&
1386 SecXPCDictionaryCopyDictionaryOptional(response, kSecTrustInfoKey, info, error) &&
1387 SecXPCDictionaryCopyChainOptional(response, kSecTrustChainKey, chain, error) &&
1388 ((tr = SecXPCDictionaryGetNonZeroInteger(response, kSecTrustResultKey, error)) != kSecTrustResultInvalid);
1389 });
1390 return tr;
1391 }
1392
1393 OSStatus validate_array_of_items(CFArrayRef array, CFStringRef arrayItemType, CFTypeID itemTypeID, bool required) {
1394 OSStatus result = errSecSuccess;
1395 CFIndex index, count;
1396 count = (array) ? CFArrayGetCount(array) : 0;
1397 if (!count && required) {
1398 secerror("no %@ in array!", arrayItemType);
1399 result = errSecParam;
1400 }
1401 for (index = 0; index < count; index++) {
1402 CFTypeRef item = (CFTypeRef) CFArrayGetValueAtIndex(array, index);
1403 if (!item) {
1404 secerror("%@ %@ (index %d)", arrayItemType, CFSTR("reference is nil"), (int)index);
1405 result = errSecParam;
1406 continue;
1407 }
1408 if (CFGetTypeID(item) != itemTypeID) {
1409 secerror("%@ %@ (index %d)", arrayItemType, CFSTR("is not the expected CF type"), (int)index);
1410 result = errSecParam;
1411 }
1412 // certificates
1413 if (CFGetTypeID(item) == SecCertificateGetTypeID()) {
1414 SecCertificateRef certificate = (SecCertificateRef) item;
1415 CFIndex length = SecCertificateGetLength(certificate);
1416 const UInt8 *bytes = SecCertificateGetBytePtr(certificate);
1417 if (!length) {
1418 secerror("%@ %@ (index %d)", arrayItemType, CFSTR("has zero length"), (int)index);
1419 result = errSecParam;
1420 }
1421 if (!bytes) {
1422 secerror("%@ %@ (index %d)", arrayItemType, CFSTR("has nil bytes"), (int)index);
1423 result = errSecParam;
1424 }
1425 #if SECTRUST_VERBOSE_DEBUG
1426 secerror("%@[%d] of %d = %ld bytes @ 0x%lX", arrayItemType, (int)index, (int)count, (size_t)length, (uintptr_t)bytes);
1427 #endif
1428 }
1429 // policies
1430 if (CFGetTypeID(item) == SecPolicyGetTypeID()) {
1431 SecPolicyRef policy = (SecPolicyRef) item;
1432 CFStringRef oidStr = policy->_oid;
1433 if (!oidStr || (CFGetTypeID(oidStr) != CFStringGetTypeID())) {
1434 oidStr = CFSTR("has invalid OID string!");
1435 secerror("%@ %@ (index %d)", arrayItemType, oidStr, (int)index);
1436 }
1437 #if SECTRUST_VERBOSE_DEBUG
1438 secerror("%@[%d] of %d = \"%@\" 0x%lX", arrayItemType, (int)index, (int)count, oidStr, (uintptr_t)policy);
1439 #endif
1440 }
1441 }
1442 return result;
1443 }
1444
1445 static OSStatus SecTrustValidateInput(SecTrustRef trust) {
1446 OSStatus status, result = errSecSuccess;
1447
1448 // certificates (required)
1449 status = validate_array_of_items(trust->_certificates, CFSTR("certificate"), SecCertificateGetTypeID(), true);
1450 if (status) result = status;
1451 // anchors (optional)
1452 status = validate_array_of_items(trust->_anchors, CFSTR("input anchor"), SecCertificateGetTypeID(), false);
1453 if (status) result = status;
1454 // policies (required??)
1455 status = validate_array_of_items(trust->_policies, CFSTR("policy"), SecPolicyGetTypeID(), true);
1456 if (status) result = status;
1457 // _responses, _SCTs, _trustedLogs, ...
1458 // verify time: SecTrustGetVerifyTime(trust)
1459 // access groups: SecAccessGroupsGetCurrent()
1460
1461 return result;
1462 }
1463
1464 static OSStatus SecTrustEvaluateIfNecessary(SecTrustRef trust) {
1465 __block OSStatus result;
1466 check(trust);
1467 if (!trust)
1468 return errSecParam;
1469
1470 __block CFAbsoluteTime verifyTime = SecTrustGetVerifyTime(trust);
1471 SecTrustAddPolicyAnchors(trust);
1472 dispatch_sync(trust->_trustQueue, ^{
1473 if (trust->_trustResult != kSecTrustResultInvalid) {
1474 result = errSecSuccess;
1475 return;
1476 }
1477
1478 trust->_trustResult = kSecTrustResultOtherError; /* to avoid potential recursion */
1479
1480 CFReleaseNull(trust->_chain);
1481 CFReleaseNull(trust->_details);
1482 CFReleaseNull(trust->_info);
1483 if (trust->_legacy_info_array) {
1484 free(trust->_legacy_info_array);
1485 trust->_legacy_info_array = NULL;
1486 }
1487 if (trust->_legacy_status_array) {
1488 free(trust->_legacy_status_array);
1489 trust->_legacy_status_array = NULL;
1490 }
1491
1492 os_activity_initiate("SecTrustEvaluateIfNecessary", OS_ACTIVITY_FLAG_DEFAULT, ^{
1493 SecTrustValidateInput(trust);
1494
1495 /* @@@ 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. */
1496 result = SecOSStatusWith(^bool (CFErrorRef *error) {
1497 trust->_trustResult = TRUSTD_XPC(sec_trust_evaluate,
1498 handle_trust_evaluate_xpc,
1499 trust->_certificates, trust->_anchors, trust->_anchorsOnly, trust->_keychainsAllowed,
1500 trust->_policies, trust->_responses, trust->_SCTs, trust->_trustedLogs,
1501 verifyTime, SecAccessGroupsGetCurrent(), trust->_exceptions,
1502 &trust->_details, &trust->_info, &trust->_chain, error);
1503 if (trust->_trustResult == kSecTrustResultInvalid /* TODO check domain */ &&
1504 SecErrorGetOSStatus(*error) == errSecNotAvailable &&
1505 CFArrayGetCount(trust->_certificates)) {
1506 /* We failed to talk to securityd. The only time this should
1507 happen is when we are running prior to launchd enabling
1508 registration of services. This currently happens when we
1509 are running from the ramdisk. To make ASR happy we initialize
1510 _chain and return success with a failure as the trustResult, to
1511 make it seem like we did a cert evaluation, so ASR can extract
1512 the public key from the leaf. */
1513 SecCertificateRef leafCert = (SecCertificateRef)CFArrayGetValueAtIndex(trust->_certificates, 0);
1514 CFArrayRef leafCertArray = CFArrayCreate(NULL, (const void**)&leafCert, 1, &kCFTypeArrayCallBacks);
1515 trust->_chain = leafCertArray;
1516 if (error)
1517 CFReleaseNull(*error);
1518 return true;
1519 }
1520 return trust->_trustResult != kSecTrustResultInvalid;
1521 });
1522 });
1523 });
1524 return result;
1525 }
1526
1527 /* Helper for the qsort below. */
1528 static int compare_strings(const void *a1, const void *a2) {
1529 CFStringRef s1 = *(CFStringRef *)a1;
1530 CFStringRef s2 = *(CFStringRef *)a2;
1531 return (int) CFStringCompare(s1, s2, kCFCompareForcedOrdering);
1532 }
1533
1534 CFStringRef SecTrustCopyFailureDescription(SecTrustRef trust) {
1535 if (!trust) {
1536 return NULL;
1537 }
1538 CFMutableStringRef reason = CFStringCreateMutable(NULL, 0);
1539 SecTrustEvaluateIfNecessary(trust);
1540 __block CFArrayRef details = NULL;
1541 dispatch_sync(trust->_trustQueue, ^{
1542 details = CFRetainSafe(trust->_details);
1543 });
1544 CFIndex pathLength = details ? CFArrayGetCount(details) : 0;
1545 for (CFIndex ix = 0; ix < pathLength; ++ix) {
1546 CFDictionaryRef detail = (CFDictionaryRef)CFArrayGetValueAtIndex(details, ix);
1547 CFIndex dCount = CFDictionaryGetCount(detail);
1548 if (dCount) {
1549 if (ix == 0)
1550 CFStringAppend(reason, CFSTR(" [leaf"));
1551 else if (ix == pathLength - 1)
1552 CFStringAppend(reason, CFSTR(" [root"));
1553 else
1554 CFStringAppendFormat(reason, NULL, CFSTR(" [ca%" PRIdCFIndex ), ix);
1555
1556 const void *keys[dCount];
1557 CFDictionaryGetKeysAndValues(detail, &keys[0], NULL);
1558 qsort(&keys[0], dCount, sizeof(keys[0]), compare_strings);
1559 for (CFIndex kix = 0; kix < dCount; ++kix) {
1560 CFStringRef key = keys[kix];
1561 const void *value = CFDictionaryGetValue(detail, key);
1562 CFStringAppendFormat(reason, NULL, CFSTR(" %@%@"), key,
1563 (CFGetTypeID(value) == CFBooleanGetTypeID()
1564 ? CFSTR("") : value));
1565 }
1566 CFStringAppend(reason, CFSTR("]"));
1567 }
1568 }
1569 CFReleaseSafe(details);
1570 return reason;
1571 }
1572
1573 #if TARGET_OS_OSX
1574 /* On OS X we need SecTrustCopyPublicKey to give us a CDSA-based SecKeyRef,
1575 so we will refer to this one internally as SecTrustCopyPublicKey_ios,
1576 and call it from SecTrustCopyPublicKey.
1577 */
1578 SecKeyRef SecTrustCopyPublicKey_ios(SecTrustRef trust)
1579 #else
1580 SecKeyRef SecTrustCopyPublicKey(SecTrustRef trust)
1581 #endif
1582 {
1583 if (!trust) {
1584 return NULL;
1585 }
1586 __block SecKeyRef publicKey = NULL;
1587 dispatch_sync(trust->_trustQueue, ^{
1588 if (trust->_publicKey) {
1589 publicKey = CFRetainSafe(trust->_publicKey);
1590 return;
1591 }
1592 SecCertificateRef leaf = (SecCertificateRef)CFArrayGetValueAtIndex(trust->_certificates, 0);
1593 #if TARGET_OS_OSX
1594 trust->_publicKey = SecCertificateCopyPublicKey_ios(leaf);
1595 #else
1596 trust->_publicKey = SecCertificateCopyPublicKey(leaf);
1597 #endif
1598 if (trust->_publicKey) {
1599 publicKey = CFRetainSafe(trust->_publicKey);
1600 }
1601 });
1602 /* If we couldn't get a public key from the leaf cert alone. */
1603 if (!publicKey) {
1604 SecTrustEvaluateIfNecessary(trust);
1605 dispatch_sync(trust->_trustQueue, ^{
1606 if (trust->_chain) {
1607 SecCertificateRef cert = (SecCertificateRef)CFArrayGetValueAtIndex(trust->_chain, 0);
1608 #if TARGET_OS_OSX
1609 trust->_publicKey = SecCertificateCopyPublicKey_ios(cert);
1610 #else
1611 trust->_publicKey = SecCertificateCopyPublicKey(cert);
1612 #endif
1613 publicKey = CFRetainSafe(trust->_publicKey);
1614 }
1615 });
1616 }
1617 return publicKey;
1618 }
1619
1620 CFIndex SecTrustGetCertificateCount(SecTrustRef trust) {
1621 if (!trust) {
1622 return 0;
1623 }
1624 SecTrustEvaluateIfNecessary(trust);
1625 __block CFIndex certCount = 1;
1626 dispatch_sync(trust->_trustQueue, ^{
1627 if (trust->_chain) {
1628 certCount = CFArrayGetCount(trust->_chain);
1629 }
1630 });
1631 return certCount;
1632 }
1633
1634 SecCertificateRef SecTrustGetCertificateAtIndex(SecTrustRef trust,
1635 CFIndex ix) {
1636 if (!trust) {
1637 return NULL;
1638 }
1639 __block SecCertificateRef cert = NULL;
1640 if (ix == 0) {
1641 dispatch_sync(trust->_trustQueue, ^{
1642 cert = (SecCertificateRef)CFArrayGetValueAtIndex(trust->_certificates, 0);
1643 });
1644 return cert;
1645 }
1646 SecTrustEvaluateIfNecessary(trust);
1647 dispatch_sync(trust->_trustQueue, ^{
1648 if (trust->_chain) {
1649 cert = (SecCertificateRef)CFArrayGetValueAtIndex(trust->_chain, ix);
1650 }
1651 });
1652 return cert;
1653 }
1654
1655 CFDictionaryRef SecTrustCopyInfo(SecTrustRef trust) {
1656 if (!trust) {
1657 return NULL;
1658 }
1659 SecTrustEvaluateIfNecessary(trust);
1660 __block CFDictionaryRef info = NULL;
1661 dispatch_sync(trust->_trustQueue, ^{
1662 info = CFRetainSafe(trust->_info);
1663 });
1664 return info;
1665 }
1666
1667 CFArrayRef SecTrustGetTrustExceptionsArray(SecTrustRef trust) {
1668 if (!trust) {
1669 return NULL;
1670 }
1671 __block CFArrayRef exceptions = NULL;
1672 dispatch_sync(trust->_trustQueue, ^{
1673 exceptions = trust->_exceptions;
1674 });
1675 return exceptions;
1676 }
1677
1678 CFDataRef SecTrustCopyExceptions(SecTrustRef trust) {
1679 /* Stash the old exceptions and run an evaluation with no exceptions filtered. */
1680 __block CFArrayRef oldExceptions = NULL;
1681 dispatch_sync(trust->_trustQueue, ^{
1682 if (trust->_exceptions) {
1683 oldExceptions = trust->_exceptions;
1684 trust->_exceptions = NULL;
1685 }
1686 });
1687 SecTrustSetNeedsEvaluation(trust);
1688
1689 /* Create the new exceptions based on an unfiltered eval. */
1690 __block CFArrayRef details = NULL;
1691 SecTrustEvaluateIfNecessary(trust);
1692 dispatch_sync(trust->_trustQueue, ^{
1693 details = CFRetainSafe(trust->_details);
1694 });
1695 CFIndex pathLength = details ? CFArrayGetCount(details) : 0;
1696 CFMutableArrayRef exceptions = CFArrayCreateMutable(kCFAllocatorDefault, pathLength, &kCFTypeArrayCallBacks);
1697 CFIndex ix;
1698 for (ix = 0; ix < pathLength; ++ix) {
1699 CFDictionaryRef detail = (CFDictionaryRef)CFArrayGetValueAtIndex(details, ix);
1700 CFIndex detailCount = CFDictionaryGetCount(detail);
1701 CFMutableDictionaryRef exception;
1702 if (ix == 0 || detailCount > 0) {
1703 exception = CFDictionaryCreateMutableCopy(kCFAllocatorDefault, detailCount + 1, detail);
1704 SecCertificateRef certificate = SecTrustGetCertificateAtIndex(trust, ix);
1705 CFDataRef digest = SecCertificateGetSHA1Digest(certificate);
1706 CFDictionaryAddValue(exception, kSecCertificateDetailSHA1Digest, digest);
1707 } else {
1708 /* Add empty exception dictionaries for non leaf certs which have no exceptions to save space. */
1709 exception = (CFMutableDictionaryRef)CFDictionaryCreate(kCFAllocatorDefault, NULL, NULL, 0,
1710 &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
1711 }
1712 CFArrayAppendValue(exceptions, exception);
1713 CFReleaseNull(exception);
1714 }
1715
1716 /* Restore the stashed exceptions. */
1717 if (oldExceptions) {
1718 dispatch_sync(trust->_trustQueue, ^{
1719 trust->_exceptions = oldExceptions;
1720 });
1721 SecTrustSetNeedsEvaluation(trust);
1722 }
1723
1724 /* Remove any trailing empty dictionaries to save even more space (we skip the leaf
1725 since it will never be empty). */
1726 for (ix = pathLength; ix-- > 1;) {
1727 CFDictionaryRef exception = (CFDictionaryRef)CFArrayGetValueAtIndex(exceptions, ix);
1728 if (CFDictionaryGetCount(exception) == 0) {
1729 CFArrayRemoveValueAtIndex(exceptions, ix);
1730 } else {
1731 break;
1732 }
1733 }
1734
1735 CFDataRef encodedExceptions = CFPropertyListCreateData(kCFAllocatorDefault,
1736 exceptions, kCFPropertyListBinaryFormat_v1_0, 0, NULL);
1737 CFRelease(exceptions);
1738 CFReleaseSafe(details);
1739 return encodedExceptions;
1740 }
1741
1742 bool SecTrustSetExceptions(SecTrustRef trust, CFDataRef encodedExceptions) {
1743 if (!trust) {
1744 return false;
1745 }
1746 CFArrayRef exceptions = NULL;
1747
1748 if (NULL != encodedExceptions) {
1749 exceptions = (CFArrayRef)CFPropertyListCreateWithData(kCFAllocatorDefault,
1750 encodedExceptions, kCFPropertyListImmutable, NULL, NULL);
1751 }
1752
1753 if (exceptions && CFGetTypeID(exceptions) != CFArrayGetTypeID()) {
1754 CFRelease(exceptions);
1755 exceptions = NULL;
1756 }
1757
1758 dispatch_sync(trust->_trustQueue, ^{
1759 CFReleaseSafe(trust->_exceptions);
1760 trust->_exceptions = exceptions;
1761 });
1762
1763 /* We changed the exceptions -- so we need to re-evaluate */
1764 SecTrustSetNeedsEvaluation(trust);
1765
1766 /* If there is a valid exception entry for our current leaf we're golden. */
1767 if (SecTrustGetExceptionForCertificateAtIndex(trust, 0))
1768 return true;
1769
1770 /* The passed in exceptions didn't match our current leaf, so we discard it. */
1771 dispatch_sync(trust->_trustQueue, ^{
1772 CFReleaseNull(trust->_exceptions);
1773 });
1774 return false;
1775 }
1776
1777 #if TARGET_OS_OSX
1778 OSStatus
1779 SecTrustSetOptions(SecTrustRef trustRef, SecTrustOptionFlags options)
1780 {
1781 /* bridge to support API functionality for legacy callers */
1782 OSStatus status = errSecSuccess;
1783
1784 /* No options or none that trigger the exceptions behavior */
1785 if (!options ||
1786 0 == (options & (kSecTrustOptionAllowExpired |
1787 kSecTrustOptionImplicitAnchors |
1788 kSecTrustOptionAllowExpiredRoot))) {
1789 return status;
1790 }
1791
1792 __block CFMutableArrayRef exceptions = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
1793 if (!exceptions) { return errSecAllocate; }
1794
1795 /* Add the new options to the old_exceptions when those exceptions are tied to a particular cert.
1796 * If not tied to a particular cert, we reset the exceptions based on the input options. */
1797 CFArrayRef old_exceptions = SecTrustGetTrustExceptionsArray(trustRef);
1798 if (old_exceptions && SecTrustGetExceptionForCertificateAtIndex(trustRef, 0)) {
1799 CFIndex ix, count = CFArrayGetCount(old_exceptions);
1800 for (ix = 0; ix < count; ix++) {
1801 CFMutableDictionaryRef exception_dictionary = CFDictionaryCreateMutableCopy(NULL, 0, (CFDictionaryRef)CFArrayGetValueAtIndex(old_exceptions, ix));
1802 if (!exception_dictionary) { status = errSecAllocate; goto out; }
1803 if ((options & kSecTrustOptionAllowExpired) != 0) {
1804 CFDictionaryAddValue(exception_dictionary, kSecPolicyCheckTemporalValidity, kCFBooleanFalse);
1805 }
1806 if ((options & (kSecTrustOptionImplicitAnchors | kSecTrustOptionAllowExpiredRoot)) != 0) {
1807 /* Check that root is self-signed. */
1808 Boolean isSelfSigned = false;
1809 SecCertificateRef cert = SecTrustGetCertificateAtIndex(trustRef, ix);
1810 if (cert && (errSecSuccess == SecCertificateIsSelfSigned(cert, &isSelfSigned)) &&
1811 isSelfSigned) {
1812 if ((options & kSecTrustOptionImplicitAnchors) != 0) {
1813 CFDictionaryAddValue(exception_dictionary, kSecPolicyCheckAnchorTrusted, kCFBooleanFalse);
1814 } else if ((options & kSecTrustOptionAllowExpiredRoot) != 0) {
1815 CFDictionaryAddValue(exception_dictionary, kSecPolicyCheckTemporalValidity, kCFBooleanFalse);
1816 }
1817 }
1818 }
1819 CFArrayAppendValue(exceptions, exception_dictionary);
1820 CFReleaseNull(exception_dictionary);
1821 }
1822 } else {
1823 /* Create a new exceptions array. Warning, this takes advantage of implementation details of the exceptions mechanism. */
1824 CFMutableDictionaryRef exception_dictionary = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks,
1825 &kCFTypeDictionaryValueCallBacks);
1826 if (!exception_dictionary) { status = errSecAllocate; goto out; }
1827 if ((options & kSecTrustOptionAllowExpired) != 0) {
1828 CFDictionaryAddValue(exception_dictionary, kSecPolicyCheckTemporalValidity, kCFBooleanFalse);
1829 }
1830 if ((options & kSecTrustOptionAllowExpiredRoot) != 0) {
1831 CFDictionaryAddValue(exception_dictionary, kSecPolicyCheckValidRoot, kCFBooleanFalse);
1832 }
1833 if ((options & kSecTrustOptionImplicitAnchors) != 0) {
1834 CFDictionaryAddValue(exception_dictionary, kSecPolicyCheckAnchorTrusted, kCFBooleanFalse);
1835 }
1836 CFArrayAppendValue(exceptions, exception_dictionary);
1837 CFReleaseNull(exception_dictionary);
1838 }
1839
1840 /* Set exceptions */
1841 dispatch_sync(trustRef->_trustQueue, ^{
1842 CFReleaseSafe(trustRef->_exceptions);
1843 trustRef->_exceptions = CFRetainSafe(exceptions);
1844 });
1845 /* We changed the exceptions -- so we need to re-evaluate */
1846 SecTrustSetNeedsEvaluation(trustRef);
1847
1848 out:
1849 CFReleaseNull(exceptions);
1850 return status;
1851 }
1852 #endif
1853
1854 CFArrayRef SecTrustCopySummaryPropertiesAtIndex(SecTrustRef trust, CFIndex ix) {
1855 CFMutableArrayRef summary;
1856 SecCertificateRef certificate = SecTrustGetCertificateAtIndex(trust, ix);
1857 summary = SecCertificateCopySummaryProperties(certificate,
1858 SecTrustGetVerifyTime(trust));
1859 /* FIXME Add more details in the failure case. */
1860
1861 return summary;
1862 }
1863
1864 CFArrayRef SecTrustCopyDetailedPropertiesAtIndex(SecTrustRef trust, CFIndex ix) {
1865 CFArrayRef summary;
1866 SecCertificateRef certificate = SecTrustGetCertificateAtIndex(trust, ix);
1867 summary = SecCertificateCopyProperties(certificate);
1868
1869 return summary;
1870 }
1871
1872 struct TrustFailures {
1873 bool badLinkage;
1874 bool unknownCritExtn;
1875 bool untrustedAnchor;
1876 bool hostnameMismatch;
1877 bool policyFail;
1878 bool invalidCert;
1879 bool weakKey;
1880 bool weakHash;
1881 bool revocation;
1882 };
1883
1884 static void applyDetailProperty(const void *_key, const void *_value,
1885 void *context) {
1886 CFStringRef key = (CFStringRef)_key;
1887 struct TrustFailures *tf = (struct TrustFailures *)context;
1888 if (CFGetTypeID(_value) != CFBooleanGetTypeID()) {
1889 /* Value isn't a CFBooleanRef, oh no! */
1890 return;
1891 }
1892 CFBooleanRef value = (CFBooleanRef)_value;
1893 if (CFBooleanGetValue(value)) {
1894 /* Not an actual failure so we don't report it. */
1895 return;
1896 }
1897
1898 /* @@@ FIXME: Report a different return value when something is in the
1899 details but masked out by an exception and use that below for display
1900 purposes. */
1901 if (CFEqual(key, kSecPolicyCheckIdLinkage)) {
1902 tf->badLinkage = true;
1903 } else if (CFEqual(key, kSecPolicyCheckCriticalExtensions)) {
1904 tf->unknownCritExtn = true;
1905 } else if (CFEqual(key, kSecPolicyCheckAnchorTrusted)
1906 || CFEqual(key, kSecPolicyCheckAnchorSHA1)
1907 || CFEqual(key, kSecPolicyCheckAnchorSHA256)
1908 || CFEqual(key, kSecPolicyCheckAnchorApple)) {
1909 tf->untrustedAnchor = true;
1910 } else if (CFEqual(key, kSecPolicyCheckSSLHostname)) {
1911 tf->hostnameMismatch = true;
1912 } else if (CFEqual(key, kSecPolicyCheckTemporalValidity)) {
1913 tf->invalidCert = true;
1914 } else if (CFEqual(key, kSecPolicyCheckWeakKeySize)) {
1915 tf->weakKey = true;
1916 } else if (CFEqual(key, kSecPolicyCheckWeakSignature)) {
1917 tf->weakHash = true;
1918 } else if (CFEqual(key, kSecPolicyCheckRevocation)) {
1919 tf->revocation = true;
1920 } else
1921 /* Anything else is a policy failure. */
1922 #if 0
1923 if (CFEqual(key, kSecPolicyCheckNonEmptySubject)
1924 || CFEqual(key, kSecPolicyCheckBasicConstraints)
1925 || CFEqual(key, kSecPolicyCheckKeyUsage)
1926 || CFEqual(key, kSecPolicyCheckExtendedKeyUsage)
1927 || CFEqual(key, kSecPolicyCheckIssuerCommonName)
1928 || CFEqual(key, kSecPolicyCheckSubjectCommonNamePrefix)
1929 || CFEqual(key, kSecPolicyCheckChainLength)
1930 || CFEqual(key, kSecPolicyCheckNotValidBefore))
1931 #endif
1932 {
1933 tf->policyFail = true;
1934 }
1935 }
1936
1937 static void appendError(CFMutableArrayRef properties, CFStringRef error, bool localized) {
1938 CFStringRef localizedError = NULL;
1939 if (!error) {
1940 return;
1941 } else if (localized) {
1942 //%%% "SecCertificate" should be changed to "Certificate": rdar://37517120
1943 localizedError = SecFrameworkCopyLocalizedString(error, CFSTR("SecCertificate"));
1944 } else {
1945 localizedError = (CFStringRef) CFRetainSafe(error);
1946 }
1947 appendProperty(properties, kSecPropertyTypeError, NULL, NULL,
1948 localizedError, localized);
1949 CFReleaseNull(localizedError);
1950 }
1951
1952 #if TARGET_OS_OSX
1953 /* OS X properties array has a different structure and is implemented SecTrust.cpp. */
1954 CFArrayRef SecTrustCopyProperties_ios(SecTrustRef trust)
1955 #else
1956 CFArrayRef SecTrustCopyProperties(SecTrustRef trust)
1957 #endif
1958 {
1959 if (!trust) {
1960 return NULL;
1961 }
1962 SecTrustEvaluateIfNecessary(trust);
1963 bool localized = true;
1964 __block CFArrayRef details = NULL;
1965 dispatch_sync(trust->_trustQueue, ^{
1966 details = CFRetainSafe(trust->_details);
1967 });
1968 if (!details)
1969 return NULL;
1970
1971 struct TrustFailures tf = {};
1972
1973 CFIndex ix, count = CFArrayGetCount(details);
1974 for (ix = 0; ix < count; ++ix) {
1975 CFDictionaryRef detail = (CFDictionaryRef)
1976 CFArrayGetValueAtIndex(details, ix);
1977 /* We now have a detail dictionary for certificate at index ix, with
1978 a key value pair for each failed policy check. Let's convert it
1979 from Ro-Man form into something a Hu-Man can understand. */
1980 CFDictionaryApplyFunction(detail, applyDetailProperty, &tf);
1981 }
1982
1983 CFMutableArrayRef properties = CFArrayCreateMutable(kCFAllocatorDefault, 0,
1984 &kCFTypeArrayCallBacks);
1985 /* The badLinkage and unknownCritExtn failures are short circuited, since
1986 you can't recover from those errors. */
1987 if (tf.badLinkage) {
1988 appendError(properties, CFSTR("Invalid certificate chain linkage."), localized);
1989 } else if (tf.unknownCritExtn) {
1990 appendError(properties, CFSTR("One or more unsupported critical extensions found."), localized);
1991 } else {
1992 if (tf.untrustedAnchor) {
1993 appendError(properties, CFSTR("Root certificate is not trusted."), localized);
1994 }
1995 if (tf.hostnameMismatch) {
1996 appendError(properties, CFSTR("Hostname mismatch."), localized);
1997 }
1998 if (tf.policyFail) {
1999 appendError(properties, CFSTR("Policy requirements not met."), localized);
2000 }
2001 if (tf.invalidCert) {
2002 appendError(properties, CFSTR("One or more certificates have expired or are not valid yet."), localized);
2003 }
2004 if (tf.weakKey) {
2005 appendError(properties, CFSTR("One or more certificates is using a weak key size."), localized);
2006 }
2007 if (tf.weakHash) {
2008 appendError(properties, CFSTR("One or more certificates is using a weak signature algorithm."), localized);
2009 }
2010 if (tf.revocation) {
2011 appendError(properties, CFSTR("One or more certificates have been revoked."), localized);
2012 }
2013 }
2014
2015 if (CFArrayGetCount(properties) == 0) {
2016 /* The certificate chain is trusted, return an empty plist */
2017 CFReleaseNull(properties);
2018 }
2019
2020 CFReleaseNull(details);
2021 return properties;
2022 }
2023
2024 #if TARGET_OS_OSX
2025 static void _AppendStatusCode(CFMutableArrayRef array, OSStatus statusCode) {
2026 if (!array) {
2027 return;
2028 }
2029 SInt32 num = statusCode;
2030 CFNumberRef numRef = CFNumberCreate(NULL, kCFNumberSInt32Type, &num);
2031 if (!numRef) {
2032 return;
2033 }
2034 CFArrayAppendValue(array, numRef);
2035 CFRelease(numRef);
2036 }
2037 #endif
2038
2039 static CFArrayRef _SecTrustCopyDetails(SecTrustRef trust) {
2040 if (!trust) {
2041 return NULL;
2042 }
2043 __block CFArrayRef details = NULL;
2044 dispatch_sync(trust->_trustQueue, ^{
2045 details = CFRetainSafe(trust->_details);
2046 });
2047 #if TARGET_OS_OSX
2048 // Include status codes in the per-certificate details (rdar://27930542)
2049 CFMutableArrayRef newDetails = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
2050 if (!newDetails) {
2051 CFReleaseSafe(details);
2052 return NULL;
2053 }
2054 CFIndex index, chainLen = (details) ? CFArrayGetCount(details) : 0;
2055 for (index = 0; index < chainLen; index++) {
2056 CFDictionaryRef detailDict = CFArrayGetValueAtIndex(details, index);
2057 CFMutableDictionaryRef newDict = CFDictionaryCreateMutableCopy(NULL, 0, detailDict);
2058 CFMutableArrayRef statusCodes = CFArrayCreateMutable(kCFAllocatorDefault,
2059 0, &kCFTypeArrayCallBacks);
2060 if (statusCodes) {
2061 CFIndex i, numCodes = 0;
2062 SInt32 *codes = SecTrustCopyStatusCodes(trust, index, &numCodes);
2063 if (codes) {
2064 for (i = 0; i < numCodes; i++) {
2065 OSStatus scode = (OSStatus)codes[i];
2066 _AppendStatusCode(statusCodes, scode);
2067 }
2068 free(codes);
2069 }
2070 if (CFArrayGetCount(statusCodes) > 0) {
2071 CFDictionarySetValue(newDict, kSecCertificateDetailStatusCodes, statusCodes);
2072 }
2073 CFRelease(statusCodes);
2074 }
2075 if (newDict) {
2076 CFArrayAppendValue(newDetails, newDict);
2077 CFRelease(newDict);
2078 }
2079 }
2080 CFReleaseSafe(details);
2081 return newDetails;
2082 #else
2083 return details;
2084 #endif
2085 }
2086
2087 CFDictionaryRef SecTrustCopyResult(SecTrustRef trust) {
2088 // Builds and returns a dictionary of evaluation results.
2089 if (!trust) {
2090 return NULL;
2091 }
2092 __block CFMutableDictionaryRef results = CFDictionaryCreateMutable(NULL, 0,
2093 &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
2094
2095 SecTrustEvaluateIfNecessary(trust);
2096 __block CFArrayRef details = _SecTrustCopyDetails(trust);
2097
2098 dispatch_sync(trust->_trustQueue, ^{
2099 // kSecTrustResultDetails (per-cert results)
2100 if (details) {
2101 CFDictionarySetValue(results, (const void *)kSecTrustResultDetails, (const void *)details);
2102 CFRelease(details);
2103 }
2104
2105 // kSecTrustResultValue (overall trust result)
2106 CFNumberRef numValue = CFNumberCreate(NULL, kCFNumberSInt32Type, &trust->_trustResult);
2107 if (numValue) {
2108 CFDictionarySetValue(results, (const void *)kSecTrustResultValue, (const void *)numValue);
2109 CFRelease(numValue);
2110 }
2111 CFDictionaryRef info = trust->_info;
2112 if (trust->_trustResult == kSecTrustResultInvalid || !info) {
2113 return; // we have nothing more to add
2114 }
2115
2116 // kSecTrustEvaluationDate
2117 CFDateRef evaluationDate = trust->_verifyDate;
2118 if (evaluationDate) {
2119 CFDictionarySetValue(results, (const void *)kSecTrustEvaluationDate, (const void *)evaluationDate);
2120 }
2121
2122 // kSecTrustCertificateTransparency
2123 CFBooleanRef ctValue;
2124 if (CFDictionaryGetValueIfPresent(info, kSecTrustInfoCertificateTransparencyKey, (const void **)&ctValue)) {
2125 CFDictionarySetValue(results, (const void *)kSecTrustCertificateTransparency, (const void *)ctValue);
2126 }
2127
2128 // kSecTrustExtendedValidation
2129 CFBooleanRef evValue;
2130 if (CFDictionaryGetValueIfPresent(info, kSecTrustInfoExtendedValidationKey, (const void **)&evValue)) {
2131 CFDictionarySetValue(results, (const void *)kSecTrustExtendedValidation, (const void *)evValue);
2132 }
2133
2134 // kSecTrustOrganizationName
2135 CFStringRef organizationName;
2136 if (CFDictionaryGetValueIfPresent(info, kSecTrustInfoCompanyNameKey, (const void **)&organizationName)) {
2137 CFDictionarySetValue(results, (const void *)kSecTrustOrganizationName, (const void *)organizationName);
2138 }
2139
2140 // kSecTrustRevocationChecked
2141 CFBooleanRef revocationChecked;
2142 if (CFDictionaryGetValueIfPresent(info, kSecTrustRevocationChecked, (const void **)&revocationChecked)) {
2143 CFDictionarySetValue(results, (const void *)kSecTrustRevocationChecked, (const void *)revocationChecked);
2144 }
2145
2146 // kSecTrustRevocationReason
2147 CFNumberRef revocationReason;
2148 if (CFDictionaryGetValueIfPresent(info, kSecTrustRevocationReason, (const void **)&revocationReason)) {
2149 CFDictionarySetValue(results, (const void *)kSecTrustRevocationReason, (const void *)revocationReason);
2150 }
2151
2152 // kSecTrustRevocationValidUntilDate
2153 CFDateRef validUntilDate;
2154 if (CFDictionaryGetValueIfPresent(info, kSecTrustRevocationValidUntilDate, (const void **)&validUntilDate)) {
2155 CFDictionarySetValue(results, (const void *)kSecTrustRevocationValidUntilDate, (const void *)validUntilDate);
2156 }
2157 });
2158
2159 return results;
2160 }
2161
2162 #define do_if_registered(sdp, ...) if (gTrustd && gTrustd->sdp) { return gTrustd->sdp(__VA_ARGS__); }
2163
2164 static bool xpc_dictionary_entry_is_type(xpc_object_t dictionary, const char *key, xpc_type_t type) {
2165 xpc_object_t value = xpc_dictionary_get_value(dictionary, key);
2166 return value && (xpc_get_type(value) == type);
2167 }
2168
2169 static uint64_t do_ota_pki_op (enum SecXPCOperation op, CFErrorRef *error) {
2170 uint64_t num = 0;
2171 xpc_object_t message = securityd_create_message(op, error);
2172 if (message) {
2173 xpc_object_t response = securityd_message_with_reply_sync(message, error);
2174 if (response && xpc_dictionary_entry_is_type(response, kSecXPCKeyResult, XPC_TYPE_UINT64)) {
2175 num = (int64_t) xpc_dictionary_get_uint64(response, kSecXPCKeyResult);
2176 }
2177 if (response && error && xpc_dictionary_entry_is_type(response, kSecXPCKeyError, XPC_TYPE_DICTIONARY)) {
2178 xpc_object_t xpc_error = xpc_dictionary_get_value(response, kSecXPCKeyError);
2179 if (xpc_error) {
2180 *error = SecCreateCFErrorWithXPCObject(xpc_error);
2181 }
2182 }
2183 xpc_release_safe(message);
2184 xpc_release_safe(response);
2185 }
2186 return num;
2187 }
2188
2189
2190 // version 0 -> error, so we need to start at version 1 or later.
2191 uint64_t SecTrustGetTrustStoreVersionNumber(CFErrorRef *error) {
2192 do_if_registered(sec_ota_pki_trust_store_version, error);
2193
2194 os_activity_t activity = os_activity_create("SecTrustGetTrustStoreVersionNumber", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_DEFAULT);
2195 os_activity_scope(activity);
2196
2197 uint64_t num = do_ota_pki_op(sec_ota_pki_trust_store_version_id, error);
2198
2199 os_release(activity);
2200 return num;
2201 }
2202
2203 uint64_t SecTrustOTAPKIGetUpdatedAsset(CFErrorRef *error) {
2204 do_if_registered(sec_ota_pki_get_new_asset, error);
2205
2206 os_activity_t activity = os_activity_create("SecTrustOTAPKIGetUpdatedAsset", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_DEFAULT);
2207 os_activity_scope(activity);
2208
2209 uint64_t num = do_ota_pki_op(kSecXPCOpOTAPKIGetNewAsset, error);
2210
2211 os_release(activity);
2212 return num;
2213 }
2214
2215 bool SecTrustReportTLSAnalytics(CFStringRef eventName, xpc_object_t eventAttributes, CFErrorRef *error) {
2216 if (!eventName || !eventAttributes) {
2217 return false;
2218 }
2219 do_if_registered(sec_tls_analytics_report, eventName, eventAttributes, error);
2220
2221 os_activity_t activity = os_activity_create("SecTrustReportTLSAnalytics", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_DEFAULT);
2222 os_activity_scope(activity);
2223
2224 __block bool result = false;
2225 securityd_send_sync_and_do(kSecXPCOpTLSAnaltyicsReport, error, ^bool(xpc_object_t message, CFErrorRef *block_error) {
2226 if (!SecXPCDictionarySetString(message, kSecTrustEventNameKey, eventName, block_error)) {
2227 return false;
2228 }
2229 xpc_dictionary_set_value(message, kSecTrustEventAttributesKey, eventAttributes);
2230 return true;
2231 }, ^bool(xpc_object_t response, CFErrorRef *block_error) {
2232 result = SecXPCDictionaryGetBool(response, kSecXPCKeyResult, block_error);
2233 return true;
2234 });
2235
2236 os_release(activity);
2237 return result;
2238 }
2239
2240 /*
2241 * This function performs an evaluation of the leaf certificate only, and
2242 * does so in the process that called it. Its primary use is in SecItemCopyMatching
2243 * when kSecMatchPolicy is in the dictionary.
2244 */
2245 OSStatus SecTrustEvaluateLeafOnly(SecTrustRef trust, SecTrustResultType *result) {
2246 if (!trust) {
2247 return errSecParam;
2248 }
2249 OSStatus status = errSecSuccess;
2250 SecTrustResultType trustResult = kSecTrustResultInvalid;
2251 if((status = SecTrustValidateInput(trust))) {
2252 return status;
2253 }
2254
2255 struct OpaqueSecLeafPVC pvc;
2256 SecCertificateRef leaf = SecTrustGetCertificateAtIndex(trust, 0);
2257 __block CFArrayRef policies = NULL;
2258 dispatch_sync(trust->_trustQueue, ^{
2259 policies = CFRetainSafe(trust->_policies);
2260 });
2261 SecLeafPVCInit(&pvc, leaf, policies, SecTrustGetVerifyTime(trust));
2262
2263 if(!SecLeafPVCLeafChecks(&pvc)) {
2264 trustResult = kSecTrustResultRecoverableTrustFailure;
2265 } else {
2266 trustResult = kSecTrustResultUnspecified;
2267 }
2268
2269 /* Set other result context information */
2270 dispatch_sync(trust->_trustQueue, ^{
2271 trust->_trustResult = trustResult;
2272 trust->_details = CFRetainSafe(pvc.details);
2273 trust->_info = CFDictionaryCreateMutable(kCFAllocatorDefault, 0,
2274 &kCFTypeDictionaryKeyCallBacks,
2275 &kCFTypeDictionaryValueCallBacks);
2276 CFMutableArrayRef leafCert = CFArrayCreateMutableCopy(NULL, 1, trust->_certificates);
2277 trust->_chain = leafCert;
2278 });
2279
2280 SecLeafPVCDelete(&pvc);
2281
2282 /* log to syslog when there is a trust failure */
2283 if (trustResult != kSecTrustResultUnspecified) {
2284 CFStringRef failureDesc = SecTrustCopyFailureDescription(trust);
2285 secerror("%@", failureDesc);
2286 CFRelease(failureDesc);
2287 }
2288
2289 if (result) {
2290 *result = trustResult;
2291 }
2292
2293 CFReleaseSafe(policies);
2294 return status;
2295 }
2296
2297 static void deserializeCert(const void *value, void *context) {
2298 CFDataRef certData = (CFDataRef)value;
2299 if (isData(certData)) {
2300 SecCertificateRef cert = SecCertificateCreateWithData(NULL, certData);
2301 if (cert) {
2302 CFArrayAppendValue((CFMutableArrayRef)context, cert);
2303 CFRelease(cert);
2304 }
2305 }
2306 }
2307
2308 static CF_RETURNS_RETAINED CFArrayRef SecCertificateArrayDeserialize(CFArrayRef serializedCertificates) {
2309 CFMutableArrayRef result = NULL;
2310 require_quiet(isArray(serializedCertificates), errOut);
2311 CFIndex count = CFArrayGetCount(serializedCertificates);
2312 result = CFArrayCreateMutable(kCFAllocatorDefault, count, &kCFTypeArrayCallBacks);
2313 CFRange all_certs = { 0, count };
2314 CFArrayApplyFunction(serializedCertificates, all_certs, deserializeCert, result);
2315 errOut:
2316 return result;
2317 }
2318
2319 static void serializeCertificate(const void *value, void *context) {
2320 SecCertificateRef cert = (SecCertificateRef)value;
2321 if (cert && SecCertificateGetTypeID() == CFGetTypeID(cert)) {
2322 CFDataRef certData = SecCertificateCopyData(cert);
2323 if (certData) {
2324 CFArrayAppendValue((CFMutableArrayRef)context, certData);
2325 CFRelease(certData);
2326 }
2327 }
2328 }
2329
2330 static CF_RETURNS_RETAINED CFArrayRef SecCertificateArraySerialize(CFArrayRef certificates) {
2331 CFMutableArrayRef result = NULL;
2332 require_quiet(isArray(certificates), errOut);
2333 CFIndex count = CFArrayGetCount(certificates);
2334 result = CFArrayCreateMutable(NULL, count, &kCFTypeArrayCallBacks);
2335 CFRange all_certificates = { 0, count};
2336 CFArrayApplyFunction(certificates, all_certificates, serializeCertificate, result);
2337 errOut:
2338 return result;
2339 }
2340
2341 static CFPropertyListRef SecTrustCopyPlist(SecTrustRef trust) {
2342 __block CFMutableDictionaryRef output = NULL;
2343 output = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks,
2344 &kCFTypeDictionaryValueCallBacks);
2345
2346 dispatch_sync(trust->_trustQueue, ^{
2347 if (trust->_certificates) {
2348 CFArrayRef serializedCerts = SecCertificateArraySerialize(trust->_certificates);
2349 if (serializedCerts) {
2350 CFDictionaryAddValue(output, CFSTR(kSecTrustCertificatesKey), serializedCerts);
2351 CFRelease(serializedCerts);
2352 }
2353 }
2354 if (trust->_anchors) {
2355 CFArrayRef serializedAnchors = SecCertificateArraySerialize(trust->_anchors);
2356 if (serializedAnchors) {
2357 CFDictionaryAddValue(output, CFSTR(kSecTrustAnchorsKey), serializedAnchors);
2358 CFRelease(serializedAnchors);
2359 }
2360 }
2361 if (trust->_policies) {
2362 CFArrayRef serializedPolicies = SecPolicyArrayCreateSerialized(trust->_policies);
2363 if (serializedPolicies) {
2364 CFDictionaryAddValue(output, CFSTR(kSecTrustPoliciesKey), serializedPolicies);
2365 CFRelease(serializedPolicies);
2366 }
2367 }
2368 if (trust->_responses) {
2369 CFDictionaryAddValue(output, CFSTR(kSecTrustResponsesKey), trust->_responses);
2370 }
2371 if (trust->_SCTs) {
2372 CFDictionaryAddValue(output, CFSTR(kSecTrustSCTsKey), trust->_SCTs);
2373 }
2374 if (trust->_trustedLogs) {
2375 CFDictionaryAddValue(output, CFSTR(kSecTrustTrustedLogsKey), trust->_trustedLogs);
2376 }
2377 if (trust->_verifyDate) {
2378 CFDictionaryAddValue(output, CFSTR(kSecTrustVerifyDateKey), trust->_verifyDate);
2379 }
2380 if (trust->_chain) {
2381 CFArrayRef serializedCerts = SecCertificateArraySerialize(trust->_chain);
2382 if (serializedCerts) {
2383 CFDictionaryAddValue(output, CFSTR(kSecTrustChainKey), serializedCerts);
2384 CFRelease(serializedCerts);
2385 }
2386 }
2387 if (trust->_details) {
2388 CFDictionaryAddValue(output, CFSTR(kSecTrustDetailsKey), trust->_details);
2389 }
2390 if (trust->_info) {
2391 CFDictionaryAddValue(output, CFSTR(kSecTrustInfoKey), trust->_info);
2392 }
2393 if (trust->_exceptions) {
2394 CFDictionaryAddValue(output, CFSTR(kSecTrustExceptionsKey), trust->_exceptions);
2395 }
2396 CFNumberRef trustResult = CFNumberCreate(NULL, kCFNumberSInt32Type, &trust->_trustResult);
2397 if (trustResult) {
2398 CFDictionaryAddValue(output, CFSTR(kSecTrustResultKey), trustResult);
2399 }
2400 CFReleaseNull(trustResult);
2401 if (trust->_anchorsOnly) {
2402 CFDictionaryAddValue(output, CFSTR(kSecTrustAnchorsOnlyKey), kCFBooleanTrue);
2403 } else {
2404 CFDictionaryAddValue(output, CFSTR(kSecTrustAnchorsOnlyKey), kCFBooleanFalse);
2405 }
2406 if (trust->_keychainsAllowed) {
2407 CFDictionaryAddValue(output, CFSTR(kSecTrustKeychainsAllowedKey), kCFBooleanTrue);
2408 } else {
2409 CFDictionaryAddValue(output, CFSTR(kSecTrustKeychainsAllowedKey), kCFBooleanFalse);
2410 }
2411 });
2412
2413 return output;
2414 }
2415
2416 CFDataRef SecTrustSerialize(SecTrustRef trust, CFErrorRef *error) {
2417 CFPropertyListRef plist = NULL;
2418 CFDataRef derTrust = NULL;
2419 require_action_quiet(trust, out,
2420 SecError(errSecParam, error, CFSTR("null trust input")));
2421 require_action_quiet(plist = SecTrustCopyPlist(trust), out,
2422 SecError(errSecDecode, error, CFSTR("unable to create trust plist")));
2423 require_quiet(derTrust = CFPropertyListCreateDERData(NULL, plist, error), out);
2424
2425 out:
2426 CFReleaseNull(plist);
2427 return derTrust;
2428 }
2429
2430 static OSStatus SecTrustCreateFromPlist(CFPropertyListRef plist, SecTrustRef CF_RETURNS_RETAINED *trust) {
2431 OSStatus status = errSecParam;
2432 SecTrustRef output = NULL;
2433 CFTypeRef serializedCertificates = NULL, serializedPolicies = NULL, serializedAnchors = NULL;
2434 CFNumberRef trustResultNum = NULL;
2435 CFArrayRef certificates = NULL, policies = NULL, anchors = NULL, responses = NULL,
2436 SCTs = NULL, trustedLogs = NULL, details = NULL, exceptions = NULL, chain = NULL;
2437 CFDateRef verifyDate = NULL;
2438 CFDictionaryRef info = NULL;
2439
2440 require_quiet(CFDictionaryGetTypeID() == CFGetTypeID(plist), out);
2441 require_quiet(serializedCertificates = CFDictionaryGetValue(plist, CFSTR(kSecTrustCertificatesKey)), out);
2442 require_quiet(certificates = SecCertificateArrayDeserialize(serializedCertificates), out);
2443 require_quiet(serializedPolicies = CFDictionaryGetValue(plist, CFSTR(kSecTrustPoliciesKey)), out);
2444 require_quiet(policies = SecPolicyArrayCreateDeserialized(serializedPolicies), out);
2445 require_noerr_quiet(status = SecTrustCreateWithCertificates(certificates, policies, &output), out);
2446
2447 serializedAnchors = CFDictionaryGetValue(plist, CFSTR(kSecTrustAnchorsKey));
2448 if (isArray(serializedAnchors)) {
2449 anchors = SecCertificateArrayDeserialize(serializedAnchors);
2450 output->_anchors = anchors;
2451 }
2452 responses = CFDictionaryGetValue(plist, CFSTR(kSecTrustResponsesKey));
2453 if (isArray(responses)) {
2454 output->_responses = CFRetainSafe(responses);
2455 }
2456 SCTs = CFDictionaryGetValue(plist, CFSTR(kSecTrustSCTsKey));
2457 if (isArray(responses)) {
2458 output->_SCTs = CFRetainSafe(SCTs);
2459 }
2460 trustedLogs = CFDictionaryGetValue(plist, CFSTR(kSecTrustTrustedLogsKey));
2461 if (isArray(trustedLogs)) {
2462 output->_trustedLogs = CFRetainSafe(trustedLogs);
2463 }
2464 verifyDate = CFDictionaryGetValue(plist, CFSTR(kSecTrustVerifyDateKey));
2465 if (isDate(verifyDate)) {
2466 output->_verifyDate = CFRetainSafe(verifyDate);
2467 }
2468 chain = CFDictionaryGetValue(plist, CFSTR(kSecTrustChainKey));
2469 if (isArray(chain)) {
2470 output->_chain = SecCertificateArrayDeserialize(chain);
2471 }
2472 details = CFDictionaryGetValue(plist, CFSTR(kSecTrustDetailsKey));
2473 if (isArray(details)) {
2474 output->_details = CFRetainSafe(details);
2475 }
2476 info = CFDictionaryGetValue(plist, CFSTR(kSecTrustInfoKey));
2477 if (isDictionary(info)) {
2478 output->_info = CFRetainSafe(info);
2479 }
2480 exceptions = CFDictionaryGetValue(plist, CFSTR(kSecTrustExceptionsKey));
2481 if (isArray(exceptions)) {
2482 output->_exceptions = CFRetainSafe(exceptions);
2483 }
2484 int32_t trustResult = -1;
2485 trustResultNum = CFDictionaryGetValue(plist, CFSTR(kSecTrustResultKey));
2486 if (isNumber(trustResultNum) && CFNumberGetValue(trustResultNum, kCFNumberSInt32Type, &trustResult) &&
2487 (trustResult >= 0)) {
2488 output->_trustResult = trustResult;
2489 } else {
2490 status = errSecParam;
2491 }
2492 if (CFDictionaryGetValue(plist, CFSTR(kSecTrustAnchorsOnlyKey)) == kCFBooleanTrue) {
2493 output->_anchorsOnly = true;
2494 } /* false is set by default */
2495 if (CFDictionaryGetValue(plist, CFSTR(kSecTrustKeychainsAllowedKey)) == kCFBooleanFalse) {
2496 output->_keychainsAllowed = false;
2497 } /* true is set by default */
2498
2499 out:
2500 if (errSecSuccess == status && trust) {
2501 *trust = output;
2502 }
2503 CFReleaseNull(policies);
2504 CFReleaseNull(certificates);
2505 return status;
2506 }
2507
2508 SecTrustRef SecTrustDeserialize(CFDataRef serializedTrust, CFErrorRef *error) {
2509 SecTrustRef trust = NULL;
2510 CFPropertyListRef plist = NULL;
2511 OSStatus status = errSecSuccess;
2512 require_action_quiet(serializedTrust, out,
2513 SecError(errSecParam, error, CFSTR("null serialized trust input")));
2514 require_quiet(plist = CFPropertyListCreateWithDERData(NULL, serializedTrust,
2515 kCFPropertyListImmutable, NULL, error), out);
2516 require_noerr_action_quiet(status = SecTrustCreateFromPlist(plist, &trust), out,
2517 SecError(status, error, CFSTR("unable to create trust ref")));
2518
2519 out:
2520 CFReleaseNull(plist);
2521 return trust;
2522 }