2 * Copyright (c) 2006-2010 Apple Inc. All Rights Reserved.
4 * @APPLE_LICENSE_HEADER_START@
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
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.
21 * @APPLE_LICENSE_HEADER_END@
23 * SecTrustServer.c - certificate trust evaluation engine
25 * Created by Michael Brouwer on 12/12/08.
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>
35 #include <utilities/SecIOFormat.h>
36 #include <utilities/SecDispatchRelease.h>
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>
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"
66 /********************************************************
67 ***************** OTA Trust support ********************
68 ********************************************************/
71 #ifndef SECITEM_SHIM_OSX
73 static CFArrayRef
subject_to_anchors(CFDataRef nic
);
74 static CFArrayRef
CopyCertsFromIndices(CFArrayRef offsets
);
76 static CFArrayRef
subject_to_anchors(CFDataRef nic
)
78 CFArrayRef result
= NULL
;
85 SecOTAPKIRef otapkiref
= SecOTAPKICopyCurrentOTAPKIRef();
86 if (NULL
== otapkiref
)
91 CFDictionaryRef lookupTable
= SecOTAPKICopyAnchorLookupTable(otapkiref
);
94 if (NULL
== lookupTable
)
99 unsigned char subject_digest
[CC_SHA1_DIGEST_LENGTH
];
100 memset(subject_digest
, 0, CC_SHA1_DIGEST_LENGTH
);
102 (void)CC_SHA1(CFDataGetBytePtr(nic
), (CC_LONG
)CFDataGetLength(nic
), subject_digest
);
103 CFDataRef sha1Digest
= CFDataCreateWithBytesNoCopy(kCFAllocatorDefault
, subject_digest
, CC_SHA1_DIGEST_LENGTH
, kCFAllocatorNull
);
106 result
= (CFArrayRef
)CFDictionaryGetValue(lookupTable
, sha1Digest
);
107 CFReleaseSafe(lookupTable
);
108 CFReleaseSafe(sha1Digest
);
113 static CFArrayRef
CopyCertDataFromIndices(CFArrayRef offsets
)
115 CFMutableArrayRef result
= NULL
;
117 SecOTAPKIRef otapkiref
= SecOTAPKICopyCurrentOTAPKIRef();
118 if (NULL
== otapkiref
)
123 const char* anchorTable
= SecOTAPKIGetAnchorTable(otapkiref
);
124 if (NULL
== anchorTable
)
126 CFReleaseSafe(otapkiref
);
130 CFIndex num_offsets
= CFArrayGetCount(offsets
);
132 result
= CFArrayCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeArrayCallBacks
);
134 for (CFIndex idx
= 0; idx
< num_offsets
; idx
++)
136 CFNumberRef offset
= (CFNumberRef
)CFArrayGetValueAtIndex(offsets
, idx
);
137 uint32_t offset_value
= 0;
138 if (CFNumberGetValue(offset
, kCFNumberSInt32Type
, &offset_value
))
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);
145 int32_t cert_data_length
= *((int32_t * )pDataPtr
);
146 pDataPtr
+= sizeof(uint32_t);
148 CFDataRef cert_data
= CFDataCreateWithBytesNoCopy(kCFAllocatorDefault
, (const UInt8
*)pDataPtr
,
149 cert_data_length
, kCFAllocatorNull
);
150 if (NULL
!= cert_data
)
152 CFArrayAppendValue(result
, cert_data
);
153 CFReleaseSafe(cert_data
);
157 CFReleaseSafe(otapkiref
);
161 static CFArrayRef
CopyCertsFromIndices(CFArrayRef offsets
)
163 CFMutableArrayRef result
= NULL
;
165 CFArrayRef cert_data_array
= CopyCertDataFromIndices(offsets
);
167 if (NULL
!= cert_data_array
)
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
++)
173 CFDataRef cert_data
= (CFDataRef
)CFArrayGetValueAtIndex(cert_data_array
, idx
);
174 if (NULL
!= cert_data
)
176 SecCertificateRef cert
= SecCertificateCreateWithData(kCFAllocatorDefault
, cert_data
);
179 CFArrayAppendValue(result
, cert
);
184 CFRelease(cert_data_array
);
191 /********************************************************
192 *************** END OTA Trust support ******************
193 ********************************************************/
195 #define MAX_CHAIN_LENGTH 15
197 /* Forward declaration for use in SecCertificateSource. */
198 static void SecPathBuilderExtendPaths(void *context
, CFArrayRef parents
);
202 // MARK: SecCertificateSource
203 /********************************************************
204 ************ SecCertificateSource object ***************
205 ********************************************************/
207 typedef struct SecCertificateSource
*SecCertificateSourceRef
;
208 typedef void(*SecCertificateSourceParents
)(void *, CFArrayRef
);
209 typedef bool(*CopyParents
)(SecCertificateSourceRef source
,
210 SecCertificateRef certificate
, void *context
, SecCertificateSourceParents
);
211 typedef bool(*Contains
)(SecCertificateSourceRef source
,
212 SecCertificateRef certificate
);
214 struct SecCertificateSource
{
215 CopyParents copyParents
;
219 static bool SecCertificateSourceCopyParents(SecCertificateSourceRef source
,
220 SecCertificateRef certificate
,
221 void *context
, SecCertificateSourceParents callback
) {
222 return source
->copyParents(source
, certificate
, context
, callback
);
225 static bool SecCertificateSourceContains(SecCertificateSourceRef source
,
226 SecCertificateRef certificate
) {
227 return source
->contains(source
, certificate
);
231 // MARK: SecItemCertificateSource
232 /********************************************************
233 *********** SecItemCertificateSource object ************
234 ********************************************************/
235 struct SecItemCertificateSource
{
236 struct SecCertificateSource base
;
237 CFArrayRef accessGroups
;
239 typedef struct SecItemCertificateSource
*SecItemCertificateSourceRef
;
241 static CFTypeRef
SecItemCertificateSourceResultsPost(CFTypeRef raw_results
) {
242 if (isArray(raw_results
)) {
243 CFMutableArrayRef result
= CFArrayCreateMutable(kCFAllocatorDefault
, CFArrayGetCount(raw_results
), &kCFTypeArrayCallBacks
);
244 CFArrayForEach(raw_results
, ^(const void *value
) {
245 SecCertificateRef cert
= SecCertificateCreateWithData(kCFAllocatorDefault
, value
);
247 CFArrayAppendValue(result
, cert
);
252 } else if (isData(raw_results
)) {
253 return SecCertificateCreateWithData(kCFAllocatorDefault
, (CFDataRef
)raw_results
);
258 static bool SecItemCertificateSourceCopyParents(
259 SecCertificateSourceRef source
, SecCertificateRef certificate
,
260 void *context
, SecCertificateSourceParents callback
) {
261 SecItemCertificateSourceRef msource
= (SecItemCertificateSourceRef
)source
;
262 /* FIXME: Search for things other than just subject of our issuer if we
263 have a subjectID or authorityKeyIdentifier. */
264 CFDataRef normalizedIssuer
=
265 SecCertificateGetNormalizedIssuerContent(certificate
);
266 const void *keys
[] = {
273 kSecClassCertificate
,
278 CFDictionaryRef query
= CFDictionaryCreate(NULL
, keys
, values
, 4,
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
);
287 CFRelease(localError
);
290 CFTypeRef certs
= SecItemCertificateSourceResultsPost(results
);
291 CFReleaseSafe(results
);
292 callback(context
, certs
);
293 CFReleaseSafe(certs
);
297 static bool SecItemCertificateSourceContains(SecCertificateSourceRef source
,
298 SecCertificateRef certificate
) {
299 SecItemCertificateSourceRef msource
= (SecItemCertificateSourceRef
)source
;
300 /* Lookup a certificate by issuer and serial number. */
301 CFDataRef normalizedSubject
=
302 SecCertificateGetNormalizedSubjectContent(certificate
);
303 CFDataRef serialNumber
=
304 SecCertificateCopySerialNumber(certificate
);
305 const void *keys
[] = {
312 kSecClassCertificate
,
317 CFDictionaryRef query
= CFDictionaryCreate(NULL
, keys
, values
, 5,
319 CFErrorRef localError
= NULL
;
320 CFTypeRef results
= NULL
;
321 bool ok
= _SecItemCopyMatching(query
, msource
->accessGroups
, &results
, &localError
);
323 CFRelease(serialNumber
);
324 CFReleaseSafe(results
);
326 if (CFErrorGetCode(localError
) != errSecItemNotFound
) {
327 secdebug("trust", "_SecItemCopyMatching: %@", localError
);
329 CFRelease(localError
);
335 static SecCertificateSourceRef
SecItemCertificateSourceCreate(CFArrayRef accessGroups
) {
336 SecItemCertificateSourceRef result
= (SecItemCertificateSourceRef
)malloc(sizeof(*result
));
337 result
->base
.copyParents
= SecItemCertificateSourceCopyParents
;
338 result
->base
.contains
= SecItemCertificateSourceContains
;
339 result
->accessGroups
= accessGroups
;
340 CFRetainSafe(accessGroups
);
341 return (SecCertificateSourceRef
)result
;
344 static void SecItemCertificateSourceDestroy(SecCertificateSourceRef source
) {
345 SecItemCertificateSourceRef msource
= (SecItemCertificateSourceRef
)source
;
346 CFReleaseSafe(msource
->accessGroups
);
351 // MARK: SecSystemAnchorSource
352 /********************************************************
353 *********** SecSystemAnchorSource object ************
354 ********************************************************/
356 static bool SecSystemAnchorSourceCopyParents(
357 SecCertificateSourceRef source
, SecCertificateRef certificate
,
358 void *context
, SecCertificateSourceParents callback
) {
359 #ifndef SECITEM_SHIM_OSX
360 CFArrayRef parents
= NULL
;
361 CFArrayRef anchors
= NULL
;
362 SecOTAPKIRef otapkiref
= NULL
;
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 */
369 otapkiref
= SecOTAPKICopyCurrentOTAPKIRef();
370 require_quiet(otapkiref
, errOut
);
371 anchors
= subject_to_anchors(nic
);
372 require_quiet(anchors
, errOut
);
373 parents
= CopyCertsFromIndices(anchors
);
376 callback(context
, parents
);
377 CFReleaseSafe(parents
);
378 CFReleaseSafe(otapkiref
);
383 /* Quick thought: we can eliminate this method if we search anchor sources
384 before all others and we remember if we got a cert from an anchorsource. */
385 static bool SecSystemAnchorSourceContains(SecCertificateSourceRef source
,
386 SecCertificateRef certificate
) {
388 #ifndef SECITEM_SHIM_OSX
389 CFArrayRef anchors
= NULL
;
390 SecOTAPKIRef otapkiref
= NULL
;
391 CFArrayRef cert_datas
= NULL
;
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 */
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
);
405 CFIndex cert_length
= SecCertificateGetLength(certificate
);
406 const UInt8
*cert_data_ptr
= SecCertificateGetBytePtr(certificate
);
408 CFIndex num_cert_datas
= CFArrayGetCount(cert_datas
);
409 for (CFIndex idx
= 0; idx
< num_cert_datas
; idx
++)
411 CFDataRef cert_data
= (CFDataRef
)CFArrayGetValueAtIndex(cert_datas
, idx
);
413 if (NULL
!= cert_data
)
415 if (CFGetTypeID(cert_data
) == CFDataGetTypeID())
417 CFIndex aCert_Length
= CFDataGetLength(cert_data
);
418 const UInt8
* aCert_Data_Ptr
= CFDataGetBytePtr(cert_data
);
420 if (aCert_Length
== cert_length
)
422 if (!memcmp(cert_data_ptr
, aCert_Data_Ptr
, cert_length
))
433 CFReleaseSafe(cert_datas
);
434 CFReleaseSafe(otapkiref
);
441 struct SecCertificateSource kSecSystemAnchorSource
= {
442 SecSystemAnchorSourceCopyParents
,
443 SecSystemAnchorSourceContains
447 // MARK: SecUserAnchorSource
448 /********************************************************
449 *********** SecUserAnchorSource object ************
450 ********************************************************/
451 static bool SecUserAnchorSourceCopyParents(
452 SecCertificateSourceRef source
, SecCertificateRef certificate
,
453 void *context
, SecCertificateSourceParents callback
) {
454 CFArrayRef parents
= SecTrustStoreCopyParents(
455 SecTrustStoreForDomain(kSecTrustStoreDomainUser
), certificate
, NULL
);
456 callback(context
, parents
);
457 CFReleaseSafe(parents
);
461 static bool SecUserAnchorSourceContains(SecCertificateSourceRef source
,
462 SecCertificateRef certificate
) {
463 return SecTrustStoreContains(
464 SecTrustStoreForDomain(kSecTrustStoreDomainUser
), certificate
);
467 struct SecCertificateSource kSecUserAnchorSource
= {
468 SecUserAnchorSourceCopyParents
,
469 SecUserAnchorSourceContains
473 // MARK: SecMemoryCertificateSource
474 /********************************************************
475 *********** SecMemoryCertificateSource object ************
476 ********************************************************/
477 struct SecMemoryCertificateSource
{
478 struct SecCertificateSource base
;
479 CFMutableSetRef certificates
;
480 CFMutableDictionaryRef subjects
;
482 typedef struct SecMemoryCertificateSource
*SecMemoryCertificateSourceRef
;
484 static bool SecMemoryCertificateSourceCopyParents(
485 SecCertificateSourceRef source
, SecCertificateRef certificate
,
486 void *context
, SecCertificateSourceParents callback
) {
487 SecMemoryCertificateSourceRef msource
=
488 (SecMemoryCertificateSourceRef
)source
;
489 CFDataRef normalizedIssuer
=
490 SecCertificateGetNormalizedIssuerContent(certificate
);
491 CFArrayRef parents
= CFDictionaryGetValue(msource
->subjects
,
493 /* FIXME filter parents by subjectID if certificate has an
494 authorityKeyIdentifier. */
495 secdebug("trust", "%@ parents -> %@", certificate
, parents
);
496 callback(context
, parents
);
500 static bool SecMemoryCertificateSourceContains(SecCertificateSourceRef source
,
501 SecCertificateRef certificate
) {
502 SecMemoryCertificateSourceRef msource
=
503 (SecMemoryCertificateSourceRef
)source
;
504 return CFSetContainsValue(msource
->certificates
, certificate
);
507 static void dictAddValueToArrayForKey(CFMutableDictionaryRef dict
,
508 const void *key
, const void *value
) {
512 CFMutableArrayRef values
=
513 (CFMutableArrayRef
)CFDictionaryGetValue(dict
, key
);
515 values
= CFArrayCreateMutable(kCFAllocatorDefault
, 0,
516 &kCFTypeArrayCallBacks
);
517 CFDictionaryAddValue(dict
, key
, values
);
522 CFArrayAppendValue(values
, value
);
525 static void SecMemoryCertificateSourceApplierFunction(const void *value
,
527 SecMemoryCertificateSourceRef msource
=
528 (SecMemoryCertificateSourceRef
)context
;
529 SecCertificateRef certificate
= (SecCertificateRef
)value
;
531 /* CFSet's API has no way to combine these 2 operations into 1 sadly. */
532 if (CFSetContainsValue(msource
->certificates
, certificate
))
534 CFSetAddValue(msource
->certificates
, certificate
);
536 CFDataRef key
= SecCertificateGetNormalizedSubjectContent(certificate
);
537 dictAddValueToArrayForKey(msource
->subjects
, key
, value
);
540 static SecCertificateSourceRef
SecMemoryCertificateSourceCreate(
541 CFArrayRef certificates
) {
542 SecMemoryCertificateSourceRef result
= (SecMemoryCertificateSourceRef
)
543 malloc(sizeof(*result
));
544 result
->base
.copyParents
= SecMemoryCertificateSourceCopyParents
;
545 result
->base
.contains
= SecMemoryCertificateSourceContains
;
546 CFIndex count
= CFArrayGetCount(certificates
);
547 result
->certificates
= CFSetCreateMutable(kCFAllocatorDefault
, count
,
548 &kCFTypeSetCallBacks
);
549 result
->subjects
= CFDictionaryCreateMutable(kCFAllocatorDefault
,
550 count
, &kCFTypeDictionaryKeyCallBacks
,
551 &kCFTypeDictionaryValueCallBacks
);
552 CFRange range
= { 0, count
};
553 CFArrayApplyFunction(certificates
, range
,
554 SecMemoryCertificateSourceApplierFunction
, result
);
556 return (SecCertificateSourceRef
)result
;
559 static void SecMemoryCertificateSourceDestroy(
560 SecCertificateSourceRef source
) {
561 SecMemoryCertificateSourceRef msource
=
562 (SecMemoryCertificateSourceRef
)source
;
563 CFRelease(msource
->certificates
);
564 CFRelease(msource
->subjects
);
569 // MARK: SecCAIssuerCertificateSource
570 /********************************************************
571 ********* SecCAIssuerCertificateSource object **********
572 ********************************************************/
573 static bool SecCAIssuerCertificateSourceCopyParents(
574 SecCertificateSourceRef source
, SecCertificateRef certificate
,
575 void *context
, SecCertificateSourceParents callback
) {
576 return SecCAIssuerCopyParents(certificate
, SecPathBuilderGetQueue((SecPathBuilderRef
)context
), context
, callback
);
579 static bool SecCAIssuerCertificateSourceContains(
580 SecCertificateSourceRef source
, SecCertificateRef certificate
) {
584 struct SecCertificateSource kSecCAIssuerSource
= {
585 SecCAIssuerCertificateSourceCopyParents
,
586 SecCAIssuerCertificateSourceContains
590 // MARK: SecPathBuilder
591 /********************************************************
592 *************** SecPathBuilder object ******************
593 ********************************************************/
594 struct SecPathBuilder
{
595 dispatch_queue_t queue
;
596 SecCertificateSourceRef certificateSource
;
597 SecCertificateSourceRef itemCertificateSource
;
598 SecCertificateSourceRef anchorSource
;
599 CFMutableArrayRef anchorSources
;
600 CFIndex nextParentSource
;
601 CFMutableArrayRef parentSources
;
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
;
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
617 CFMutableArrayRef rejectedPaths
;
618 /* Trusted anchor, satisfies the policies so far. */
619 CFMutableArrayRef candidatePaths
;
623 CFArrayRef leafDetails
;
627 bool considerRejected
;
628 bool considerPartials
;
629 bool canAccessNetwork
;
631 struct OpaqueSecPVC path
;
632 SecCertificatePathRef bestPath
;
636 bool (*state
)(SecPathBuilderRef
);
637 SecPathBuilderCompleted completed
;
641 /* State functions. Return false if a async job was scheduled, return
642 true to execute the next state. */
643 static bool SecPathBuilderGetNext(SecPathBuilderRef builder
);
644 static bool SecPathBuilderValidatePath(SecPathBuilderRef builder
);
645 static bool SecPathBuilderDidValidatePath(SecPathBuilderRef builder
);
646 static bool SecPathBuilderComputeDetails(SecPathBuilderRef builder
);
647 static bool SecPathBuilderReportResult(SecPathBuilderRef builder
);
649 /* Forward declarations. */
650 static bool SecPathBuilderIsAnchor(SecPathBuilderRef builder
,
651 SecCertificateRef certificate
);
653 /* IDEA: policies could be made cabable of replacing incoming anchors and
654 anchorsOnly argument values. For example some policies require the
655 Apple Inc. CA and not any other anchor. This can be done in
656 SecPathBuilderLeafCertificateChecks since this only runs once. */
657 static void SecPathBuilderLeafCertificateChecks(SecPathBuilderRef builder
,
658 SecCertificatePathRef path
) {
659 CFMutableDictionaryRef certDetail
= CFDictionaryCreateMutable(
660 kCFAllocatorDefault
, 0, &kCFTypeDictionaryKeyCallBacks
,
661 &kCFTypeDictionaryValueCallBacks
);
662 builder
->leafDetails
= CFArrayCreate(kCFAllocatorDefault
,
663 (const void **)&certDetail
, 1, &kCFTypeArrayCallBacks
);
664 CFRelease(certDetail
);
665 SecPVCRef pvc
= &builder
->path
;
666 SecPVCSetPath(pvc
, path
, builder
->leafDetails
);
667 builder
->considerRejected
= !SecPVCLeafChecks(pvc
);
670 static void SecPathBuilderInit(SecPathBuilderRef builder
,
671 CFArrayRef certificates
, CFArrayRef anchors
, bool anchorsOnly
,
672 CFArrayRef policies
, CFAbsoluteTime verifyTime
, CFArrayRef accessGroups
,
673 SecPathBuilderCompleted completed
, const void *context
) {
674 secdebug("alloc", "%p", builder
);
675 CFAllocatorRef allocator
= kCFAllocatorDefault
;
677 builder
->queue
= dispatch_queue_create("builder", DISPATCH_QUEUE_SERIAL
);
679 builder
->nextParentSource
= 1;
680 builder
->considerPartials
= false;
681 builder
->canAccessNetwork
= true;
683 builder
->anchorSources
= CFArrayCreateMutable(allocator
, 0, NULL
);
684 builder
->parentSources
= CFArrayCreateMutable(allocator
, 0, NULL
);
685 builder
->allPaths
= CFSetCreateMutable(allocator
, 0,
686 &kCFTypeSetCallBacks
);
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;
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;
699 /* Let's create all the certificate sources we might want to use. */
700 builder
->certificateSource
=
701 SecMemoryCertificateSourceCreate(certificates
);
703 builder
->anchorSource
= SecMemoryCertificateSourceCreate(anchors
);
705 builder
->anchorSource
= NULL
;
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
);
713 builder
->itemCertificateSource
= SecItemCertificateSourceCreate(accessGroups
);
714 CFArrayAppendValue(builder
->parentSources
, builder
->itemCertificateSource
);
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
);
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
);
726 CFArrayAppendValue(builder
->parentSources
, &kSecCAIssuerSource
);
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
);
738 SecPathBuilderLeafCertificateChecks(builder
, path
);
741 builder
->activations
= 0;
742 builder
->state
= SecPathBuilderGetNext
;
743 builder
->completed
= completed
;
744 builder
->context
= context
;
747 SecPathBuilderRef
SecPathBuilderCreate(CFArrayRef certificates
,
748 CFArrayRef anchors
, bool anchorsOnly
, CFArrayRef policies
,
749 CFAbsoluteTime verifyTime
, CFArrayRef accessGroups
,
750 SecPathBuilderCompleted completed
, const void *context
) {
751 SecPathBuilderRef builder
= malloc(sizeof(*builder
));
752 SecPathBuilderInit(builder
, certificates
, anchors
, anchorsOnly
,
753 policies
, verifyTime
, accessGroups
, completed
, context
);
757 static void SecPathBuilderDestroy(SecPathBuilderRef builder
) {
758 secdebug("alloc", "%p", builder
);
759 dispatch_release_null(builder
->queue
);
760 if (builder
->anchorSource
)
761 SecMemoryCertificateSourceDestroy(builder
->anchorSource
);
762 if (builder
->certificateSource
)
763 SecMemoryCertificateSourceDestroy(builder
->certificateSource
);
764 if (builder
->itemCertificateSource
)
765 SecItemCertificateSourceDestroy(builder
->itemCertificateSource
);
766 CFReleaseSafe(builder
->anchorSources
);
767 CFReleaseSafe(builder
->parentSources
);
768 CFReleaseSafe(builder
->allPaths
);
769 CFReleaseSafe(builder
->partialPaths
);
770 CFReleaseSafe(builder
->rejectedPaths
);
771 CFReleaseSafe(builder
->candidatePaths
);
772 CFReleaseSafe(builder
->leafDetails
);
774 SecPVCDelete(&builder
->path
);
777 bool SecPathBuilderCanAccessNetwork(SecPathBuilderRef builder
) {
778 return builder
->canAccessNetwork
;
781 void SecPathBuilderSetCanAccessNetwork(SecPathBuilderRef builder
, bool allow
) {
782 if (builder
->canAccessNetwork
!= allow
) {
783 builder
->canAccessNetwork
= allow
;
785 secdebug("http", "network access re-enabled by policy");
786 /* re-enabling network_access re-adds kSecCAIssuerSource as
788 CFArrayAppendValue(builder
->parentSources
, &kSecCAIssuerSource
);
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
);
797 CFArrayRemoveValueAtIndex(builder
->parentSources
, ix
);
802 static bool SecPathBuilderIsAnchor(SecPathBuilderRef builder
,
803 SecCertificateRef certificate
) {
804 /* We always look through all anchor sources. */
805 CFIndex count
= CFArrayGetCount(builder
->anchorSources
);
807 for (ix
= 0; ix
< count
; ++ix
) {
808 SecCertificateSourceRef source
= (SecCertificateSourceRef
)
809 CFArrayGetValueAtIndex(builder
->anchorSources
, ix
);
810 if (SecCertificateSourceContains(source
, certificate
)) {
817 /* Return false if path is not a partial, if path was a valid candidate it
818 will have been added to builder->candidatePaths, if path was rejected
819 by the parent certificate checks (because it's expired or some other
820 static chaining check failed) it will have been added to rejectedPaths.
821 Return true path if path is a partial. */
822 static bool SecPathBuilderIsPartial(SecPathBuilderRef builder
,
823 SecCertificatePathRef path
) {
824 SecPVCRef pvc
= &builder
->path
;
825 SecPVCSetPath(pvc
, path
, NULL
);
827 if (!builder
->considerRejected
&& !SecPVCParentCertificateChecks(pvc
,
828 SecPVCGetCertificateCount(pvc
) - 1)) {
829 secdebug("trust", "Found rejected path %@", path
);
830 CFArrayAppendValue(builder
->rejectedPaths
, path
);
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
);
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
);
854 /* Given the builder, a partial chain partial and the parents array, construct
855 a SecCertificatePath for each parent. After discarding previously
856 considered paths and paths with cycles, sort out which array each path
857 should go in, if any. */
858 static void SecPathBuilderProccessParents(SecPathBuilderRef builder
,
859 SecCertificatePathRef partial
, CFArrayRef parents
) {
860 CFIndex rootIX
= SecCertificatePathGetCount(partial
) - 1;
861 CFIndex num_parents
= parents
? CFArrayGetCount(parents
) : 0;
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
,
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
);
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
);
889 if (!CFSetContainsValue(builder
->allPaths
, path
)) {
890 CFSetAddValue(builder
->allPaths
, path
);
892 SecCertificatePathSetIsAnchored(path
);
893 if (SecPathBuilderIsPartial(builder
, path
)) {
894 /* Insert path right at the current position since it's a new
896 CFArrayInsertValueAtIndex(builder
->partialPaths
,
897 ++builder
->partialIX
, path
);
898 secdebug("trust", "Adding partial for parent %" PRIdCFIndex
"/%" PRIdCFIndex
" %@",
899 parentIX
+ 1, num_parents
, path
);
901 secdebug("trust", "found new path %@", path
);
907 /* Callback for the SecPathBuilderGetNext() functions call to
908 SecCertificateSourceCopyParents(). */
909 static void SecPathBuilderExtendPaths(void *context
, CFArrayRef parents
) {
910 SecPathBuilderRef builder
= (SecPathBuilderRef
)context
;
911 SecCertificatePathRef partial
= (SecCertificatePathRef
)
912 CFArrayGetValueAtIndex(builder
->partialPaths
, builder
->partialIX
);
913 secdebug("async", "%@ parents %@", partial
, parents
);
914 SecPathBuilderProccessParents(builder
, partial
, parents
);
916 builder
->state
= SecPathBuilderGetNext
;
917 SecPathBuilderStep(builder
);
920 static bool SecPathBuilderGetNext(SecPathBuilderRef builder
) {
921 /* If we have any candidates left to go return those first. */
922 if (CFArrayGetCount(builder
->candidatePaths
)) {
923 SecCertificatePathRef path
= (SecCertificatePathRef
)
924 CFArrayGetValueAtIndex(builder
->candidatePaths
, 0);
925 CFArrayRemoveValueAtIndex(builder
->candidatePaths
, 0);
926 secdebug("trust", "SecPathBuilderGetNext returning candidate %@",
928 SecPVCSetPath(&builder
->path
, path
, NULL
);
929 builder
->state
= SecPathBuilderValidatePath
;
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
);
942 SecCertificatePathRef path
= (SecCertificatePathRef
)
943 CFArrayGetValueAtIndex(builder
->rejectedPaths
, rejectedIX
);
944 if (SecPathBuilderIsPartial(builder
, path
)) {
945 CFArrayInsertValueAtIndex(builder
->partialPaths
,
946 ++builder
->partialIX
, path
);
948 CFArrayRemoveValueAtIndex(builder
->rejectedPaths
, rejectedIX
);
950 /* Keep going until we have moved all rejected partials into
951 the regular partials or candidates array. */
956 /* If builder->partialIX is < 0 we have considered all partial chains
957 this block must ensure partialIX >= 0 if execution continues past
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
);
966 /* We've run out of new sources to consider so let's look at
967 rejected chains and after that even consider partials
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");
979 /* We're all out of options, so we can't produce any more
980 candidates. Let's calculate details and return the best
982 builder
->state
= SecPathBuilderComputeDetails
;
986 builder
->partialIX
= CFArrayGetCount(builder
->partialPaths
) - 1;
987 secdebug("trust", "re-checking %" PRIdCFIndex
" partials", builder
->partialIX
+ 1);
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
;
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
),
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
);
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
);
1028 SecCertificatePathSetNextSourceIndex(partial
, sourceIX
+ 1);
1029 SecCertificateRef root
= SecCertificatePathGetRoot(partial
);
1030 return SecCertificateSourceCopyParents(source
, root
,
1031 builder
, SecPathBuilderExtendPaths
);
1033 --builder
->partialIX
;
1039 /* One or more of the policies did not accept the candidate path. */
1040 static void SecPathBuilderReject(SecPathBuilderRef builder
) {
1042 SecPVCRef pvc
= &builder
->path
;
1044 builder
->state
= SecPathBuilderGetNext
;
1046 if (builder
->bestPathIsEV
&& !pvc
->is_ev
) {
1047 /* We never replace an ev reject with a non ev reject. */
1051 CFIndex rejectScore
= builder
->rejectScore
;
1052 CFIndex score
= SecCertificatePathScore(builder
->path
.path
,
1053 SecPVCGetVerifyTime(&builder
->path
));
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
1058 if (pvc
->is_ev
&& !builder
->bestPathIsEV
) {
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
;
1074 /* Do this last so that changes to rejectScore above will take affect. */
1075 if (!builder
->bestPath
|| score
> rejectScore
) {
1076 if (builder
->bestPath
) {
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
);
1084 secdebug("reject", "%sev reject score: %" PRIdCFIndex
" %@",
1085 (pvc
->is_ev
? "" : "non "), score
, builder
->path
.path
);
1088 builder
->rejectScore
= score
;
1089 builder
->bestPath
= pvc
->path
;
1090 builder
->bestPathIsEV
= pvc
->is_ev
;
1092 secdebug("reject", "%sev reject score: %" PRIdCFIndex
" lower than %" PRIdCFIndex
" %@",
1093 (pvc
->is_ev
? "" : "non "), score
, rejectScore
, builder
->path
.path
);
1097 /* All policies accepted the candidate path. */
1098 static void SecPathBuilderAccept(SecPathBuilderRef 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
;
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
;
1115 builder
->state
= SecPathBuilderGetNext
;
1118 /* Return true iff a given path satisfies all the specified policies at
1120 static bool SecPathBuilderValidatePath(SecPathBuilderRef builder
) {
1121 SecPVCRef pvc
= &builder
->path
;
1123 if (builder
->considerRejected
) {
1124 SecPathBuilderReject(builder
);
1128 builder
->state
= SecPathBuilderDidValidatePath
;
1129 return SecPVCPathChecks(pvc
);
1132 static bool SecPathBuilderDidValidatePath(SecPathBuilderRef builder
) {
1133 SecPVCRef pvc
= &builder
->path
;
1135 SecPathBuilderAccept(builder
);
1137 SecPathBuilderReject(builder
);
1139 assert(builder
->state
!= SecPathBuilderDidValidatePath
);
1143 static bool SecPathBuilderComputeDetails(SecPathBuilderRef builder
) {
1145 SecPVCRef pvc
= &builder
->path
;
1147 if (!builder
->caller_wants_details
) {
1148 SecPVCSetPath(pvc
, builder
->bestPath
, NULL
);
1149 pvc
->result
= builder
->rejectScore
== INTPTR_MAX
;
1150 builder
->state
= SecPathBuilderReportResult
;
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
);
1172 builder
->state
= SecPathBuilderReportResult
;
1173 bool completed
= SecPVCPathChecks(pvc
);
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;
1183 static bool SecPathBuilderReportResult(SecPathBuilderRef builder
) {
1184 SecPVCRef pvc
= &builder
->path
;
1185 if (pvc
->info
&& pvc
->is_ev
&& pvc
->result
) {
1186 CFDictionarySetValue(pvc
->info
, kSecTrustInfoExtendedValidationKey
,
1188 SecCertificateRef leaf
= SecPVCGetCertificateAtIndex(pvc
, 0);
1189 CFStringRef leafCompanyName
= SecCertificateCopyCompanyName(leaf
);
1190 if (leafCompanyName
) {
1191 CFDictionarySetValue(pvc
->info
, kSecTrustInfoCompanyNameKey
,
1193 CFRelease(leafCompanyName
);
1196 CFAbsoluteTime nextUpdate
= SecPVCGetEarliestNextUpdate(pvc
);
1197 if (nextUpdate
== 0) {
1198 CFDictionarySetValue(pvc
->info
, kSecTrustInfoRevocationKey
,
1201 CFDateRef validUntil
= CFDateCreate(kCFAllocatorDefault
, nextUpdate
);
1202 CFDictionarySetValue(pvc
->info
, kSecTrustInfoRevocationValidUntilKey
,
1204 CFRelease(validUntil
);
1205 CFDictionarySetValue(pvc
->info
, kSecTrustInfoRevocationKey
,
1211 /* This will trigger the outer step function to call the completion
1213 builder
->state
= NULL
;
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
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.
1232 bool SecPathBuilderStep(SecPathBuilderRef builder
) {
1233 if (builder
->activations
) {
1234 secdebug("async", "activations: %lu returning true",
1235 builder
->activations
);
1239 secdebug("async", "activations: %lu", builder
->activations
);
1240 builder
->activations
++;
1241 while (builder
->state
&& builder
->state(builder
));
1242 --builder
->activations
;
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
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. */
1258 SecTrustResultType result
= (builder
->rejectScore
== INTPTR_MAX
1259 ? kSecTrustResultUnspecified
: kSecTrustResultRecoverableTrustFailure
);
1261 secdebug("trust", "completed: %@ details: %@ result: %d",
1262 builder
->bestPath
, builder
->path
.details
, result
);
1264 if (builder
->completed
) {
1265 builder
->completed(builder
->context
, builder
->bestPath
,
1266 builder
->path
.details
, builder
->path
.info
, result
);
1269 /* Finally, destroy the builder and free it. */
1270 SecPathBuilderDestroy(builder
);
1276 dispatch_queue_t
SecPathBuilderGetQueue(SecPathBuilderRef builder
) {
1277 return builder
->queue
;
1281 // MARK: SecTrustServer
1282 /********************************************************
1283 ****************** SecTrustServer **********************
1284 ********************************************************/
1286 typedef void (^SecTrustServerEvaluationCompleted
)(SecTrustResultType tr
, CFArrayRef details
, CFDictionaryRef info
, SecCertificatePathRef chain
, CFErrorRef error
);
1289 SecTrustServerEvaluateCompleted(const void *userData
,
1290 SecCertificatePathRef chain
, CFArrayRef details
, CFDictionaryRef info
,
1291 SecTrustResultType result
) {
1292 SecTrustServerEvaluationCompleted evaluated
= (SecTrustServerEvaluationCompleted
)userData
;
1293 evaluated(result
, details
, info
, chain
, NULL
);
1294 Block_release(evaluated
);
1298 SecTrustServerEvaluateBlock(CFArrayRef certificates
, CFArrayRef anchors
, bool anchorsOnly
, CFArrayRef policies
, CFAbsoluteTime verifyTime
, __unused CFArrayRef accessGroups
, void (^evaluated
)(SecTrustResultType tr
, CFArrayRef details
, CFDictionaryRef info
, SecCertificatePathRef chain
, CFErrorRef error
)) {
1299 SecTrustServerEvaluationCompleted userData
= Block_copy(evaluated
);
1300 /* Call the actual evaluator function. */
1301 SecPathBuilderRef builder
= SecPathBuilderCreate(certificates
, anchors
,
1302 anchorsOnly
, policies
,
1303 verifyTime
, accessGroups
,
1304 SecTrustServerEvaluateCompleted
, userData
);
1305 dispatch_async(builder
->queue
, ^{ SecPathBuilderStep(builder
); });
1309 // NO_SERVER Shim code only, xpc interface should call SecTrustServerEvaluateBlock() directly
1310 SecTrustResultType
SecTrustServerEvaluate(CFArrayRef certificates
, CFArrayRef anchors
, bool anchorsOnly
, CFArrayRef policies
, CFAbsoluteTime verifyTime
, __unused CFArrayRef accessGroups
, CFArrayRef
*pdetails
, CFDictionaryRef
*pinfo
, SecCertificatePathRef
*pchain
, CFErrorRef
*perror
) {
1311 dispatch_semaphore_t done
= dispatch_semaphore_create(0);
1312 __block SecTrustResultType result
= kSecTrustResultInvalid
;
1313 SecTrustServerEvaluateBlock(certificates
, anchors
, anchorsOnly
, policies
, verifyTime
, accessGroups
, ^(SecTrustResultType tr
, CFArrayRef details
, CFDictionaryRef info
, SecCertificatePathRef chain
, CFErrorRef error
) {
1315 if (tr
== kSecTrustResultInvalid
) {
1318 CFRetainSafe(error
);
1322 *pdetails
= details
;
1323 CFRetainSafe(details
);
1331 CFRetainSafe(chain
);
1334 dispatch_semaphore_signal(done
);
1336 dispatch_semaphore_wait(done
, DISPATCH_TIME_FOREVER
);