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