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