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
73static CFArrayRef subject_to_anchors(CFDataRef nic);
74static CFArrayRef CopyCertsFromIndices(CFArrayRef offsets);
75
76static 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
113static 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
161static 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. */
198static void SecPathBuilderExtendPaths(void *context, CFArrayRef parents);
199
200
201// MARK: -
202// MARK: SecCertificateSource
203/********************************************************
204 ************ SecCertificateSource object ***************
205 ********************************************************/
206
207typedef struct SecCertificateSource *SecCertificateSourceRef;
208typedef void(*SecCertificateSourceParents)(void *, CFArrayRef);
209typedef bool(*CopyParents)(SecCertificateSourceRef source,
210	SecCertificateRef certificate, void *context, SecCertificateSourceParents);
211typedef bool(*Contains)(SecCertificateSourceRef source,
212	SecCertificateRef certificate);
213
214struct SecCertificateSource {
215	CopyParents		copyParents;
216	Contains		contains;
217};
218
219static bool SecCertificateSourceCopyParents(SecCertificateSourceRef source,
220    SecCertificateRef certificate,
221    void *context, SecCertificateSourceParents callback) {
222    return source->copyParents(source, certificate, context, callback);
223}
224
225static 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 ********************************************************/
235struct SecItemCertificateSource {
236	struct SecCertificateSource base;
237	CFArrayRef accessGroups;
238};
239typedef struct SecItemCertificateSource *SecItemCertificateSourceRef;
240
241static 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
258static 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
297static 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
335static 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
344static 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
356static 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
375errOut:
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. */
385static 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
432errOut:
433	CFReleaseSafe(cert_datas);
434	CFReleaseSafe(otapkiref);
435#endif
436    return result;
437}
438
439
440
441struct SecCertificateSource kSecSystemAnchorSource = {
442	SecSystemAnchorSourceCopyParents,
443	SecSystemAnchorSourceContains
444};
445
446// MARK: -
447// MARK: SecUserAnchorSource
448/********************************************************
449 *********** SecUserAnchorSource object ************
450 ********************************************************/
451static 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
461static bool SecUserAnchorSourceContains(SecCertificateSourceRef source,
462	SecCertificateRef certificate) {
463    return SecTrustStoreContains(
464        SecTrustStoreForDomain(kSecTrustStoreDomainUser), certificate);
465}
466
467struct SecCertificateSource kSecUserAnchorSource = {
468	SecUserAnchorSourceCopyParents,
469	SecUserAnchorSourceContains
470};
471
472// MARK: -
473// MARK: SecMemoryCertificateSource
474/********************************************************
475 *********** SecMemoryCertificateSource object ************
476 ********************************************************/
477struct SecMemoryCertificateSource {
478	struct SecCertificateSource base;
479	CFMutableSetRef certificates;
480	CFMutableDictionaryRef subjects;
481};
482typedef struct SecMemoryCertificateSource *SecMemoryCertificateSourceRef;
483
484static 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
500static bool SecMemoryCertificateSourceContains(SecCertificateSourceRef source,
501	SecCertificateRef certificate) {
502	SecMemoryCertificateSourceRef msource =
503		(SecMemoryCertificateSourceRef)source;
504	return CFSetContainsValue(msource->certificates, certificate);
505}
506
507static 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
525static 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
540static 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
559static 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 ********************************************************/
573static bool SecCAIssuerCertificateSourceCopyParents(
574	SecCertificateSourceRef source, SecCertificateRef certificate,
575        void *context, SecCertificateSourceParents callback) {
576    return SecCAIssuerCopyParents(certificate, SecPathBuilderGetQueue((SecPathBuilderRef)context), context, callback);
577}
578
579static bool SecCAIssuerCertificateSourceContains(
580    SecCertificateSourceRef source, SecCertificateRef certificate) {
581	return false;
582}
583
584struct SecCertificateSource kSecCAIssuerSource = {
585	SecCAIssuerCertificateSourceCopyParents,
586	SecCAIssuerCertificateSourceContains
587};
588
589// MARK: -
590// MARK: SecPathBuilder
591/********************************************************
592 *************** SecPathBuilder object ******************
593 ********************************************************/
594struct 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. */
643static bool SecPathBuilderGetNext(SecPathBuilderRef builder);
644static bool SecPathBuilderValidatePath(SecPathBuilderRef builder);
645static bool SecPathBuilderDidValidatePath(SecPathBuilderRef builder);
646static bool SecPathBuilderComputeDetails(SecPathBuilderRef builder);
647static bool SecPathBuilderReportResult(SecPathBuilderRef builder);
648
649/* Forward declarations. */
650static 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. */
657static 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
670static 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
747SecPathBuilderRef 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
757static 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
777bool SecPathBuilderCanAccessNetwork(SecPathBuilderRef builder) {
778    return builder->canAccessNetwork;
779}
780
781void 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
802static 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. */
822static 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. */
858static 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(). */
909static 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
920static 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. */
1040static 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. */
1098static 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. */
1120static 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
1132static 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
1143static 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
1183static 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 */
1232bool 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
1276dispatch_queue_t SecPathBuilderGetQueue(SecPathBuilderRef builder) {
1277    return builder->queue;
1278}
1279
1280// MARK: -
1281// MARK: SecTrustServer
1282/********************************************************
1283 ****************** SecTrustServer **********************
1284 ********************************************************/
1285
1286typedef void (^SecTrustServerEvaluationCompleted)(SecTrustResultType tr, CFArrayRef details, CFDictionaryRef info, SecCertificatePathRef chain, CFErrorRef error);
1287
1288static void
1289SecTrustServerEvaluateCompleted(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
1297void
1298SecTrustServerEvaluateBlock(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
1310SecTrustResultType 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}
1340