]> git.saurik.com Git - apple/security.git/blob - OSX/sec/Security/SecTrust.c
Security-57740.51.3.tar.gz
[apple/security.git] / OSX / sec / Security / SecTrust.c
1 /*
2 * Copyright (c) 2006-2016 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/SecItemPriv.h>
30 #include <Security/SecCertificateInternal.h>
31 #include <Security/SecCertificatePath.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 <CoreFoundation/CFRuntime.h>
40 #include <CoreFoundation/CFSet.h>
41 #include <CoreFoundation/CFString.h>
42 #include <CoreFoundation/CFNumber.h>
43 #include <CoreFoundation/CFArray.h>
44 #include <CoreFoundation/CFPropertyList.h>
45 #include <AssertMacros.h>
46 #include <stdbool.h>
47 #include <string.h>
48 #include <stdlib.h>
49 #include <syslog.h>
50 #include <pthread.h>
51 #include <os/activity.h>
52
53 #include <utilities/SecIOFormat.h>
54 #include <utilities/SecCFError.h>
55 #include <utilities/SecCFWrappers.h>
56 #include <utilities/SecCertificateTrace.h>
57 #include <utilities/debugging.h>
58 #include <utilities/der_plist.h>
59 #include <utilities/SecDispatchRelease.h>
60
61 #include "SecRSAKey.h"
62 #include <libDER/oids.h>
63
64 #include <ipc/securityd_client.h>
65
66 #include <securityd/SecTrustServer.h>
67
68 #define SEC_CONST_DECL(k,v) const CFStringRef k = CFSTR(v);
69
70 SEC_CONST_DECL (kSecTrustInfoExtendedValidationKey, "ExtendedValidation");
71 SEC_CONST_DECL (kSecTrustInfoCompanyNameKey, "CompanyName");
72 SEC_CONST_DECL (kSecTrustInfoRevocationKey, "Revocation");
73 SEC_CONST_DECL (kSecTrustInfoRevocationValidUntilKey, "RevocationValidUntil");
74 SEC_CONST_DECL (kSecTrustInfoCertificateTransparencyKey, "CertificateTransparency");
75 SEC_CONST_DECL (kSecTrustInfoCertificateTransparencyWhiteListKey, "CertificateTransparencyWhiteList");
76
77 /* Public trust result constants */
78 SEC_CONST_DECL (kSecTrustEvaluationDate, "TrustEvaluationDate");
79 SEC_CONST_DECL (kSecTrustExtendedValidation, "TrustExtendedValidation");
80 SEC_CONST_DECL (kSecTrustOrganizationName, "Organization");
81 SEC_CONST_DECL (kSecTrustResultValue, "TrustResultValue");
82 SEC_CONST_DECL (kSecTrustRevocationChecked, "TrustRevocationChecked");
83 SEC_CONST_DECL (kSecTrustRevocationReason, "TrustRevocationReason");
84 SEC_CONST_DECL (kSecTrustRevocationValidUntilDate, "TrustExpirationDate");
85 SEC_CONST_DECL (kSecTrustResultDetails, "TrustResultDetails");
86 SEC_CONST_DECL (kSecTrustCertificateTransparency, "TrustCertificateTransparency");
87 SEC_CONST_DECL (kSecTrustCertificateTransparencyWhiteList, "TrustCertificateTransparencyWhiteList");
88
89 #pragma mark -
90 #pragma mark SecTrust
91
92 /********************************************************
93 ****************** SecTrust object *********************
94 ********************************************************/
95 struct __SecTrust {
96 CFRuntimeBase _base;
97 CFArrayRef _certificates;
98 CFArrayRef _anchors;
99 CFTypeRef _policies;
100 CFArrayRef _responses;
101 CFArrayRef _SCTs;
102 CFArrayRef _trustedLogs;
103 CFDateRef _verifyDate;
104 SecCertificatePathRef _chain;
105 SecKeyRef _publicKey;
106 CFArrayRef _details;
107 CFDictionaryRef _info;
108 CFArrayRef _exceptions;
109
110 /* Note that a value of kSecTrustResultInvalid (0)
111 * indicates the trust must be (re)evaluated; any
112 * functions which modify trust parameters in a way
113 * that would invalidate the current result must set
114 * this value back to kSecTrustResultInvalid.
115 */
116 SecTrustResultType _trustResult;
117
118 /* If true we don't trust any anchors other than the ones in _anchors. */
119 bool _anchorsOnly;
120 /* If false we shouldn't search keychains for parents or anchors. */
121 bool _keychainsAllowed;
122
123 /* Data blobs for legacy CSSM_TP_APPLE_EVIDENCE_INFO structure,
124 * to support callers of SecTrustGetResult on OS X. Since fields of
125 * one structure contain pointers into the other, these cannot be
126 * serialized; if a SecTrust is being serialized or copied, these values
127 * should just be initialized to NULL in the copy and built when needed. */
128 void* _legacy_info_array;
129 void* _legacy_status_array;
130
131 /* The trust result as determined by the trust server,
132 * before the caller's exceptions are applied.
133 */
134 SecTrustResultType _trustResultBeforeExceptions;
135
136 /* Dispatch queue for thread-safety */
137 dispatch_queue_t _trustQueue;
138
139 /* === IMPORTANT! ===
140 * Any change to this structure definition
141 * must also be made in the TSecTrust structure,
142 * located in SecTrust.cpp. To avoid problems,
143 * new fields should always be appended at the
144 * end of the structure.
145 */
146 };
147
148 /* Forward declarations of static functions. */
149 static OSStatus SecTrustEvaluateIfNecessary(SecTrustRef trust);
150
151 /* Static functions. */
152 static CFStringRef SecTrustCopyFormatDescription(CFTypeRef cf, CFDictionaryRef formatOptions) {
153 SecTrustRef trust = (SecTrustRef)cf;
154 return CFStringCreateWithFormat(kCFAllocatorDefault, NULL,
155 CFSTR("<SecTrustRef: %p>"), trust);
156 }
157
158 static void SecTrustDestroy(CFTypeRef cf) {
159 SecTrustRef trust = (SecTrustRef)cf;
160
161 dispatch_release_null(trust->_trustQueue);
162 CFReleaseNull(trust->_certificates);
163 CFReleaseNull(trust->_policies);
164 CFReleaseNull(trust->_responses);
165 CFReleaseNull(trust->_SCTs);
166 CFReleaseNull(trust->_trustedLogs);
167 CFReleaseNull(trust->_verifyDate);
168 CFReleaseNull(trust->_anchors);
169 CFReleaseNull(trust->_chain);
170 CFReleaseNull(trust->_publicKey);
171 CFReleaseNull(trust->_details);
172 CFReleaseNull(trust->_info);
173 CFReleaseNull(trust->_exceptions);
174
175 if (trust->_legacy_info_array) {
176 free(trust->_legacy_info_array);
177 }
178 if (trust->_legacy_status_array) {
179 free(trust->_legacy_status_array);
180 }
181 }
182
183 /* Public API functions. */
184 CFGiblisFor(SecTrust)
185
186 OSStatus SecTrustCreateWithCertificates(CFTypeRef certificates,
187 CFTypeRef policies, SecTrustRef *trust) {
188 OSStatus status = errSecParam;
189 CFAllocatorRef allocator = kCFAllocatorDefault;
190 CFArrayRef l_certs = NULL, l_policies = NULL;
191 SecTrustRef result = NULL;
192
193 check(certificates);
194 check(trust);
195 CFTypeID certType = CFGetTypeID(certificates);
196 if (certType == CFArrayGetTypeID()) {
197 /* We need at least 1 certificate. */
198 require_quiet(CFArrayGetCount(certificates) > 0, errOut);
199 l_certs = CFArrayCreateCopy(allocator, certificates);
200 } else if (certType == SecCertificateGetTypeID()) {
201 l_certs = CFArrayCreate(allocator, &certificates, 1,
202 &kCFTypeArrayCallBacks);
203 } else {
204 goto errOut;
205 }
206 if (!l_certs) {
207 status = errSecAllocate;
208 goto errOut;
209 }
210
211 if (!policies) {
212 CFTypeRef policy = SecPolicyCreateBasicX509();
213 l_policies = CFArrayCreate(allocator, &policy, 1,
214 &kCFTypeArrayCallBacks);
215 CFRelease(policy);
216 }
217 else if (CFGetTypeID(policies) == CFArrayGetTypeID()) {
218 l_policies = CFArrayCreateCopy(allocator, policies);
219 }
220 else if (CFGetTypeID(policies) == SecPolicyGetTypeID()) {
221 l_policies = CFArrayCreate(allocator, &policies, 1,
222 &kCFTypeArrayCallBacks);
223 } else {
224 goto errOut;
225 }
226 if (!l_policies) {
227 status = errSecAllocate;
228 goto errOut;
229 }
230
231 CFIndex size = sizeof(struct __SecTrust);
232 require_quiet(result = (SecTrustRef)_CFRuntimeCreateInstance(allocator,
233 SecTrustGetTypeID(), size - sizeof(CFRuntimeBase), 0), errOut);
234 memset((char*)result + sizeof(result->_base), 0,
235 sizeof(*result) - sizeof(result->_base));
236 status = errSecSuccess;
237
238 errOut:
239 if (status) {
240 CFReleaseSafe(result);
241 CFReleaseSafe(l_certs);
242 CFReleaseSafe(l_policies);
243 } else {
244 result->_certificates = l_certs;
245 result->_policies = l_policies;
246 result->_keychainsAllowed = true;
247 result->_trustQueue = dispatch_queue_create("trust", DISPATCH_QUEUE_SERIAL);
248 if (trust)
249 *trust = result;
250 else
251 CFReleaseSafe(result);
252 }
253 return status;
254 }
255
256 OSStatus SecTrustCopyInputCertificates(SecTrustRef trust, CFArrayRef *certificates) {
257 if (!trust || !certificates) {
258 return errSecParam;
259 }
260 __block CFArrayRef certArray = NULL;
261 dispatch_sync(trust->_trustQueue, ^{
262 certArray = CFArrayCreateCopy(NULL, trust->_certificates);
263 });
264 if (!certArray) {
265 return errSecAllocate;
266 }
267 *certificates = certArray;
268 return errSecSuccess;
269 }
270
271 OSStatus SecTrustAddToInputCertificates(SecTrustRef trust, CFTypeRef certificates) {
272 if (!trust || !certificates) {
273 return errSecParam;
274 }
275 __block CFMutableArrayRef newCertificates = NULL;
276 dispatch_sync(trust->_trustQueue, ^{
277 newCertificates = CFArrayCreateMutableCopy(NULL, 0, trust->_certificates);
278 });
279
280 if (isArray(certificates)) {
281 CFArrayAppendArray(newCertificates, certificates,
282 CFRangeMake(0, CFArrayGetCount(certificates)));
283 } else if (CFGetTypeID(certificates) == SecCertificateGetTypeID()) {
284 CFArrayAppendValue(newCertificates, certificates);
285 } else {
286 CFReleaseNull(newCertificates);
287 return errSecParam;
288 }
289
290 dispatch_sync(trust->_trustQueue, ^{
291 CFReleaseNull(trust->_certificates);
292 trust->_certificates = (CFArrayRef)newCertificates;
293 });
294
295 return errSecSuccess;
296 }
297
298 static void SecTrustSetNeedsEvaluation(SecTrustRef trust) {
299 check(trust);
300 if (trust) {
301 dispatch_sync(trust->_trustQueue, ^{
302 trust->_trustResult = kSecTrustResultInvalid;
303 trust->_trustResultBeforeExceptions = kSecTrustResultInvalid;
304 });
305 }
306 }
307
308 OSStatus SecTrustSetAnchorCertificatesOnly(SecTrustRef trust,
309 Boolean anchorCertificatesOnly) {
310 if (!trust) {
311 return errSecParam;
312 }
313 SecTrustSetNeedsEvaluation(trust);
314 trust->_anchorsOnly = anchorCertificatesOnly;
315
316 return errSecSuccess;
317 }
318
319 OSStatus SecTrustSetAnchorCertificates(SecTrustRef trust,
320 CFArrayRef anchorCertificates) {
321 if (!trust) {
322 return errSecParam;
323 }
324 SecTrustSetNeedsEvaluation(trust);
325 if (anchorCertificates)
326 CFRetain(anchorCertificates);
327 dispatch_sync(trust->_trustQueue, ^{
328 if (trust->_anchors)
329 CFRelease(trust->_anchors);
330 trust->_anchors = anchorCertificates;
331 });
332 trust->_anchorsOnly = (anchorCertificates != NULL);
333
334 return errSecSuccess;
335 }
336
337 OSStatus SecTrustCopyCustomAnchorCertificates(SecTrustRef trust,
338 CFArrayRef *anchors) {
339 if (!trust|| !anchors) {
340 return errSecParam;
341 }
342 __block CFArrayRef anchorsArray = NULL;
343 dispatch_sync(trust->_trustQueue, ^{
344 if (trust->_anchors) {
345 anchorsArray = CFArrayCreateCopy(kCFAllocatorDefault, trust->_anchors);
346 }
347 });
348
349 *anchors = anchorsArray;
350 return errSecSuccess;
351 }
352
353 OSStatus SecTrustSetOCSPResponse(SecTrustRef trust, CFTypeRef responseData) {
354 if (!trust) {
355 return errSecParam;
356 }
357 SecTrustSetNeedsEvaluation(trust);
358 CFArrayRef responseArray = NULL;
359 if (responseData) {
360 if (CFGetTypeID(responseData) == CFArrayGetTypeID()) {
361 responseArray = CFArrayCreateCopy(kCFAllocatorDefault, responseData);
362 } else if (CFGetTypeID(responseData) == CFDataGetTypeID()) {
363 responseArray = CFArrayCreate(kCFAllocatorDefault, &responseData, 1,
364 &kCFTypeArrayCallBacks);
365 } else {
366 return errSecParam;
367 }
368 }
369 dispatch_sync(trust->_trustQueue, ^{
370 if (trust->_responses)
371 CFRelease(trust->_responses);
372 trust->_responses = responseArray;
373 });
374 return errSecSuccess;
375 }
376
377 OSStatus SecTrustSetSignedCertificateTimestamps(SecTrustRef trust, CFArrayRef sctArray) {
378 if (!trust) {
379 return errSecParam;
380 }
381 SecTrustSetNeedsEvaluation(trust);
382 dispatch_sync(trust->_trustQueue, ^{
383 CFRetainAssign(trust->_SCTs, sctArray);
384 });
385 return errSecSuccess;
386 }
387
388 OSStatus SecTrustSetTrustedLogs(SecTrustRef trust, CFArrayRef trustedLogs) {
389 if (!trust) {
390 return errSecParam;
391 }
392 SecTrustSetNeedsEvaluation(trust);
393 dispatch_sync(trust->_trustQueue, ^{
394 CFRetainAssign(trust->_trustedLogs, trustedLogs);
395 });
396 return errSecSuccess;
397 }
398
399 OSStatus SecTrustSetVerifyDate(SecTrustRef trust, CFDateRef verifyDate) {
400 if (!trust) {
401 return errSecParam;
402 }
403 SecTrustSetNeedsEvaluation(trust);
404 check(verifyDate);
405 dispatch_sync(trust->_trustQueue, ^{
406 CFRetainAssign(trust->_verifyDate, verifyDate);
407 });
408 return errSecSuccess;
409 }
410
411 OSStatus SecTrustSetPolicies(SecTrustRef trust, CFTypeRef newPolicies) {
412 if (!trust || !newPolicies) {
413 return errSecParam;
414 }
415 SecTrustSetNeedsEvaluation(trust);
416 check(newPolicies);
417
418 __block CFArrayRef policyArray = NULL;
419 if (CFGetTypeID(newPolicies) == CFArrayGetTypeID()) {
420 policyArray = CFArrayCreateCopy(kCFAllocatorDefault, newPolicies);
421 } else if (CFGetTypeID(newPolicies) == SecPolicyGetTypeID()) {
422 policyArray = CFArrayCreate(kCFAllocatorDefault, &newPolicies, 1,
423 &kCFTypeArrayCallBacks);
424 } else {
425 return errSecParam;
426 }
427
428 dispatch_sync(trust->_trustQueue, ^{
429 CFReleaseSafe(trust->_policies);
430 trust->_policies = policyArray;
431 });
432
433 return errSecSuccess;
434 }
435
436 OSStatus SecTrustSetKeychainsAllowed(SecTrustRef trust, Boolean allowed) {
437 if (!trust) {
438 return errSecParam;
439 }
440 SecTrustSetNeedsEvaluation(trust);
441 trust->_keychainsAllowed = allowed;
442
443 return errSecSuccess;
444 }
445
446 OSStatus SecTrustGetKeychainsAllowed(SecTrustRef trust, Boolean *allowed) {
447 if (!trust || !allowed) {
448 return errSecParam;
449 }
450 *allowed = trust->_keychainsAllowed;
451
452 return errSecSuccess;
453 }
454
455 OSStatus SecTrustCopyPolicies(SecTrustRef trust, CFArrayRef *policies) {
456 if (!trust|| !policies) {
457 return errSecParam;
458 }
459 __block CFArrayRef policyArray = NULL;
460 dispatch_sync(trust->_trustQueue, ^{
461 policyArray = CFArrayCreateCopy(kCFAllocatorDefault, trust->_policies);
462 });
463 if (!policyArray) {
464 return errSecAllocate;
465 }
466 *policies = policyArray;
467 return errSecSuccess;
468 }
469
470 static OSStatus SecTrustSetOptionInPolicies(CFArrayRef policies, CFStringRef key, CFTypeRef value) {
471 OSStatus status = errSecSuccess;
472 require_action(policies && CFGetTypeID(policies) == CFArrayGetTypeID(), out, status = errSecInternal);
473 for (int i=0; i < CFArrayGetCount(policies); i++) {
474 SecPolicyRef policy = NULL;
475 require_action_quiet(policy = (SecPolicyRef)CFArrayGetValueAtIndex(policies, i), out, status = errSecInternal);
476 CFMutableDictionaryRef options = NULL;
477 require_action_quiet(options = CFDictionaryCreateMutableCopy(NULL, 0, policy->_options), out, status = errSecAllocate);
478 CFDictionaryAddValue(options, key, value);
479 CFReleaseNull(policy->_options);
480 policy->_options = options;
481 }
482 out:
483 return status;
484 }
485
486 static OSStatus SecTrustRemoveOptionInPolicies(CFArrayRef policies, CFStringRef key) {
487 OSStatus status = errSecSuccess;
488 require_action(policies && CFGetTypeID(policies) == CFArrayGetTypeID(), out, status = errSecInternal);
489 for (int i=0; i < CFArrayGetCount(policies); i++) {
490 SecPolicyRef policy = NULL;
491 require_action_quiet(policy = (SecPolicyRef)CFArrayGetValueAtIndex(policies, i), out, status = errSecInternal);
492 if (CFDictionaryGetValue(policy->_options, key)) {
493 CFMutableDictionaryRef options = NULL;
494 require_action_quiet(options = CFDictionaryCreateMutableCopy(NULL, 0, policy->_options), out, status = errSecAllocate);
495 CFDictionaryRemoveValue(options, key);
496 CFReleaseNull(policy->_options);
497 policy->_options = options;
498 }
499 }
500 out:
501 return status;
502 }
503
504 static CF_RETURNS_RETAINED CFArrayRef SecTrustCopyOptionsFromPolicies(CFArrayRef policies, CFStringRef key) {
505 CFMutableArrayRef foundValues = NULL;
506 foundValues = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
507 for (int i=0; i < CFArrayGetCount(policies); i++) {
508 SecPolicyRef policy = (SecPolicyRef)CFArrayGetValueAtIndex(policies, i);
509 CFTypeRef value = CFDictionaryGetValue(policy->_options, key);
510 if (value) {
511 CFArrayAppendValue(foundValues, value);
512 }
513 }
514 if (!CFArrayGetCount(foundValues)) {
515 CFReleaseNull(foundValues);
516 return NULL;
517 }
518 else {
519 return foundValues;
520 }
521 }
522
523 /* The only effective way to disable network fetch is within the policy options:
524 * presence of the kSecPolicyCheckNoNetworkAccess key in any of the policies
525 * will prevent network access for fetching.
526 * The current SecTrustServer implementation doesn't distinguish between network
527 * access for revocation and network access for fetching.
528 */
529 OSStatus SecTrustSetNetworkFetchAllowed(SecTrustRef trust, Boolean allowFetch) {
530 if (!trust) {
531 return errSecParam;
532 }
533 __block OSStatus status = errSecSuccess;
534 dispatch_sync(trust->_trustQueue, ^{
535 if (!allowFetch) {
536 status = SecTrustSetOptionInPolicies(trust->_policies, kSecPolicyCheckNoNetworkAccess, kCFBooleanTrue);
537 } else {
538 status = SecTrustRemoveOptionInPolicies(trust->_policies, kSecPolicyCheckNoNetworkAccess);
539 }
540 });
541 return status;
542 }
543
544 OSStatus SecTrustGetNetworkFetchAllowed(SecTrustRef trust, Boolean *allowFetch) {
545 if (!trust || !allowFetch) {
546 return errSecParam;
547 }
548 __block CFArrayRef foundValues = NULL;
549 dispatch_sync(trust->_trustQueue, ^{
550 foundValues = SecTrustCopyOptionsFromPolicies(trust->_policies, kSecPolicyCheckNoNetworkAccess);
551 });
552 if (foundValues) {
553 *allowFetch = false;
554 } else {
555 *allowFetch = true;
556 }
557 CFReleaseNull(foundValues);
558 return errSecSuccess;
559 }
560
561 CFAbsoluteTime SecTrustGetVerifyTime(SecTrustRef trust) {
562 __block CFAbsoluteTime verifyTime = CFAbsoluteTimeGetCurrent();
563 if (!trust) {
564 return verifyTime;
565 }
566 dispatch_sync(trust->_trustQueue, ^{
567 if (trust->_verifyDate) {
568 verifyTime = CFDateGetAbsoluteTime(trust->_verifyDate);
569 } else {
570 trust->_verifyDate = CFDateCreate(CFGetAllocator(trust), verifyTime);
571 }
572 });
573
574 return verifyTime;
575 }
576
577 CFArrayRef SecTrustGetDetails(SecTrustRef trust) {
578 if (!trust) {
579 return NULL;
580 }
581 SecTrustEvaluateIfNecessary(trust);
582 return trust->_details;
583 }
584
585 OSStatus SecTrustGetTrustResult(SecTrustRef trust,
586 SecTrustResultType *result) {
587 if (!trust || !result) {
588 return errSecParam;
589 }
590 dispatch_sync(trust->_trustQueue, ^{
591 *result = trust->_trustResult;
592 });
593 return errSecSuccess;
594 }
595
596 static CFStringRef kSecCertificateDetailSHA1Digest = CFSTR("SHA1Digest");
597
598 static CFDictionaryRef SecTrustGetExceptionForCertificateAtIndex(SecTrustRef trust, CFIndex ix) {
599 CFDictionaryRef exception = NULL;
600 __block CFArrayRef exceptions = NULL;
601 dispatch_sync(trust->_trustQueue, ^{
602 exceptions = CFRetainSafe(trust->_exceptions);
603 });
604 if (!exceptions || ix >= CFArrayGetCount(exceptions)) {
605 goto out;
606 }
607
608 SecCertificateRef certificate = SecTrustGetCertificateAtIndex(trust, ix);
609 if (!certificate) {
610 goto out;
611 }
612
613 exception = (CFDictionaryRef)CFArrayGetValueAtIndex(exceptions, ix);
614 if (CFGetTypeID(exception) != CFDictionaryGetTypeID()) {
615 exception = NULL;
616 goto out;
617 }
618
619 /* If the exception contains the current certificates sha1Digest in the
620 kSecCertificateDetailSHA1Digest key then we use it otherwise we ignore it. */
621 CFDataRef sha1Digest = SecCertificateGetSHA1Digest(certificate);
622 CFTypeRef digestValue = CFDictionaryGetValue(exception, kSecCertificateDetailSHA1Digest);
623 if (!digestValue || !CFEqual(sha1Digest, digestValue))
624 exception = NULL;
625
626 out:
627 CFReleaseSafe(exceptions);
628 return exception;
629 }
630
631 struct SecTrustFilteredDetailContext {
632 CFDictionaryRef exception;
633 CFMutableDictionaryRef filteredDetail;
634 };
635
636 static void SecTrustFilterDetail(const void *key, const void *value, void *context) {
637 struct SecTrustFilteredDetailContext *ctx = (struct SecTrustFilteredDetailContext *)context;
638 if (!key || !value || !ctx->exception || !ctx->filteredDetail) {
639 return;
640 }
641 if (CFEqual(kSecCertificateDetailSHA1Digest, key)) {
642 return; /* ignore SHA1 hash entry */
643 }
644 CFTypeRef exceptionValue = CFDictionaryGetValue(ctx->exception, key);
645 if (exceptionValue && CFEqual(exceptionValue, value)) {
646 /* both key and value match the exception */
647 CFDictionaryRemoveValue(ctx->filteredDetail, key);
648 }
649 }
650
651 CFArrayRef SecTrustCopyFilteredDetails(SecTrustRef trust) {
652 if (!trust) {
653 return NULL;
654 }
655 SecTrustEvaluateIfNecessary(trust);
656 __block CFArrayRef details = NULL;
657 dispatch_sync(trust->_trustQueue, ^{
658 details = CFRetainSafe(trust->_details);
659 });
660 CFIndex ix, pathLength = details ? CFArrayGetCount(details) : 0;
661 CFMutableArrayRef filteredDetails = CFArrayCreateMutable(kCFAllocatorDefault, pathLength, &kCFTypeArrayCallBacks);
662 if (!filteredDetails) {
663 CFReleaseNull(details);
664 return NULL;
665 }
666 for (ix = 0; ix < pathLength; ++ix) {
667 CFDictionaryRef detail = (CFDictionaryRef)CFArrayGetValueAtIndex(details, ix);
668 CFIndex count = (detail) ? CFDictionaryGetCount(detail) : 0;
669 CFMutableDictionaryRef filteredDetail = CFDictionaryCreateMutableCopy(kCFAllocatorDefault, count, detail);
670 CFDictionaryRef exception = SecTrustGetExceptionForCertificateAtIndex(trust, ix);
671 if (exception) {
672 /* for each entry in the detail dictionary, remove from filteredDetail
673 if it also appears in the corresponding exception dictionary. */
674 struct SecTrustFilteredDetailContext context = { exception, filteredDetail };
675 CFDictionaryApplyFunction(detail, SecTrustFilterDetail, &context);
676 }
677 if (filteredDetail) {
678 CFArrayAppendValue(filteredDetails, filteredDetail);
679 CFReleaseSafe(filteredDetail);
680 }
681 }
682 CFReleaseNull(details);
683 return filteredDetails;
684 }
685
686 struct SecTrustCheckExceptionContext {
687 CFDictionaryRef exception;
688 bool exceptionNotFound;
689
690 };
691
692 static void SecTrustCheckException(const void *key, const void *value, void *context) {
693 struct SecTrustCheckExceptionContext *cec = (struct SecTrustCheckExceptionContext *)context;
694 if (cec->exception) {
695 CFTypeRef exceptionValue = CFDictionaryGetValue(cec->exception, key);
696 if (!exceptionValue || !CFEqual(value, exceptionValue)) {
697 cec->exceptionNotFound = true;
698 }
699 } else {
700 cec->exceptionNotFound = true;
701 }
702 }
703
704 #if TARGET_OS_IPHONE
705 static CFArrayRef SecTrustCreatePolicyAnchorsArray(const UInt8* certData, CFIndex certLength)
706 {
707 CFArrayRef array = NULL;
708 CFAllocatorRef allocator = kCFAllocatorDefault;
709 SecCertificateRef cert = SecCertificateCreateWithBytes(allocator, certData, certLength);
710 if (cert) {
711 array = CFArrayCreate(allocator, (const void **)&cert, 1, &kCFTypeArrayCallBacks);
712 CFReleaseSafe(cert);
713 }
714 return array;
715 }
716 #endif
717
718 static void SecTrustAddPolicyAnchors(SecTrustRef trust)
719 {
720 /* Provide anchor certificates specifically required by certain policies.
721 This is used to evaluate test policies where the anchor is not provided
722 in the root store and may not be able to be supplied by the caller.
723 */
724 if (!trust) { return; }
725 __block CFArrayRef policies = NULL;
726 dispatch_sync(trust->_trustQueue, ^{
727 policies = CFRetain(trust->_policies);
728 });
729 CFIndex ix, count = CFArrayGetCount(policies);
730 for (ix = 0; ix < count; ++ix) {
731 SecPolicyRef policy = (SecPolicyRef) CFArrayGetValueAtIndex(policies, ix);
732 if (policy) {
733 #if TARGET_OS_IPHONE
734 if (CFEqual(policy->_oid, kSecPolicyAppleTestSMPEncryption)) {
735 __block CFArrayRef policyAnchors = SecTrustCreatePolicyAnchorsArray(_SEC_TestAppleRootCAECC, sizeof(_SEC_TestAppleRootCAECC));
736 dispatch_sync(trust->_trustQueue, ^{
737 CFReleaseSafe(trust->_anchors);
738 trust->_anchors = policyAnchors;
739 });
740 trust->_anchorsOnly = true;
741 break;
742 }
743 #endif
744 }
745 }
746 CFReleaseSafe(policies);
747 }
748
749
750 // uncomment for verbose debug logging (debug builds only)
751 //#define CERT_TRUST_DUMP 1
752
753 #if CERT_TRUST_DUMP
754 static void sectrustlog(int priority, const char *format, ...)
755 {
756 #ifndef NDEBUG
757 // log everything
758 #else
759 if (priority < LOG_NOTICE) // log warnings and errors
760 #endif
761 {
762 va_list list;
763 va_start(list, format);
764 vsyslog(priority, format, list);
765 va_end(list);
766 }
767 }
768
769 static void sectrustshow(CFTypeRef obj, const char *context)
770 {
771 #ifndef NDEBUG
772 CFStringRef desc = CFCopyDescription(obj);
773 if (!desc) return;
774
775 CFIndex length = CFStringGetMaximumSizeForEncoding(CFStringGetLength(desc), kCFStringEncodingUTF8) + 1;
776 char* buffer = (char*) malloc(length);
777 if (buffer) {
778 Boolean converted = CFStringGetCString(desc, buffer, length, kCFStringEncodingUTF8);
779 if (converted) {
780 const char *prefix = (context) ? context : "";
781 const char *separator = (context) ? " " : "";
782 sectrustlog(LOG_NOTICE, "%s%s%s", prefix, separator, buffer);
783 }
784 free(buffer);
785 }
786 CFRelease(desc);
787 #endif
788 }
789
790 static void cert_trust_dump(SecTrustRef trust) {
791 SecCertificateRef leaf = SecTrustGetCertificateAtIndex(trust, 0);
792 CFStringRef name = (leaf) ? SecCertificateCopySubjectSummary(leaf) : NULL;
793 secerror("leaf \"%@\"", name);
794 secerror(": result = %d", (int) trust->_trustResult);
795 if (trust->_chain) {
796 CFIndex ix, count = SecCertificatePathGetCount(trust->_chain);
797 CFMutableArrayRef chain = CFArrayCreateMutable(kCFAllocatorDefault, count, &kCFTypeArrayCallBacks);
798 for (ix = 0; ix < count; ix++) {
799 SecCertificateRef cert = SecCertificatePathGetCertificateAtIndex(trust->_chain, ix);
800 if (cert) {
801 CFArrayAppendValue(chain, cert);
802 }
803 }
804 sectrustshow(chain, "chain:");
805 CFReleaseSafe(chain);
806 }
807 secerror(": %ld certificates, %ld anchors, %ld policies, %ld details",
808 (trust->_certificates) ? (long)CFArrayGetCount(trust->_certificates) : 0,
809 (trust->_anchors) ? (long)CFArrayGetCount(trust->_anchors) : 0,
810 (trust->_policies) ? (long)CFArrayGetCount(trust->_policies) : 0,
811 (trust->_details) ? (long)CFArrayGetCount(trust->_details) : 0);
812
813 sectrustshow(trust->_verifyDate, "verify date:");
814 sectrustshow(trust->_certificates, "certificates:");
815 sectrustshow(trust->_anchors, "anchors:");
816 sectrustshow(trust->_policies, "policies:");
817 sectrustshow(trust->_details, "details:");
818 sectrustshow(trust->_info, "info:");
819
820 CFReleaseSafe(name);
821 }
822 #else
823 static void cert_trust_dump(SecTrustRef trust) {}
824 #endif
825
826
827 OSStatus SecTrustEvaluate(SecTrustRef trust, SecTrustResultType *result) {
828 if (!trust) {
829 return errSecParam;
830 }
831 OSStatus status = SecTrustEvaluateIfNecessary(trust);
832 if (status) {
833 return status;
834 }
835 /* post-process trust result based on exceptions */
836 __block SecTrustResultType trustResult = kSecTrustResultInvalid;
837 dispatch_sync(trust->_trustQueue, ^{
838 trustResult = trust->_trustResult;
839 });
840 if (trustResult == kSecTrustResultUnspecified) {
841 /* If leaf is in exceptions -> proceed, otherwise unspecified. */
842 if (SecTrustGetExceptionForCertificateAtIndex(trust, 0))
843 trustResult = kSecTrustResultProceed;
844 } else if (trustResult == kSecTrustResultRecoverableTrustFailure) {
845 /* If we have exceptions get details and match to exceptions. */
846 __block CFArrayRef details = NULL;
847 dispatch_sync(trust->_trustQueue, ^{
848 details = CFRetainSafe(trust->_details);
849 });
850 CFIndex pathLength = details ? CFArrayGetCount(details) : 0;
851 struct SecTrustCheckExceptionContext context = {};
852 CFIndex ix;
853 for (ix = 0; ix < pathLength; ++ix) {
854 CFDictionaryRef detail = (CFDictionaryRef)CFArrayGetValueAtIndex(details, ix);
855 context.exception = SecTrustGetExceptionForCertificateAtIndex(trust, ix);
856 CFDictionaryApplyFunction(detail, SecTrustCheckException, &context);
857 if (context.exceptionNotFound) {
858 break;
859 }
860 }
861 CFReleaseSafe(details);
862 __block bool done = false;
863 dispatch_sync(trust->_trustQueue, ^{
864 if (!trust->_exceptions || !CFArrayGetCount(trust->_exceptions)) {
865 done = true;
866 }
867 });
868 if (done) {
869 goto DoneCheckingTrust;
870 }
871 if (!context.exceptionNotFound)
872 trustResult = kSecTrustResultProceed;
873 }
874 DoneCheckingTrust:
875 dispatch_sync(trust->_trustQueue, ^{
876 trust->_trustResult = trustResult;
877 });
878
879 /* log to syslog when there is a trust failure */
880 if (trustResult != kSecTrustResultProceed &&
881 trustResult != kSecTrustResultConfirm &&
882 trustResult != kSecTrustResultUnspecified) {
883 CFStringRef failureDesc = SecTrustCopyFailureDescription(trust);
884 secerror("%{public}@", failureDesc);
885 CFRelease(failureDesc);
886 }
887
888
889 if (result) {
890 *result = trustResult;
891 }
892
893 return status;
894 }
895
896 OSStatus SecTrustEvaluateAsync(SecTrustRef trust,
897 dispatch_queue_t queue, SecTrustCallback result)
898 {
899 CFRetainSafe(trust);
900 dispatch_async(queue, ^{
901 SecTrustResultType trustResult;
902 if (errSecSuccess != SecTrustEvaluate(trust, &trustResult)) {
903 trustResult = kSecTrustResultInvalid;
904 }
905 result(trust, trustResult);
906 CFReleaseSafe(trust);
907 });
908 return errSecSuccess;
909 }
910
911 static bool append_certificate_to_xpc_array(SecCertificateRef certificate, xpc_object_t xpc_certificates);
912 static xpc_object_t copy_xpc_certificates_array(CFArrayRef certificates);
913 xpc_object_t copy_xpc_policies_array(CFArrayRef policies);
914 OSStatus validate_array_of_items(CFArrayRef array, CFStringRef arrayItemType, CFTypeID itemTypeID, bool required);
915
916 static bool append_certificate_to_xpc_array(SecCertificateRef certificate, xpc_object_t xpc_certificates) {
917 if (!certificate) {
918 return true; // NOOP
919 }
920 size_t length = SecCertificateGetLength(certificate);
921 const uint8_t *bytes = SecCertificateGetBytePtr(certificate);
922 if (!length || !bytes) {
923 return false;
924 }
925 xpc_array_set_data(xpc_certificates, XPC_ARRAY_APPEND, bytes, length);
926 return true;
927 }
928
929 static xpc_object_t copy_xpc_certificates_array(CFArrayRef certificates) {
930 xpc_object_t xpc_certificates = xpc_array_create(NULL, 0);
931 if (!xpc_certificates) {
932 return NULL;
933 }
934 CFIndex ix, count = CFArrayGetCount(certificates);
935 for (ix = 0; ix < count; ++ix) {
936 SecCertificateRef certificate = (SecCertificateRef) CFArrayGetValueAtIndex(certificates, ix);
937 #if SECTRUST_VERBOSE_DEBUG
938 size_t length = SecCertificateGetLength(certificate);
939 const uint8_t *bytes = SecCertificateGetBytePtr(certificate);
940 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);
941 #endif
942 if (!append_certificate_to_xpc_array(certificate, xpc_certificates)) {
943 xpc_release(xpc_certificates);
944 xpc_certificates = NULL;
945 break;
946 }
947 }
948 return xpc_certificates;
949 }
950
951 static bool SecXPCDictionarySetCertificates(xpc_object_t message, const char *key, CFArrayRef certificates, CFErrorRef *error) {
952 xpc_object_t xpc_certificates = copy_xpc_certificates_array(certificates);
953 if (!xpc_certificates) {
954 SecError(errSecAllocate, error, CFSTR("failed to create xpc_array of certificates"));
955 return false;
956 }
957 xpc_dictionary_set_value(message, key, xpc_certificates);
958 xpc_release(xpc_certificates);
959 return true;
960 }
961
962 static bool SecXPCDictionarySetPolicies(xpc_object_t message, const char *key, CFArrayRef policies, CFErrorRef *error) {
963 xpc_object_t xpc_policies = copy_xpc_policies_array(policies);
964 if (!xpc_policies) {
965 SecError(errSecAllocate, error, CFSTR("failed to create xpc_array of policies"));
966 return false;
967 }
968 xpc_dictionary_set_value(message, key, xpc_policies);
969 xpc_release(xpc_policies);
970 return true;
971 }
972
973
974 static bool CFDataAppendToXPCArray(CFDataRef data, xpc_object_t xpc_data_array, CFErrorRef *error) {
975 if (!data)
976 return true; // NOOP
977
978 size_t length = CFDataGetLength(data);
979 const uint8_t *bytes = CFDataGetBytePtr(data);
980 if (!length || !bytes)
981 return SecError(errSecParam, error, CFSTR("invalid CFDataRef"));
982
983 xpc_array_set_data(xpc_data_array, XPC_ARRAY_APPEND, bytes, length);
984 return true;
985 }
986
987
988 static xpc_object_t CFDataArrayCopyXPCArray(CFArrayRef data_array, CFErrorRef *error) {
989 xpc_object_t xpc_data_array;
990 require_action_quiet(xpc_data_array = xpc_array_create(NULL, 0), exit,
991 SecError(errSecAllocate, error, CFSTR("failed to create xpc_array")));
992 CFIndex ix, count = CFArrayGetCount(data_array);
993 for (ix = 0; ix < count; ++ix) {
994 if (!CFDataAppendToXPCArray((CFDataRef)CFArrayGetValueAtIndex(data_array, ix), xpc_data_array, error)) {
995 xpc_release(xpc_data_array);
996 return NULL;
997 }
998 }
999
1000 exit:
1001 return xpc_data_array;
1002 }
1003
1004 static bool SecXPCDictionarySetDataArray(xpc_object_t message, const char *key, CFArrayRef data_array, CFErrorRef *error) {
1005 xpc_object_t xpc_data_array = CFDataArrayCopyXPCArray(data_array, error);
1006 if (!xpc_data_array)
1007 return false;
1008 xpc_dictionary_set_value(message, key, xpc_data_array);
1009 xpc_release(xpc_data_array);
1010 return true;
1011 }
1012
1013 static bool SecXPCDictionaryCopyChainOptional(xpc_object_t message, const char *key, SecCertificatePathRef *path, CFErrorRef *error) {
1014 xpc_object_t xpc_path = xpc_dictionary_get_value(message, key);
1015 if (!xpc_path) {
1016 *path = NULL;
1017 return true;
1018 }
1019 *path = SecCertificatePathCreateWithXPCArray(xpc_path, error);
1020 return *path;
1021 }
1022
1023 static int SecXPCDictionaryGetNonZeroInteger(xpc_object_t message, const char *key, CFErrorRef *error) {
1024 int64_t value = xpc_dictionary_get_int64(message, key);
1025 if (!value) {
1026 SecError(errSecInternal, error, CFSTR("object for key %s is 0"), key);
1027 }
1028 return (int)value;
1029 }
1030
1031 static SecTrustResultType certs_anchors_bool_bool_policies_responses_scts_logs_date_ag_to_details_info_chain_int_error_request(enum SecXPCOperation op, CFArrayRef certificates, CFArrayRef anchors, bool anchorsOnly, bool keychainsAllowed, CFArrayRef policies, CFArrayRef responses, CFArrayRef SCTs, CFArrayRef trustedLogs, CFAbsoluteTime verifyTime, __unused CFArrayRef accessGroups, CFArrayRef *details, CFDictionaryRef *info, SecCertificatePathRef *chain, CFErrorRef *error)
1032 {
1033 __block SecTrustResultType tr = kSecTrustResultInvalid;
1034 securityd_send_sync_and_do(op, error, ^bool(xpc_object_t message, CFErrorRef *error) {
1035 if (!SecXPCDictionarySetCertificates(message, kSecTrustCertificatesKey, certificates, error))
1036 return false;
1037 if (anchors && !SecXPCDictionarySetCertificates(message, kSecTrustAnchorsKey, anchors, error))
1038 return false;
1039 if (anchorsOnly)
1040 xpc_dictionary_set_bool(message, kSecTrustAnchorsOnlyKey, anchorsOnly);
1041 xpc_dictionary_set_bool(message, kSecTrustKeychainsAllowedKey, keychainsAllowed);
1042 if (!SecXPCDictionarySetPolicies(message, kSecTrustPoliciesKey, policies, error))
1043 return false;
1044 if (responses && !SecXPCDictionarySetDataArray(message, kSecTrustResponsesKey, responses, error))
1045 return false;
1046 if (SCTs && !SecXPCDictionarySetDataArray(message, kSecTrustSCTsKey, SCTs, error))
1047 return false;
1048 if (trustedLogs && !SecXPCDictionarySetPList(message, kSecTrustTrustedLogsKey, trustedLogs, error))
1049 return false;
1050 xpc_dictionary_set_double(message, kSecTrustVerifyDateKey, verifyTime);
1051 return true;
1052 }, ^bool(xpc_object_t response, CFErrorRef *error) {
1053 secdebug("trust", "response: %@", response);
1054 return SecXPCDictionaryCopyArrayOptional(response, kSecTrustDetailsKey, details, error) &&
1055 SecXPCDictionaryCopyDictionaryOptional(response, kSecTrustInfoKey, info, error) &&
1056 SecXPCDictionaryCopyChainOptional(response, kSecTrustChainKey, chain, error) &&
1057 ((tr = SecXPCDictionaryGetNonZeroInteger(response, kSecTrustResultKey, error)) != kSecTrustResultInvalid);
1058 });
1059 return tr;
1060 }
1061
1062 OSStatus validate_array_of_items(CFArrayRef array, CFStringRef arrayItemType, CFTypeID itemTypeID, bool required) {
1063 OSStatus result = errSecSuccess;
1064 CFIndex index, count;
1065 count = (array) ? CFArrayGetCount(array) : 0;
1066 if (!count && required) {
1067 secerror("no %@ in array!", arrayItemType);
1068 result = errSecParam;
1069 }
1070 for (index = 0; index < count; index++) {
1071 CFTypeRef item = (CFTypeRef) CFArrayGetValueAtIndex(array, index);
1072 if (!item) {
1073 secerror("%@ %@ (index %d)", arrayItemType, CFSTR("reference is nil"), (int)index);
1074 result = errSecParam;
1075 continue;
1076 }
1077 if (CFGetTypeID(item) != itemTypeID) {
1078 secerror("%@ %@ (index %d)", arrayItemType, CFSTR("is not the expected CF type"), (int)index);
1079 result = errSecParam;
1080 }
1081 // certificates
1082 if (CFGetTypeID(item) == SecCertificateGetTypeID()) {
1083 SecCertificateRef certificate = (SecCertificateRef) item;
1084 CFIndex length = SecCertificateGetLength(certificate);
1085 const UInt8 *bytes = SecCertificateGetBytePtr(certificate);
1086 if (!length) {
1087 secerror("%@ %@ (index %d)", arrayItemType, CFSTR("has zero length"), (int)index);
1088 result = errSecParam;
1089 }
1090 if (!bytes) {
1091 secerror("%@ %@ (index %d)", arrayItemType, CFSTR("has nil bytes"), (int)index);
1092 result = errSecParam;
1093 }
1094 #if SECTRUST_VERBOSE_DEBUG
1095 secerror("%@[%d] of %d = %ld bytes @ 0x%lX", arrayItemType, (int)index, (int)count, (size_t)length, (uintptr_t)bytes);
1096 #endif
1097 }
1098 // policies
1099 if (CFGetTypeID(item) == SecPolicyGetTypeID()) {
1100 SecPolicyRef policy = (SecPolicyRef) item;
1101 CFStringRef oidStr = policy->_oid;
1102 if (!oidStr || (CFGetTypeID(oidStr) != CFStringGetTypeID())) {
1103 oidStr = CFSTR("has invalid OID string!");
1104 secerror("%@ %@ (index %d)", arrayItemType, oidStr, (int)index);
1105 }
1106 #if SECTRUST_VERBOSE_DEBUG
1107 secerror("%@[%d] of %d = \"%@\" 0x%lX", arrayItemType, (int)index, (int)count, oidStr, (uintptr_t)policy);
1108 #endif
1109 }
1110 }
1111 return result;
1112 }
1113
1114 static OSStatus SecTrustValidateInput(SecTrustRef trust) {
1115 OSStatus status, result = errSecSuccess;
1116
1117 // certificates (required)
1118 status = validate_array_of_items(trust->_certificates, CFSTR("certificate"), SecCertificateGetTypeID(), true);
1119 if (status) result = status;
1120 // anchors (optional)
1121 status = validate_array_of_items(trust->_anchors, CFSTR("input anchor"), SecCertificateGetTypeID(), false);
1122 if (status) result = status;
1123 // policies (required??)
1124 status = validate_array_of_items(trust->_policies, CFSTR("policy"), SecPolicyGetTypeID(), true);
1125 if (status) result = status;
1126 // _responses, _SCTs, _trustedLogs, ...
1127 // verify time: SecTrustGetVerifyTime(trust)
1128 // access groups: SecAccessGroupsGetCurrent()
1129
1130 return result;
1131 }
1132
1133
1134 static void SecTrustPostEvaluate(SecTrustRef trust) {
1135 if (!trust) { return; }
1136
1137 CFIndex pathLength = (trust->_details) ? CFArrayGetCount(trust->_details) : 0;
1138 CFIndex ix;
1139 for (ix = 0; ix < pathLength; ++ix) {
1140 CFDictionaryRef detail = (CFDictionaryRef)CFArrayGetValueAtIndex(trust->_details, ix);
1141 if ((ix == 0) && CFDictionaryContainsKey(detail, kSecPolicyCheckBlackListedLeaf)) {
1142 trust->_trustResult = kSecTrustResultFatalTrustFailure;
1143 return;
1144 }
1145 if (CFDictionaryContainsKey(detail, kSecPolicyCheckBlackListedKey)) {
1146 trust->_trustResult = kSecTrustResultFatalTrustFailure;
1147 return;
1148 }
1149 }
1150 }
1151
1152 static OSStatus SecTrustEvaluateIfNecessary(SecTrustRef trust) {
1153 __block OSStatus result;
1154 check(trust);
1155 if (!trust)
1156 return errSecParam;
1157
1158 __block CFAbsoluteTime verifyTime = SecTrustGetVerifyTime(trust);
1159 SecTrustAddPolicyAnchors(trust);
1160 dispatch_sync(trust->_trustQueue, ^{
1161 if (trust->_trustResult != kSecTrustResultInvalid) {
1162 result = errSecSuccess;
1163 return;
1164 }
1165
1166 trust->_trustResult = kSecTrustResultOtherError; /* to avoid potential recursion */
1167
1168 CFReleaseNull(trust->_chain);
1169 CFReleaseNull(trust->_details);
1170 CFReleaseNull(trust->_info);
1171 if (trust->_legacy_info_array) {
1172 free(trust->_legacy_info_array);
1173 trust->_legacy_info_array = NULL;
1174 }
1175 if (trust->_legacy_status_array) {
1176 free(trust->_legacy_status_array);
1177 trust->_legacy_status_array = NULL;
1178 }
1179
1180 os_activity_initiate("SecTrustEvaluateIfNecessary", OS_ACTIVITY_FLAG_DEFAULT, ^{
1181 SecTrustValidateInput(trust);
1182
1183 /* @@@ 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. */
1184 result = SecOSStatusWith(^bool (CFErrorRef *error) {
1185 trust->_trustResult = SECURITYD_XPC(sec_trust_evaluate,
1186 certs_anchors_bool_bool_policies_responses_scts_logs_date_ag_to_details_info_chain_int_error_request,
1187 trust->_certificates, trust->_anchors, trust->_anchorsOnly, trust->_keychainsAllowed,
1188 trust->_policies, trust->_responses, trust->_SCTs, trust->_trustedLogs,
1189 verifyTime, SecAccessGroupsGetCurrent(),
1190 &trust->_details, &trust->_info, &trust->_chain, error);
1191 if (trust->_trustResult == kSecTrustResultInvalid /* TODO check domain */ &&
1192 SecErrorGetOSStatus(*error) == errSecNotAvailable &&
1193 CFArrayGetCount(trust->_certificates)) {
1194 /* We failed to talk to securityd. The only time this should
1195 happen is when we are running prior to launchd enabling
1196 registration of services. This currently happens when we
1197 are running from the ramdisk. To make ASR happy we initialize
1198 _chain and return success with a failure as the trustResult, to
1199 make it seem like we did a cert evaluation, so ASR can extract
1200 the public key from the leaf. */
1201 trust->_chain = SecCertificatePathCreate(NULL, (SecCertificateRef)CFArrayGetValueAtIndex(trust->_certificates, 0), NULL);
1202 if (error)
1203 CFReleaseNull(*error);
1204 return true;
1205 }
1206 SecTrustPostEvaluate(trust);
1207 trust->_trustResultBeforeExceptions = trust->_trustResult;
1208 return trust->_trustResult != kSecTrustResultInvalid;
1209 });
1210 });
1211 });
1212 return result;
1213 }
1214
1215 /* Helper for the qsort below. */
1216 static int compare_strings(const void *a1, const void *a2) {
1217 CFStringRef s1 = *(CFStringRef *)a1;
1218 CFStringRef s2 = *(CFStringRef *)a2;
1219 return (int) CFStringCompare(s1, s2, kCFCompareForcedOrdering);
1220 }
1221
1222 CFStringRef SecTrustCopyFailureDescription(SecTrustRef trust) {
1223 if (!trust) {
1224 return NULL;
1225 }
1226 CFMutableStringRef reason = CFStringCreateMutable(NULL, 0);
1227 SecTrustEvaluateIfNecessary(trust);
1228 __block CFArrayRef details = NULL;
1229 dispatch_sync(trust->_trustQueue, ^{
1230 details = CFRetainSafe(trust->_details);
1231 });
1232 CFIndex pathLength = details ? CFArrayGetCount(details) : 0;
1233 for (CFIndex ix = 0; ix < pathLength; ++ix) {
1234 CFDictionaryRef detail = (CFDictionaryRef)CFArrayGetValueAtIndex(details, ix);
1235 CFIndex dCount = CFDictionaryGetCount(detail);
1236 if (dCount) {
1237 if (ix == 0)
1238 CFStringAppend(reason, CFSTR(" [leaf"));
1239 else if (ix == pathLength - 1)
1240 CFStringAppend(reason, CFSTR(" [root"));
1241 else
1242 CFStringAppendFormat(reason, NULL, CFSTR(" [ca%" PRIdCFIndex ), ix);
1243
1244 const void *keys[dCount];
1245 CFDictionaryGetKeysAndValues(detail, &keys[0], NULL);
1246 qsort(&keys[0], dCount, sizeof(keys[0]), compare_strings);
1247 for (CFIndex kix = 0; kix < dCount; ++kix) {
1248 CFStringRef key = keys[kix];
1249 const void *value = CFDictionaryGetValue(detail, key);
1250 CFStringAppendFormat(reason, NULL, CFSTR(" %@%@"), key,
1251 (CFGetTypeID(value) == CFBooleanGetTypeID()
1252 ? CFSTR("") : value));
1253 }
1254 CFStringAppend(reason, CFSTR("]"));
1255 }
1256 }
1257 CFReleaseSafe(details);
1258 return reason;
1259 }
1260
1261 #if TARGET_OS_OSX
1262 /* On OS X we need SecTrustCopyPublicKey to give us a CDSA-based SecKeyRef,
1263 so we will refer to this one internally as SecTrustCopyPublicKey_ios,
1264 and call it from SecTrustCopyPublicKey.
1265 */
1266 SecKeyRef SecTrustCopyPublicKey_ios(SecTrustRef trust)
1267 #else
1268 SecKeyRef SecTrustCopyPublicKey(SecTrustRef trust)
1269 #endif
1270 {
1271 if (!trust) {
1272 return NULL;
1273 }
1274 __block SecKeyRef publicKey = NULL;
1275 dispatch_sync(trust->_trustQueue, ^{
1276 if (trust->_publicKey) {
1277 publicKey = CFRetainSafe(trust->_publicKey);
1278 return;
1279 }
1280 SecCertificateRef leaf = (SecCertificateRef)CFArrayGetValueAtIndex(trust->_certificates, 0);
1281 #if TARGET_OS_OSX
1282 trust->_publicKey = SecCertificateCopyPublicKey_ios(leaf);
1283 #else
1284 trust->_publicKey = SecCertificateCopyPublicKey(leaf);
1285 #endif
1286 if (trust->_publicKey) {
1287 publicKey = CFRetainSafe(trust->_publicKey);
1288 }
1289 });
1290 /* If we couldn't get a public key from the leaf cert alone. */
1291 if (!publicKey) {
1292 SecTrustEvaluateIfNecessary(trust);
1293 dispatch_sync(trust->_trustQueue, ^{
1294 if (trust->_chain) {
1295 trust->_publicKey = SecCertificatePathCopyPublicKeyAtIndex(trust->_chain, 0);
1296 publicKey = CFRetainSafe(trust->_publicKey);
1297 }
1298 });
1299 }
1300 return publicKey;
1301 }
1302
1303 CFIndex SecTrustGetCertificateCount(SecTrustRef trust) {
1304 if (!trust) {
1305 return 0;
1306 }
1307 SecTrustEvaluateIfNecessary(trust);
1308 __block CFIndex certCount = 1;
1309 dispatch_sync(trust->_trustQueue, ^{
1310 if (trust->_chain) {
1311 certCount = SecCertificatePathGetCount(trust->_chain);
1312 }
1313 });
1314 return certCount;
1315 }
1316
1317 SecCertificateRef SecTrustGetCertificateAtIndex(SecTrustRef trust,
1318 CFIndex ix) {
1319 if (!trust) {
1320 return NULL;
1321 }
1322 __block SecCertificateRef cert = NULL;
1323 if (ix == 0) {
1324 dispatch_sync(trust->_trustQueue, ^{
1325 cert = (SecCertificateRef)CFArrayGetValueAtIndex(trust->_certificates, 0);
1326 });
1327 return cert;
1328 }
1329 SecTrustEvaluateIfNecessary(trust);
1330 dispatch_sync(trust->_trustQueue, ^{
1331 if (trust->_chain) {
1332 cert = SecCertificatePathGetCertificateAtIndex(trust->_chain, ix);
1333 }
1334 });
1335 return cert;
1336 }
1337
1338 CFDictionaryRef SecTrustCopyInfo(SecTrustRef trust) {
1339 if (!trust) {
1340 return NULL;
1341 }
1342 SecTrustEvaluateIfNecessary(trust);
1343 __block CFDictionaryRef info = NULL;
1344 dispatch_sync(trust->_trustQueue, ^{
1345 info = CFRetainSafe(trust->_info);
1346 });
1347 return info;
1348 }
1349
1350 CFArrayRef SecTrustGetTrustExceptionsArray(SecTrustRef trust) {
1351 return trust->_exceptions;
1352 }
1353
1354 CFDataRef SecTrustCopyExceptions(SecTrustRef trust) {
1355 __block CFArrayRef details = NULL;
1356 SecTrustEvaluateIfNecessary(trust);
1357 dispatch_sync(trust->_trustQueue, ^{
1358 details = CFRetainSafe(trust->_details);
1359 });
1360 CFIndex pathLength = details ? CFArrayGetCount(details) : 0;
1361 CFMutableArrayRef exceptions = CFArrayCreateMutable(kCFAllocatorDefault, pathLength, &kCFTypeArrayCallBacks);
1362 CFIndex ix;
1363 for (ix = 0; ix < pathLength; ++ix) {
1364 CFDictionaryRef detail = (CFDictionaryRef)CFArrayGetValueAtIndex(details, ix);
1365 CFIndex detailCount = CFDictionaryGetCount(detail);
1366 CFMutableDictionaryRef exception;
1367 if (ix == 0 || detailCount > 0) {
1368 exception = CFDictionaryCreateMutableCopy(kCFAllocatorDefault, detailCount + 1, detail);
1369 SecCertificateRef certificate = SecTrustGetCertificateAtIndex(trust, ix);
1370 CFDataRef digest = SecCertificateGetSHA1Digest(certificate);
1371 CFDictionaryAddValue(exception, kSecCertificateDetailSHA1Digest, digest);
1372 } else {
1373 /* Add empty exception dictionaries for non leaf certs which have no exceptions to save space. */
1374 exception = (CFMutableDictionaryRef)CFDictionaryCreate(kCFAllocatorDefault, NULL, NULL, 0,
1375 &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
1376 }
1377 CFArrayAppendValue(exceptions, exception);
1378 CFRelease(exception);
1379 }
1380
1381 /* Remove any trailing empty dictionaries to save even more space (we skip the leaf
1382 since it will never be empty). */
1383 for (ix = pathLength; ix-- > 1;) {
1384 CFDictionaryRef exception = (CFDictionaryRef)CFArrayGetValueAtIndex(exceptions, ix);
1385 if (CFDictionaryGetCount(exception) == 0) {
1386 CFArrayRemoveValueAtIndex(exceptions, ix);
1387 } else {
1388 break;
1389 }
1390 }
1391
1392 CFDataRef encodedExceptions = CFPropertyListCreateData(kCFAllocatorDefault,
1393 exceptions, kCFPropertyListBinaryFormat_v1_0, 0, NULL);
1394 CFRelease(exceptions);
1395 CFReleaseSafe(details);
1396 return encodedExceptions;
1397 }
1398
1399 bool SecTrustSetExceptions(SecTrustRef trust, CFDataRef encodedExceptions) {
1400 if (!trust) {
1401 return false;
1402 }
1403 CFArrayRef exceptions = NULL;
1404
1405 if (NULL != encodedExceptions) {
1406 exceptions = (CFArrayRef)CFPropertyListCreateWithData(kCFAllocatorDefault,
1407 encodedExceptions, kCFPropertyListImmutable, NULL, NULL);
1408 }
1409
1410 if (exceptions && CFGetTypeID(exceptions) != CFArrayGetTypeID()) {
1411 CFRelease(exceptions);
1412 exceptions = NULL;
1413 }
1414
1415 dispatch_sync(trust->_trustQueue, ^{
1416 if (trust->_exceptions && !exceptions) {
1417 /* Exceptions are currently set and now we are clearing them. */
1418 trust->_trustResult = trust->_trustResultBeforeExceptions;
1419 }
1420
1421 CFReleaseSafe(trust->_exceptions);
1422 trust->_exceptions = exceptions;
1423 });
1424
1425 /* If there is a valid exception entry for our current leaf we're golden. */
1426 if (SecTrustGetExceptionForCertificateAtIndex(trust, 0))
1427 return true;
1428
1429 /* The passed in exceptions didn't match our current leaf, so we discard it. */
1430 dispatch_sync(trust->_trustQueue, ^{
1431 CFReleaseNull(trust->_exceptions);
1432 });
1433 return false;
1434 }
1435
1436 CFArrayRef SecTrustCopySummaryPropertiesAtIndex(SecTrustRef trust, CFIndex ix) {
1437 CFMutableArrayRef summary;
1438 SecCertificateRef certificate = SecTrustGetCertificateAtIndex(trust, ix);
1439 summary = SecCertificateCopySummaryProperties(certificate,
1440 SecTrustGetVerifyTime(trust));
1441 /* FIXME Add more details in the failure case. */
1442
1443 return summary;
1444 }
1445
1446 CFArrayRef SecTrustCopyDetailedPropertiesAtIndex(SecTrustRef trust, CFIndex ix) {
1447 CFArrayRef summary;
1448 SecCertificateRef certificate = SecTrustGetCertificateAtIndex(trust, ix);
1449 summary = SecCertificateCopyProperties(certificate);
1450
1451 return summary;
1452 }
1453
1454 #if 0
1455
1456
1457
1458 /* Valid chain.
1459 Can be on any non root cert in the chain.
1460 Priority: Top down
1461 Short circuit: Yes (No other errors matter after this one)
1462 Non recoverable error
1463 Trust UI: Invalid certificate chain linkage
1464 Cert UI: Invalid linkage to parent certificate
1465 */
1466 CFStringRef kSecPolicyCheckIdLinkage = CFSTR("IdLinkage");
1467
1468 /* X.509 required checks.
1469 Can be on any cert in the chain
1470 Priority: Top down
1471 Short circuit: Yes (No other errors matter after this one)
1472 Non recoverable error
1473 Trust UI: (One or more) unsupported critical extensions found.
1474 */
1475 /* If we have no names for the extention oids use:
1476 Cert UI: One or more unsupported critical extensions found (Non recoverable error).
1477 Cert UI: Unsupported 'foo', 'bar', baz' critical extensions found.
1478 */
1479 CFStringRef kSecPolicyCheckCriticalExtensions = CFSTR("CriticalExtensions");
1480 /* Cert UI: Unsupported critical Qualified Certificate Statements extension found (Non recoverable error). */
1481 CFStringRef kSecPolicyCheckQualifiedCertStatements = CFSTR("QualifiedCertStatements");
1482 /* Cert UI: Certificate has an empty subject (and no critial subjectAltname). */
1483
1484 /* Trusted root.
1485 Only apply to the anchor.
1486 Priority: N/A
1487 Short circuit: No (Under discussion)
1488 Recoverable
1489 Trust UI: Root certificate is not trusted (for this policy/app/host/whatever?)
1490 Cert UI: Not a valid anchor
1491 */
1492 CFStringRef kSecPolicyCheckAnchorTrusted = CFSTR("AnchorTrusted");
1493 CFStringRef kSecPolicyCheckAnchorSHA1 = CFSTR("AnchorSHA1");
1494
1495 CFStringRef kSecPolicyCheckAnchorApple = CFSTR("AnchorApple");
1496 CFStringRef kSecPolicyAppleAnchorIncludeTestRoots = CFSTR("AnchorAppleTestRoots");
1497
1498 /* Binding.
1499 Only applies to leaf
1500 Priority: N/A
1501 Short Circuit: No
1502 Recoverable
1503 Trust UI: (Hostname|email address) mismatch
1504 */
1505 CFStringRef kSecPolicyCheckSSLHostname = CFSTR("SSLHostname");
1506
1507 /* Policy specific checks.
1508 Can be on any cert in the chain
1509 Priority: Top down
1510 Short Circuit: No
1511 Recoverable
1512 Trust UI: Certificate chain is not valid for the current policy.
1513 OR: (One or more) certificates in the chain are not valid for the current policy/application
1514 */
1515 CFStringRef kSecPolicyCheckNonEmptySubject = CFSTR("NonEmptySubject");
1516 /* Cert UI: Non CA certificate used as CA.
1517 Cert UI: CA certificate used as leaf.
1518 Cert UI: Cert chain length exceeded.
1519 Cert UI: Basic constraints extension not critical (non fatal).
1520 Cert UI: Leaf certificate has basic constraints extension (non fatal).
1521 */
1522 CFStringRef kSecPolicyCheckBasicConstraints = CFSTR("BasicConstraints");
1523 CFStringRef kSecPolicyCheckKeyUsage = CFSTR("KeyUsage");
1524 CFStringRef kSecPolicyCheckExtendedKeyUsage = CFSTR("ExtendedKeyUsage");
1525 /* Checks that the issuer of the leaf has exactly one Common Name and that it
1526 matches the specified string. */
1527 CFStringRef kSecPolicyCheckIssuerCommonName = CFSTR("IssuerCommonName");
1528 /* Checks that the leaf has exactly one Common Name and that it has the
1529 specified string as a prefix. */
1530 CFStringRef kSecPolicyCheckSubjectCommonNamePrefix = CFSTR("SubjectCommonNamePrefix");
1531 /* Check that the certificate chain length matches the specificed CFNumberRef
1532 length. */
1533 CFStringRef kSecPolicyCheckChainLength = CFSTR("ChainLength");
1534 CFStringRef kSecPolicyCheckNotValidBefore = CFSTR("NotValidBefore");
1535
1536 /* Expiration.
1537 Can be on any cert in the chain
1538 Priority: Top down
1539 Short Circuit: No
1540 Recoverable
1541 Trust UI: One or more certificates have expired or are not valid yet.
1542 OS: The (root|intermediate|leaf) certificate (expired on 'date'|is not valid until 'date')
1543 Cert UI: Certificate (expired on 'date'|is not valid until 'date')
1544 */
1545 CFStringRef kSecPolicyCheckValidIntermediates = CFSTR("ValidIntermediates");
1546 CFStringRef kSecPolicyCheckValidLeaf = CFSTR("ValidLeaf");
1547 CFStringRef kSecPolicyCheckValidRoot = CFSTR("ValidRoot");
1548
1549 #endif
1550
1551 struct TrustFailures {
1552 bool badLinkage;
1553 bool unknownCritExtn;
1554 bool untrustedAnchor;
1555 bool hostnameMismatch;
1556 bool policyFail;
1557 bool invalidCert;
1558 bool weakKey;
1559 bool revocation;
1560 };
1561
1562 static void applyDetailProperty(const void *_key, const void *_value,
1563 void *context) {
1564 CFStringRef key = (CFStringRef)_key;
1565 struct TrustFailures *tf = (struct TrustFailures *)context;
1566 if (CFGetTypeID(_value) != CFBooleanGetTypeID()) {
1567 /* Value isn't a CFBooleanRef, oh no! */
1568 return;
1569 }
1570 CFBooleanRef value = (CFBooleanRef)_value;
1571 if (CFBooleanGetValue(value)) {
1572 /* Not an actual failure so we don't report it. */
1573 return;
1574 }
1575
1576 /* @@@ FIXME: Report a different return value when something is in the
1577 details but masked out by an exception and use that below for display
1578 purposes. */
1579 if (CFEqual(key, kSecPolicyCheckIdLinkage)) {
1580 tf->badLinkage = true;
1581 } else if (CFEqual(key, kSecPolicyCheckCriticalExtensions)
1582 || CFEqual(key, kSecPolicyCheckQualifiedCertStatements)) {
1583 tf->unknownCritExtn = true;
1584 } else if (CFEqual(key, kSecPolicyCheckAnchorTrusted)
1585 || CFEqual(key, kSecPolicyCheckAnchorSHA1)
1586 || CFEqual(key, kSecPolicyCheckAnchorSHA256)
1587 || CFEqual(key, kSecPolicyCheckAnchorApple)) {
1588 tf->untrustedAnchor = true;
1589 } else if (CFEqual(key, kSecPolicyCheckSSLHostname)) {
1590 tf->hostnameMismatch = true;
1591 } else if (CFEqual(key, kSecPolicyCheckValidIntermediates)
1592 || CFEqual(key, kSecPolicyCheckValidLeaf)
1593 || CFEqual(key, kSecPolicyCheckValidRoot)) {
1594 tf->invalidCert = true;
1595 } else if (CFEqual(key, kSecPolicyCheckWeakIntermediates)
1596 || CFEqual(key, kSecPolicyCheckWeakLeaf)
1597 || CFEqual(key, kSecPolicyCheckWeakRoot)) {
1598 tf->weakKey = true;
1599 } else if (CFEqual(key, kSecPolicyCheckRevocation)) {
1600 tf->revocation = true;
1601 } else
1602 /* Anything else is a policy failure. */
1603 #if 0
1604 if (CFEqual(key, kSecPolicyCheckNonEmptySubject)
1605 || CFEqual(key, kSecPolicyCheckBasicConstraints)
1606 || CFEqual(key, kSecPolicyCheckKeyUsage)
1607 || CFEqual(key, kSecPolicyCheckExtendedKeyUsage)
1608 || CFEqual(key, kSecPolicyCheckIssuerCommonName)
1609 || CFEqual(key, kSecPolicyCheckSubjectCommonNamePrefix)
1610 || CFEqual(key, kSecPolicyCheckChainLength)
1611 || CFEqual(key, kSecPolicyCheckNotValidBefore))
1612 #endif
1613 {
1614 tf->policyFail = true;
1615 }
1616 }
1617
1618 static void appendError(CFMutableArrayRef properties, CFStringRef error) {
1619 CFStringRef localizedError = SecFrameworkCopyLocalizedString(error,
1620 CFSTR("SecCertificate"));
1621 if (!localizedError) {
1622 //secerror("WARNING: localized error string was not found in Security.framework");
1623 localizedError = CFRetain(error);
1624 }
1625 appendProperty(properties, kSecPropertyTypeError, NULL, NULL,
1626 localizedError);
1627 CFReleaseNull(localizedError);
1628 }
1629
1630 #if TARGET_OS_OSX
1631 /* OS X properties array has a different structure and is implemented SecTrust.cpp. */
1632 CFArrayRef SecTrustCopyProperties_ios(SecTrustRef trust)
1633 #else
1634 CFArrayRef SecTrustCopyProperties(SecTrustRef trust)
1635 #endif
1636 {
1637 if (!trust) {
1638 return NULL;
1639 }
1640 SecTrustEvaluateIfNecessary(trust);
1641 __block CFArrayRef details = NULL;
1642 dispatch_sync(trust->_trustQueue, ^{
1643 details = CFRetainSafe(trust->_details);
1644 });
1645 if (!details)
1646 return NULL;
1647
1648 struct TrustFailures tf = {};
1649
1650 CFIndex ix, count = CFArrayGetCount(details);
1651 for (ix = 0; ix < count; ++ix) {
1652 CFDictionaryRef detail = (CFDictionaryRef)
1653 CFArrayGetValueAtIndex(details, ix);
1654 /* We now have a detail dictionary for certificate at index ix, with
1655 a key value pair for each failed policy check. Let's convert it
1656 from Ro-Man form into something a Hu-Man can understand. */
1657 CFDictionaryApplyFunction(detail, applyDetailProperty, &tf);
1658 }
1659
1660 CFMutableArrayRef properties = CFArrayCreateMutable(kCFAllocatorDefault, 0,
1661 &kCFTypeArrayCallBacks);
1662 /* The badLinkage and unknownCritExtn failures are short circuited, since
1663 you can't recover from those errors. */
1664 if (tf.badLinkage) {
1665 appendError(properties, CFSTR("Invalid certificate chain linkage."));
1666 } else if (tf.unknownCritExtn) {
1667 appendError(properties, CFSTR("One or more unsupported critical extensions found."));
1668 } else {
1669 if (tf.untrustedAnchor) {
1670 appendError(properties, CFSTR("Root certificate is not trusted."));
1671 }
1672 if (tf.hostnameMismatch) {
1673 appendError(properties, CFSTR("Hostname mismatch."));
1674 }
1675 if (tf.policyFail) {
1676 appendError(properties, CFSTR("Policy requirements not met."));
1677 }
1678 if (tf.invalidCert) {
1679 appendError(properties, CFSTR("One or more certificates have expired or are not valid yet."));
1680 }
1681 if (tf.weakKey) {
1682 appendError(properties, CFSTR("One or more certificates is using a weak key size."));
1683 }
1684 if (tf.revocation) {
1685 appendError(properties, CFSTR("One or more certificates have been revoked."));
1686 }
1687 }
1688
1689 if (CFArrayGetCount(properties) == 0) {
1690 /* The certificate chain is trusted, return an empty plist */
1691 CFReleaseNull(properties);
1692 }
1693
1694 CFReleaseNull(details);
1695 return properties;
1696 }
1697
1698 CFDictionaryRef SecTrustCopyResult(SecTrustRef trust) {
1699 // Builds and returns a dictionary of evaluation results.
1700 if (!trust) {
1701 return NULL;
1702 }
1703 __block CFMutableDictionaryRef results = CFDictionaryCreateMutable(NULL, 0,
1704 &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
1705
1706 SecTrustEvaluateIfNecessary(trust);
1707 dispatch_sync(trust->_trustQueue, ^{
1708 // kSecTrustResultDetails (per-cert results)
1709 CFArrayRef details = trust->_details;
1710 if (details) {
1711 CFDictionarySetValue(results, (const void *)kSecTrustResultDetails, (const void *)details);
1712 }
1713
1714 // kSecTrustResultValue (overall trust result)
1715 CFNumberRef numValue = CFNumberCreate(NULL, kCFNumberSInt32Type, &trust->_trustResult);
1716 if (numValue) {
1717 CFDictionarySetValue(results, (const void *)kSecTrustResultValue, (const void *)numValue);
1718 CFRelease(numValue);
1719 }
1720 CFDictionaryRef info = trust->_info;
1721 if (trust->_trustResult == kSecTrustResultInvalid || !info) {
1722 return; // we have nothing more to add
1723 }
1724
1725 // kSecTrustEvaluationDate
1726 CFDateRef evaluationDate = trust->_verifyDate;
1727 if (evaluationDate) {
1728 CFDictionarySetValue(results, (const void *)kSecTrustEvaluationDate, (const void *)evaluationDate);
1729 }
1730
1731 // kSecTrustCertificateTransparency
1732 CFBooleanRef ctValue;
1733 if (CFDictionaryGetValueIfPresent(info, kSecTrustInfoCertificateTransparencyKey, (const void **)&ctValue)) {
1734 CFDictionarySetValue(results, (const void *)kSecTrustCertificateTransparency, (const void *)ctValue);
1735 }
1736
1737 // kSecTrustCertificateTransparencyWhiteList
1738 CFBooleanRef ctWhiteListValue;
1739 if (CFDictionaryGetValueIfPresent(info, kSecTrustInfoCertificateTransparencyWhiteListKey, (const void **)&ctWhiteListValue)) {
1740 CFDictionarySetValue(results, (const void *)kSecTrustCertificateTransparencyWhiteList, (const void *)ctWhiteListValue);
1741 }
1742
1743 // kSecTrustExtendedValidation
1744 CFBooleanRef evValue;
1745 if (CFDictionaryGetValueIfPresent(info, kSecTrustInfoExtendedValidationKey, (const void **)&evValue)) {
1746 CFDictionarySetValue(results, (const void *)kSecTrustExtendedValidation, (const void *)evValue);
1747 }
1748
1749 // kSecTrustOrganizationName
1750 CFStringRef organizationName;
1751 if (CFDictionaryGetValueIfPresent(info, kSecTrustInfoCompanyNameKey, (const void **)&organizationName)) {
1752 CFDictionarySetValue(results, (const void *)kSecTrustOrganizationName, (const void *)organizationName);
1753 }
1754
1755 // kSecTrustRevocationChecked
1756 CFBooleanRef revocationChecked;
1757 if (CFDictionaryGetValueIfPresent(info, kSecTrustRevocationChecked, (const void **)&revocationChecked)) {
1758 CFDictionarySetValue(results, (const void *)kSecTrustRevocationChecked, (const void *)revocationChecked);
1759 }
1760
1761 // kSecTrustRevocationReason
1762 CFNumberRef revocationReason;
1763 if (CFDictionaryGetValueIfPresent(info, kSecTrustRevocationReason, (const void **)&revocationReason)) {
1764 CFDictionarySetValue(results, (const void *)kSecTrustRevocationReason, (const void *)revocationReason);
1765 }
1766
1767 // kSecTrustRevocationValidUntilDate
1768 CFDateRef validUntilDate;
1769 if (CFDictionaryGetValueIfPresent(info, kSecTrustRevocationValidUntilDate, (const void **)&validUntilDate)) {
1770 CFDictionarySetValue(results, (const void *)kSecTrustRevocationValidUntilDate, (const void *)validUntilDate);
1771 }
1772 });
1773
1774 return results;
1775 }
1776
1777 // Return 0 upon error.
1778 static int to_int_error_request(enum SecXPCOperation op, CFErrorRef *error) {
1779 __block int64_t result = 0;
1780 securityd_send_sync_and_do(op, error, NULL, ^bool(xpc_object_t response, CFErrorRef *error) {
1781 result = xpc_dictionary_get_int64(response, kSecXPCKeyResult);
1782 if (!result)
1783 return SecError(errSecInternal, error, CFSTR("int64 missing in response"));
1784 return true;
1785 });
1786 return (int)result;
1787 }
1788
1789 // version 0 -> error, so we need to start at version 1 or later.
1790 OSStatus SecTrustGetOTAPKIAssetVersionNumber(int* versionNumber)
1791 {
1792 OSStatus result;
1793 os_activity_t trace_activity = os_activity_start("SecTrustGetOTAPKIAssetVersionNumber", OS_ACTIVITY_FLAG_DEFAULT);
1794 result = SecOSStatusWith(^bool(CFErrorRef *error) {
1795 if (!versionNumber)
1796 return SecError(errSecParam, error, CFSTR("versionNumber is NULL"));
1797
1798 return (*versionNumber = SECURITYD_XPC(sec_ota_pki_asset_version, to_int_error_request, error)) != 0;
1799 });
1800
1801 os_activity_end(trace_activity);
1802 return result;
1803 }
1804
1805 #define do_if_registered(sdp, ...) if (gSecurityd && gSecurityd->sdp) { return gSecurityd->sdp(__VA_ARGS__); }
1806
1807 static bool xpc_dictionary_entry_is_type(xpc_object_t dictionary, const char *key, xpc_type_t type)
1808 {
1809 xpc_object_t value = xpc_dictionary_get_value(dictionary, key);
1810
1811 return value && (xpc_get_type(value) == type);
1812 }
1813
1814 OSStatus SecTrustOTAPKIGetUpdatedAsset(int* didUpdateAsset)
1815 {
1816 CFErrorRef error = NULL;
1817 do_if_registered(sec_ota_pki_get_new_asset, &error);
1818
1819 int64_t num = 0;
1820 xpc_object_t message = securityd_create_message(kSecXPCOpOTAPKIGetNewAsset, &error);
1821 if (message)
1822 {
1823 xpc_object_t response = securityd_message_with_reply_sync(message, &error);
1824
1825 if (response && xpc_dictionary_entry_is_type(response, kSecXPCKeyResult, XPC_TYPE_INT64))
1826 {
1827 num = (int64_t) xpc_dictionary_get_int64(response, kSecXPCKeyResult);
1828 xpc_release(response);
1829 }
1830
1831 xpc_release(message);
1832 }
1833
1834 if (NULL != didUpdateAsset)
1835 {
1836 *didUpdateAsset = (int)num;
1837 }
1838 return noErr;
1839 }
1840
1841 /*
1842 * This function performs an evaluation of the leaf certificate only, and
1843 * does so in the process that called it. Its primary use is in SecItemCopyMatching
1844 * when kSecMatchPolicy is in the dictionary.
1845 */
1846 OSStatus SecTrustEvaluateLeafOnly(SecTrustRef trust, SecTrustResultType *result) {
1847 if (!trust) {
1848 return errSecParam;
1849 }
1850 OSStatus status = errSecSuccess;
1851 SecTrustResultType trustResult = kSecTrustResultInvalid;
1852 if((status = SecTrustValidateInput(trust))) {
1853 return status;
1854 }
1855
1856 struct OpaqueSecLeafPVC pvc;
1857 SecCertificateRef leaf = SecTrustGetCertificateAtIndex(trust, 0);
1858 __block CFArrayRef policies = NULL;
1859 dispatch_sync(trust->_trustQueue, ^{
1860 policies = CFRetainSafe(trust->_policies);
1861 });
1862 SecLeafPVCInit(&pvc, leaf, policies, SecTrustGetVerifyTime(trust));
1863
1864 if(!SecLeafPVCLeafChecks(&pvc)) {
1865 trustResult = kSecTrustResultRecoverableTrustFailure;
1866 } else {
1867 trustResult = kSecTrustResultUnspecified;
1868 }
1869
1870 /* Set other result context information */
1871 dispatch_sync(trust->_trustQueue, ^{
1872 trust->_trustResult = trustResult;
1873 trust->_details = CFRetainSafe(pvc.details);
1874 trust->_info = CFDictionaryCreateMutable(kCFAllocatorDefault, 0,
1875 &kCFTypeDictionaryKeyCallBacks,
1876 &kCFTypeDictionaryValueCallBacks);
1877 trust->_chain = SecCertificatePathCreate(NULL, (SecCertificateRef)CFArrayGetValueAtIndex(trust->_certificates, 0), NULL);
1878 });
1879
1880 SecLeafPVCDelete(&pvc);
1881
1882 /* log to syslog when there is a trust failure */
1883 if (trustResult != kSecTrustResultUnspecified) {
1884 CFStringRef failureDesc = SecTrustCopyFailureDescription(trust);
1885 secerror("%@", failureDesc);
1886 CFRelease(failureDesc);
1887 }
1888
1889 if (result) {
1890 *result = trustResult;
1891 }
1892
1893 CFReleaseSafe(policies);
1894 return status;
1895 }
1896
1897 static void deserializeCert(const void *value, void *context) {
1898 CFDataRef certData = (CFDataRef)value;
1899 if (isData(certData)) {
1900 SecCertificateRef cert = SecCertificateCreateWithData(NULL, certData);
1901 if (cert) {
1902 CFArrayAppendValue((CFMutableArrayRef)context, cert);
1903 CFRelease(cert);
1904 }
1905 }
1906 }
1907
1908 static CF_RETURNS_RETAINED CFArrayRef SecCertificateArrayDeserialize(CFArrayRef serializedCertificates) {
1909 CFMutableArrayRef result = NULL;
1910 require_quiet(isArray(serializedCertificates), errOut);
1911 CFIndex count = CFArrayGetCount(serializedCertificates);
1912 result = CFArrayCreateMutable(kCFAllocatorDefault, count, &kCFTypeArrayCallBacks);
1913 CFRange all_certs = { 0, count };
1914 CFArrayApplyFunction(serializedCertificates, all_certs, deserializeCert, result);
1915 errOut:
1916 return result;
1917 }
1918
1919 static void serializeCertificate(const void *value, void *context) {
1920 SecCertificateRef cert = (SecCertificateRef)value;
1921 if (cert && SecCertificateGetTypeID() == CFGetTypeID(cert)) {
1922 CFDataRef certData = SecCertificateCopyData(cert);
1923 if (certData) {
1924 CFArrayAppendValue((CFMutableArrayRef)context, certData);
1925 CFRelease(certData);
1926 }
1927 }
1928 }
1929
1930 static CFArrayRef SecCertificateArraySerialize(CFArrayRef certificates) {
1931 CFMutableArrayRef result = NULL;
1932 require_quiet(isArray(certificates), errOut);
1933 CFIndex count = CFArrayGetCount(certificates);
1934 result = CFArrayCreateMutable(NULL, count, &kCFTypeArrayCallBacks);
1935 CFRange all_certificates = { 0, count};
1936 CFArrayApplyFunction(certificates, all_certificates, serializeCertificate, result);
1937 errOut:
1938 return result;
1939 }
1940
1941 static CFPropertyListRef SecTrustCopyPlist(SecTrustRef trust) {
1942 __block CFMutableDictionaryRef output = NULL;
1943 output = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks,
1944 &kCFTypeDictionaryValueCallBacks);
1945
1946 dispatch_sync(trust->_trustQueue, ^{
1947 if (trust->_certificates) {
1948 CFArrayRef serializedCerts = SecCertificateArraySerialize(trust->_certificates);
1949 if (serializedCerts) {
1950 CFDictionaryAddValue(output, CFSTR(kSecTrustCertificatesKey), serializedCerts);
1951 CFRelease(serializedCerts);
1952 }
1953 }
1954 if (trust->_anchors) {
1955 CFArrayRef serializedAnchors = SecCertificateArraySerialize(trust->_anchors);
1956 if (serializedAnchors) {
1957 CFDictionaryAddValue(output, CFSTR(kSecTrustAnchorsKey), serializedAnchors);
1958 CFRelease(serializedAnchors);
1959 }
1960 }
1961 if (trust->_policies) {
1962 CFArrayRef serializedPolicies = SecPolicyArrayCreateSerialized(trust->_policies);
1963 if (serializedPolicies) {
1964 CFDictionaryAddValue(output, CFSTR(kSecTrustPoliciesKey), serializedPolicies);
1965 CFRelease(serializedPolicies);
1966 }
1967 }
1968 if (trust->_responses) {
1969 CFDictionaryAddValue(output, CFSTR(kSecTrustResponsesKey), trust->_responses);
1970 }
1971 if (trust->_SCTs) {
1972 CFDictionaryAddValue(output, CFSTR(kSecTrustSCTsKey), trust->_SCTs);
1973 }
1974 if (trust->_trustedLogs) {
1975 CFDictionaryAddValue(output, CFSTR(kSecTrustTrustedLogsKey), trust->_trustedLogs);
1976 }
1977 if (trust->_verifyDate) {
1978 CFDictionaryAddValue(output, CFSTR(kSecTrustVerifyDateKey), trust->_verifyDate);
1979 }
1980 if (trust->_chain) {
1981 CFArrayRef serializedChain = SecCertificatePathCreateSerialized(trust->_chain, NULL);
1982 if (serializedChain) {
1983 CFDictionaryAddValue(output, CFSTR(kSecTrustChainKey), serializedChain);
1984 CFRelease(serializedChain);
1985 }
1986 }
1987 if (trust->_details) {
1988 CFDictionaryAddValue(output, CFSTR(kSecTrustDetailsKey), trust->_details);
1989 }
1990 if (trust->_info) {
1991 CFDictionaryAddValue(output, CFSTR(kSecTrustInfoKey), trust->_info);
1992 }
1993 if (trust->_exceptions) {
1994 CFDictionaryAddValue(output, CFSTR(kSecTrustExceptionsKey), trust->_exceptions);
1995 }
1996 CFNumberRef trustResult = CFNumberCreate(NULL, kCFNumberSInt32Type, &trust->_trustResult);
1997 if (trustResult) {
1998 CFDictionaryAddValue(output, CFSTR(kSecTrustResultKey), trustResult);
1999 }
2000 CFReleaseNull(trustResult);
2001 if (trust->_anchorsOnly) {
2002 CFDictionaryAddValue(output, CFSTR(kSecTrustAnchorsOnlyKey), kCFBooleanTrue);
2003 } else {
2004 CFDictionaryAddValue(output, CFSTR(kSecTrustAnchorsOnlyKey), kCFBooleanFalse);
2005 }
2006 if (trust->_keychainsAllowed) {
2007 CFDictionaryAddValue(output, CFSTR(kSecTrustKeychainsAllowedKey), kCFBooleanTrue);
2008 } else {
2009 CFDictionaryAddValue(output, CFSTR(kSecTrustKeychainsAllowedKey), kCFBooleanFalse);
2010 }
2011 });
2012
2013 return output;
2014 }
2015
2016 CFDataRef SecTrustSerialize(SecTrustRef trust, CFErrorRef *error) {
2017 CFPropertyListRef plist = NULL;
2018 CFDataRef derTrust = NULL;
2019 require_action_quiet(trust, out,
2020 SecError(errSecParam, error, CFSTR("null trust input")));
2021 require_action_quiet(plist = SecTrustCopyPlist(trust), out,
2022 SecError(errSecDecode, error, CFSTR("unable to create trust plist")));
2023 require_quiet(derTrust = CFPropertyListCreateDERData(NULL, plist, error), out);
2024
2025 out:
2026 CFReleaseNull(plist);
2027 return derTrust;
2028 }
2029
2030 static OSStatus SecTrustCreateFromPlist(CFPropertyListRef plist, SecTrustRef CF_RETURNS_RETAINED *trust) {
2031 OSStatus status = errSecParam;
2032 SecTrustRef output = NULL;
2033 CFTypeRef serializedCertificates = NULL, serializedPolicies = NULL, serializedAnchors = NULL,
2034 serializedChain = NULL;
2035 CFNumberRef trustResultNum = NULL;
2036 CFArrayRef certificates = NULL, policies = NULL, anchors = NULL, responses = NULL,
2037 SCTs = NULL, trustedLogs = NULL, details = NULL, exceptions = NULL;
2038 CFDateRef verifyDate = NULL;
2039 CFDictionaryRef info = NULL;
2040 SecCertificatePathRef chain = NULL;
2041
2042 require_quiet(CFDictionaryGetTypeID() == CFGetTypeID(plist), out);
2043 require_quiet(serializedCertificates = CFDictionaryGetValue(plist, CFSTR(kSecTrustCertificatesKey)), out);
2044 require_quiet(certificates = SecCertificateArrayDeserialize(serializedCertificates), out);
2045 require_quiet(serializedPolicies = CFDictionaryGetValue(plist, CFSTR(kSecTrustPoliciesKey)), out);
2046 require_quiet(policies = SecPolicyArrayCreateDeserialized(serializedPolicies), out);
2047 require_noerr_quiet(status = SecTrustCreateWithCertificates(certificates, policies, &output), out);
2048
2049 serializedAnchors = CFDictionaryGetValue(plist, CFSTR(kSecTrustAnchorsKey));
2050 if (isArray(serializedAnchors)) {
2051 anchors = SecCertificateArrayDeserialize(serializedAnchors);
2052 output->_anchors = anchors;
2053 }
2054 responses = CFDictionaryGetValue(plist, CFSTR(kSecTrustResponsesKey));
2055 if (isArray(responses)) {
2056 output->_responses = CFRetainSafe(responses);
2057 }
2058 SCTs = CFDictionaryGetValue(plist, CFSTR(kSecTrustSCTsKey));
2059 if (isArray(responses)) {
2060 output->_SCTs = CFRetainSafe(SCTs);
2061 }
2062 trustedLogs = CFDictionaryGetValue(plist, CFSTR(kSecTrustTrustedLogsKey));
2063 if (isArray(trustedLogs)) {
2064 output->_trustedLogs = CFRetainSafe(trustedLogs);
2065 }
2066 verifyDate = CFDictionaryGetValue(plist, CFSTR(kSecTrustVerifyDateKey));
2067 if (isDate(verifyDate)) {
2068 output->_verifyDate = CFRetainSafe(verifyDate);
2069 }
2070 serializedChain = CFDictionaryGetValue(plist, CFSTR(kSecTrustChainKey));
2071 if (isArray(serializedChain)) {
2072 chain = SecCertificatePathCreateDeserialized(serializedChain, NULL);
2073 output->_chain = chain;
2074 }
2075 details = CFDictionaryGetValue(plist, CFSTR(kSecTrustDetailsKey));
2076 if (isArray(details)) {
2077 output->_details = CFRetainSafe(details);
2078 }
2079 info = CFDictionaryGetValue(plist, CFSTR(kSecTrustInfoKey));
2080 if (isDictionary(info)) {
2081 output->_info = CFRetainSafe(info);
2082 }
2083 exceptions = CFDictionaryGetValue(plist, CFSTR(kSecTrustExceptionsKey));
2084 if (isArray(exceptions)) {
2085 output->_exceptions = CFRetainSafe(exceptions);
2086 }
2087 int32_t trustResult = -1;
2088 trustResultNum = CFDictionaryGetValue(plist, CFSTR(kSecTrustResultKey));
2089 if (isNumber(trustResultNum) && CFNumberGetValue(trustResultNum, kCFNumberSInt32Type, &trustResult) &&
2090 (trustResult >= 0)) {
2091 output->_trustResult = trustResult;
2092 } else {
2093 status = errSecParam;
2094 }
2095 if (CFDictionaryGetValue(plist, CFSTR(kSecTrustAnchorsOnlyKey)) == kCFBooleanTrue) {
2096 output->_anchorsOnly = true;
2097 } /* false is set by default */
2098 if (CFDictionaryGetValue(plist, CFSTR(kSecTrustKeychainsAllowedKey)) == kCFBooleanFalse) {
2099 output->_keychainsAllowed = false;
2100 } /* true is set by default */
2101
2102 out:
2103 if (errSecSuccess == status && trust) {
2104 *trust = output;
2105 }
2106 CFReleaseNull(policies);
2107 CFReleaseNull(certificates);
2108 return status;
2109 }
2110
2111 SecTrustRef SecTrustDeserialize(CFDataRef serializedTrust, CFErrorRef *error) {
2112 SecTrustRef trust = NULL;
2113 CFPropertyListRef plist = NULL;
2114 OSStatus status = errSecSuccess;
2115 require_action_quiet(serializedTrust, out,
2116 SecError(errSecParam, error, CFSTR("null serialized trust input")));
2117 require_quiet(plist = CFPropertyListCreateWithDERData(NULL, serializedTrust,
2118 kCFPropertyListImmutable, NULL, error), out);
2119 require_noerr_action_quiet(status = SecTrustCreateFromPlist(plist, &trust), out,
2120 SecError(status, error, CFSTR("unable to create trust ref")));
2121
2122 out:
2123 CFReleaseNull(plist);
2124 return trust;
2125 }