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