]> git.saurik.com Git - apple/security.git/blob - OSX/sec/securityd/SecTrustServer.c
Security-57740.31.2.tar.gz
[apple/security.git] / OSX / sec / securityd / SecTrustServer.c
1 /*
2 * Copyright (c) 2006-2010,2012-2016 Apple Inc. All Rights Reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 *
23 * SecTrustServer.c - certificate trust evaluation engine
24 *
25 *
26 */
27
28 #include <securityd/SecTrustServer.h>
29 #include <securityd/SecPolicyServer.h>
30 #include <securityd/SecTrustStoreServer.h>
31 #include <securityd/SecCAIssuerRequest.h>
32 #include <securityd/SecItemServer.h>
33
34 #include <utilities/SecIOFormat.h>
35 #include <utilities/SecDispatchRelease.h>
36 #include <utilities/SecAppleAnchorPriv.h>
37
38 #include <Security/SecTrustPriv.h>
39 #include <Security/SecItem.h>
40 #include <Security/SecCertificateInternal.h>
41 #include <Security/SecCertificatePath.h>
42 #include <Security/SecFramework.h>
43 #include <Security/SecPolicyPriv.h>
44 #include <Security/SecPolicyInternal.h>
45 #include <Security/SecTrustSettingsPriv.h>
46 #include <Security/SecTask.h>
47 #include <CoreFoundation/CFRuntime.h>
48 #include <CoreFoundation/CFSet.h>
49 #include <CoreFoundation/CFString.h>
50 #include <CoreFoundation/CFNumber.h>
51 #include <CoreFoundation/CFArray.h>
52 #include <CoreFoundation/CFPropertyList.h>
53 #include <AssertMacros.h>
54 #include <stdbool.h>
55 #include <string.h>
56 #include <stdlib.h>
57 #include <limits.h>
58 #include <sys/codesign.h>
59 #include <Security/SecBase.h>
60 #include "SecRSAKey.h"
61 #include <libDER/oids.h>
62 #include <utilities/debugging.h>
63 #include <utilities/SecCFWrappers.h>
64 #include <Security/SecInternal.h>
65 #include <ipc/securityd_client.h>
66 #include <CommonCrypto/CommonDigest.h>
67 #include "OTATrustUtilities.h"
68 #include "personalization.h"
69 #include <utilities/SecInternalReleasePriv.h>
70
71 #if TARGET_OS_OSX
72 #include <Security/SecTaskPriv.h>
73 #endif
74
75
76 /********************************************************
77 ***************** OTA Trust support ********************
78 ********************************************************/
79
80
81 //#ifndef SECITEM_SHIM_OSX
82
83 static CFArrayRef subject_to_anchors(CFDataRef nic);
84 static CFArrayRef CopyCertsFromIndices(CFArrayRef offsets);
85
86 static CFArrayRef subject_to_anchors(CFDataRef nic)
87 {
88 CFArrayRef result = NULL;
89
90 if (NULL == nic)
91 {
92 return result;
93 }
94
95 SecOTAPKIRef otapkiref = SecOTAPKICopyCurrentOTAPKIRef();
96 if (NULL == otapkiref)
97 {
98 return result;
99 }
100
101 CFDictionaryRef lookupTable = SecOTAPKICopyAnchorLookupTable(otapkiref);
102 CFRelease(otapkiref);
103
104 if (NULL == lookupTable)
105 {
106 return result;
107 }
108
109 unsigned char subject_digest[CC_SHA1_DIGEST_LENGTH];
110 memset(subject_digest, 0, CC_SHA1_DIGEST_LENGTH);
111
112 (void)CC_SHA1(CFDataGetBytePtr(nic), (CC_LONG)CFDataGetLength(nic), subject_digest);
113 CFDataRef sha1Digest = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, subject_digest, CC_SHA1_DIGEST_LENGTH, kCFAllocatorNull);
114
115
116 result = (CFArrayRef)CFDictionaryGetValue(lookupTable, sha1Digest);
117 CFReleaseSafe(lookupTable);
118 CFReleaseSafe(sha1Digest);
119
120 return result;
121 }
122
123 static CFArrayRef CopyCertDataFromIndices(CFArrayRef offsets)
124 {
125 CFMutableArrayRef result = NULL;
126
127 SecOTAPKIRef otapkiref = SecOTAPKICopyCurrentOTAPKIRef();
128 if (NULL == otapkiref)
129 {
130 return result;
131 }
132
133 const char* anchorTable = SecOTAPKIGetAnchorTable(otapkiref);
134 if (NULL == anchorTable)
135 {
136 CFReleaseSafe(otapkiref);
137 return result;
138 }
139
140 CFIndex num_offsets = CFArrayGetCount(offsets);
141
142 result = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
143
144 for (CFIndex idx = 0; idx < num_offsets; idx++)
145 {
146 CFNumberRef offset = (CFNumberRef)CFArrayGetValueAtIndex(offsets, idx);
147 uint32_t offset_value = 0;
148 if (CFNumberGetValue(offset, kCFNumberSInt32Type, &offset_value))
149 {
150 char* pDataPtr = (char *)(anchorTable + offset_value);
151 //int32_t record_length = *((int32_t * )pDataPtr);
152 //record_length = record_length;
153 pDataPtr += sizeof(uint32_t);
154
155 int32_t cert_data_length = *((int32_t * )pDataPtr);
156 pDataPtr += sizeof(uint32_t);
157
158 CFDataRef cert_data = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, (const UInt8 *)pDataPtr,
159 cert_data_length, kCFAllocatorNull);
160 if (NULL != cert_data)
161 {
162 CFArrayAppendValue(result, cert_data);
163 CFReleaseSafe(cert_data);
164 }
165 }
166 }
167 CFReleaseSafe(otapkiref);
168 return result;
169 }
170
171 static CFArrayRef CopyCertsFromIndices(CFArrayRef offsets)
172 {
173 CFMutableArrayRef result = NULL;
174
175 CFArrayRef cert_data_array = CopyCertDataFromIndices(offsets);
176
177 if (NULL != cert_data_array)
178 {
179 result = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
180 CFIndex num_cert_datas = CFArrayGetCount(cert_data_array);
181 for (CFIndex idx = 0; idx < num_cert_datas; idx++)
182 {
183 CFDataRef cert_data = (CFDataRef)CFArrayGetValueAtIndex(cert_data_array, idx);
184 if (NULL != cert_data)
185 {
186 SecCertificateRef cert = SecCertificateCreateWithData(kCFAllocatorDefault, cert_data);
187 if (NULL != cert)
188 {
189 CFArrayAppendValue(result, cert);
190 CFRelease(cert);
191 }
192 }
193 }
194 CFRelease(cert_data_array);
195 }
196 return result;
197
198 }
199 //#endif // SECITEM_SHIM_OSX
200
201 /********************************************************
202 *************** END OTA Trust support ******************
203 ********************************************************/
204
205 #define MAX_CHAIN_LENGTH 15
206 #define ACCEPT_PATH_SCORE 10000000
207
208 /* Forward declaration for use in SecCertificateSource. */
209 static void SecPathBuilderExtendPaths(void *context, CFArrayRef parents);
210
211
212 // MARK: -
213 // MARK: SecCertificateSource
214 /********************************************************
215 ************ SecCertificateSource object ***************
216 ********************************************************/
217
218 typedef struct SecCertificateSource *SecCertificateSourceRef;
219 typedef void(*SecCertificateSourceParents)(void *, CFArrayRef);
220 typedef bool(*CopyParents)(SecCertificateSourceRef source,
221 SecCertificateRef certificate, void *context, SecCertificateSourceParents);
222 typedef CFArrayRef(*CopyConstraints)(SecCertificateSourceRef source,
223 SecCertificateRef certificate);
224 typedef bool(*Contains)(SecCertificateSourceRef source,
225 SecCertificateRef certificate);
226
227 struct SecCertificateSource {
228 CopyParents copyParents;
229 CopyConstraints copyUsageConstraints;
230 Contains contains;
231 };
232
233 static bool SecCertificateSourceCopyParents(SecCertificateSourceRef source,
234 SecCertificateRef certificate,
235 void *context, SecCertificateSourceParents callback) {
236 return source->copyParents(source, certificate, context, callback);
237 }
238
239 static CFArrayRef SecCertificateSourceCopyUsageConstraints(
240 SecCertificateSourceRef source, SecCertificateRef certificate) {
241 if (source->copyUsageConstraints) {
242 return source->copyUsageConstraints(source, certificate);
243 } else {
244 return NULL;
245 }
246 }
247
248 static bool SecCertificateSourceContains(SecCertificateSourceRef source,
249 SecCertificateRef certificate) {
250 return source->contains(source, certificate);
251 }
252
253 // MARK: -
254 // MARK: SecItemCertificateSource
255 /********************************************************
256 *********** SecItemCertificateSource object ************
257 ********************************************************/
258 struct SecItemCertificateSource {
259 struct SecCertificateSource base;
260 CFArrayRef accessGroups;
261 };
262 typedef struct SecItemCertificateSource *SecItemCertificateSourceRef;
263
264 static CFTypeRef SecItemCertificateSourceResultsPost(CFTypeRef raw_results) {
265 if (isArray(raw_results)) {
266 CFMutableArrayRef result = CFArrayCreateMutable(kCFAllocatorDefault, CFArrayGetCount(raw_results), &kCFTypeArrayCallBacks);
267 CFArrayForEach(raw_results, ^(const void *value) {
268 SecCertificateRef cert = SecCertificateCreateWithData(kCFAllocatorDefault, value);
269 if (cert) {
270 CFArrayAppendValue(result, cert);
271 CFRelease(cert);
272 }
273 });
274 return result;
275 } else if (isData(raw_results)) {
276 return SecCertificateCreateWithData(kCFAllocatorDefault, (CFDataRef)raw_results);
277 }
278 return NULL;
279 }
280
281 static bool SecItemCertificateSourceCopyParents(
282 SecCertificateSourceRef source, SecCertificateRef certificate,
283 void *context, SecCertificateSourceParents callback) {
284 SecItemCertificateSourceRef msource = (SecItemCertificateSourceRef)source;
285 /* FIXME: Search for things other than just subject of our issuer if we
286 have a subjectID or authorityKeyIdentifier. */
287 CFDataRef normalizedIssuer =
288 SecCertificateGetNormalizedIssuerContent(certificate);
289 const void *keys[] = {
290 kSecClass,
291 kSecReturnData,
292 kSecMatchLimit,
293 kSecAttrSubject
294 },
295 *values[] = {
296 kSecClassCertificate,
297 kCFBooleanTrue,
298 kSecMatchLimitAll,
299 normalizedIssuer
300 };
301 CFDictionaryRef query = CFDictionaryCreate(NULL, keys, values, 4,
302 NULL, NULL);
303 CFTypeRef results = NULL;
304 SecurityClient client = {
305 .task = NULL,
306 .accessGroups = msource->accessGroups,
307 .allowSystemKeychain = true,
308 .allowSyncBubbleKeychain = false,
309 .isNetworkExtension = false,
310 };
311
312 /* We can make this async or run this on a queue now easily. */
313 CFErrorRef localError = NULL;
314 if (!_SecItemCopyMatching(query, &client, &results, &localError)) {
315 if (localError && (CFErrorGetCode(localError) != errSecItemNotFound)) {
316 secdebug("trust", "_SecItemCopyMatching: %@", localError);
317 }
318 CFReleaseSafe(localError);
319 }
320 CFRelease(query);
321 CFTypeRef certs = SecItemCertificateSourceResultsPost(results);
322 CFReleaseSafe(results);
323 callback(context, certs);
324 CFReleaseSafe(certs);
325 return true;
326 }
327
328 static bool SecItemCertificateSourceContains(SecCertificateSourceRef source,
329 SecCertificateRef certificate) {
330 SecItemCertificateSourceRef msource = (SecItemCertificateSourceRef)source;
331 /* Look up a certificate by issuer and serial number. */
332 CFDataRef normalizedIssuer = SecCertificateGetNormalizedIssuerContent(certificate);
333 CFRetainSafe(normalizedIssuer);
334 CFDataRef serialNumber =
335 #if (TARGET_OS_MAC && !(TARGET_OS_EMBEDDED || TARGET_OS_IPHONE))
336 SecCertificateCopySerialNumber(certificate, NULL);
337 #else
338 SecCertificateCopySerialNumber(certificate);
339 #endif
340 const void *keys[] = {
341 kSecClass,
342 kSecMatchLimit,
343 kSecAttrIssuer,
344 kSecAttrSerialNumber
345 },
346 *values[] = {
347 kSecClassCertificate,
348 kSecMatchLimitOne,
349 normalizedIssuer,
350 serialNumber
351 };
352 SecurityClient client = {
353 .task = NULL,
354 .accessGroups = msource->accessGroups,
355 .allowSystemKeychain = true,
356 .allowSyncBubbleKeychain = false,
357 .isNetworkExtension = false,
358 };
359 CFDictionaryRef query = CFDictionaryCreate(NULL, keys, values, 4, NULL, NULL);
360 CFErrorRef localError = NULL;
361 CFTypeRef results = NULL;
362 bool ok = _SecItemCopyMatching(query, &client, &results, &localError);
363 CFReleaseSafe(query);
364 CFReleaseSafe(serialNumber);
365 CFReleaseSafe(normalizedIssuer);
366 CFReleaseSafe(results);
367 if (!ok) {
368 if (CFErrorGetCode(localError) != errSecItemNotFound) {
369 secdebug("trust", "_SecItemCopyMatching: %@", localError);
370 }
371 CFReleaseSafe(localError);
372 return false;
373 }
374 return true;
375 }
376
377 static SecCertificateSourceRef SecItemCertificateSourceCreate(CFArrayRef accessGroups) {
378 SecItemCertificateSourceRef result = (SecItemCertificateSourceRef)malloc(sizeof(*result));
379 result->base.copyParents = SecItemCertificateSourceCopyParents;
380 result->base.copyUsageConstraints = NULL;
381 result->base.contains = SecItemCertificateSourceContains;
382 result->accessGroups = accessGroups;
383 CFRetainSafe(accessGroups);
384 return (SecCertificateSourceRef)result;
385 }
386
387 static void SecItemCertificateSourceDestroy(SecCertificateSourceRef source) {
388 SecItemCertificateSourceRef msource = (SecItemCertificateSourceRef)source;
389 CFReleaseSafe(msource->accessGroups);
390 free(msource);
391 }
392
393 // MARK: -
394 // MARK: SecSystemAnchorSource
395 /********************************************************
396 *********** SecSystemAnchorSource object ************
397 ********************************************************/
398
399 static bool SecSystemAnchorSourceCopyParents(
400 SecCertificateSourceRef source, SecCertificateRef certificate,
401 void *context, SecCertificateSourceParents callback) {
402 //#ifndef SECITEM_SHIM_OSX
403 CFArrayRef parents = NULL;
404 CFArrayRef anchors = NULL;
405 SecOTAPKIRef otapkiref = NULL;
406
407 CFDataRef nic = SecCertificateGetNormalizedIssuerContent(certificate);
408 /* 64 bits cast: the worst that can happen here is we truncate the length and match an actual anchor.
409 It does not matter since we would be returning the wrong anchors */
410 assert((unsigned long)CFDataGetLength(nic)<UINT_MAX); /* Debug check. correct as long as CFIndex is signed long */
411
412 otapkiref = SecOTAPKICopyCurrentOTAPKIRef();
413 require_quiet(otapkiref, errOut);
414 anchors = subject_to_anchors(nic);
415 require_quiet(anchors, errOut);
416 parents = CopyCertsFromIndices(anchors);
417
418 errOut:
419 callback(context, parents);
420 CFReleaseSafe(parents);
421 CFReleaseSafe(otapkiref);
422 //#endif // SECITEM_SHIM_OSX
423 return true;
424 }
425
426 /* Quick thought: we can eliminate this method if we search anchor sources
427 before all others and we remember if we got a cert from an anchorsource. */
428 static bool SecSystemAnchorSourceContains(SecCertificateSourceRef source,
429 SecCertificateRef certificate) {
430 bool result = false;
431 CFArrayRef anchors = NULL;
432 SecOTAPKIRef otapkiref = NULL;
433 CFArrayRef cert_datas = NULL;
434
435 CFDataRef nic = SecCertificateGetNormalizedSubjectContent(certificate);
436 /* 64 bits cast: the worst that can happen here is we truncate the length and match an actual anchor.
437 It does not matter since we would be returning the wrong anchors */
438 assert((unsigned long)CFDataGetLength(nic)<UINT_MAX); /* Debug check. correct as long as CFIndex is signed long */
439
440 otapkiref = SecOTAPKICopyCurrentOTAPKIRef();
441 require_quiet(otapkiref, errOut);
442 anchors = subject_to_anchors(nic);
443 require_quiet(anchors, errOut);
444 cert_datas = CopyCertDataFromIndices(anchors);
445 require_quiet(cert_datas, errOut);
446
447 CFIndex cert_length = SecCertificateGetLength(certificate);
448 const UInt8 *cert_data_ptr = SecCertificateGetBytePtr(certificate);
449
450 CFIndex num_cert_datas = CFArrayGetCount(cert_datas);
451 for (CFIndex idx = 0; idx < num_cert_datas; idx++)
452 {
453 CFDataRef cert_data = (CFDataRef)CFArrayGetValueAtIndex(cert_datas, idx);
454
455 if (NULL != cert_data)
456 {
457 if (CFGetTypeID(cert_data) == CFDataGetTypeID())
458 {
459 CFIndex aCert_Length = CFDataGetLength(cert_data);
460 const UInt8* aCert_Data_Ptr = CFDataGetBytePtr(cert_data);
461
462 if (aCert_Length == cert_length)
463 {
464 if (!memcmp(cert_data_ptr, aCert_Data_Ptr, cert_length))
465 {
466 result = true;
467 break;
468 }
469 }
470 }
471 }
472 }
473
474 errOut:
475 CFReleaseSafe(cert_datas);
476 CFReleaseSafe(otapkiref);
477 return result;
478 }
479
480
481
482 struct SecCertificateSource kSecSystemAnchorSource = {
483 SecSystemAnchorSourceCopyParents,
484 NULL,
485 SecSystemAnchorSourceContains
486 };
487
488 #if TARGET_OS_IPHONE
489 // MARK: -
490 // MARK: SecUserAnchorSource
491 /********************************************************
492 ************* SecUserAnchorSource object ***************
493 ********************************************************/
494 static bool SecUserAnchorSourceCopyParents(
495 SecCertificateSourceRef source, SecCertificateRef certificate,
496 void *context, SecCertificateSourceParents callback) {
497 CFArrayRef parents = SecTrustStoreCopyParents(
498 SecTrustStoreForDomain(kSecTrustStoreDomainUser), certificate, NULL);
499 callback(context, parents);
500 CFReleaseSafe(parents);
501 return true;
502 }
503
504 static CFArrayRef SecUserAnchorSourceCopyUsageConstraints(
505 SecCertificateSourceRef source, SecCertificateRef certificate) {
506 CFDataRef digest = SecCertificateGetSHA1Digest(certificate);
507 if (!digest)
508 return NULL;
509 CFArrayRef usageConstraints = NULL;
510 bool ok = _SecTrustStoreCopyUsageConstraints(
511 SecTrustStoreForDomain(kSecTrustStoreDomainUser), digest, &usageConstraints, NULL);
512 return (ok) ? usageConstraints : NULL;
513 }
514
515 static bool SecUserAnchorSourceContains(SecCertificateSourceRef source,
516 SecCertificateRef certificate) {
517 return SecTrustStoreContains(
518 SecTrustStoreForDomain(kSecTrustStoreDomainUser), certificate);
519 }
520
521 struct SecCertificateSource kSecUserAnchorSource = {
522 SecUserAnchorSourceCopyParents,
523 SecUserAnchorSourceCopyUsageConstraints,
524 SecUserAnchorSourceContains
525 };
526 #endif
527
528 // MARK: -
529 // MARK: SecMemoryCertificateSource
530 /********************************************************
531 ********** SecMemoryCertificateSource object ***********
532 ********************************************************/
533 struct SecMemoryCertificateSource {
534 struct SecCertificateSource base;
535 CFMutableSetRef certificates;
536 CFMutableDictionaryRef subjects;
537 };
538 typedef struct SecMemoryCertificateSource *SecMemoryCertificateSourceRef;
539
540 static bool SecMemoryCertificateSourceCopyParents(
541 SecCertificateSourceRef source, SecCertificateRef certificate,
542 void *context, SecCertificateSourceParents callback) {
543 SecMemoryCertificateSourceRef msource =
544 (SecMemoryCertificateSourceRef)source;
545 CFDataRef normalizedIssuer =
546 SecCertificateGetNormalizedIssuerContent(certificate);
547 CFArrayRef parents = (normalizedIssuer) ? CFDictionaryGetValue(msource->subjects,
548 normalizedIssuer) : NULL;
549 /* FIXME filter parents by subjectID if certificate has an
550 authorityKeyIdentifier. */
551 secdebug("trust", "%@ parents -> %@", certificate, parents);
552 callback(context, parents);
553 return true;
554 }
555
556 static bool SecMemoryCertificateSourceContains(SecCertificateSourceRef source,
557 SecCertificateRef certificate) {
558 SecMemoryCertificateSourceRef msource =
559 (SecMemoryCertificateSourceRef)source;
560 return CFSetContainsValue(msource->certificates, certificate);
561 }
562
563 static void dictAddValueToArrayForKey(CFMutableDictionaryRef dict,
564 const void *key, const void *value) {
565 if (!key)
566 return;
567
568 CFMutableArrayRef values =
569 (CFMutableArrayRef)CFDictionaryGetValue(dict, key);
570 if (!values) {
571 values = CFArrayCreateMutable(kCFAllocatorDefault, 0,
572 &kCFTypeArrayCallBacks);
573 CFDictionaryAddValue(dict, key, values);
574 CFRelease(values);
575 }
576
577 if (values)
578 CFArrayAppendValue(values, value);
579 }
580
581 static void SecMemoryCertificateSourceApplierFunction(const void *value,
582 void *context) {
583 SecMemoryCertificateSourceRef msource =
584 (SecMemoryCertificateSourceRef)context;
585 SecCertificateRef certificate = (SecCertificateRef)value;
586
587 /* CFSet's API has no way to combine these 2 operations into 1 sadly. */
588 if (CFSetContainsValue(msource->certificates, certificate))
589 return;
590 CFSetAddValue(msource->certificates, certificate);
591
592 CFDataRef key = SecCertificateGetNormalizedSubjectContent(certificate);
593 dictAddValueToArrayForKey(msource->subjects, key, value);
594 }
595
596 static SecCertificateSourceRef SecMemoryCertificateSourceCreate(
597 CFArrayRef certificates) {
598 SecMemoryCertificateSourceRef result = (SecMemoryCertificateSourceRef)
599 malloc(sizeof(*result));
600 result->base.copyParents = SecMemoryCertificateSourceCopyParents;
601 result->base.copyUsageConstraints = NULL;
602 result->base.contains = SecMemoryCertificateSourceContains;
603 CFIndex count = CFArrayGetCount(certificates);
604 result->certificates = CFSetCreateMutable(kCFAllocatorDefault, count,
605 &kCFTypeSetCallBacks);
606 result->subjects = CFDictionaryCreateMutable(kCFAllocatorDefault,
607 count, &kCFTypeDictionaryKeyCallBacks,
608 &kCFTypeDictionaryValueCallBacks);
609 CFRange range = { 0, count };
610 CFArrayApplyFunction(certificates, range,
611 SecMemoryCertificateSourceApplierFunction, result);
612
613 return (SecCertificateSourceRef)result;
614 }
615
616 static void SecMemoryCertificateSourceDestroy(
617 SecCertificateSourceRef source) {
618 SecMemoryCertificateSourceRef msource =
619 (SecMemoryCertificateSourceRef)source;
620 CFRelease(msource->certificates);
621 CFRelease(msource->subjects);
622 free(msource);
623 }
624
625 // MARK: -
626 // MARK: SecCAIssuerCertificateSource
627 /********************************************************
628 ********* SecCAIssuerCertificateSource object **********
629 ********************************************************/
630 static bool SecCAIssuerCertificateSourceCopyParents(
631 SecCertificateSourceRef source, SecCertificateRef certificate,
632 void *context, SecCertificateSourceParents callback) {
633 return SecCAIssuerCopyParents(certificate, SecPathBuilderGetQueue((SecPathBuilderRef)context), context, callback);
634 }
635
636 static bool SecCAIssuerCertificateSourceContains(
637 SecCertificateSourceRef source, SecCertificateRef certificate) {
638 return false;
639 }
640
641 struct SecCertificateSource kSecCAIssuerSource = {
642 SecCAIssuerCertificateSourceCopyParents,
643 NULL,
644 SecCAIssuerCertificateSourceContains
645 };
646
647 #if (SECTRUST_OSX && TARGET_OS_MAC && !(TARGET_OS_EMBEDDED || TARGET_OS_IPHONE || TARGET_IPHONE_SIMULATOR))
648 #include <Security/SecItemPriv.h>
649 // MARK: -
650 // MARK: SecLegacyCertificateSource
651 /********************************************************
652 ********** SecLegacyCertificateSource object ***********
653 ********************************************************/
654
655 static bool SecLegacyCertificateSourceCopyParents(
656 SecCertificateSourceRef source, SecCertificateRef certificate,
657 void *context, SecCertificateSourceParents callback) {
658 CFArrayRef parents = SecItemCopyParentCertificates(certificate, NULL);
659 callback(context, parents);
660 CFReleaseSafe(parents);
661 return true;
662 }
663
664 static bool SecLegacyCertificateSourceContains(
665 SecCertificateSourceRef source, SecCertificateRef certificate) {
666 SecCertificateRef cert = SecItemCopyStoredCertificate(certificate, NULL);
667 bool result = (cert) ? true : false;
668 CFReleaseSafe(cert);
669 return result;
670 }
671
672 struct SecCertificateSource kSecLegacyCertificateSource = {
673 SecLegacyCertificateSourceCopyParents,
674 NULL,
675 SecLegacyCertificateSourceContains
676 };
677 #endif /* SecLegacyCertificateSource */
678
679 #if (SECTRUST_OSX && TARGET_OS_MAC && !(TARGET_OS_EMBEDDED || TARGET_OS_IPHONE || TARGET_IPHONE_SIMULATOR))
680 // MARK: -
681 // MARK: SecLegacyAnchorSource
682 /********************************************************
683 ************ SecLegacyAnchorSource object **************
684 ********************************************************/
685
686 static bool SecLegacyAnchorSourceCopyParents(
687 SecCertificateSourceRef source, SecCertificateRef certificate,
688 void *context, SecCertificateSourceParents callback) {
689 CFMutableArrayRef anchors = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
690 CFArrayRef parents = SecItemCopyParentCertificates(certificate, NULL);
691 CFArrayRef trusted = NULL;
692 if (parents == NULL) {
693 goto finish;
694 }
695 /* Get the custom anchors which have been trusted in the user and admin domains.
696 * We don't need system domain roots here, since SecSystemAnchorSource provides those.
697 */
698 OSStatus status = SecTrustSettingsCopyCertificatesForUserAdminDomains(&trusted);
699 if (status == errSecSuccess && trusted) {
700 CFIndex index, count = CFArrayGetCount(parents);
701 for (index = 0; index < count; index++) {
702 SecCertificateRef parent = (SecCertificateRef)CFArrayGetValueAtIndex(parents, index);
703 if (parent && CFArrayContainsValue(trusted, CFRangeMake(0, CFArrayGetCount(trusted)), parent)) {
704 CFArrayAppendValue(anchors, parent);
705 }
706 }
707 }
708
709 finish:
710 callback(context, anchors);
711 CFReleaseSafe(anchors);
712 CFReleaseSafe(parents);
713 CFReleaseSafe(trusted);
714 return true;
715 }
716
717 static CFArrayRef SecLegacyAnchorSourceCopyUsageConstraints(
718 SecCertificateSourceRef source, SecCertificateRef certificate) {
719
720 CFArrayRef result = NULL;
721 CFArrayRef userTrustSettings = NULL, adminTrustSettings = NULL;
722
723 OSStatus status = SecTrustSettingsCopyTrustSettings(certificate,
724 kSecTrustSettingsDomainUser,
725 &userTrustSettings);
726 if ((status == errSecSuccess) && (userTrustSettings != NULL)) {
727 result = CFRetain(userTrustSettings);
728 }
729
730 status = SecTrustSettingsCopyTrustSettings(certificate,
731 kSecTrustSettingsDomainAdmin,
732 &adminTrustSettings);
733 /* user trust settings overrule admin trust settings */
734 if ((status == errSecSuccess) && (adminTrustSettings != NULL) && (result == NULL)) {
735 result = CFRetain(adminTrustSettings);
736 }
737
738 CFReleaseNull(userTrustSettings);
739 CFReleaseNull(adminTrustSettings);
740 return result;
741 }
742
743 static bool SecLegacyAnchorSourceContains(
744 SecCertificateSourceRef source, SecCertificateRef certificate) {
745 if (certificate == NULL) {
746 return false;
747 }
748 CFArrayRef trusted = NULL;
749 bool result = false;
750 OSStatus status = SecTrustSettingsCopyCertificatesForUserAdminDomains(&trusted);
751 if ((status == errSecSuccess) && (trusted != NULL)) {
752 CFIndex index, count = CFArrayGetCount(trusted);
753 for (index = 0; index < count; index++) {
754 SecCertificateRef anchor = (SecCertificateRef)CFArrayGetValueAtIndex(trusted, index);
755 if (anchor && CFEqual(anchor, certificate)) {
756 result = true;
757 break;
758 }
759 }
760 }
761 CFReleaseSafe(trusted);
762 return result;
763 }
764
765 struct SecCertificateSource kSecLegacyAnchorSource = {
766 SecLegacyAnchorSourceCopyParents,
767 SecLegacyAnchorSourceCopyUsageConstraints,
768 SecLegacyAnchorSourceContains
769 };
770 #endif /* SecLegacyAnchorSource */
771
772 // MARK: -
773 // MARK: SecPathBuilder
774 /********************************************************
775 *************** SecPathBuilder object ******************
776 ********************************************************/
777 struct SecPathBuilder {
778 dispatch_queue_t queue;
779 CFDataRef clientAuditToken;
780 SecCertificateSourceRef certificateSource;
781 SecCertificateSourceRef itemCertificateSource;
782 SecCertificateSourceRef anchorSource;
783 SecCertificateSourceRef appleAnchorSource;
784 CFMutableArrayRef anchorSources;
785 CFIndex nextParentSource;
786 CFMutableArrayRef parentSources;
787 CFArrayRef ocspResponses; // Stapled OCSP responses
788 CFArrayRef signedCertificateTimestamps; // Stapled SCTs
789 CFArrayRef trustedLogs; // Trusted CT logs
790
791 /* Hashed set of all paths we've constructed so far, used to prevent
792 re-considering a path that was already constructed once before.
793 Note that this is the only container in which certificatePath
794 objects are retained.
795 Every certificatePath being considered is always in allPaths and in at
796 most one of partialPaths, rejectedPaths, candidatePath or extendedPaths
797 all of which don't retain their values. */
798 CFMutableSetRef allPaths;
799
800 /* No trusted anchor, satisfies the linking to intermediates for all
801 policies (unless considerRejected is true). */
802 CFMutableArrayRef partialPaths;
803 /* No trusted anchor, does not satisfy linking to intermediates for all
804 policies. */
805 CFMutableArrayRef rejectedPaths;
806 /* Trusted anchor, satisfies the policies so far. */
807 CFMutableArrayRef candidatePaths;
808
809 CFIndex partialIX;
810
811 CFArrayRef leafDetails;
812
813 CFIndex bestPathScore;
814
815 bool considerRejected;
816 bool considerPartials;
817 bool canAccessNetwork;
818
819 struct OpaqueSecPVC path;
820 SecCertificatePathRef bestPath;
821 bool bestPathIsEV;
822 bool bestPathIsSHA2;
823 bool denyBestPath;
824
825 CFIndex activations;
826 bool (*state)(SecPathBuilderRef);
827 SecPathBuilderCompleted completed;
828 const void *context;
829 };
830
831 /* State functions. Return false if a async job was scheduled, return
832 true to execute the next state. */
833 static bool SecPathBuilderGetNext(SecPathBuilderRef builder);
834 static bool SecPathBuilderValidatePath(SecPathBuilderRef builder);
835 static bool SecPathBuilderDidValidatePath(SecPathBuilderRef builder);
836 static bool SecPathBuilderComputeDetails(SecPathBuilderRef builder);
837 static bool SecPathBuilderReportResult(SecPathBuilderRef builder);
838
839 /* Forward declarations. */
840 static bool SecPathBuilderIsAnchor(SecPathBuilderRef builder,
841 SecCertificateRef certificate, SecCertificateSourceRef *foundInSource);
842
843 /* IDEA: policies could be made capable of replacing incoming anchors and
844 anchorsOnly argument values. For example, some policies require the
845 Apple Inc. CA and not any other anchor. This can be done in
846 SecPathBuilderLeafCertificateChecks since this only runs once. */
847 static void SecPathBuilderLeafCertificateChecks(SecPathBuilderRef builder,
848 SecCertificatePathRef path) {
849 CFMutableDictionaryRef certDetail = CFDictionaryCreateMutable(
850 kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks,
851 &kCFTypeDictionaryValueCallBacks);
852 builder->leafDetails = CFArrayCreate(kCFAllocatorDefault,
853 (const void **)&certDetail, 1, &kCFTypeArrayCallBacks);
854 CFRelease(certDetail);
855 SecPVCRef pvc = &builder->path;
856 SecPVCSetPath(pvc, path, builder->leafDetails);
857 builder->considerRejected = !SecPVCLeafChecks(pvc);
858 }
859
860 static void SecPathBuilderInit(SecPathBuilderRef builder,
861 CFDataRef clientAuditToken, CFArrayRef certificates,
862 CFArrayRef anchors, bool anchorsOnly, bool keychainsAllowed,
863 CFArrayRef policies, CFArrayRef ocspResponses,
864 CFArrayRef signedCertificateTimestamps, CFArrayRef trustedLogs,
865 CFAbsoluteTime verifyTime, CFArrayRef accessGroups,
866 SecPathBuilderCompleted completed, const void *context) {
867 secdebug("alloc", "%p", builder);
868 CFAllocatorRef allocator = kCFAllocatorDefault;
869
870 builder->clientAuditToken = (CFDataRef)
871 ((clientAuditToken) ? CFRetain(clientAuditToken) : NULL);
872 builder->queue = dispatch_queue_create("builder", DISPATCH_QUEUE_SERIAL);
873
874 builder->nextParentSource = 1;
875 #if !TARGET_OS_WATCH
876 builder->canAccessNetwork = true;
877 #endif
878
879 builder->anchorSources = CFArrayCreateMutable(allocator, 0, NULL);
880 builder->parentSources = CFArrayCreateMutable(allocator, 0, NULL);
881 builder->allPaths = CFSetCreateMutable(allocator, 0,
882 &kCFTypeSetCallBacks);
883
884 builder->partialPaths = CFArrayCreateMutable(allocator, 0, NULL);
885 builder->rejectedPaths = CFArrayCreateMutable(allocator, 0, NULL);
886 builder->candidatePaths = CFArrayCreateMutable(allocator, 0, NULL);
887
888 /* Init the policy verification context. */
889 SecPVCInit(&builder->path, builder, policies, verifyTime);
890
891 /* Let's create all the certificate sources we might want to use. */
892 builder->certificateSource =
893 SecMemoryCertificateSourceCreate(certificates);
894 if (anchors) {
895 builder->anchorSource = SecMemoryCertificateSourceCreate(anchors);
896 }
897
898 bool allowNonProduction = false;
899 builder->appleAnchorSource = SecMemoryCertificateSourceCreate(SecGetAppleTrustAnchors(allowNonProduction));
900
901
902 /** Parent Sources
903 ** The order here avoids the most expensive methods if the cheaper methods
904 ** produce an acceptable chain: client-provided, keychains, network-fetched.
905 **/
906 #if !TARGET_OS_BRIDGE
907 CFArrayAppendValue(builder->parentSources, builder->certificateSource);
908 builder->itemCertificateSource = SecItemCertificateSourceCreate(accessGroups);
909 if (keychainsAllowed) {
910 CFArrayAppendValue(builder->parentSources, builder->itemCertificateSource);
911 #if TARGET_OS_OSX
912 /* On OS X, need additional parent source to search legacy keychain files. */
913 if (kSecLegacyCertificateSource.contains && kSecLegacyCertificateSource.copyParents) {
914 CFArrayAppendValue(builder->parentSources, &kSecLegacyCertificateSource);
915 }
916 #endif
917 }
918 if (anchorsOnly) {
919 /* Add the Apple, system, and user anchor certificate db to the search list
920 if we don't explicitly trust them. */
921 CFArrayAppendValue(builder->parentSources, builder->appleAnchorSource);
922 CFArrayAppendValue(builder->parentSources, &kSecSystemAnchorSource);
923 #if TARGET_OS_IPHONE
924 CFArrayAppendValue(builder->parentSources, &kSecUserAnchorSource);
925 #endif
926 }
927 if (keychainsAllowed && builder->canAccessNetwork) {
928 CFArrayAppendValue(builder->parentSources, &kSecCAIssuerSource);
929 }
930 #else /* TARGET_OS_BRIDGE */
931 /* Bridge can only access memory sources. */
932 CFArrayAppendValue(builder->parentSources, builder->certificateSource);
933 if (anchorsOnly) {
934 /* Add the Apple, system, and user anchor certificate db to the search list
935 if we don't explicitly trust them. */
936 CFArrayAppendValue(builder->parentSources, builder->appleAnchorSource);
937 }
938 #endif /* !TARGET_OS_BRIDGE */
939
940 /** Anchor Sources
941 ** The order here allows a client-provided anchor to overrule
942 ** a user or admin trust setting which can overrule the system anchors.
943 ** Apple's anchors cannot be overriden by a trust setting.
944 **/
945 #if !TARGET_OS_BRIDGE
946 if (builder->anchorSource) {
947 CFArrayAppendValue(builder->anchorSources, builder->anchorSource);
948 }
949 if (!anchorsOnly) {
950 /* Only add the system and user anchor certificate db to the
951 anchorSources if we are supposed to trust them. */
952 CFArrayAppendValue(builder->anchorSources, builder->appleAnchorSource);
953 #if TARGET_OS_IPHONE
954 CFArrayAppendValue(builder->anchorSources, &kSecUserAnchorSource);
955 #else /* TARGET_OS_OSX */
956 if (keychainsAllowed && kSecLegacyAnchorSource.contains && kSecLegacyAnchorSource.copyParents) {
957 CFArrayAppendValue(builder->anchorSources, &kSecLegacyAnchorSource);
958 }
959 #endif
960 CFArrayAppendValue(builder->anchorSources, &kSecSystemAnchorSource);
961 }
962 #else /* TARGET_OS_BRIDGE */
963 /* Bridge can only access memory sources. */
964 if (builder->anchorSource) {
965 CFArrayAppendValue(builder->anchorSources, builder->anchorSource);
966 }
967 if (!anchorsOnly) {
968 CFArrayAppendValue(builder->anchorSources, builder->appleAnchorSource);
969 }
970 #endif /* !TARGET_OS_BRIDGE */
971
972 /* Now let's get the leaf cert and turn it into a path. */
973 SecCertificateRef leaf =
974 (SecCertificateRef)CFArrayGetValueAtIndex(certificates, 0);
975 SecCertificateSourceRef source = NULL;
976 bool isAnchor = false;
977 CFArrayRef constraints = NULL;
978 if (SecPathBuilderIsAnchor(builder, leaf, &source)) {
979 isAnchor = true;
980 }
981 if (source) {
982 constraints = SecCertificateSourceCopyUsageConstraints(source, leaf);
983 }
984 SecCertificatePathRef path = SecCertificatePathCreate(NULL, leaf, constraints);
985 CFReleaseSafe(constraints);
986 CFSetAddValue(builder->allPaths, path);
987 CFArrayAppendValue(builder->partialPaths, path);
988 if (isAnchor) {
989 SecCertificatePathSetIsAnchored(path);
990 CFArrayAppendValue(builder->candidatePaths, path);
991 }
992 SecPathBuilderLeafCertificateChecks(builder, path);
993 CFRelease(path);
994
995 builder->ocspResponses = CFRetainSafe(ocspResponses);
996 builder->signedCertificateTimestamps = CFRetainSafe(signedCertificateTimestamps);
997
998 if(trustedLogs) {
999 builder->trustedLogs = CFRetainSafe(trustedLogs);
1000 } else {
1001 SecOTAPKIRef otapkiref = SecOTAPKICopyCurrentOTAPKIRef();
1002 builder->trustedLogs = SecOTAPKICopyTrustedCTLogs(otapkiref);
1003 CFReleaseSafe(otapkiref);
1004 }
1005
1006 builder->state = SecPathBuilderGetNext;
1007 builder->completed = completed;
1008 builder->context = context;
1009 }
1010
1011 SecPathBuilderRef SecPathBuilderCreate(CFDataRef clientAuditToken,
1012 CFArrayRef certificates, CFArrayRef anchors, bool anchorsOnly,
1013 bool keychainsAllowed, CFArrayRef policies, CFArrayRef ocspResponses,
1014 CFArrayRef signedCertificateTimestamps, CFArrayRef trustedLogs,
1015 CFAbsoluteTime verifyTime, CFArrayRef accessGroups,
1016 SecPathBuilderCompleted completed, const void *context) {
1017 SecPathBuilderRef builder = malloc(sizeof(*builder));
1018 memset(builder, 0, sizeof(*builder));
1019 SecPathBuilderInit(builder, clientAuditToken, certificates,
1020 anchors, anchorsOnly, keychainsAllowed, policies, ocspResponses,
1021 signedCertificateTimestamps, trustedLogs, verifyTime,
1022 accessGroups, completed, context);
1023 return builder;
1024 }
1025
1026 static void SecPathBuilderDestroy(SecPathBuilderRef builder) {
1027 secdebug("alloc", "%p", builder);
1028 dispatch_release_null(builder->queue);
1029 if (builder->anchorSource) {
1030 SecMemoryCertificateSourceDestroy(builder->anchorSource); }
1031 if (builder->certificateSource) {
1032 SecMemoryCertificateSourceDestroy(builder->certificateSource); }
1033 if (builder->itemCertificateSource) {
1034 SecItemCertificateSourceDestroy(builder->itemCertificateSource); }
1035 if (builder->appleAnchorSource) {
1036 SecMemoryCertificateSourceDestroy(builder->appleAnchorSource); }
1037 CFReleaseSafe(builder->clientAuditToken);
1038 CFReleaseSafe(builder->anchorSources);
1039 CFReleaseSafe(builder->parentSources);
1040 CFReleaseSafe(builder->allPaths);
1041 CFReleaseSafe(builder->partialPaths);
1042 CFReleaseSafe(builder->rejectedPaths);
1043 CFReleaseSafe(builder->candidatePaths);
1044 CFReleaseSafe(builder->leafDetails);
1045 CFReleaseSafe(builder->ocspResponses);
1046 CFReleaseSafe(builder->signedCertificateTimestamps);
1047 CFReleaseSafe(builder->trustedLogs);
1048
1049 SecPVCDelete(&builder->path);
1050 }
1051
1052 bool SecPathBuilderCanAccessNetwork(SecPathBuilderRef builder) {
1053 return builder->canAccessNetwork;
1054 }
1055
1056 void SecPathBuilderSetCanAccessNetwork(SecPathBuilderRef builder, bool allow) {
1057 if (builder->canAccessNetwork != allow) {
1058 builder->canAccessNetwork = allow;
1059 if (allow) {
1060 #if !TARGET_OS_WATCH
1061 secinfo("http", "network access re-enabled by policy");
1062 /* re-enabling network_access re-adds kSecCAIssuerSource as
1063 a parent source. */
1064 CFArrayAppendValue(builder->parentSources, &kSecCAIssuerSource);
1065 #else
1066 secnotice("http", "network access not allowed on WatchOS");
1067 builder->canAccessNetwork = false;
1068 #endif
1069 } else {
1070 secinfo("http", "network access disabled by policy");
1071 /* disabling network_access removes kSecCAIssuerSource from
1072 the list of parent sources. */
1073 CFIndex ix = CFArrayGetFirstIndexOfValue(builder->parentSources,
1074 CFRangeMake(0, CFArrayGetCount(builder->parentSources)),
1075 &kSecCAIssuerSource);
1076 if (ix >= 0)
1077 CFArrayRemoveValueAtIndex(builder->parentSources, ix);
1078 }
1079 }
1080 }
1081
1082 CFArrayRef SecPathBuilderCopyOCSPResponses(SecPathBuilderRef builder)
1083 {
1084 return CFRetainSafe(builder->ocspResponses);
1085 }
1086
1087 CFArrayRef SecPathBuilderCopySignedCertificateTimestamps(SecPathBuilderRef builder)
1088 {
1089 return CFRetainSafe(builder->signedCertificateTimestamps);
1090 }
1091
1092 CFArrayRef SecPathBuilderCopyTrustedLogs(SecPathBuilderRef builder)
1093 {
1094 return CFRetainSafe(builder->trustedLogs);
1095 }
1096
1097 /* This function assumes that the input source is an anchor source */
1098 static bool SecPathBuilderIsAnchorPerConstraints(SecPathBuilderRef builder, SecCertificateSourceRef source,
1099 SecCertificateRef certificate) {
1100 bool result = false;
1101 CFArrayRef constraints = NULL;
1102 constraints = SecCertificateSourceCopyUsageConstraints(source, certificate);
1103
1104 /* Unrestricted certificates:
1105 * -those that come from anchor sources with no constraints
1106 * -self-signed certificates with empty contraints arrays
1107 */
1108 Boolean selfSigned = false;
1109 require(errSecSuccess == SecCertificateIsSelfSigned(certificate, &selfSigned), out);
1110 if ((NULL == source->copyUsageConstraints) ||
1111 (constraints && (CFArrayGetCount(constraints) == 0) && selfSigned)) {
1112 secinfo("trust", "unrestricted anchor%s",
1113 (NULL == source->copyUsageConstraints) ? " source" : "");
1114 result = true;
1115 goto out;
1116 }
1117
1118 /* Get the trust settings result for the PVC */
1119 require(constraints, out);
1120 SecTrustSettingsResult settingsResult = kSecTrustSettingsResultInvalid;
1121 settingsResult = SecPVCGetTrustSettingsResult(&builder->path,
1122 certificate,
1123 constraints);
1124 if ((selfSigned && settingsResult == kSecTrustSettingsResultTrustRoot) ||
1125 (!selfSigned && settingsResult == kSecTrustSettingsResultTrustAsRoot)) {
1126 // For our purposes, this is an anchor.
1127 secinfo("trust", "complex trust settings anchor");
1128 result = true;
1129 }
1130
1131 if (settingsResult == kSecTrustSettingsResultDeny) {
1132 /* We consider denied certs "anchors" because the trust decision
1133 is set regardless of building the chain further. The policy
1134 validation will handle rejecting this chain. */
1135 secinfo("trust", "complex trust settings denied anchor");
1136 result = true;
1137 }
1138
1139 out:
1140 CFReleaseNull(constraints);
1141 return result;
1142 }
1143
1144 /* Source returned in foundInSource has the same lifetime as the builder. */
1145 static bool SecPathBuilderIsAnchor(SecPathBuilderRef builder,
1146 SecCertificateRef certificate, SecCertificateSourceRef *foundInSource) {
1147 /* We look through the anchor sources in order. They are ordered in
1148 SecPathBuilderInit so that process anchors override user anchors which
1149 override system anchors. */
1150 CFIndex count = CFArrayGetCount(builder->anchorSources);
1151 CFIndex ix;
1152 for (ix = 0; ix < count; ++ix) {
1153 SecCertificateSourceRef source = (SecCertificateSourceRef)
1154 CFArrayGetValueAtIndex(builder->anchorSources, ix);
1155 if (SecCertificateSourceContains(source, certificate)) {
1156 if (foundInSource)
1157 *foundInSource = source;
1158 if (SecPathBuilderIsAnchorPerConstraints(builder, source, certificate)) {
1159 return true;
1160 }
1161 }
1162 }
1163 return false;
1164 }
1165
1166 /* Return false if path is not a partial, if path was a valid candidate it
1167 will have been added to builder->candidatePaths, if path was rejected
1168 by the parent certificate checks (because it's expired or some other
1169 static chaining check failed) it will have been added to rejectedPaths.
1170 Return true path if path is a partial. */
1171 static bool SecPathBuilderIsPartial(SecPathBuilderRef builder,
1172 SecCertificatePathRef path) {
1173 SecPVCRef pvc = &builder->path;
1174 SecPVCSetPath(pvc, path, NULL);
1175
1176 if (!builder->considerRejected && !SecPVCParentCertificateChecks(pvc,
1177 SecPVCGetCertificateCount(pvc) - 1)) {
1178 secdebug("trust", "Found rejected path %@", path);
1179 CFArrayAppendValue(builder->rejectedPaths, path);
1180 return false;
1181 }
1182
1183 SecPathVerifyStatus vstatus = SecCertificatePathVerify(path);
1184 /* Candidate paths with failed signatures are discarded. */
1185 if (vstatus == kSecPathVerifyFailed) {
1186 secdebug("trust", "Verify failed for path %@", path);
1187 return false;
1188 }
1189
1190 if (vstatus == kSecPathVerifySuccess) {
1191 /* The signature chain verified sucessfully, now let's find
1192 out if we have an anchor for path. */
1193 if (SecCertificatePathIsAnchored(path)) {
1194 secdebug("trust", "Adding candidate %@", path);
1195 CFArrayAppendValue(builder->candidatePaths, path);
1196 }
1197 /* The path is not partial if the last cert is self-signed. */
1198 if ((SecCertificatePathSelfSignedIndex(path) >= 0) &&
1199 (SecCertificatePathSelfSignedIndex(path) == SecCertificatePathGetCount(path)-1)) {
1200 return false;
1201 }
1202 }
1203
1204 return true;
1205 }
1206
1207 /* Given the builder, a partial chain partial and the parents array, construct
1208 a SecCertificatePath for each parent. After discarding previously
1209 considered paths and paths with cycles, sort out which array each path
1210 should go in, if any. */
1211 static void SecPathBuilderProcessParents(SecPathBuilderRef builder,
1212 SecCertificatePathRef partial, CFArrayRef parents) {
1213 CFIndex rootIX = SecCertificatePathGetCount(partial) - 1;
1214 CFIndex num_parents = parents ? CFArrayGetCount(parents) : 0;
1215 CFIndex parentIX;
1216 for (parentIX = 0; parentIX < num_parents; ++parentIX) {
1217 SecCertificateRef parent = (SecCertificateRef)
1218 CFArrayGetValueAtIndex(parents, parentIX);
1219 CFIndex ixOfParent = SecCertificatePathGetIndexOfCertificate(partial,
1220 parent);
1221 if (ixOfParent != kCFNotFound) {
1222 /* partial already contains parent. Let's not add the same
1223 certificate again. */
1224 if (ixOfParent == rootIX) {
1225 /* parent is equal to the root of the partial, so partial
1226 looks to be self issued. */
1227 SecCertificatePathSetSelfIssued(partial);
1228 }
1229 continue;
1230 }
1231
1232 /* FIXME Add more sanity checks to see that parent really can be
1233 a parent of partial_root. subjectKeyID == authorityKeyID,
1234 signature algorithm matches public key algorithm, etc. */
1235 SecCertificateSourceRef source = NULL;
1236 bool is_anchor = SecPathBuilderIsAnchor(builder, parent, &source);
1237 CFArrayRef constraints = (source) ? SecCertificateSourceCopyUsageConstraints(source, parent) : NULL;
1238 SecCertificatePathRef path = SecCertificatePathCreate(partial, parent, constraints);
1239 CFReleaseSafe(constraints);
1240 if (!path)
1241 continue;
1242 if (!CFSetContainsValue(builder->allPaths, path)) {
1243 CFSetAddValue(builder->allPaths, path);
1244 if (is_anchor)
1245 SecCertificatePathSetIsAnchored(path);
1246 if (SecPathBuilderIsPartial(builder, path)) {
1247 /* Insert path right at the current position since it's a new
1248 candiate partial. */
1249 CFArrayInsertValueAtIndex(builder->partialPaths,
1250 ++builder->partialIX, path);
1251 secdebug("trust", "Adding partial for parent %" PRIdCFIndex "/%" PRIdCFIndex " %@",
1252 parentIX + 1, num_parents, path);
1253 }
1254 secdebug("trust", "found new path %@", path);
1255 }
1256 CFRelease(path);
1257 }
1258 }
1259
1260 /* Callback for the SecPathBuilderGetNext() functions call to
1261 SecCertificateSourceCopyParents(). */
1262 static void SecPathBuilderExtendPaths(void *context, CFArrayRef parents) {
1263 SecPathBuilderRef builder = (SecPathBuilderRef)context;
1264 SecCertificatePathRef partial = (SecCertificatePathRef)
1265 CFArrayGetValueAtIndex(builder->partialPaths, builder->partialIX);
1266 secdebug("async", "%@ parents %@", partial, parents);
1267 SecPathBuilderProcessParents(builder, partial, parents);
1268
1269 builder->state = SecPathBuilderGetNext;
1270 SecPathBuilderStep(builder);
1271 }
1272
1273 static bool SecPathBuilderGetNext(SecPathBuilderRef builder) {
1274 /* If we have any candidates left to go return those first. */
1275 if (CFArrayGetCount(builder->candidatePaths)) {
1276 SecCertificatePathRef path = (SecCertificatePathRef)
1277 CFArrayGetValueAtIndex(builder->candidatePaths, 0);
1278 CFArrayRemoveValueAtIndex(builder->candidatePaths, 0);
1279 secdebug("trust", "SecPathBuilderGetNext returning candidate %@",
1280 path);
1281 SecPVCSetPath(&builder->path, path, NULL);
1282 builder->state = SecPathBuilderValidatePath;
1283 return true;
1284 }
1285
1286 /* If we are considering rejected chains we check each rejected path
1287 with SecPathBuilderIsPartial() which checks the signature chain and
1288 either drops the path if it's not properly signed, add it as a
1289 candidate if it has a trusted anchor, or adds it as a partial
1290 to be considered once we finish considering all the rejects. */
1291 if (builder->considerRejected) {
1292 CFIndex rejectedIX = CFArrayGetCount(builder->rejectedPaths);
1293 if (rejectedIX) {
1294 rejectedIX--;
1295 SecCertificatePathRef path = (SecCertificatePathRef)
1296 CFArrayGetValueAtIndex(builder->rejectedPaths, rejectedIX);
1297 if (SecPathBuilderIsPartial(builder, path)) {
1298 CFArrayInsertValueAtIndex(builder->partialPaths,
1299 ++builder->partialIX, path);
1300 }
1301 CFArrayRemoveValueAtIndex(builder->rejectedPaths, rejectedIX);
1302
1303 /* Keep going until we have moved all rejected partials into
1304 the regular partials or candidates array. */
1305 return true;
1306 }
1307 }
1308
1309 /* If builder->partialIX is < 0 we have considered all partial chains
1310 this block must ensure partialIX >= 0 if execution continues past
1311 it's end. */
1312 if (builder->partialIX < 0) {
1313 CFIndex num_sources = CFArrayGetCount(builder->parentSources);
1314 if (builder->nextParentSource < num_sources) {
1315 builder->nextParentSource++;
1316 secdebug("trust", "broading search to %" PRIdCFIndex "/%" PRIdCFIndex " sources",
1317 builder->nextParentSource, num_sources);
1318 } else {
1319 /* We've run out of new sources to consider so let's look at
1320 rejected chains and after that even consider partials
1321 directly.
1322 FIXME we might not want to consider partial paths that
1323 are subsets of other partial paths, or not consider them
1324 at all if we already have an anchored reject. */
1325 if (!builder->considerRejected) {
1326 builder->considerRejected = true;
1327 secdebug("trust", "considering rejected paths");
1328 } else if (!builder->considerPartials) {
1329 builder->considerPartials = true;
1330 secdebug("trust", "considering partials");
1331 } else {
1332 /* We're all out of options, so we can't produce any more
1333 candidates. Let's calculate details and return the best
1334 path we found. */
1335 builder->state = SecPathBuilderComputeDetails;
1336 return true;
1337 }
1338 }
1339 builder->partialIX = CFArrayGetCount(builder->partialPaths) - 1;
1340 secdebug("trust", "re-checking %" PRIdCFIndex " partials", builder->partialIX + 1);
1341 return true;
1342 }
1343
1344 /* We know builder->partialIX >= 0 if we get here. */
1345 SecCertificatePathRef partial = (SecCertificatePathRef)
1346 CFArrayGetValueAtIndex(builder->partialPaths, builder->partialIX);
1347 /* Don't try to extend partials anymore once we are in the considerPartials
1348 state, since at this point every partial has been extended with every
1349 possible parentSource already. */
1350 if (builder->considerPartials) {
1351 --builder->partialIX;
1352 SecPVCSetPath(&builder->path, partial, NULL);
1353 builder->state = SecPathBuilderValidatePath;
1354 return true;
1355 }
1356
1357 /* Attempt to extend this partial path with another certificate. This
1358 should give us a list of potential parents to consider. */
1359 secdebug("trust", "looking for parents of partial %" PRIdCFIndex "/%" PRIdCFIndex ": %@",
1360 builder->partialIX + 1, CFArrayGetCount(builder->partialPaths),
1361 partial);
1362
1363 /* Attempt to extend partial, leaving all possible extended versions
1364 of partial in builder->extendedPaths. */
1365 CFIndex sourceIX = SecCertificatePathGetNextSourceIndex(partial);
1366 CFIndex num_anchor_sources = CFArrayGetCount(builder->anchorSources);
1367 if (sourceIX < num_anchor_sources + builder->nextParentSource) {
1368 SecCertificateSourceRef source;
1369 if (sourceIX < num_anchor_sources) {
1370 source = (SecCertificateSourceRef)
1371 CFArrayGetValueAtIndex(builder->anchorSources, sourceIX);
1372 secdebug("trust", "searching anchor source %" PRIdCFIndex "/%" PRIdCFIndex, sourceIX + 1,
1373 num_anchor_sources);
1374 } else {
1375 CFIndex parentIX = sourceIX - num_anchor_sources;
1376 source = (SecCertificateSourceRef)
1377 CFArrayGetValueAtIndex(builder->parentSources, parentIX);
1378 secdebug("trust", "searching parent source %" PRIdCFIndex "/%" PRIdCFIndex, parentIX + 1,
1379 builder->nextParentSource);
1380 }
1381 SecCertificatePathSetNextSourceIndex(partial, sourceIX + 1);
1382 SecCertificateRef root = SecCertificatePathGetRoot(partial);
1383 return SecCertificateSourceCopyParents(source, root,
1384 builder, SecPathBuilderExtendPaths);
1385 } else {
1386 --builder->partialIX;
1387 }
1388
1389 return true;
1390 }
1391
1392 /* One or more of the policies did not accept the candidate path. */
1393 static void SecPathBuilderReject(SecPathBuilderRef builder) {
1394 check(builder);
1395 SecPVCRef pvc = &builder->path;
1396
1397 builder->state = SecPathBuilderGetNext;
1398
1399 if (builder->bestPathIsEV && !pvc->is_ev) {
1400 /* We never replace an ev reject with a non ev reject. */
1401 return;
1402 }
1403
1404 CFIndex bestPathScore = builder->bestPathScore;
1405 CFIndex score = SecCertificatePathScore(builder->path.path,
1406 SecPVCGetVerifyTime(&builder->path));
1407
1408 /* The current chain is valid for EV, but revocation checking failed. We
1409 replace any previously accepted or rejected non EV chains with the
1410 current one. */
1411 if (pvc->is_ev && !builder->bestPathIsEV) {
1412 bestPathScore = 0;
1413 }
1414
1415 #if 0
1416 if (pvc->is_ev) {
1417 /* Since this means we found a valid ev chain that was revoked,
1418 we might want to switch directly to the
1419 SecPathBuilderComputeDetails state here if we think further
1420 searching for new chains is pointless. For now we'll keep
1421 going, since we could accept an alternate EV certification
1422 path that isn't revoked. */
1423 builder->state = SecPathBuilderComputeDetails;
1424 }
1425 #endif
1426
1427 /* Do this last so that changes to bestPathScore above will take effect. */
1428 if (!builder->bestPath || score > bestPathScore) {
1429 if (builder->bestPath) {
1430 secinfo("reject",
1431 "replacing %sev %s score: %ld with %sev score: %" PRIdCFIndex " %@",
1432 (builder->bestPathIsEV ? "" : "non "),
1433 (builder->bestPathScore > ACCEPT_PATH_SCORE ? "accept" : "reject"),
1434 builder->bestPathScore,
1435 (pvc->is_ev ? "" : "non "), (long)score, builder->path.path);
1436 } else {
1437 secinfo("reject", "%sev score: %" PRIdCFIndex " %@",
1438 (pvc->is_ev ? "" : "non "), score, builder->path.path);
1439 }
1440
1441 builder->bestPathScore = score;
1442 builder->bestPath = pvc->path;
1443 builder->bestPathIsEV = pvc->is_ev;
1444 builder->denyBestPath = SecPVCCheckUsageConstraints(pvc);
1445 } else {
1446 secinfo("reject", "%sev score: %" PRIdCFIndex " lower than %" PRIdCFIndex " %@",
1447 (pvc->is_ev ? "" : "non "), score, bestPathScore, builder->path.path);
1448 }
1449 }
1450
1451 /* All policies accepted the candidate path. */
1452 static void SecPathBuilderAccept(SecPathBuilderRef builder) {
1453 check(builder);
1454 SecPVCRef pvc = &builder->path;
1455 bool isSHA2 = !SecCertificatePathHasWeakHash(pvc->path);
1456 bool isOptionallySHA2 = !SecCertificateIsWeakHash(SecPVCGetCertificateAtIndex(pvc, 0));
1457 CFIndex bestScore = builder->bestPathScore;
1458 /* Score this path. Note that all points awarded or deducted in
1459 * SecCertificatePathScore are < 100,000 */
1460 CFIndex currScore = (SecCertificatePathScore(pvc->path, pvc->verifyTime) +
1461 ACCEPT_PATH_SCORE + // 10,000,000 points for accepting
1462 ((pvc->is_ev) ? 1000000 : 0)); //1,000,000 points for EV
1463 if (currScore > bestScore) {
1464 // current path is better than existing best path
1465 secinfo("accept", "replacing %sev %s score: %ld with %sev score: %" PRIdCFIndex " %@",
1466 (builder->bestPathIsEV ? "" : "non "),
1467 (builder->bestPathScore > ACCEPT_PATH_SCORE ? "accept" : "reject"),
1468 builder->bestPathScore,
1469 (pvc->is_ev ? "" : "non "), (long)currScore, builder->path.path);
1470
1471 builder->bestPathScore = currScore;
1472 builder->bestPathIsEV = pvc->is_ev;
1473 builder->bestPathIsSHA2 = isSHA2;
1474 builder->bestPath = pvc->path;
1475 builder->denyBestPath = SecPVCCheckUsageConstraints(pvc); /* should always be false */
1476 }
1477
1478 /* If we found the best accept we can, we want to switch directly to the
1479 SecPathBuilderComputeDetails state here, since we're done. */
1480 if ((pvc->is_ev || !pvc->optionally_ev) && (isSHA2 || !isOptionallySHA2))
1481 builder->state = SecPathBuilderComputeDetails;
1482 else
1483 builder->state = SecPathBuilderGetNext;
1484 }
1485
1486 /* Return true iff a given path satisfies all the specified policies at
1487 verifyTime. */
1488 static bool SecPathBuilderValidatePath(SecPathBuilderRef builder) {
1489 SecPVCRef pvc = &builder->path;
1490
1491 if (builder->considerRejected) {
1492 SecPathBuilderReject(builder);
1493 return true;
1494 }
1495
1496 builder->state = SecPathBuilderDidValidatePath;
1497 return SecPVCPathChecks(pvc);
1498 }
1499
1500 static bool SecPathBuilderDidValidatePath(SecPathBuilderRef builder) {
1501 SecPVCRef pvc = &builder->path;
1502 if (pvc->result) {
1503 SecPathBuilderAccept(builder);
1504 } else {
1505 SecPathBuilderReject(builder);
1506 }
1507 assert(builder->state != SecPathBuilderDidValidatePath);
1508 return true;
1509 }
1510
1511 static bool SecPathBuilderComputeDetails(SecPathBuilderRef builder) {
1512 // foobar
1513 SecPVCRef pvc = &builder->path;
1514 #if 0
1515 if (!builder->caller_wants_details) {
1516 SecPVCSetPath(pvc, builder->bestPath, NULL);
1517 pvc->result = builder->bestPathScore > ACCEPT_PATH_SCORE;
1518 builder->state = SecPathBuilderReportResult;
1519 return true;
1520 }
1521 #endif
1522 CFIndex ix, pathLength = SecCertificatePathGetCount(builder->bestPath);
1523 CFMutableArrayRef details = CFArrayCreateMutableCopy(kCFAllocatorDefault,
1524 pathLength, builder->leafDetails);
1525 CFRetainSafe(details);
1526 SecPVCSetPath(pvc, builder->bestPath, details);
1527 /* Only report on EV stuff if the bestPath actually was valid for EV. */
1528 pvc->optionally_ev = builder->bestPathIsEV;
1529 pvc->info = CFDictionaryCreateMutable(kCFAllocatorDefault,
1530 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
1531 for (ix = 1; ix < pathLength; ++ix) {
1532 CFMutableDictionaryRef certDetail = CFDictionaryCreateMutable(
1533 kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks,
1534 &kCFTypeDictionaryValueCallBacks);
1535 CFArrayAppendValue(details, certDetail);
1536 CFRelease(certDetail);
1537 SecPVCParentCertificateChecks(pvc, ix);
1538 SecPVCGrayListedKeyChecks(pvc, ix);
1539 SecPVCBlackListedKeyChecks(pvc, ix);
1540 }
1541 builder->state = SecPathBuilderReportResult;
1542 bool completed = SecPVCPathChecks(pvc);
1543
1544 /* Reject the certificate if it was accepted before but we failed it now. */
1545 if (builder->bestPathScore > ACCEPT_PATH_SCORE && !pvc->result) {
1546 builder->bestPathScore = 0;
1547 }
1548
1549 /* Accept a partial path if certificate is on the allow list
1550 and is temporally valid and passed all PVC checks. */
1551 if (completed && pvc->is_allowlisted && pvc->result &&
1552 builder->bestPathScore < ACCEPT_PATH_SCORE &&
1553 SecCertificatePathIsValid(pvc->path, pvc->verifyTime)) {
1554 builder->bestPathScore += ACCEPT_PATH_SCORE;
1555 }
1556
1557 CFReleaseSafe(details);
1558
1559 return completed;
1560 }
1561
1562
1563 static bool SecPathBuilderReportResult(SecPathBuilderRef builder) {
1564 SecPVCRef pvc = &builder->path;
1565 bool haveRevocationResponse = false;
1566 if (pvc->info && pvc->is_ev && pvc->result) {
1567 CFDictionarySetValue(pvc->info, kSecTrustInfoExtendedValidationKey,
1568 kCFBooleanTrue); /* iOS key */
1569 CFDictionarySetValue(pvc->info, kSecTrustExtendedValidation,
1570 kCFBooleanTrue); /* unified API key */
1571 SecCertificateRef leaf = SecPVCGetCertificateAtIndex(pvc, 0);
1572 CFStringRef leafCompanyName = SecCertificateCopyCompanyName(leaf);
1573 if (leafCompanyName) {
1574 CFDictionarySetValue(pvc->info, kSecTrustInfoCompanyNameKey,
1575 leafCompanyName); /* iOS key */
1576 CFDictionarySetValue(pvc->info, kSecTrustOrganizationName,
1577 leafCompanyName); /* unified API key */
1578 CFRelease(leafCompanyName);
1579 }
1580 if (pvc->rvcs) {
1581 CFAbsoluteTime nextUpdate = SecPVCGetEarliestNextUpdate(pvc);
1582 if (nextUpdate == 0) {
1583 /* populate revocation info for failed revocation check */
1584 CFDictionarySetValue(pvc->info, kSecTrustInfoRevocationKey,
1585 kCFBooleanFalse); /* iOS key */
1586 CFDictionarySetValue(pvc->info, kSecTrustRevocationChecked,
1587 kCFBooleanFalse); /* unified API key */
1588 }
1589 }
1590 }
1591
1592 if (pvc->info && pvc->result && pvc->rvcs) {
1593 CFAbsoluteTime nextUpdate = SecPVCGetEarliestNextUpdate(pvc);
1594 if (nextUpdate != 0) {
1595 /* always populate revocation info for successful revocation check */
1596 haveRevocationResponse = true;
1597 CFDateRef validUntil = CFDateCreate(kCFAllocatorDefault, nextUpdate);
1598 CFDictionarySetValue(pvc->info, kSecTrustInfoRevocationValidUntilKey,
1599 validUntil); /* iOS key */
1600 CFDictionarySetValue(pvc->info, kSecTrustRevocationValidUntilDate,
1601 validUntil); /* unified API key */
1602 CFRelease(validUntil);
1603 CFDictionarySetValue(pvc->info, kSecTrustInfoRevocationKey,
1604 kCFBooleanTrue); /* iOS key */
1605 CFDictionarySetValue(pvc->info, kSecTrustRevocationChecked,
1606 kCFBooleanTrue); /* unified API key */
1607 }
1608 }
1609
1610 if (pvc->info && pvc->result && pvc->response_required && !haveRevocationResponse) {
1611 builder->bestPathScore = 0;
1612 SecPVCSetResultForced(pvc, kSecPolicyCheckRevocationResponseRequired,
1613 0, kCFBooleanFalse, true);
1614 }
1615
1616 if (pvc->info && pvc->is_ct && pvc->result) {
1617 CFDictionarySetValue(pvc->info, kSecTrustInfoCertificateTransparencyKey,
1618 kCFBooleanTrue);
1619 }
1620
1621 if (pvc->info && pvc->is_ct_whitelisted && pvc->result) {
1622 CFDictionarySetValue(pvc->info, kSecTrustInfoCertificateTransparencyWhiteListKey,
1623 kCFBooleanTrue);
1624 }
1625
1626
1627 /* This will trigger the outer step function to call the completion
1628 function. */
1629 builder->state = NULL;
1630 return false;
1631 }
1632
1633 /* @function SecPathBuilderStep
1634 @summary This is the core of the async engine.
1635 @description Return false iff job is complete, true if a network request
1636 is pending.
1637 builder->state is a function pointer which is to be invoked.
1638 If you call this function from within a builder->state invocation it
1639 immediately returns true.
1640 Otherwise the following steps are repeated endlessly (unless a step returns)
1641 builder->state is invoked. If it returns true and builder->state is still
1642 non NULL this proccess is repeated.
1643 If a state returns false, SecPathBuilder will return true
1644 if builder->state is non NULL.
1645 If builder->state is NULL then regardless of what the state function returns
1646 the completion callback will be invoked and the builder will be deallocated.
1647 */
1648 bool SecPathBuilderStep(SecPathBuilderRef builder) {
1649 if (builder->activations) {
1650 secdebug("async", "activations: %lu returning true",
1651 builder->activations);
1652 return true;
1653 }
1654
1655 secdebug("async", "activations: %lu", builder->activations);
1656 builder->activations++;
1657 while (builder->state && builder->state(builder));
1658 --builder->activations;
1659
1660 if (builder->state) {
1661 secdebug("async", "waiting for async reply, exiting");
1662 /* A state returned false, it's waiting for network traffic. Let's
1663 return. */
1664 return true;
1665 }
1666
1667 if (builder->activations) {
1668 /* There is still at least one other running instance of this builder
1669 somewhere on the stack, we let that instance take care of sending
1670 the client a response. */
1671 return false;
1672 }
1673
1674 SecTrustResultType result = kSecTrustResultInvalid;
1675 if (builder->denyBestPath) {
1676 result = kSecTrustResultDeny;
1677 } else if (builder->bestPathScore > ACCEPT_PATH_SCORE) {
1678 result = kSecTrustResultUnspecified;
1679 } else {
1680 result = kSecTrustResultRecoverableTrustFailure;
1681 }
1682
1683 secinfo("trust", "completed: %@ details: %@ result: %d",
1684 builder->bestPath, builder->path.details, result);
1685
1686 if (builder->completed) {
1687 builder->completed(builder->context, builder->bestPath,
1688 builder->path.details, builder->path.info, result);
1689 }
1690
1691 /* Finally, destroy the builder and free it. */
1692 SecPathBuilderDestroy(builder);
1693 free(builder);
1694
1695 return false;
1696 }
1697
1698 dispatch_queue_t SecPathBuilderGetQueue(SecPathBuilderRef builder) {
1699 return (builder) ? builder->queue : NULL;
1700 }
1701
1702 CFDataRef SecPathBuilderCopyClientAuditToken(SecPathBuilderRef builder) {
1703 return (builder) ? (CFDataRef)CFRetainSafe(builder->clientAuditToken) : NULL;
1704 }
1705
1706 // MARK: -
1707 // MARK: SecTrustServer
1708 /********************************************************
1709 ****************** SecTrustServer **********************
1710 ********************************************************/
1711
1712 typedef void (^SecTrustServerEvaluationCompleted)(SecTrustResultType tr, CFArrayRef details, CFDictionaryRef info, SecCertificatePathRef chain, CFErrorRef error);
1713
1714 static void
1715 SecTrustServerEvaluateCompleted(const void *userData,
1716 SecCertificatePathRef chain, CFArrayRef details, CFDictionaryRef info,
1717 SecTrustResultType result) {
1718 SecTrustServerEvaluationCompleted evaluated = (SecTrustServerEvaluationCompleted)userData;
1719 evaluated(result, details, info, chain, NULL);
1720 Block_release(evaluated);
1721 }
1722
1723 void
1724 SecTrustServerEvaluateBlock(CFDataRef clientAuditToken, CFArrayRef certificates, CFArrayRef anchors, bool anchorsOnly, bool keychainsAllowed, CFArrayRef policies, CFArrayRef responses, CFArrayRef SCTs, CFArrayRef trustedLogs, CFAbsoluteTime verifyTime, __unused CFArrayRef accessGroups, void (^evaluated)(SecTrustResultType tr, CFArrayRef details, CFDictionaryRef info, SecCertificatePathRef chain, CFErrorRef error)) {
1725 SecTrustServerEvaluationCompleted userData = Block_copy(evaluated);
1726 /* Call the actual evaluator function. */
1727 SecPathBuilderRef builder = SecPathBuilderCreate(clientAuditToken,
1728 certificates, anchors,
1729 anchorsOnly, keychainsAllowed, policies,
1730 responses, SCTs, trustedLogs,
1731 verifyTime, accessGroups,
1732 SecTrustServerEvaluateCompleted, userData);
1733 dispatch_async(builder->queue, ^{ SecPathBuilderStep(builder); });
1734 }
1735
1736
1737 // NO_SERVER Shim code only, xpc interface should call SecTrustServerEvaluateBlock() directly
1738 SecTrustResultType SecTrustServerEvaluate(CFArrayRef certificates, CFArrayRef anchors, bool anchorsOnly, bool keychainsAllowed, CFArrayRef policies, CFArrayRef responses, CFArrayRef SCTs, CFArrayRef trustedLogs, CFAbsoluteTime verifyTime, __unused CFArrayRef accessGroups, CFArrayRef *pdetails, CFDictionaryRef *pinfo, SecCertificatePathRef *pchain, CFErrorRef *perror) {
1739 dispatch_semaphore_t done = dispatch_semaphore_create(0);
1740 __block SecTrustResultType result = kSecTrustResultInvalid;
1741 SecTrustServerEvaluateBlock(NULL, certificates, anchors, anchorsOnly, keychainsAllowed, policies, responses, SCTs, trustedLogs, verifyTime, accessGroups, ^(SecTrustResultType tr, CFArrayRef details, CFDictionaryRef info, SecCertificatePathRef chain, CFErrorRef error) {
1742 result = tr;
1743 if (tr == kSecTrustResultInvalid) {
1744 if (perror) {
1745 *perror = error;
1746 CFRetainSafe(error);
1747 }
1748 } else {
1749 if (pdetails) {
1750 *pdetails = details;
1751 CFRetainSafe(details);
1752 }
1753 if (pinfo) {
1754 *pinfo = info;
1755 CFRetainSafe(info);
1756 }
1757 if (pchain) {
1758 *pchain = chain;
1759 CFRetainSafe(chain);
1760 }
1761 }
1762 dispatch_semaphore_signal(done);
1763 });
1764 dispatch_semaphore_wait(done, DISPATCH_TIME_FOREVER);
1765
1766 return result;
1767 }