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