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