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