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