]> git.saurik.com Git - apple/security.git/blob - OSX/sec/Security/SecTrust.c
Security-57337.20.44.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
1222 /* Binding.
1223 Only applies to leaf
1224 Priority: N/A
1225 Short Circuit: No
1226 Recoverable
1227 Trust UI: (Hostname|email address) mismatch
1228 */
1229 CFStringRef kSecPolicyCheckSSLHostname = CFSTR("SSLHostname");
1230
1231 /* Policy specific checks.
1232 Can be on any cert in the chain
1233 Priority: Top down
1234 Short Circuit: No
1235 Recoverable
1236 Trust UI: Certificate chain is not valid for the current policy.
1237 OR: (One or more) certificates in the chain are not valid for the current policy/application
1238 */
1239 CFStringRef kSecPolicyCheckNonEmptySubject = CFSTR("NonEmptySubject");
1240 /* Cert UI: Non CA certificate used as CA.
1241 Cert UI: CA certificate used as leaf.
1242 Cert UI: Cert chain length exceeded.
1243 Cert UI: Basic constraints extension not critical (non fatal).
1244 Cert UI: Leaf certificate has basic constraints extension (non fatal).
1245 */
1246 CFStringRef kSecPolicyCheckBasicContraints = CFSTR("BasicContraints");
1247 CFStringRef kSecPolicyCheckKeyUsage = CFSTR("KeyUsage");
1248 CFStringRef kSecPolicyCheckExtendedKeyUsage = CFSTR("ExtendedKeyUsage");
1249 /* Checks that the issuer of the leaf has exactly one Common Name and that it
1250 matches the specified string. */
1251 CFStringRef kSecPolicyCheckIssuerCommonName = CFSTR("IssuerCommonName");
1252 /* Checks that the leaf has exactly one Common Name and that it has the
1253 specified string as a prefix. */
1254 CFStringRef kSecPolicyCheckSubjectCommonNamePrefix = CFSTR("SubjectCommonNamePrefix");
1255 /* Check that the certificate chain length matches the specificed CFNumberRef
1256 length. */
1257 CFStringRef kSecPolicyCheckChainLength = CFSTR("ChainLength");
1258 CFStringRef kSecPolicyCheckNotValidBefore = CFSTR("NotValidBefore");
1259
1260 /* Expiration.
1261 Can be on any cert in the chain
1262 Priority: Top down
1263 Short Circuit: No
1264 Recoverable
1265 Trust UI: One or more certificates have expired or are not valid yet.
1266 OS: The (root|intermediate|leaf) certificate (expired on 'date'|is not valid until 'date')
1267 Cert UI: Certificate (expired on 'date'|is not valid until 'date')
1268 */
1269 CFStringRef kSecPolicyCheckValidIntermediates = CFSTR("ValidIntermediates");
1270 CFStringRef kSecPolicyCheckValidLeaf = CFSTR("ValidLeaf");
1271 CFStringRef kSecPolicyCheckValidRoot = CFSTR("ValidRoot");
1272
1273 #endif
1274
1275 struct TrustFailures {
1276 bool badLinkage;
1277 bool unknownCritExtn;
1278 bool untrustedAnchor;
1279 bool hostnameMismatch;
1280 bool policyFail;
1281 bool invalidCert;
1282 };
1283
1284 static void applyDetailProperty(const void *_key, const void *_value,
1285 void *context) {
1286 CFStringRef key = (CFStringRef)_key;
1287 struct TrustFailures *tf = (struct TrustFailures *)context;
1288 if (CFGetTypeID(_value) != CFBooleanGetTypeID()) {
1289 /* Value isn't a CFBooleanRef, oh no! */
1290 return;
1291 }
1292 CFBooleanRef value = (CFBooleanRef)_value;
1293 if (CFBooleanGetValue(value)) {
1294 /* Not an actual failure so we don't report it. */
1295 return;
1296 }
1297
1298 /* @@@ FIXME: Report a different return value when something is in the
1299 details but masked out by an exception and use that below for display
1300 purposes. */
1301 if (CFEqual(key, kSecPolicyCheckIdLinkage)) {
1302 tf->badLinkage = true;
1303 } else if (CFEqual(key, kSecPolicyCheckCriticalExtensions)
1304 || CFEqual(key, kSecPolicyCheckQualifiedCertStatements)) {
1305 tf->unknownCritExtn = true;
1306 } else if (CFEqual(key, kSecPolicyCheckAnchorTrusted)
1307 || CFEqual(key, kSecPolicyCheckAnchorSHA1)
1308 || CFEqual(key, kSecPolicyCheckAnchorApple)) {
1309 tf->untrustedAnchor = true;
1310 } else if (CFEqual(key, kSecPolicyCheckSSLHostname)) {
1311 tf->hostnameMismatch = true;
1312 } else if (CFEqual(key, kSecPolicyCheckValidIntermediates)
1313 || CFEqual(key, kSecPolicyCheckValidLeaf)
1314 || CFEqual(key, kSecPolicyCheckValidRoot)) {
1315 tf->invalidCert = true;
1316 } else
1317 /* Anything else is a policy failure. */
1318 #if 0
1319 if (CFEqual(key, kSecPolicyCheckNonEmptySubject)
1320 || CFEqual(key, kSecPolicyCheckBasicContraints)
1321 || CFEqual(key, kSecPolicyCheckKeyUsage)
1322 || CFEqual(key, kSecPolicyCheckExtendedKeyUsage)
1323 || CFEqual(key, kSecPolicyCheckIssuerCommonName)
1324 || CFEqual(key, kSecPolicyCheckSubjectCommonNamePrefix)
1325 || CFEqual(key, kSecPolicyCheckChainLength)
1326 || CFEqual(key, kSecPolicyCheckNotValidBefore))
1327 #endif
1328 {
1329 tf->policyFail = true;
1330 }
1331 }
1332
1333 static void appendError(CFMutableArrayRef properties, CFStringRef error) {
1334 CFStringRef localizedError = SecFrameworkCopyLocalizedString(error,
1335 CFSTR("SecCertificate"));
1336 if (!localizedError) {
1337 //secerror("WARNING: localized error string was not found in Security.framework");
1338 localizedError = CFRetain(error);
1339 }
1340 appendProperty(properties, kSecPropertyTypeError, NULL, NULL,
1341 localizedError);
1342 CFReleaseNull(localizedError);
1343 }
1344
1345 CFArrayRef SecTrustCopyProperties(SecTrustRef trust) {
1346 CFArrayRef details = SecTrustGetDetails(trust);
1347 if (!details)
1348 return NULL;
1349
1350 struct TrustFailures tf = {};
1351
1352 CFIndex ix, count = CFArrayGetCount(details);
1353 for (ix = 0; ix < count; ++ix) {
1354 CFDictionaryRef detail = (CFDictionaryRef)
1355 CFArrayGetValueAtIndex(details, ix);
1356 /* We now have a detail dictionary for certificate at index ix, with
1357 a key value pair for each failed policy check. Let's convert it
1358 from Ro-Man form into something a Hu-Man can understand. */
1359 CFDictionaryApplyFunction(detail, applyDetailProperty, &tf);
1360 }
1361
1362 CFMutableArrayRef properties = CFArrayCreateMutable(kCFAllocatorDefault, 0,
1363 &kCFTypeArrayCallBacks);
1364 /* The badLinkage and unknownCritExtn failures are short circuited, since
1365 you can't recover from those errors. */
1366 if (tf.badLinkage) {
1367 appendError(properties, CFSTR("Invalid certificate chain linkage."));
1368 } else if (tf.unknownCritExtn) {
1369 appendError(properties, CFSTR("One or more unsupported critical extensions found."));
1370 } else {
1371 if (tf.untrustedAnchor) {
1372 appendError(properties, CFSTR("Root certificate is not trusted."));
1373 }
1374 if (tf.hostnameMismatch) {
1375 appendError(properties, CFSTR("Hostname mismatch."));
1376 }
1377 if (tf.policyFail) {
1378 appendError(properties, CFSTR("Policy requirements not met."));
1379 }
1380 if (tf.invalidCert) {
1381 appendError(properties, CFSTR("One or more certificates have expired or are not valid yet."));
1382 }
1383 }
1384
1385 if (CFArrayGetCount(properties) == 0) {
1386 /* The certificate chain is trusted, return an empty plist */
1387 #if (TARGET_OS_MAC && !(TARGET_OS_EMBEDDED || TARGET_OS_IPHONE))
1388 // return empty (non-null) plist
1389 #else
1390 // return NULL plist
1391 CFReleaseNull(properties);
1392 #endif
1393 }
1394
1395 return properties;
1396 }
1397
1398 CFDictionaryRef SecTrustCopyResult(SecTrustRef trust) {
1399 // Builds and returns a dictionary of evaluation results.
1400 if (!trust) {
1401 return NULL;
1402 }
1403 CFMutableDictionaryRef results = CFDictionaryCreateMutable(NULL, 0,
1404 &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
1405
1406 // kSecTrustResultDetails (per-cert results)
1407 CFArrayRef details = SecTrustGetDetails(trust);
1408 if (details) {
1409 CFDictionarySetValue(results, (const void *)kSecTrustResultDetails, (const void *)details);
1410 }
1411
1412 // kSecTrustResultValue (overall trust result)
1413 CFNumberRef numValue = CFNumberCreate(NULL, kCFNumberSInt32Type, &trust->_trustResult);
1414 if (numValue) {
1415 CFDictionarySetValue(results, (const void *)kSecTrustResultValue, (const void *)numValue);
1416 CFRelease(numValue);
1417 }
1418 CFDictionaryRef info = trust->_info;
1419 if (trust->_trustResult == kSecTrustResultInvalid || !info) {
1420 return results; // we have nothing more to add
1421 }
1422
1423 // kSecTrustEvaluationDate
1424 CFDateRef evaluationDate = trust->_verifyDate;
1425 if (evaluationDate) {
1426 CFDictionarySetValue(results, (const void *)kSecTrustEvaluationDate, (const void *)evaluationDate);
1427 }
1428
1429 // kSecTrustCertificateTransparency
1430 CFBooleanRef ctValue;
1431 if (CFDictionaryGetValueIfPresent(info, kSecTrustInfoCertificateTransparencyKey, (const void **)&ctValue)) {
1432 CFDictionarySetValue(results, (const void *)kSecTrustCertificateTransparency, (const void *)ctValue);
1433 }
1434
1435 // kSecTrustExtendedValidation
1436 CFBooleanRef evValue;
1437 if (CFDictionaryGetValueIfPresent(info, kSecTrustInfoExtendedValidationKey, (const void **)&evValue)) {
1438 CFDictionarySetValue(results, (const void *)kSecTrustExtendedValidation, (const void *)evValue);
1439 }
1440
1441 // kSecTrustOrganizationName
1442 CFStringRef organizationName;
1443 if (CFDictionaryGetValueIfPresent(info, kSecTrustInfoCompanyNameKey, (const void **)&organizationName)) {
1444 CFDictionarySetValue(results, (const void *)kSecTrustOrganizationName, (const void *)organizationName);
1445 }
1446
1447 // kSecTrustRevocationChecked
1448 CFBooleanRef revocationChecked;
1449 if (CFDictionaryGetValueIfPresent(info, kSecTrustRevocationChecked, (const void **)&revocationChecked)) {
1450 CFDictionarySetValue(results, (const void *)kSecTrustRevocationChecked, (const void *)revocationChecked);
1451 }
1452
1453 // kSecTrustRevocationReason
1454 CFNumberRef revocationReason;
1455 if (CFDictionaryGetValueIfPresent(info, kSecTrustRevocationReason, (const void **)&revocationReason)) {
1456 CFDictionarySetValue(results, (const void *)kSecTrustRevocationReason, (const void *)revocationReason);
1457 }
1458
1459 // kSecTrustRevocationValidUntilDate
1460 CFDateRef validUntilDate;
1461 if (CFDictionaryGetValueIfPresent(info, kSecTrustRevocationValidUntilDate, (const void **)&validUntilDate)) {
1462 CFDictionarySetValue(results, (const void *)kSecTrustRevocationValidUntilDate, (const void *)validUntilDate);
1463 }
1464
1465 return results;
1466 }
1467
1468 // Return 0 upon error.
1469 static int to_int_error_request(enum SecXPCOperation op, CFErrorRef *error) {
1470 __block int64_t result = 0;
1471 securityd_send_sync_and_do(op, error, NULL, ^bool(xpc_object_t response, CFErrorRef *error) {
1472 result = xpc_dictionary_get_int64(response, kSecXPCKeyResult);
1473 if (!result)
1474 return SecError(errSecInternal, error, CFSTR("int64 missing in response"));
1475 return true;
1476 });
1477 return (int)result;
1478 }
1479
1480 // version 0 -> error, so we need to start at version 1 or later.
1481 OSStatus SecTrustGetOTAPKIAssetVersionNumber(int* versionNumber)
1482 {
1483 OSStatus result;
1484 os_activity_t trace_activity = os_activity_start("SecTrustGetOTAPKIAssetVersionNumber", OS_ACTIVITY_FLAG_DEFAULT);
1485 result = SecOSStatusWith(^bool(CFErrorRef *error) {
1486 if (!versionNumber)
1487 return SecError(errSecParam, error, CFSTR("versionNumber is NULL"));
1488
1489 return (*versionNumber = SECURITYD_XPC(sec_ota_pki_asset_version, to_int_error_request, error)) != 0;
1490 });
1491
1492 os_activity_end(trace_activity);
1493 return result;
1494 }
1495
1496 #define do_if_registered(sdp, ...) if (gSecurityd && gSecurityd->sdp) { return gSecurityd->sdp(__VA_ARGS__); }
1497
1498 static bool xpc_dictionary_entry_is_type(xpc_object_t dictionary, const char *key, xpc_type_t type)
1499 {
1500 xpc_object_t value = xpc_dictionary_get_value(dictionary, key);
1501
1502 return value && (xpc_get_type(value) == type);
1503 }
1504
1505 OSStatus SecTrustOTAPKIGetUpdatedAsset(int* didUpdateAsset)
1506 {
1507 CFErrorRef error = NULL;
1508 do_if_registered(sec_ota_pki_get_new_asset, &error);
1509
1510 int64_t num = 0;
1511 xpc_object_t message = securityd_create_message(kSecXPCOpOTAPKIGetNewAsset, &error);
1512 if (message)
1513 {
1514 xpc_object_t response = securityd_message_with_reply_sync(message, &error);
1515
1516 if (response && xpc_dictionary_entry_is_type(response, kSecXPCKeyResult, XPC_TYPE_INT64))
1517 {
1518 num = (int64_t) xpc_dictionary_get_int64(response, kSecXPCKeyResult);
1519 xpc_release(response);
1520 }
1521
1522 xpc_release(message);
1523 }
1524
1525 if (NULL != didUpdateAsset)
1526 {
1527 *didUpdateAsset = (int)num;
1528 }
1529 return noErr;
1530 }
1531
1532
1533 #if 0
1534 // MARK: -
1535 // MARK: SecTrustNode
1536 /********************************************************
1537 **************** SecTrustNode object *******************
1538 ********************************************************/
1539 typedef uint8_t SecFetchingState;
1540 enum {
1541 kSecFetchingStatePassedIn = 0,
1542 kSecFetchingStateLocal,
1543 kSecFetchingStateFromURL,
1544 kSecFetchingStateDone,
1545 };
1546
1547 typedef uint8_t SecTrustState;
1548 enum {
1549 kSecTrustStateUnknown = 0,
1550 kSecTrustStateNotSigner,
1551 kSecTrustStateValidSigner,
1552 };
1553
1554 typedef struct __SecTrustNode *SecTrustNodeRef;
1555 struct __SecTrustNode {
1556 SecTrustNodeRef _child;
1557 SecCertificateRef _certificate;
1558
1559 /* Cached information about _certificate */
1560 bool _isAnchor;
1561 bool _isSelfSigned;
1562
1563 /* Set of all certificates we have ever considered as a parent. We use
1564 this to avoid having to recheck certs when we go to the next phase. */
1565 CFMutableSet _certificates;
1566
1567 /* Parents that are still partial chains we haven't yet considered. */
1568 CFMutableSet _partials;
1569 /* Parents that are still partial chains we have rejected. We reconsider
1570 these if we get to the final phase and we still haven't found a valid
1571 candidate. */
1572 CFMutableSet _rejected_partials;
1573
1574 /* Parents that are complete chains we haven't yet considered. */
1575 CFMutableSet _candidates;
1576 /* Parents that are complete chains we have rejected. */
1577 CFMutableSet _rejected_candidates;
1578
1579 /* State of candidate fetching. */
1580 SecFetchingState _fetchingState;
1581
1582 /* Trust state of _candidates[_candidateIndex] */
1583 SecTrustState _trustState;
1584 };
1585 typedef struct __SecTrustNode SecTrustNode;
1586
1587 /* Forward declarations of static functions. */
1588 static CFStringRef SecTrustNodeDescribe(CFTypeRef cf);
1589 static void SecTrustNodeDestroy(CFTypeRef cf);
1590
1591 /* Static functions. */
1592 static CFStringRef SecTrustNodeCopyDescription(CFTypeRef cf) {
1593 SecTrustNodeRef node = (SecTrustNodeRef)cf;
1594 return CFStringCreateWithFormat(kCFAllocatorDefault, NULL,
1595 CFSTR("<SecTrustNodeRef: %p>"), node);
1596 }
1597
1598 static void SecTrustNodeDestroy(CFTypeRef cf) {
1599 SecTrustNodeRef trust = (SecTrustNodeRef)cf;
1600 if (trust->_child) {
1601 free(trust->_child);
1602 }
1603 if (trust->_certificate) {
1604 free(trust->_certificate);
1605 }
1606 if (trust->_candidates) {
1607 CFRelease(trust->_candidates);
1608 }
1609 }
1610
1611 /* SecTrustNode API functions. */
1612 CFGiblisFor(SecTrustNode)
1613
1614 SecTrustNodeRef SecTrustNodeCreate(SecTrustRef trust,
1615 SecCertificateRef certificate, SecTrustNodeRef child) {
1616 CFAllocatorRef allocator = kCFAllocatorDefault;
1617 check(trust);
1618 check(certificate);
1619
1620 CFIndex size = sizeof(struct __SecTrustNode);
1621 SecTrustNodeRef result = (SecTrustNodeRef)_CFRuntimeCreateInstance(
1622 allocator, SecTrustNodeGetTypeID(), size - sizeof(CFRuntimeBase), 0);
1623 if (!result)
1624 return NULL;
1625
1626 memset((char*)result + sizeof(result->_base), 0,
1627 sizeof(*result) - sizeof(result->_base));
1628 if (child) {
1629 CFRetain(child);
1630 result->_child = child;
1631 }
1632 CFRetain(certificate);
1633 result->_certificate = certificate;
1634 result->_isAnchor = SecTrustCertificateIsAnchor(certificate);
1635
1636 return result;
1637 }
1638
1639 SecCertificateRef SecTrustGetCertificate(SecTrustNodeRef node) {
1640 check(node);
1641 return node->_certificate;
1642 }
1643
1644 CFArrayRef SecTrustNodeCopyProperties(SecTrustNodeRef node,
1645 SecTrustRef trust) {
1646 check(node);
1647 check(trust);
1648 CFMutableArrayRef summary = SecCertificateCopySummaryProperties(
1649 node->_certificate, SecTrustGetVerifyTime(trust));
1650 /* FIXME Add more details in the failure case. */
1651 return summary;
1652 }
1653
1654 /* Attempt to verify this node's signature chain down to the child. */
1655 SecTrustState SecTrustNodeVerifySignatureChain(SecTrustNodeRef node) {
1656 /* FIXME */
1657 return kSecTrustStateUnknown;
1658 }
1659
1660
1661 /* See if the next candidate works. */
1662 SecTrustNodeRef SecTrustNodeCopyNextCandidate(SecTrustNodeRef node,
1663 SecTrustRef trust, SecFetchingState fetchingState) {
1664 check(node);
1665 check(trust);
1666
1667 CFAbsoluteTime verifyTime = SecTrustGetVerifyTime(trust);
1668
1669 for (;;) {
1670 /* If we have any unconsidered candidates left check those first. */
1671 while (node->_candidateIndex < CFArrayGetCount(node->_candidates)) {
1672 SecCertificateRef candidate = (SecCertificateRef)
1673 CFArrayGetValueAtIndex(node->_candidates, node->_candidateIndex);
1674 if (node->_fetchingState != kSecFetchingStateDone) {
1675 /* If we still have potential sources to fetch other candidates
1676 from we ignore expired candidates. */
1677 if (!SecCertificateIsValidOn(candidate, verifyTime)) {
1678 node->_candidateIndex++;
1679 continue;
1680 }
1681 }
1682
1683 SecTrustNodeRef parent = SecTrustNodeCreate(candidate, node);
1684 CFArrayRemoveValueAtIndex(node->_candidates, node->_candidateIndex);
1685 if (SecTrustNodeVerifySignatureChain(parent) ==
1686 kSecTrustStateNotSigner) {
1687 /* This candidate parent is not a valid signer of its
1688 child. */
1689 CFRelease(parent);
1690 /* If another signature failed further down the chain we need
1691 to backtrack down to whatever child is still a valid
1692 candidate and has additional candidates to consider.
1693 @@@ We really want to make the fetchingState a global of
1694 SecTrust itself as well and not have any node go beyond the
1695 current state of SecTrust if there are other (read cheap)
1696 options to consider. */
1697 continue;
1698 }
1699 return parent;
1700 }
1701
1702 /* We've run out of candidates in our current state so let's try to
1703 find some more. Note we fetch candidates in increasing order of
1704 cost in the hope we won't ever get to the more expensive fetching
1705 methods. */
1706 SecCertificateRef certificate = node->_certificate;
1707 switch (node->_fetchingState) {
1708 case kSecFetchingStatePassedIn:
1709 /* Get the list of candidates from SecTrust. */
1710 CFDataRef akid = SecCertificateGetAuthorityKeyID(certificate);
1711 if (akid) {
1712 SecTrustAppendCandidatesWithAuthorityKeyID(akid, node->_candidates);
1713 } else {
1714 CFDataRef issuer =
1715 SecCertificateGetNormalizedIssuerContent(certificate);
1716 SecTrustAppendCandidatesWithSubject(issuer, node->_candidates);
1717 }
1718 node->_fetchingState = kSecFetchingStateLocal;
1719 break;
1720 case kSecFetchingStateLocal:
1721 /* Lookup candidates in the local database. */
1722 node->_fetchingState = kSecFetchingStateFromURL;
1723 break;
1724 case kSecFetchingStateFromURL:
1725 node->_fetchingState = kSecFetchingStateCheckExpired;
1726 break;
1727 case kSecFetchingStateCheckExpired:
1728 /* Time to start considering expired candidates as well. */
1729 node->_candidateIndex = 0;
1730 node->_fetchingState = kSecFetchingStateDone;
1731 break;
1732 case kSecFetchingStateDone;
1733 return NULL;
1734 }
1735 }
1736
1737 CFAllocatorRef allocator = CFGetAllocator(node);
1738
1739 /* A trust node has a number of states.
1740 1) Look for issuing certificates by asking SecTrust about known
1741 parent certificates.
1742 2) Look for issuing certificates in certificate databases (keychains)
1743 3) Look for issuing certificates by going out to the web if the nodes
1744 certificate has a issuer location URL.
1745 4) Look through expired or not yet valid candidates we have put aside.
1746
1747 We go though the stages 1 though 3 looking for candidate issuer
1748 certificates. If a candidate certificate is not valid at verifyTime
1749 we put it in a to be examined later queue. If a candidate certificate
1750 is valid we verify if it actually signed our certificate (if possible).
1751 If not we discard it and continue on to the next candidate certificate.
1752 If it is we return a new SecTrustNodeRef for that certificate. */
1753
1754 CFMutableArrayRef issuers = CFArrayCreateMutable(allocator, 0,
1755 &kCFTypeArrayCallBacks);
1756
1757 /* Find a node's parent. */
1758 certificate = node->_certificate;
1759 CFDataRef akid = SecCertificateGetAuthorityKeyID(certificate);
1760 CFTypeRef candidates = NULL;
1761 if (akid) {
1762 candidates = (CFTypeRef)CFDictionaryGetValueForKey(skidDict, akid);
1763 if (candidates) {
1764 addValidIssuersFrom(issuers, certificate, candidates, true);
1765 }
1766 }
1767 if (!candidates) {
1768 CFDataRef issuer =
1769 SecCertificateGetNormalizedIssuerContent(certificate);
1770 candidates = (CFTypeRef)
1771 CFDictionaryGetValueForKey(subjectDict, issuer);
1772 addValidIssuersFrom(issuers, certificate, candidates, false);
1773 }
1774
1775 if (CFArrayGetCount(issuers) == 0) {
1776 /* O no! we can't find an issuer for this certificate. Let's see
1777 if we can find one in the local database. */
1778 }
1779
1780 return errSecSuccess;
1781 }
1782
1783 CFArrayRef SecTrustNodeCopyNextChain(SecTrustNodeRef node,
1784 SecTrustRef trust) {
1785 /* Return the next full chain that isn't a reject unless we are in
1786 a state where we consider returning rejects. */
1787
1788 switch (node->_fetchingState) {
1789 case kSecFetchingStatePassedIn:
1790 /* Get the list of candidates from SecTrust. */
1791 CFDataRef akid = SecCertificateGetAuthorityKeyID(certificate);
1792 if (akid) {
1793 SecTrustAppendCandidatesWithAuthorityKeyID(akid, node->_candidates);
1794 } else {
1795 CFDataRef issuer =
1796 SecCertificateGetNormalizedIssuerContent(certificate);
1797 SecTrustAppendCandidatesWithSubject(issuer, node->_candidates);
1798 }
1799 node->_fetchingState = kSecFetchingStateLocal;
1800 break;
1801 case kSecFetchingStateLocal:
1802 /* Lookup candidates in the local database. */
1803 node->_fetchingState = kSecFetchingStateFromURL;
1804 break;
1805 case kSecFetchingStateFromURL:
1806 node->_fetchingState = kSecFetchingStateCheckExpired;
1807 break;
1808 case kSecFetchingStateCheckExpired:
1809 /* Time to start considering expired candidates as well. */
1810 node->_candidateIndex = 0;
1811 node->_fetchingState = kSecFetchingStateDone;
1812 break;
1813 case kSecFetchingStateDone;
1814 return NULL;
1815 }
1816 }
1817
1818 class Source {
1819 Iterator parentIterator(Cert);
1820 };
1821
1822 class NodeCache {
1823 Set nodes;
1824
1825 static bool unique(Node node) {
1826 if (nodes.contains(node))
1827 return false;
1828 nodes.add(node);
1829 return true;
1830 }
1831
1832 static bool isAnchor(Cert cert);
1833 };
1834
1835 class Node {
1836 Cert cert;
1837 Node child;
1838 int nextSource;
1839 Iterator parentIterator; /* For current source of parents. */
1840
1841 Node(Cert inCert) : child(nil), cert(inCert), nextSource(0) {}
1842 Node(Node inChild, Cert inCert) : child(inChild), cert(inCert),
1843 nextSource(0) {}
1844
1845 CertPath certPath() {
1846 CertPath path;
1847 Node node = this;
1848 while (node) {
1849 path.add(node.cert);
1850 node = node.child;
1851 }
1852 return path;
1853 }
1854
1855 void contains(Cert cert) {
1856 Node node = this;
1857 while (node) {
1858 if (cert == node.cert)
1859 return true;
1860 node = node.child;
1861 }
1862 return false;
1863 }
1864
1865 Node nextParent(Array currentSources) {
1866 for (;;) {
1867 if (!nextSource ||
1868 parentIterator == currentSources[nextSource - 1].end()) {
1869 if (nextSource == currentSources.count) {
1870 /* We ran out of parent sources. */
1871 return nil;
1872 }
1873 parentIterator = currentSources[nextSource++].begin();
1874 }
1875 Certificate cert = *parentIterator++;
1876 /* Check for cycles and self signed chains. */
1877 if (!contains(cert)) {
1878 Node node = Node(this, parent);
1879 if (!NodeCache.unique(node))
1880 return node;
1881 }
1882 }
1883 }
1884 };
1885
1886
1887 class PathBuilder {
1888 List nodes;
1889 List rejects;
1890 Array currentSources;
1891 Iterator nit;
1892 Array allSources;
1893 Iterator sourceIT;
1894 CertPath chain;
1895
1896 PathBuilder(Cert cert) {
1897 nodes.append(Node(cert));
1898 nit = nodes.begin();
1899 sourceIT = allSources.begin();
1900 }
1901
1902 nextAnchoredPath() {
1903 if (nit == nodes.end()) {
1904 /* We should add another source to the list of sources to
1905 search. */
1906 if (sourceIT == allSources.end()) {
1907 /* No more sources to add. */
1908 }
1909 currentSources += *sourceIT++;
1910 /* Resort nodes by size. */
1911 Nodes.sortBySize();
1912 nit = nodes.begin();
1913 /* Set the source list for all nodes. */
1914
1915 }
1916 while (Node node = *nit) {
1917 Node candidate = node.nextParent(currentSources);
1918 if (!candidate) {
1919 /* The current node has no more candidate parents so move
1920 along. */
1921 nit++;
1922 continue;
1923 }
1924
1925 if (candidate.isAnchored) {
1926 candidates.append(candidate);
1927 } else
1928 nodes.insert(candidate, nit);
1929 }
1930 }
1931
1932 findValidPath() {
1933 while (Node node = nextAnchoredPath()) {
1934 if (node.isValid()) {
1935 chain = node.certPath;
1936 break;
1937 }
1938 rejects.append(node);
1939 }
1940 }
1941 }
1942
1943
1944 #endif