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