2 * Copyright (c) 2006-2010,2012-2014 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
28 #include <securityd/SecTrustServer.h>
29 #include <securityd/SecPolicyServer.h>
30 #include <securityd/SecTrustStoreServer.h>
31 #include <securityd/SecCAIssuerRequest.h>
32 #include <securityd/SecItemServer.h>
34 #include <utilities/SecIOFormat.h>
35 #include <utilities/SecDispatchRelease.h>
37 #include <Security/SecTrustPriv.h>
38 #include <Security/SecItem.h>
39 #include <Security/SecCertificateInternal.h>
40 #include <Security/SecCertificatePath.h>
41 #include <Security/SecFramework.h>
42 #include <Security/SecPolicyInternal.h>
43 #include <CoreFoundation/CFRuntime.h>
44 #include <CoreFoundation/CFSet.h>
45 #include <CoreFoundation/CFString.h>
46 #include <CoreFoundation/CFNumber.h>
47 #include <CoreFoundation/CFArray.h>
48 #include <CoreFoundation/CFPropertyList.h>
49 #include <AssertMacros.h>
54 #include <Security/SecBase.h>
55 #include "SecRSAKey.h"
56 #include <libDER/oids.h>
57 #include <utilities/debugging.h>
58 #include <utilities/SecCFWrappers.h>
59 #include <Security/SecInternal.h>
60 #include <ipc/securityd_client.h>
61 #include <CommonCrypto/CommonDigest.h>
62 #include "OTATrustUtilities.h"
65 /********************************************************
66 ***************** OTA Trust support ********************
67 ********************************************************/
70 #ifndef SECITEM_SHIM_OSX
72 static CFArrayRef
subject_to_anchors(CFDataRef nic
);
73 static CFArrayRef
CopyCertsFromIndices(CFArrayRef offsets
);
75 static CFArrayRef
subject_to_anchors(CFDataRef nic
)
77 CFArrayRef result
= NULL
;
84 SecOTAPKIRef otapkiref
= SecOTAPKICopyCurrentOTAPKIRef();
85 if (NULL
== otapkiref
)
90 CFDictionaryRef lookupTable
= SecOTAPKICopyAnchorLookupTable(otapkiref
);
93 if (NULL
== lookupTable
)
98 unsigned char subject_digest
[CC_SHA1_DIGEST_LENGTH
];
99 memset(subject_digest
, 0, CC_SHA1_DIGEST_LENGTH
);
101 (void)CC_SHA1(CFDataGetBytePtr(nic
), (CC_LONG
)CFDataGetLength(nic
), subject_digest
);
102 CFDataRef sha1Digest
= CFDataCreateWithBytesNoCopy(kCFAllocatorDefault
, subject_digest
, CC_SHA1_DIGEST_LENGTH
, kCFAllocatorNull
);
105 result
= (CFArrayRef
)CFDictionaryGetValue(lookupTable
, sha1Digest
);
106 CFReleaseSafe(lookupTable
);
107 CFReleaseSafe(sha1Digest
);
112 static CFArrayRef
CopyCertDataFromIndices(CFArrayRef offsets
)
114 CFMutableArrayRef result
= NULL
;
116 SecOTAPKIRef otapkiref
= SecOTAPKICopyCurrentOTAPKIRef();
117 if (NULL
== otapkiref
)
122 const char* anchorTable
= SecOTAPKIGetAnchorTable(otapkiref
);
123 if (NULL
== anchorTable
)
125 CFReleaseSafe(otapkiref
);
129 CFIndex num_offsets
= CFArrayGetCount(offsets
);
131 result
= CFArrayCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeArrayCallBacks
);
133 for (CFIndex idx
= 0; idx
< num_offsets
; idx
++)
135 CFNumberRef offset
= (CFNumberRef
)CFArrayGetValueAtIndex(offsets
, idx
);
136 uint32_t offset_value
= 0;
137 if (CFNumberGetValue(offset
, kCFNumberSInt32Type
, &offset_value
))
139 char* pDataPtr
= (char *)(anchorTable
+ offset_value
);
140 //int32_t record_length = *((int32_t * )pDataPtr);
141 //record_length = record_length;
142 pDataPtr
+= sizeof(uint32_t);
144 int32_t cert_data_length
= *((int32_t * )pDataPtr
);
145 pDataPtr
+= sizeof(uint32_t);
147 CFDataRef cert_data
= CFDataCreateWithBytesNoCopy(kCFAllocatorDefault
, (const UInt8
*)pDataPtr
,
148 cert_data_length
, kCFAllocatorNull
);
149 if (NULL
!= cert_data
)
151 CFArrayAppendValue(result
, cert_data
);
152 CFReleaseSafe(cert_data
);
156 CFReleaseSafe(otapkiref
);
160 static CFArrayRef
CopyCertsFromIndices(CFArrayRef offsets
)
162 CFMutableArrayRef result
= NULL
;
164 CFArrayRef cert_data_array
= CopyCertDataFromIndices(offsets
);
166 if (NULL
!= cert_data_array
)
168 result
= CFArrayCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeArrayCallBacks
);
169 CFIndex num_cert_datas
= CFArrayGetCount(cert_data_array
);
170 for (CFIndex idx
= 0; idx
< num_cert_datas
; idx
++)
172 CFDataRef cert_data
= (CFDataRef
)CFArrayGetValueAtIndex(cert_data_array
, idx
);
173 if (NULL
!= cert_data
)
175 SecCertificateRef cert
= SecCertificateCreateWithData(kCFAllocatorDefault
, cert_data
);
178 CFArrayAppendValue(result
, cert
);
183 CFRelease(cert_data_array
);
190 /********************************************************
191 *************** END OTA Trust support ******************
192 ********************************************************/
194 #define MAX_CHAIN_LENGTH 15
196 /* Forward declaration for use in SecCertificateSource. */
197 static void SecPathBuilderExtendPaths(void *context
, CFArrayRef parents
);
201 // MARK: SecCertificateSource
202 /********************************************************
203 ************ SecCertificateSource object ***************
204 ********************************************************/
206 typedef struct SecCertificateSource
*SecCertificateSourceRef
;
207 typedef void(*SecCertificateSourceParents
)(void *, CFArrayRef
);
208 typedef bool(*CopyParents
)(SecCertificateSourceRef source
,
209 SecCertificateRef certificate
, void *context
, SecCertificateSourceParents
);
210 typedef bool(*Contains
)(SecCertificateSourceRef source
,
211 SecCertificateRef certificate
);
213 struct SecCertificateSource
{
214 CopyParents copyParents
;
218 static bool SecCertificateSourceCopyParents(SecCertificateSourceRef source
,
219 SecCertificateRef certificate
,
220 void *context
, SecCertificateSourceParents callback
) {
221 return source
->copyParents(source
, certificate
, context
, callback
);
224 static bool SecCertificateSourceContains(SecCertificateSourceRef source
,
225 SecCertificateRef certificate
) {
226 return source
->contains(source
, certificate
);
230 // MARK: SecItemCertificateSource
231 /********************************************************
232 *********** SecItemCertificateSource object ************
233 ********************************************************/
234 struct SecItemCertificateSource
{
235 struct SecCertificateSource base
;
236 CFArrayRef accessGroups
;
238 typedef struct SecItemCertificateSource
*SecItemCertificateSourceRef
;
240 static CFTypeRef
SecItemCertificateSourceResultsPost(CFTypeRef raw_results
) {
241 if (isArray(raw_results
)) {
242 CFMutableArrayRef result
= CFArrayCreateMutable(kCFAllocatorDefault
, CFArrayGetCount(raw_results
), &kCFTypeArrayCallBacks
);
243 CFArrayForEach(raw_results
, ^(const void *value
) {
244 SecCertificateRef cert
= SecCertificateCreateWithData(kCFAllocatorDefault
, value
);
246 CFArrayAppendValue(result
, cert
);
251 } else if (isData(raw_results
)) {
252 return SecCertificateCreateWithData(kCFAllocatorDefault
, (CFDataRef
)raw_results
);
257 static bool SecItemCertificateSourceCopyParents(
258 SecCertificateSourceRef source
, SecCertificateRef certificate
,
259 void *context
, SecCertificateSourceParents callback
) {
260 SecItemCertificateSourceRef msource
= (SecItemCertificateSourceRef
)source
;
261 /* FIXME: Search for things other than just subject of our issuer if we
262 have a subjectID or authorityKeyIdentifier. */
263 CFDataRef normalizedIssuer
=
264 SecCertificateGetNormalizedIssuerContent(certificate
);
265 const void *keys
[] = {
272 kSecClassCertificate
,
277 CFDictionaryRef query
= CFDictionaryCreate(NULL
, keys
, values
, 4,
279 CFTypeRef results
= NULL
;
280 /* We can make this async or run this on a queue now easily. */
281 CFErrorRef localError
= NULL
;
282 if (!_SecItemCopyMatching(query
, msource
->accessGroups
, &results
, &localError
)) {
283 if (CFErrorGetCode(localError
) != errSecItemNotFound
) {
284 secdebug("trust", "_SecItemCopyMatching: %@", localError
);
286 CFRelease(localError
);
289 CFTypeRef certs
= SecItemCertificateSourceResultsPost(results
);
290 CFReleaseSafe(results
);
291 callback(context
, certs
);
292 CFReleaseSafe(certs
);
296 static bool SecItemCertificateSourceContains(SecCertificateSourceRef source
,
297 SecCertificateRef certificate
) {
298 SecItemCertificateSourceRef msource
= (SecItemCertificateSourceRef
)source
;
299 /* Lookup a certificate by issuer and serial number. */
300 CFDataRef normalizedSubject
=
301 SecCertificateGetNormalizedSubjectContent(certificate
);
302 CFDataRef serialNumber
=
303 SecCertificateCopySerialNumber(certificate
);
304 const void *keys
[] = {
311 kSecClassCertificate
,
316 CFDictionaryRef query
= CFDictionaryCreate(NULL
, keys
, values
, 5,
318 CFErrorRef localError
= NULL
;
319 CFTypeRef results
= NULL
;
320 bool ok
= _SecItemCopyMatching(query
, msource
->accessGroups
, &results
, &localError
);
322 CFRelease(serialNumber
);
323 CFReleaseSafe(results
);
325 if (CFErrorGetCode(localError
) != errSecItemNotFound
) {
326 secdebug("trust", "_SecItemCopyMatching: %@", localError
);
328 CFRelease(localError
);
334 static SecCertificateSourceRef
SecItemCertificateSourceCreate(CFArrayRef accessGroups
) {
335 SecItemCertificateSourceRef result
= (SecItemCertificateSourceRef
)malloc(sizeof(*result
));
336 result
->base
.copyParents
= SecItemCertificateSourceCopyParents
;
337 result
->base
.contains
= SecItemCertificateSourceContains
;
338 result
->accessGroups
= accessGroups
;
339 CFRetainSafe(accessGroups
);
340 return (SecCertificateSourceRef
)result
;
343 static void SecItemCertificateSourceDestroy(SecCertificateSourceRef source
) {
344 SecItemCertificateSourceRef msource
= (SecItemCertificateSourceRef
)source
;
345 CFReleaseSafe(msource
->accessGroups
);
350 // MARK: SecSystemAnchorSource
351 /********************************************************
352 *********** SecSystemAnchorSource object ************
353 ********************************************************/
355 static bool SecSystemAnchorSourceCopyParents(
356 SecCertificateSourceRef source
, SecCertificateRef certificate
,
357 void *context
, SecCertificateSourceParents callback
) {
358 #ifndef SECITEM_SHIM_OSX
359 CFArrayRef parents
= NULL
;
360 CFArrayRef anchors
= NULL
;
361 SecOTAPKIRef otapkiref
= NULL
;
363 CFDataRef nic
= SecCertificateGetNormalizedIssuerContent(certificate
);
364 /* 64 bits cast: the worst that can happen here is we truncate the length and match an actual anchor.
365 It does not matter since we would be returning the wrong anchors */
366 assert((unsigned long)CFDataGetLength(nic
)<UINT_MAX
); /* Debug check. correct as long as CFIndex is signed long */
368 otapkiref
= SecOTAPKICopyCurrentOTAPKIRef();
369 require_quiet(otapkiref
, errOut
);
370 anchors
= subject_to_anchors(nic
);
371 require_quiet(anchors
, errOut
);
372 parents
= CopyCertsFromIndices(anchors
);
375 callback(context
, parents
);
376 CFReleaseSafe(parents
);
377 CFReleaseSafe(otapkiref
);
382 /* Quick thought: we can eliminate this method if we search anchor sources
383 before all others and we remember if we got a cert from an anchorsource. */
384 static bool SecSystemAnchorSourceContains(SecCertificateSourceRef source
,
385 SecCertificateRef certificate
) {
387 #ifndef SECITEM_SHIM_OSX
388 CFArrayRef anchors
= NULL
;
389 SecOTAPKIRef otapkiref
= NULL
;
390 CFArrayRef cert_datas
= NULL
;
392 CFDataRef nic
= SecCertificateGetNormalizedSubjectContent(certificate
);
393 /* 64 bits cast: the worst that can happen here is we truncate the length and match an actual anchor.
394 It does not matter since we would be returning the wrong anchors */
395 assert((unsigned long)CFDataGetLength(nic
)<UINT_MAX
); /* Debug check. correct as long as CFIndex is signed long */
397 otapkiref
= SecOTAPKICopyCurrentOTAPKIRef();
398 require_quiet(otapkiref
, errOut
);
399 anchors
= subject_to_anchors(nic
);
400 require_quiet(anchors
, errOut
);
401 cert_datas
= CopyCertDataFromIndices(anchors
);
402 require_quiet(cert_datas
, errOut
);
404 CFIndex cert_length
= SecCertificateGetLength(certificate
);
405 const UInt8
*cert_data_ptr
= SecCertificateGetBytePtr(certificate
);
407 CFIndex num_cert_datas
= CFArrayGetCount(cert_datas
);
408 for (CFIndex idx
= 0; idx
< num_cert_datas
; idx
++)
410 CFDataRef cert_data
= (CFDataRef
)CFArrayGetValueAtIndex(cert_datas
, idx
);
412 if (NULL
!= cert_data
)
414 if (CFGetTypeID(cert_data
) == CFDataGetTypeID())
416 CFIndex aCert_Length
= CFDataGetLength(cert_data
);
417 const UInt8
* aCert_Data_Ptr
= CFDataGetBytePtr(cert_data
);
419 if (aCert_Length
== cert_length
)
421 if (!memcmp(cert_data_ptr
, aCert_Data_Ptr
, cert_length
))
432 CFReleaseSafe(cert_datas
);
433 CFReleaseSafe(otapkiref
);
440 struct SecCertificateSource kSecSystemAnchorSource
= {
441 SecSystemAnchorSourceCopyParents
,
442 SecSystemAnchorSourceContains
446 // MARK: SecUserAnchorSource
447 /********************************************************
448 *********** SecUserAnchorSource object ************
449 ********************************************************/
450 static bool SecUserAnchorSourceCopyParents(
451 SecCertificateSourceRef source
, SecCertificateRef certificate
,
452 void *context
, SecCertificateSourceParents callback
) {
453 CFArrayRef parents
= SecTrustStoreCopyParents(
454 SecTrustStoreForDomain(kSecTrustStoreDomainUser
), certificate
, NULL
);
455 callback(context
, parents
);
456 CFReleaseSafe(parents
);
460 static bool SecUserAnchorSourceContains(SecCertificateSourceRef source
,
461 SecCertificateRef certificate
) {
462 return SecTrustStoreContains(
463 SecTrustStoreForDomain(kSecTrustStoreDomainUser
), certificate
);
466 struct SecCertificateSource kSecUserAnchorSource
= {
467 SecUserAnchorSourceCopyParents
,
468 SecUserAnchorSourceContains
472 // MARK: SecMemoryCertificateSource
473 /********************************************************
474 *********** SecMemoryCertificateSource object ************
475 ********************************************************/
476 struct SecMemoryCertificateSource
{
477 struct SecCertificateSource base
;
478 CFMutableSetRef certificates
;
479 CFMutableDictionaryRef subjects
;
481 typedef struct SecMemoryCertificateSource
*SecMemoryCertificateSourceRef
;
483 static bool SecMemoryCertificateSourceCopyParents(
484 SecCertificateSourceRef source
, SecCertificateRef certificate
,
485 void *context
, SecCertificateSourceParents callback
) {
486 SecMemoryCertificateSourceRef msource
=
487 (SecMemoryCertificateSourceRef
)source
;
488 CFDataRef normalizedIssuer
=
489 SecCertificateGetNormalizedIssuerContent(certificate
);
490 CFArrayRef parents
= CFDictionaryGetValue(msource
->subjects
,
492 /* FIXME filter parents by subjectID if certificate has an
493 authorityKeyIdentifier. */
494 secdebug("trust", "%@ parents -> %@", certificate
, parents
);
495 callback(context
, parents
);
499 static bool SecMemoryCertificateSourceContains(SecCertificateSourceRef source
,
500 SecCertificateRef certificate
) {
501 SecMemoryCertificateSourceRef msource
=
502 (SecMemoryCertificateSourceRef
)source
;
503 return CFSetContainsValue(msource
->certificates
, certificate
);
506 static void dictAddValueToArrayForKey(CFMutableDictionaryRef dict
,
507 const void *key
, const void *value
) {
511 CFMutableArrayRef values
=
512 (CFMutableArrayRef
)CFDictionaryGetValue(dict
, key
);
514 values
= CFArrayCreateMutable(kCFAllocatorDefault
, 0,
515 &kCFTypeArrayCallBacks
);
516 CFDictionaryAddValue(dict
, key
, values
);
521 CFArrayAppendValue(values
, value
);
524 static void SecMemoryCertificateSourceApplierFunction(const void *value
,
526 SecMemoryCertificateSourceRef msource
=
527 (SecMemoryCertificateSourceRef
)context
;
528 SecCertificateRef certificate
= (SecCertificateRef
)value
;
530 /* CFSet's API has no way to combine these 2 operations into 1 sadly. */
531 if (CFSetContainsValue(msource
->certificates
, certificate
))
533 CFSetAddValue(msource
->certificates
, certificate
);
535 CFDataRef key
= SecCertificateGetNormalizedSubjectContent(certificate
);
536 dictAddValueToArrayForKey(msource
->subjects
, key
, value
);
539 static SecCertificateSourceRef
SecMemoryCertificateSourceCreate(
540 CFArrayRef certificates
) {
541 SecMemoryCertificateSourceRef result
= (SecMemoryCertificateSourceRef
)
542 malloc(sizeof(*result
));
543 result
->base
.copyParents
= SecMemoryCertificateSourceCopyParents
;
544 result
->base
.contains
= SecMemoryCertificateSourceContains
;
545 CFIndex count
= CFArrayGetCount(certificates
);
546 result
->certificates
= CFSetCreateMutable(kCFAllocatorDefault
, count
,
547 &kCFTypeSetCallBacks
);
548 result
->subjects
= CFDictionaryCreateMutable(kCFAllocatorDefault
,
549 count
, &kCFTypeDictionaryKeyCallBacks
,
550 &kCFTypeDictionaryValueCallBacks
);
551 CFRange range
= { 0, count
};
552 CFArrayApplyFunction(certificates
, range
,
553 SecMemoryCertificateSourceApplierFunction
, result
);
555 return (SecCertificateSourceRef
)result
;
558 static void SecMemoryCertificateSourceDestroy(
559 SecCertificateSourceRef source
) {
560 SecMemoryCertificateSourceRef msource
=
561 (SecMemoryCertificateSourceRef
)source
;
562 CFRelease(msource
->certificates
);
563 CFRelease(msource
->subjects
);
568 // MARK: SecCAIssuerCertificateSource
569 /********************************************************
570 ********* SecCAIssuerCertificateSource object **********
571 ********************************************************/
572 static bool SecCAIssuerCertificateSourceCopyParents(
573 SecCertificateSourceRef source
, SecCertificateRef certificate
,
574 void *context
, SecCertificateSourceParents callback
) {
575 return SecCAIssuerCopyParents(certificate
, SecPathBuilderGetQueue((SecPathBuilderRef
)context
), context
, callback
);
578 static bool SecCAIssuerCertificateSourceContains(
579 SecCertificateSourceRef source
, SecCertificateRef certificate
) {
583 struct SecCertificateSource kSecCAIssuerSource
= {
584 SecCAIssuerCertificateSourceCopyParents
,
585 SecCAIssuerCertificateSourceContains
589 // MARK: SecPathBuilder
590 /********************************************************
591 *************** SecPathBuilder object ******************
592 ********************************************************/
593 struct SecPathBuilder
{
594 dispatch_queue_t queue
;
595 SecCertificateSourceRef certificateSource
;
596 SecCertificateSourceRef itemCertificateSource
;
597 SecCertificateSourceRef anchorSource
;
598 CFMutableArrayRef anchorSources
;
599 CFIndex nextParentSource
;
600 CFMutableArrayRef parentSources
;
602 /* Hashed set of all paths we've constructed so far, used to prevent
603 re-considering a path that was already constructed once before.
604 Note that this is the only container in which certificatePath
605 objects are retained.
606 Every certificatePath being considered is always in allPaths and in at
607 most one of partialPaths, rejectedPaths, candidatePath or extendedPaths
608 all of which don't retain their values. */
609 CFMutableSetRef allPaths
;
611 /* No trusted anchor, satisfies the linking to intermediates for all
612 policies (unless considerRejected is true). */
613 CFMutableArrayRef partialPaths
;
614 /* No trusted anchor, does not satisfy linking to intermediates for all
616 CFMutableArrayRef rejectedPaths
;
617 /* Trusted anchor, satisfies the policies so far. */
618 CFMutableArrayRef candidatePaths
;
622 CFArrayRef leafDetails
;
626 bool considerRejected
;
627 bool considerPartials
;
628 bool canAccessNetwork
;
630 struct OpaqueSecPVC path
;
631 SecCertificatePathRef bestPath
;
635 bool (*state
)(SecPathBuilderRef
);
636 SecPathBuilderCompleted completed
;
640 /* State functions. Return false if a async job was scheduled, return
641 true to execute the next state. */
642 static bool SecPathBuilderGetNext(SecPathBuilderRef builder
);
643 static bool SecPathBuilderValidatePath(SecPathBuilderRef builder
);
644 static bool SecPathBuilderDidValidatePath(SecPathBuilderRef builder
);
645 static bool SecPathBuilderComputeDetails(SecPathBuilderRef builder
);
646 static bool SecPathBuilderReportResult(SecPathBuilderRef builder
);
648 /* Forward declarations. */
649 static bool SecPathBuilderIsAnchor(SecPathBuilderRef builder
,
650 SecCertificateRef certificate
);
652 /* IDEA: policies could be made cabable of replacing incoming anchors and
653 anchorsOnly argument values. For example some policies require the
654 Apple Inc. CA and not any other anchor. This can be done in
655 SecPathBuilderLeafCertificateChecks since this only runs once. */
656 static void SecPathBuilderLeafCertificateChecks(SecPathBuilderRef builder
,
657 SecCertificatePathRef path
) {
658 CFMutableDictionaryRef certDetail
= CFDictionaryCreateMutable(
659 kCFAllocatorDefault
, 0, &kCFTypeDictionaryKeyCallBacks
,
660 &kCFTypeDictionaryValueCallBacks
);
661 builder
->leafDetails
= CFArrayCreate(kCFAllocatorDefault
,
662 (const void **)&certDetail
, 1, &kCFTypeArrayCallBacks
);
663 CFRelease(certDetail
);
664 SecPVCRef pvc
= &builder
->path
;
665 SecPVCSetPath(pvc
, path
, builder
->leafDetails
);
666 builder
->considerRejected
= !SecPVCLeafChecks(pvc
);
669 static void SecPathBuilderInit(SecPathBuilderRef builder
,
670 CFArrayRef certificates
, CFArrayRef anchors
, bool anchorsOnly
,
671 CFArrayRef policies
, CFAbsoluteTime verifyTime
, CFArrayRef accessGroups
,
672 SecPathBuilderCompleted completed
, const void *context
) {
673 secdebug("alloc", "%p", builder
);
674 CFAllocatorRef allocator
= kCFAllocatorDefault
;
676 builder
->queue
= dispatch_queue_create("builder", DISPATCH_QUEUE_SERIAL
);
678 builder
->nextParentSource
= 1;
679 builder
->considerPartials
= false;
680 builder
->canAccessNetwork
= true;
682 builder
->anchorSources
= CFArrayCreateMutable(allocator
, 0, NULL
);
683 builder
->parentSources
= CFArrayCreateMutable(allocator
, 0, NULL
);
684 builder
->allPaths
= CFSetCreateMutable(allocator
, 0,
685 &kCFTypeSetCallBacks
);
687 builder
->partialPaths
= CFArrayCreateMutable(allocator
, 0, NULL
);
688 builder
->rejectedPaths
= CFArrayCreateMutable(allocator
, 0, NULL
);
689 builder
->candidatePaths
= CFArrayCreateMutable(allocator
, 0, NULL
);
690 builder
->partialIX
= 0;
692 /* Init the policy verification context. */
693 SecPVCInit(&builder
->path
, builder
, policies
, verifyTime
);
694 builder
->bestPath
= NULL
;
695 builder
->bestPathIsEV
= false;
696 builder
->rejectScore
= 0;
698 /* Let's create all the certificate sources we might want to use. */
699 builder
->certificateSource
=
700 SecMemoryCertificateSourceCreate(certificates
);
702 builder
->anchorSource
= SecMemoryCertificateSourceCreate(anchors
);
704 builder
->anchorSource
= NULL
;
706 /* We always search certificateSource for parents since it includes the
707 leaf itself and it might be self signed. */
708 CFArrayAppendValue(builder
->parentSources
, builder
->certificateSource
);
709 if (builder
->anchorSource
) {
710 CFArrayAppendValue(builder
->anchorSources
, builder
->anchorSource
);
712 builder
->itemCertificateSource
= SecItemCertificateSourceCreate(accessGroups
);
713 CFArrayAppendValue(builder
->parentSources
, builder
->itemCertificateSource
);
715 /* Add the system and user anchor certificate db to the search list
716 if we don't explicitly trust them. */
717 CFArrayAppendValue(builder
->parentSources
, &kSecSystemAnchorSource
);
718 CFArrayAppendValue(builder
->parentSources
, &kSecUserAnchorSource
);
720 /* Only add the system and user anchor certificate db to the
721 anchorSources if we are supposed to trust them. */
722 CFArrayAppendValue(builder
->anchorSources
, &kSecSystemAnchorSource
);
723 CFArrayAppendValue(builder
->anchorSources
, &kSecUserAnchorSource
);
725 CFArrayAppendValue(builder
->parentSources
, &kSecCAIssuerSource
);
727 /* Now let's get the leaf cert and turn it into a path. */
728 SecCertificateRef leaf
=
729 (SecCertificateRef
)CFArrayGetValueAtIndex(certificates
, 0);
730 SecCertificatePathRef path
= SecCertificatePathCreate(NULL
, leaf
);
731 CFSetAddValue(builder
->allPaths
, path
);
732 CFArrayAppendValue(builder
->partialPaths
, path
);
733 if (SecPathBuilderIsAnchor(builder
, leaf
)) {
734 SecCertificatePathSetIsAnchored(path
);
735 CFArrayAppendValue(builder
->candidatePaths
, path
);
737 SecPathBuilderLeafCertificateChecks(builder
, path
);
740 builder
->activations
= 0;
741 builder
->state
= SecPathBuilderGetNext
;
742 builder
->completed
= completed
;
743 builder
->context
= context
;
746 SecPathBuilderRef
SecPathBuilderCreate(CFArrayRef certificates
,
747 CFArrayRef anchors
, bool anchorsOnly
, CFArrayRef policies
,
748 CFAbsoluteTime verifyTime
, CFArrayRef accessGroups
,
749 SecPathBuilderCompleted completed
, const void *context
) {
750 SecPathBuilderRef builder
= malloc(sizeof(*builder
));
751 SecPathBuilderInit(builder
, certificates
, anchors
, anchorsOnly
,
752 policies
, verifyTime
, accessGroups
, completed
, context
);
756 static void SecPathBuilderDestroy(SecPathBuilderRef builder
) {
757 secdebug("alloc", "%p", builder
);
758 dispatch_release_null(builder
->queue
);
759 if (builder
->anchorSource
)
760 SecMemoryCertificateSourceDestroy(builder
->anchorSource
);
761 if (builder
->certificateSource
)
762 SecMemoryCertificateSourceDestroy(builder
->certificateSource
);
763 if (builder
->itemCertificateSource
)
764 SecItemCertificateSourceDestroy(builder
->itemCertificateSource
);
765 CFReleaseSafe(builder
->anchorSources
);
766 CFReleaseSafe(builder
->parentSources
);
767 CFReleaseSafe(builder
->allPaths
);
768 CFReleaseSafe(builder
->partialPaths
);
769 CFReleaseSafe(builder
->rejectedPaths
);
770 CFReleaseSafe(builder
->candidatePaths
);
771 CFReleaseSafe(builder
->leafDetails
);
773 SecPVCDelete(&builder
->path
);
776 bool SecPathBuilderCanAccessNetwork(SecPathBuilderRef builder
) {
777 return builder
->canAccessNetwork
;
780 void SecPathBuilderSetCanAccessNetwork(SecPathBuilderRef builder
, bool allow
) {
781 if (builder
->canAccessNetwork
!= allow
) {
782 builder
->canAccessNetwork
= allow
;
784 secdebug("http", "network access re-enabled by policy");
785 /* re-enabling network_access re-adds kSecCAIssuerSource as
787 CFArrayAppendValue(builder
->parentSources
, &kSecCAIssuerSource
);
789 secdebug("http", "network access disabled by policy");
790 /* disabling network_access removes kSecCAIssuerSource from
791 the list of parent sources. */
792 CFIndex ix
= CFArrayGetFirstIndexOfValue(builder
->parentSources
,
793 CFRangeMake(0, CFArrayGetCount(builder
->parentSources
)),
794 &kSecCAIssuerSource
);
796 CFArrayRemoveValueAtIndex(builder
->parentSources
, ix
);
801 static bool SecPathBuilderIsAnchor(SecPathBuilderRef builder
,
802 SecCertificateRef certificate
) {
803 /* We always look through all anchor sources. */
804 CFIndex count
= CFArrayGetCount(builder
->anchorSources
);
806 for (ix
= 0; ix
< count
; ++ix
) {
807 SecCertificateSourceRef source
= (SecCertificateSourceRef
)
808 CFArrayGetValueAtIndex(builder
->anchorSources
, ix
);
809 if (SecCertificateSourceContains(source
, certificate
)) {
816 /* Return false if path is not a partial, if path was a valid candidate it
817 will have been added to builder->candidatePaths, if path was rejected
818 by the parent certificate checks (because it's expired or some other
819 static chaining check failed) it will have been added to rejectedPaths.
820 Return true path if path is a partial. */
821 static bool SecPathBuilderIsPartial(SecPathBuilderRef builder
,
822 SecCertificatePathRef path
) {
823 SecPVCRef pvc
= &builder
->path
;
824 SecPVCSetPath(pvc
, path
, NULL
);
826 if (!builder
->considerRejected
&& !SecPVCParentCertificateChecks(pvc
,
827 SecPVCGetCertificateCount(pvc
) - 1)) {
828 secdebug("trust", "Found rejected path %@", path
);
829 CFArrayAppendValue(builder
->rejectedPaths
, path
);
833 SecPathVerifyStatus vstatus
= SecCertificatePathVerify(path
);
834 /* Candidate paths with failed signatures are discarded. */
835 if (vstatus
== kSecPathVerifyFailed
) {
836 secdebug("trust", "Verify failed for path %@", path
);
840 if (vstatus
== kSecPathVerifySuccess
) {
841 /* The signature chain verified sucessfully, now let's find
842 out if we have an anchor for path. */
843 if (SecCertificatePathIsAnchored(path
)) {
844 secdebug("trust", "Adding candidate %@", path
);
845 CFArrayAppendValue(builder
->candidatePaths
, path
);
853 /* Given the builder, a partial chain partial and the parents array, construct
854 a SecCertificatePath for each parent. After discarding previously
855 considered paths and paths with cycles, sort out which array each path
856 should go in, if any. */
857 static void SecPathBuilderProccessParents(SecPathBuilderRef builder
,
858 SecCertificatePathRef partial
, CFArrayRef parents
) {
859 CFIndex rootIX
= SecCertificatePathGetCount(partial
) - 1;
860 CFIndex num_parents
= parents
? CFArrayGetCount(parents
) : 0;
862 bool is_anchor
= SecCertificatePathGetNextSourceIndex(partial
) <=
863 CFArrayGetCount(builder
->anchorSources
);
864 secdebug("trust", "found %" PRIdCFIndex
" candidate %s", num_parents
,
865 (is_anchor
? "anchors" : "parents"));
866 for (parentIX
= 0; parentIX
< num_parents
; ++parentIX
) {
867 SecCertificateRef parent
= (SecCertificateRef
)
868 CFArrayGetValueAtIndex(parents
, parentIX
);
869 CFIndex ixOfParent
= SecCertificatePathGetIndexOfCertificate(partial
,
871 if (ixOfParent
!= kCFNotFound
) {
872 /* partial already contains parent. Let's not add the same
873 certificate again. */
874 if (ixOfParent
== rootIX
) {
875 /* parent is equal to the root of the partial, so partial
876 looks to be self issued. */
877 SecCertificatePathSetSelfIssued(partial
);
882 /* FIXME Add more sanity checks to see that parent really can be
883 a parent of partial_root. subjectKeyID == authorityKeyID,
884 signature algorithm matches public key algorithm, etc. */
885 SecCertificatePathRef path
= SecCertificatePathCreate(partial
, parent
);
888 if (!CFSetContainsValue(builder
->allPaths
, path
)) {
889 CFSetAddValue(builder
->allPaths
, path
);
891 SecCertificatePathSetIsAnchored(path
);
892 if (SecPathBuilderIsPartial(builder
, path
)) {
893 /* Insert path right at the current position since it's a new
895 CFArrayInsertValueAtIndex(builder
->partialPaths
,
896 ++builder
->partialIX
, path
);
897 secdebug("trust", "Adding partial for parent %" PRIdCFIndex
"/%" PRIdCFIndex
" %@",
898 parentIX
+ 1, num_parents
, path
);
900 secdebug("trust", "found new path %@", path
);
906 /* Callback for the SecPathBuilderGetNext() functions call to
907 SecCertificateSourceCopyParents(). */
908 static void SecPathBuilderExtendPaths(void *context
, CFArrayRef parents
) {
909 SecPathBuilderRef builder
= (SecPathBuilderRef
)context
;
910 SecCertificatePathRef partial
= (SecCertificatePathRef
)
911 CFArrayGetValueAtIndex(builder
->partialPaths
, builder
->partialIX
);
912 secdebug("async", "%@ parents %@", partial
, parents
);
913 SecPathBuilderProccessParents(builder
, partial
, parents
);
915 builder
->state
= SecPathBuilderGetNext
;
916 SecPathBuilderStep(builder
);
919 static bool SecPathBuilderGetNext(SecPathBuilderRef builder
) {
920 /* If we have any candidates left to go return those first. */
921 if (CFArrayGetCount(builder
->candidatePaths
)) {
922 SecCertificatePathRef path
= (SecCertificatePathRef
)
923 CFArrayGetValueAtIndex(builder
->candidatePaths
, 0);
924 CFArrayRemoveValueAtIndex(builder
->candidatePaths
, 0);
925 secdebug("trust", "SecPathBuilderGetNext returning candidate %@",
927 SecPVCSetPath(&builder
->path
, path
, NULL
);
928 builder
->state
= SecPathBuilderValidatePath
;
932 /* If we are considering rejected chains we check each rejected path
933 with SecPathBuilderIsPartial() which checks the signature chain and
934 either drops the path if it's not properly signed, add it as a
935 candidate if it has a trusted anchor, or adds it as a partial
936 to be considered once we finish considering all the rejects. */
937 if (builder
->considerRejected
) {
938 CFIndex rejectedIX
= CFArrayGetCount(builder
->rejectedPaths
);
941 SecCertificatePathRef path
= (SecCertificatePathRef
)
942 CFArrayGetValueAtIndex(builder
->rejectedPaths
, rejectedIX
);
943 if (SecPathBuilderIsPartial(builder
, path
)) {
944 CFArrayInsertValueAtIndex(builder
->partialPaths
,
945 ++builder
->partialIX
, path
);
947 CFArrayRemoveValueAtIndex(builder
->rejectedPaths
, rejectedIX
);
949 /* Keep going until we have moved all rejected partials into
950 the regular partials or candidates array. */
955 /* If builder->partialIX is < 0 we have considered all partial chains
956 this block must ensure partialIX >= 0 if execution continues past
958 if (builder
->partialIX
< 0) {
959 CFIndex num_sources
= CFArrayGetCount(builder
->parentSources
);
960 if (builder
->nextParentSource
< num_sources
) {
961 builder
->nextParentSource
++;
962 secdebug("trust", "broading search to %" PRIdCFIndex
"/%" PRIdCFIndex
" sources",
963 builder
->nextParentSource
, num_sources
);
965 /* We've run out of new sources to consider so let's look at
966 rejected chains and after that even consider partials
968 FIXME we might not want to consider partial paths that
969 are subsets of other partial paths, or not consider them
970 at all if we already have an anchored reject. */
971 if (!builder
->considerRejected
) {
972 builder
->considerRejected
= true;
973 secdebug("trust", "considering rejected paths");
974 } else if (!builder
->considerPartials
) {
975 builder
->considerPartials
= true;
976 secdebug("trust", "considering partials");
978 /* We're all out of options, so we can't produce any more
979 candidates. Let's calculate details and return the best
981 builder
->state
= SecPathBuilderComputeDetails
;
985 builder
->partialIX
= CFArrayGetCount(builder
->partialPaths
) - 1;
986 secdebug("trust", "re-checking %" PRIdCFIndex
" partials", builder
->partialIX
+ 1);
990 /* We know builder->partialIX >= 0 if we get here. */
991 SecCertificatePathRef partial
= (SecCertificatePathRef
)
992 CFArrayGetValueAtIndex(builder
->partialPaths
, builder
->partialIX
);
993 /* Don't try to extend partials anymore once we are in the considerPartials
994 state, since at this point every partial has been extended with every
995 possible parentSource already. */
996 if (builder
->considerPartials
) {
997 --builder
->partialIX
;
998 SecPVCSetPath(&builder
->path
, partial
, NULL
);
999 builder
->state
= SecPathBuilderValidatePath
;
1003 /* Attempt to extend this partial path with another certificate. This
1004 should give us a list of potential parents to consider. */
1005 secdebug("trust", "looking for parents of partial %" PRIdCFIndex
"/%" PRIdCFIndex
": %@",
1006 builder
->partialIX
+ 1, CFArrayGetCount(builder
->partialPaths
),
1009 /* Attempt to extend partial, leaving all possible extended versions
1010 of partial in builder->extendedPaths. */
1011 CFIndex sourceIX
= SecCertificatePathGetNextSourceIndex(partial
);
1012 CFIndex num_anchor_sources
= CFArrayGetCount(builder
->anchorSources
);
1013 if (sourceIX
< num_anchor_sources
+ builder
->nextParentSource
) {
1014 SecCertificateSourceRef source
;
1015 if (sourceIX
< num_anchor_sources
) {
1016 source
= (SecCertificateSourceRef
)
1017 CFArrayGetValueAtIndex(builder
->anchorSources
, sourceIX
);
1018 secdebug("trust", "searching anchor source %" PRIdCFIndex
"/%" PRIdCFIndex
, sourceIX
+ 1,
1019 num_anchor_sources
);
1021 CFIndex parentIX
= sourceIX
- num_anchor_sources
;
1022 source
= (SecCertificateSourceRef
)
1023 CFArrayGetValueAtIndex(builder
->parentSources
, parentIX
);
1024 secdebug("trust", "searching parent source %" PRIdCFIndex
"/%" PRIdCFIndex
, parentIX
+ 1,
1025 builder
->nextParentSource
);
1027 SecCertificatePathSetNextSourceIndex(partial
, sourceIX
+ 1);
1028 SecCertificateRef root
= SecCertificatePathGetRoot(partial
);
1029 return SecCertificateSourceCopyParents(source
, root
,
1030 builder
, SecPathBuilderExtendPaths
);
1032 --builder
->partialIX
;
1038 /* One or more of the policies did not accept the candidate path. */
1039 static void SecPathBuilderReject(SecPathBuilderRef builder
) {
1041 SecPVCRef pvc
= &builder
->path
;
1043 builder
->state
= SecPathBuilderGetNext
;
1045 if (builder
->bestPathIsEV
&& !pvc
->is_ev
) {
1046 /* We never replace an ev reject with a non ev reject. */
1050 CFIndex rejectScore
= builder
->rejectScore
;
1051 CFIndex score
= SecCertificatePathScore(builder
->path
.path
,
1052 SecPVCGetVerifyTime(&builder
->path
));
1054 /* The current chain is valid for EV, but revocation checking failed. We
1055 replace any previously accepted or rejected non EV chains with the
1057 if (pvc
->is_ev
&& !builder
->bestPathIsEV
) {
1063 /* Since this means we found a valid ev chain that was revoked,
1064 we might want to switch directly to the
1065 SecPathBuilderComputeDetails state here if we think further
1066 searching for new chains is pointless. For now we'll keep
1067 going, since we could accept an alternate EV certification
1068 path that isn't revoked. */
1069 builder
->state
= SecPathBuilderComputeDetails
;
1073 /* Do this last so that changes to rejectScore above will take affect. */
1074 if (!builder
->bestPath
|| score
> rejectScore
) {
1075 if (builder
->bestPath
) {
1077 "replacing %sev %s score: %ld with %sev reject score: %" PRIdCFIndex
" %@",
1078 (builder
->bestPathIsEV
? "" : "non "),
1079 (builder
->rejectScore
== INTPTR_MAX
? "accept" : "reject"),
1080 builder
->rejectScore
,
1081 (pvc
->is_ev
? "" : "non "), (long)score
, builder
->path
.path
);
1083 secdebug("reject", "%sev reject score: %" PRIdCFIndex
" %@",
1084 (pvc
->is_ev
? "" : "non "), score
, builder
->path
.path
);
1087 builder
->rejectScore
= score
;
1088 builder
->bestPath
= pvc
->path
;
1089 builder
->bestPathIsEV
= pvc
->is_ev
;
1091 secdebug("reject", "%sev reject score: %" PRIdCFIndex
" lower than %" PRIdCFIndex
" %@",
1092 (pvc
->is_ev
? "" : "non "), score
, rejectScore
, builder
->path
.path
);
1096 /* All policies accepted the candidate path. */
1097 static void SecPathBuilderAccept(SecPathBuilderRef builder
) {
1099 SecPVCRef pvc
= &builder
->path
;
1100 if (pvc
->is_ev
|| !builder
->bestPathIsEV
) {
1101 secdebug("accept", "replacing %sev accept with %sev %@",
1102 (builder
->bestPathIsEV
? "" : "non "),
1103 (pvc
->is_ev
? "" : "non "), builder
->path
.path
);
1104 builder
->rejectScore
= INTPTR_MAX
; /* CFIndex is signed long which is INTPTR_T */
1105 builder
->bestPathIsEV
= pvc
->is_ev
;
1106 builder
->bestPath
= pvc
->path
;
1109 /* If we found the best accept we can we want to switch directly to the
1110 SecPathBuilderComputeDetails state here, since we're done. */
1111 if (pvc
->is_ev
|| !pvc
->optionally_ev
)
1112 builder
->state
= SecPathBuilderComputeDetails
;
1114 builder
->state
= SecPathBuilderGetNext
;
1117 /* Return true iff a given path satisfies all the specified policies at
1119 static bool SecPathBuilderValidatePath(SecPathBuilderRef builder
) {
1120 SecPVCRef pvc
= &builder
->path
;
1122 if (builder
->considerRejected
) {
1123 SecPathBuilderReject(builder
);
1127 builder
->state
= SecPathBuilderDidValidatePath
;
1128 return SecPVCPathChecks(pvc
);
1131 static bool SecPathBuilderDidValidatePath(SecPathBuilderRef builder
) {
1132 SecPVCRef pvc
= &builder
->path
;
1134 SecPathBuilderAccept(builder
);
1136 SecPathBuilderReject(builder
);
1138 assert(builder
->state
!= SecPathBuilderDidValidatePath
);
1142 static bool SecPathBuilderComputeDetails(SecPathBuilderRef builder
) {
1144 SecPVCRef pvc
= &builder
->path
;
1146 if (!builder
->caller_wants_details
) {
1147 SecPVCSetPath(pvc
, builder
->bestPath
, NULL
);
1148 pvc
->result
= builder
->rejectScore
== INTPTR_MAX
;
1149 builder
->state
= SecPathBuilderReportResult
;
1153 CFIndex ix
, pathLength
= SecCertificatePathGetCount(builder
->bestPath
);
1154 CFMutableArrayRef details
= CFArrayCreateMutableCopy(kCFAllocatorDefault
,
1155 pathLength
, builder
->leafDetails
);
1156 CFRetainSafe(details
);
1157 SecPVCSetPath(pvc
, builder
->bestPath
, details
);
1158 /* Only report on EV stuff if the bestPath actually was valid for EV. */
1159 pvc
->optionally_ev
= builder
->bestPathIsEV
;
1160 pvc
->info
= CFDictionaryCreateMutable(kCFAllocatorDefault
,
1161 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
1162 for (ix
= 1; ix
< pathLength
; ++ix
) {
1163 CFMutableDictionaryRef certDetail
= CFDictionaryCreateMutable(
1164 kCFAllocatorDefault
, 0, &kCFTypeDictionaryKeyCallBacks
,
1165 &kCFTypeDictionaryValueCallBacks
);
1166 CFArrayAppendValue(details
, certDetail
);
1167 CFRelease(certDetail
);
1168 SecPVCParentCertificateChecks(pvc
, ix
);
1169 SecPVCGrayListedKeyChecks(pvc
, ix
);
1170 SecPVCBlackListedKeyChecks(pvc
, ix
);
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;
1180 CFReleaseSafe(details
);
1185 static bool SecPathBuilderReportResult(SecPathBuilderRef builder
) {
1186 SecPVCRef pvc
= &builder
->path
;
1187 if (pvc
->info
&& pvc
->is_ev
&& pvc
->result
) {
1188 CFDictionarySetValue(pvc
->info
, kSecTrustInfoExtendedValidationKey
,
1190 SecCertificateRef leaf
= SecPVCGetCertificateAtIndex(pvc
, 0);
1191 CFStringRef leafCompanyName
= SecCertificateCopyCompanyName(leaf
);
1192 if (leafCompanyName
) {
1193 CFDictionarySetValue(pvc
->info
, kSecTrustInfoCompanyNameKey
,
1195 CFRelease(leafCompanyName
);
1198 CFAbsoluteTime nextUpdate
= SecPVCGetEarliestNextUpdate(pvc
);
1199 if (nextUpdate
== 0) {
1200 CFDictionarySetValue(pvc
->info
, kSecTrustInfoRevocationKey
,
1203 CFDateRef validUntil
= CFDateCreate(kCFAllocatorDefault
, nextUpdate
);
1204 CFDictionarySetValue(pvc
->info
, kSecTrustInfoRevocationValidUntilKey
,
1206 CFRelease(validUntil
);
1207 CFDictionarySetValue(pvc
->info
, kSecTrustInfoRevocationKey
,
1213 /* This will trigger the outer step function to call the completion
1215 builder
->state
= NULL
;
1219 /* @function SecPathBuilderStep
1220 @summary This is the core of the async engine.
1221 @description Return false iff job is complete, true if a network request
1223 builder->state is a function pointer which is to be invoked.
1224 If you call this function from within a builder->state invocation it
1225 immediately returns true.
1226 Otherwise the following steps are repeated endlessly (unless a step returns)
1227 builder->state is invoked. If it returns true and builder->state is still
1228 non NULL this proccess is repeated.
1229 If a state returns false, SecPathBuilder will return true
1230 if builder->state is non NULL.
1231 If builder->state is NULL then regardless of what the state function returns
1232 the completion callback will be invoked and the builder will be deallocated.
1234 bool SecPathBuilderStep(SecPathBuilderRef builder
) {
1235 if (builder
->activations
) {
1236 secdebug("async", "activations: %lu returning true",
1237 builder
->activations
);
1241 secdebug("async", "activations: %lu", builder
->activations
);
1242 builder
->activations
++;
1243 while (builder
->state
&& builder
->state(builder
));
1244 --builder
->activations
;
1246 if (builder
->state
) {
1247 secdebug("async", "waiting for async reply, exiting");
1248 /* A state returned false, it's waiting for network traffic. Let's
1253 if (builder
->activations
) {
1254 /* There is still at least one other running instance of this builder
1255 somewhere on the stack, we let that instance take care of sending
1256 the client a response. */
1260 SecTrustResultType result
= (builder
->rejectScore
== INTPTR_MAX
1261 ? kSecTrustResultUnspecified
: kSecTrustResultRecoverableTrustFailure
);
1263 secdebug("trust", "completed: %@ details: %@ result: %d",
1264 builder
->bestPath
, builder
->path
.details
, result
);
1266 if (builder
->completed
) {
1267 builder
->completed(builder
->context
, builder
->bestPath
,
1268 builder
->path
.details
, builder
->path
.info
, result
);
1271 /* Finally, destroy the builder and free it. */
1272 SecPathBuilderDestroy(builder
);
1278 dispatch_queue_t
SecPathBuilderGetQueue(SecPathBuilderRef builder
) {
1279 return builder
->queue
;
1283 // MARK: SecTrustServer
1284 /********************************************************
1285 ****************** SecTrustServer **********************
1286 ********************************************************/
1288 typedef void (^SecTrustServerEvaluationCompleted
)(SecTrustResultType tr
, CFArrayRef details
, CFDictionaryRef info
, SecCertificatePathRef chain
, CFErrorRef error
);
1291 SecTrustServerEvaluateCompleted(const void *userData
,
1292 SecCertificatePathRef chain
, CFArrayRef details
, CFDictionaryRef info
,
1293 SecTrustResultType result
) {
1294 SecTrustServerEvaluationCompleted evaluated
= (SecTrustServerEvaluationCompleted
)userData
;
1295 evaluated(result
, details
, info
, chain
, NULL
);
1296 Block_release(evaluated
);
1300 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
)) {
1301 SecTrustServerEvaluationCompleted userData
= Block_copy(evaluated
);
1302 /* Call the actual evaluator function. */
1303 SecPathBuilderRef builder
= SecPathBuilderCreate(certificates
, anchors
,
1304 anchorsOnly
, policies
,
1305 verifyTime
, accessGroups
,
1306 SecTrustServerEvaluateCompleted
, userData
);
1307 dispatch_async(builder
->queue
, ^{ SecPathBuilderStep(builder
); });
1311 // NO_SERVER Shim code only, xpc interface should call SecTrustServerEvaluateBlock() directly
1312 SecTrustResultType
SecTrustServerEvaluate(CFArrayRef certificates
, CFArrayRef anchors
, bool anchorsOnly
, CFArrayRef policies
, CFAbsoluteTime verifyTime
, __unused CFArrayRef accessGroups
, CFArrayRef
*pdetails
, CFDictionaryRef
*pinfo
, SecCertificatePathRef
*pchain
, CFErrorRef
*perror
) {
1313 dispatch_semaphore_t done
= dispatch_semaphore_create(0);
1314 __block SecTrustResultType result
= kSecTrustResultInvalid
;
1315 SecTrustServerEvaluateBlock(certificates
, anchors
, anchorsOnly
, policies
, verifyTime
, accessGroups
, ^(SecTrustResultType tr
, CFArrayRef details
, CFDictionaryRef info
, SecCertificatePathRef chain
, CFErrorRef error
) {
1317 if (tr
== kSecTrustResultInvalid
) {
1320 CFRetainSafe(error
);
1324 *pdetails
= details
;
1325 CFRetainSafe(details
);
1333 CFRetainSafe(chain
);
1336 dispatch_semaphore_signal(done
);
1338 dispatch_semaphore_wait(done
, DISPATCH_TIME_FOREVER
);