2 * Copyright (c) 2016-2017 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 * SecCertificateSource.c - certificate sources for trust evaluation engine
27 #include <CoreFoundation/CoreFoundation.h>
28 #include <AssertMacros.h>
30 #include <CommonCrypto/CommonDigest.h>
32 #include <Security/SecCertificate.h>
33 #include <Security/SecCertificatePriv.h>
34 #include <Security/SecItem.h>
35 #include <Security/SecItemInternal.h>
36 #include <Security/SecTrustSettingsPriv.h>
37 #include <Security/SecPolicyInternal.h>
38 #include <Security/SecPolicyPriv.h>
40 #include <utilities/debugging.h>
41 #include <utilities/SecCFWrappers.h>
43 #include <securityd/SecTrustServer.h>
44 #include <securityd/SecItemServer.h>
45 #include <securityd/SecTrustStoreServer.h>
46 #include <securityd/SecCAIssuerRequest.h>
48 #include "OTATrustUtilities.h"
49 #include "SecCertificateSource.h"
51 /********************************************************
52 ***************** OTA Trust support ********************
53 ********************************************************/
56 //#ifndef SECITEM_SHIM_OSX
58 static CFArrayRef
subject_to_anchors(CFDataRef nic
);
59 static CFArrayRef
CopyCertsFromIndices(CFArrayRef offsets
);
61 static CFArrayRef
subject_to_anchors(CFDataRef nic
)
63 CFArrayRef result
= NULL
;
70 SecOTAPKIRef otapkiref
= SecOTAPKICopyCurrentOTAPKIRef();
71 if (NULL
== otapkiref
)
76 CFDictionaryRef lookupTable
= SecOTAPKICopyAnchorLookupTable(otapkiref
);
79 if (NULL
== lookupTable
)
84 unsigned char subject_digest
[CC_SHA1_DIGEST_LENGTH
];
85 memset(subject_digest
, 0, CC_SHA1_DIGEST_LENGTH
);
87 (void)CC_SHA1(CFDataGetBytePtr(nic
), (CC_LONG
)CFDataGetLength(nic
), subject_digest
);
88 CFDataRef sha1Digest
= CFDataCreateWithBytesNoCopy(kCFAllocatorDefault
, subject_digest
, CC_SHA1_DIGEST_LENGTH
, kCFAllocatorNull
);
91 result
= (CFArrayRef
)CFDictionaryGetValue(lookupTable
, sha1Digest
);
92 CFReleaseSafe(lookupTable
);
93 CFReleaseSafe(sha1Digest
);
98 static CFArrayRef
CopyCertDataFromIndices(CFArrayRef offsets
)
100 CFMutableArrayRef result
= NULL
;
102 SecOTAPKIRef otapkiref
= SecOTAPKICopyCurrentOTAPKIRef();
103 if (NULL
== otapkiref
)
108 const char* anchorTable
= SecOTAPKIGetAnchorTable(otapkiref
);
109 if (NULL
== anchorTable
)
111 CFReleaseSafe(otapkiref
);
115 CFIndex num_offsets
= CFArrayGetCount(offsets
);
117 result
= CFArrayCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeArrayCallBacks
);
119 for (CFIndex idx
= 0; idx
< num_offsets
; idx
++)
121 CFNumberRef offset
= (CFNumberRef
)CFArrayGetValueAtIndex(offsets
, idx
);
122 uint32_t offset_value
= 0;
123 if (CFNumberGetValue(offset
, kCFNumberSInt32Type
, &offset_value
))
125 char* pDataPtr
= (char *)(anchorTable
+ offset_value
);
126 //int32_t record_length = *((int32_t * )pDataPtr);
127 //record_length = record_length;
128 pDataPtr
+= sizeof(uint32_t);
130 int32_t cert_data_length
= *((int32_t * )pDataPtr
);
131 pDataPtr
+= sizeof(uint32_t);
133 CFDataRef cert_data
= CFDataCreateWithBytesNoCopy(kCFAllocatorDefault
, (const UInt8
*)pDataPtr
,
134 cert_data_length
, kCFAllocatorNull
);
135 if (NULL
!= cert_data
)
137 CFArrayAppendValue(result
, cert_data
);
138 CFReleaseSafe(cert_data
);
142 CFReleaseSafe(otapkiref
);
146 static CFArrayRef
CopyCertsFromIndices(CFArrayRef offsets
)
148 CFMutableArrayRef result
= NULL
;
150 CFArrayRef cert_data_array
= CopyCertDataFromIndices(offsets
);
152 if (NULL
!= cert_data_array
)
154 result
= CFArrayCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeArrayCallBacks
);
155 CFIndex num_cert_datas
= CFArrayGetCount(cert_data_array
);
156 for (CFIndex idx
= 0; idx
< num_cert_datas
; idx
++)
158 CFDataRef cert_data
= (CFDataRef
)CFArrayGetValueAtIndex(cert_data_array
, idx
);
159 if (NULL
!= cert_data
)
161 SecCertificateRef cert
= SecCertificateCreateWithData(kCFAllocatorDefault
, cert_data
);
164 CFArrayAppendValue(result
, cert
);
169 CFRelease(cert_data_array
);
174 //#endif // SECITEM_SHIM_OSX
176 /********************************************************
177 *************** END OTA Trust support ******************
178 ********************************************************/
180 /********************************************************
181 ************ SecCertificateSource object ***************
182 ********************************************************/
184 bool SecCertificateSourceCopyParents(SecCertificateSourceRef source
,
185 SecCertificateRef certificate
,
186 void *context
, SecCertificateSourceParents callback
) {
187 return source
->copyParents(source
, certificate
, context
, callback
);
190 CFArrayRef
SecCertificateSourceCopyUsageConstraints(SecCertificateSourceRef source
,
191 SecCertificateRef certificate
) {
192 if (source
->copyUsageConstraints
) {
193 return source
->copyUsageConstraints(source
, certificate
);
199 bool SecCertificateSourceContains(SecCertificateSourceRef source
,
200 SecCertificateRef certificate
) {
201 return source
->contains(source
, certificate
);
205 // MARK: SecItemCertificateSource
206 /********************************************************
207 *********** SecItemCertificateSource object ************
208 ********************************************************/
209 struct SecItemCertificateSource
{
210 struct SecCertificateSource base
;
211 CFArrayRef accessGroups
;
213 typedef struct SecItemCertificateSource
*SecItemCertificateSourceRef
;
215 static CF_RETURNS_RETAINED CFArrayRef _Nullable
SecItemCertificateSourceResultsPost(CFTypeRef raw_results
) {
216 CFMutableArrayRef result
= NULL
;
217 if (isArray(raw_results
)) {
218 result
= CFArrayCreateMutable(kCFAllocatorDefault
, CFArrayGetCount(raw_results
), &kCFTypeArrayCallBacks
);
219 CFArrayForEach(raw_results
, ^(const void *value
) {
220 SecCertificateRef cert
= SecCertificateCreateWithData(kCFAllocatorDefault
, value
);
222 CFArrayAppendValue(result
, cert
);
226 } else if (isData(raw_results
)) {
227 result
= CFArrayCreateMutable(kCFAllocatorDefault
, CFArrayGetCount(raw_results
), &kCFTypeArrayCallBacks
);
228 SecCertificateRef cert
= SecCertificateCreateWithData(kCFAllocatorDefault
, (CFDataRef
)raw_results
);
230 CFArrayAppendValue(result
, cert
);
237 static bool SecItemCertificateSourceCopyParents(SecCertificateSourceRef source
, SecCertificateRef certificate
,
238 void *context
, SecCertificateSourceParents callback
) {
239 SecItemCertificateSourceRef msource
= (SecItemCertificateSourceRef
)source
;
240 CFDataRef normalizedIssuer
= SecCertificateGetNormalizedIssuerContent(certificate
);
242 CFErrorRef localError
= NULL
;
243 CFArrayRef results
= SecItemCopyParentCertificates_ios(normalizedIssuer
, msource
->accessGroups
, &localError
);
245 if (localError
&& (CFErrorGetCode(localError
) != errSecItemNotFound
)) {
246 secdebug("trust", "SecItemCopyParentCertificates_ios: %@", localError
);
248 CFReleaseSafe(localError
);
250 CFArrayRef certs
= SecItemCertificateSourceResultsPost(results
);
251 CFReleaseSafe(results
);
252 callback(context
, certs
);
253 CFReleaseSafe(certs
);
257 static bool SecItemCertificateSourceContains(SecCertificateSourceRef source
,
258 SecCertificateRef certificate
) {
259 SecItemCertificateSourceRef msource
= (SecItemCertificateSourceRef
)source
;
260 /* Look up a certificate by issuer and serial number. */
261 CFDataRef normalizedIssuer
= SecCertificateGetNormalizedIssuerContent(certificate
);
262 CFRetainSafe(normalizedIssuer
);
263 CFErrorRef localError
= NULL
;
264 CFDataRef serialNumber
= SecCertificateCopySerialNumberData(certificate
, &localError
);
265 bool result
= SecItemCertificateExists(normalizedIssuer
, serialNumber
, msource
->accessGroups
, &localError
);
267 if (CFErrorGetCode(localError
) != errSecItemNotFound
) {
268 secdebug("trust", "SecItemCertificateExists_ios: %@", localError
);
270 CFReleaseSafe(localError
);
272 CFReleaseSafe(serialNumber
);
273 CFReleaseSafe(normalizedIssuer
);
277 SecCertificateSourceRef
SecItemCertificateSourceCreate(CFArrayRef accessGroups
) {
278 SecItemCertificateSourceRef result
= (SecItemCertificateSourceRef
)malloc(sizeof(*result
));
279 result
->base
.copyParents
= SecItemCertificateSourceCopyParents
;
280 result
->base
.copyUsageConstraints
= NULL
;
281 result
->base
.contains
= SecItemCertificateSourceContains
;
282 result
->accessGroups
= accessGroups
;
283 CFRetainSafe(accessGroups
);
284 return (SecCertificateSourceRef
)result
;
287 void SecItemCertificateSourceDestroy(SecCertificateSourceRef source
) {
288 SecItemCertificateSourceRef msource
= (SecItemCertificateSourceRef
)source
;
289 CFReleaseSafe(msource
->accessGroups
);
294 // MARK: SecSystemAnchorSource
295 /********************************************************
296 *********** SecSystemAnchorSource object ************
297 ********************************************************/
299 static bool SecSystemAnchorSourceCopyParents(SecCertificateSourceRef source
, SecCertificateRef certificate
,
300 void *context
, SecCertificateSourceParents callback
) {
301 //#ifndef SECITEM_SHIM_OSX
302 CFArrayRef parents
= NULL
;
303 CFArrayRef anchors
= NULL
;
304 SecOTAPKIRef otapkiref
= NULL
;
306 CFDataRef nic
= SecCertificateGetNormalizedIssuerContent(certificate
);
307 /* 64 bits cast: the worst that can happen here is we truncate the length and match an actual anchor.
308 It does not matter since we would be returning the wrong anchors */
309 assert((unsigned long)CFDataGetLength(nic
)<UINT_MAX
); /* Debug check. correct as long as CFIndex is signed long */
311 otapkiref
= SecOTAPKICopyCurrentOTAPKIRef();
312 require_quiet(otapkiref
, errOut
);
313 anchors
= subject_to_anchors(nic
);
314 require_quiet(anchors
, errOut
);
315 parents
= CopyCertsFromIndices(anchors
);
318 callback(context
, parents
);
319 CFReleaseSafe(parents
);
320 CFReleaseSafe(otapkiref
);
321 //#endif // SECITEM_SHIM_OSX
325 static CFArrayRef
SecSystemAnchorSourceCopyUsageConstraints(SecCertificateSourceRef __unused source
,
326 SecCertificateRef __unused certificate
)
328 CFMutableArrayRef result
= NULL
;
329 CFMutableDictionaryRef options
= NULL
, strengthConstraints
= NULL
, trustRoot
= NULL
;
330 CFNumberRef trustResult
= NULL
;
332 require_quiet(options
= CFDictionaryCreateMutable(NULL
, 1,
333 &kCFTypeDictionaryKeyCallBacks
,
334 &kCFTypeDictionaryValueCallBacks
),
336 require_quiet(strengthConstraints
= CFDictionaryCreateMutable(NULL
, 1,
337 &kCFTypeDictionaryKeyCallBacks
,
338 &kCFTypeDictionaryValueCallBacks
),
340 require_quiet(trustRoot
= CFDictionaryCreateMutable(NULL
, 1,
341 &kCFTypeDictionaryKeyCallBacks
,
342 &kCFTypeDictionaryValueCallBacks
),
345 uint32_t temp
= kSecTrustSettingsResultTrustRoot
;
346 require_quiet(trustResult
= CFNumberCreate(NULL
, kCFNumberSInt32Type
, &temp
), out
);
347 CFDictionaryAddValue(trustRoot
, kSecTrustSettingsResult
, trustResult
);
349 CFDictionaryAddValue(options
, kSecPolicyCheckSystemTrustedWeakHash
, kCFBooleanTrue
);
350 CFDictionaryAddValue(options
, kSecPolicyCheckSystemTrustedWeakKey
, kCFBooleanTrue
);
351 CFDictionaryAddValue(strengthConstraints
, kSecTrustSettingsPolicyOptions
, options
);
353 require_quiet(result
= CFArrayCreateMutable(NULL
, 2, &kCFTypeArrayCallBacks
), out
);
354 CFArrayAppendValue(result
, strengthConstraints
);
355 CFArrayAppendValue(result
, trustRoot
);
358 CFReleaseNull(options
);
359 CFReleaseNull(trustResult
);
360 CFReleaseNull(trustRoot
);
361 CFReleaseNull(strengthConstraints
);
365 static bool SecSystemAnchorSourceContains(SecCertificateSourceRef source
,
366 SecCertificateRef certificate
) {
368 CFArrayRef anchors
= NULL
;
369 SecOTAPKIRef otapkiref
= NULL
;
370 CFArrayRef cert_datas
= NULL
;
372 CFDataRef nic
= SecCertificateGetNormalizedSubjectContent(certificate
);
373 /* 64 bits cast: the worst that can happen here is we truncate the length and match an actual anchor.
374 It does not matter since we would be returning the wrong anchors */
375 assert((unsigned long)CFDataGetLength(nic
)<UINT_MAX
); /* Debug check. correct as long as CFIndex is signed long */
377 otapkiref
= SecOTAPKICopyCurrentOTAPKIRef();
378 require_quiet(otapkiref
, errOut
);
379 anchors
= subject_to_anchors(nic
);
380 require_quiet(anchors
, errOut
);
381 cert_datas
= CopyCertDataFromIndices(anchors
);
382 require_quiet(cert_datas
, errOut
);
384 CFIndex cert_length
= SecCertificateGetLength(certificate
);
385 const UInt8
*cert_data_ptr
= SecCertificateGetBytePtr(certificate
);
387 CFIndex num_cert_datas
= CFArrayGetCount(cert_datas
);
388 for (CFIndex idx
= 0; idx
< num_cert_datas
; idx
++)
390 CFDataRef cert_data
= (CFDataRef
)CFArrayGetValueAtIndex(cert_datas
, idx
);
392 if (NULL
!= cert_data
)
394 if (CFGetTypeID(cert_data
) == CFDataGetTypeID())
396 CFIndex aCert_Length
= CFDataGetLength(cert_data
);
397 const UInt8
* aCert_Data_Ptr
= CFDataGetBytePtr(cert_data
);
399 if (aCert_Length
== cert_length
)
401 if (!memcmp(cert_data_ptr
, aCert_Data_Ptr
, cert_length
))
412 CFReleaseSafe(cert_datas
);
413 CFReleaseSafe(otapkiref
);
417 struct SecCertificateSource _kSecSystemAnchorSource
= {
418 SecSystemAnchorSourceCopyParents
,
419 SecSystemAnchorSourceCopyUsageConstraints
,
420 SecSystemAnchorSourceContains
423 const SecCertificateSourceRef kSecSystemAnchorSource
= &_kSecSystemAnchorSource
;
428 // MARK: SecUserAnchorSource
429 /********************************************************
430 ************* SecUserAnchorSource object ***************
431 ********************************************************/
432 static bool SecUserAnchorSourceCopyParents(SecCertificateSourceRef source
, SecCertificateRef certificate
,
433 void *context
, SecCertificateSourceParents callback
) {
434 CFArrayRef parents
= SecTrustStoreCopyParents(SecTrustStoreForDomain(kSecTrustStoreDomainUser
),
436 callback(context
, parents
);
437 CFReleaseSafe(parents
);
441 static CFArrayRef
SecUserAnchorSourceCopyUsageConstraints(SecCertificateSourceRef source
,
442 SecCertificateRef certificate
) {
443 CFDataRef digest
= SecCertificateGetSHA1Digest(certificate
);
446 CFArrayRef usageConstraints
= NULL
;
447 bool ok
= _SecTrustStoreCopyUsageConstraints(SecTrustStoreForDomain(kSecTrustStoreDomainUser
),
448 digest
, &usageConstraints
, NULL
);
450 return usageConstraints
;
452 CFReleaseNull(usageConstraints
);
457 static bool SecUserAnchorSourceContains(SecCertificateSourceRef source
,
458 SecCertificateRef certificate
) {
459 return SecTrustStoreContains(SecTrustStoreForDomain(kSecTrustStoreDomainUser
),
463 struct SecCertificateSource _kSecUserAnchorSource
= {
464 SecUserAnchorSourceCopyParents
,
465 SecUserAnchorSourceCopyUsageConstraints
,
466 SecUserAnchorSourceContains
469 const SecCertificateSourceRef kSecUserAnchorSource
= &_kSecUserAnchorSource
;
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(SecCertificateSourceRef source
, SecCertificateRef certificate
,
485 void *context
, SecCertificateSourceParents callback
) {
486 SecMemoryCertificateSourceRef msource
=
487 (SecMemoryCertificateSourceRef
)source
;
488 CFDataRef normalizedIssuer
=
489 SecCertificateGetNormalizedIssuerContent(certificate
);
490 CFArrayRef parents
= (normalizedIssuer
) ? CFDictionaryGetValue(msource
->subjects
,
491 normalizedIssuer
) : NULL
;
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
, void *context
) {
525 SecMemoryCertificateSourceRef msource
=
526 (SecMemoryCertificateSourceRef
)context
;
527 SecCertificateRef certificate
= (SecCertificateRef
)value
;
529 /* CFSet's API has no way to combine these 2 operations into 1 sadly. */
530 if (CFSetContainsValue(msource
->certificates
, certificate
))
532 CFSetAddValue(msource
->certificates
, certificate
);
534 CFDataRef key
= SecCertificateGetNormalizedSubjectContent(certificate
);
535 dictAddValueToArrayForKey(msource
->subjects
, key
, value
);
538 SecCertificateSourceRef
SecMemoryCertificateSourceCreate(CFArrayRef certificates
) {
539 SecMemoryCertificateSourceRef result
= (SecMemoryCertificateSourceRef
)
540 malloc(sizeof(*result
));
541 result
->base
.copyParents
= SecMemoryCertificateSourceCopyParents
;
542 result
->base
.copyUsageConstraints
= NULL
;
543 result
->base
.contains
= SecMemoryCertificateSourceContains
;
544 CFIndex count
= CFArrayGetCount(certificates
);
545 result
->certificates
= CFSetCreateMutable(kCFAllocatorDefault
, count
,
546 &kCFTypeSetCallBacks
);
547 result
->subjects
= CFDictionaryCreateMutable(kCFAllocatorDefault
,
548 count
, &kCFTypeDictionaryKeyCallBacks
,
549 &kCFTypeDictionaryValueCallBacks
);
550 CFRange range
= { 0, count
};
551 CFArrayApplyFunction(certificates
, range
,
552 SecMemoryCertificateSourceApplierFunction
, result
);
554 return (SecCertificateSourceRef
)result
;
557 void SecMemoryCertificateSourceDestroy(SecCertificateSourceRef source
) {
558 SecMemoryCertificateSourceRef msource
=
559 (SecMemoryCertificateSourceRef
)source
;
560 CFRelease(msource
->certificates
);
561 CFRelease(msource
->subjects
);
566 // MARK: SecCAIssuerCertificateSource
567 /********************************************************
568 ********* SecCAIssuerCertificateSource object **********
569 ********************************************************/
570 static bool SecCAIssuerCertificateSourceCopyParents(SecCertificateSourceRef source
, SecCertificateRef certificate
,
571 void *context
, SecCertificateSourceParents callback
) {
572 /* Some expired certs have dead domains. Let's not check them. */
573 SecPathBuilderRef builder
= (SecPathBuilderRef
)context
;
574 CFAbsoluteTime verifyDate
= SecPathBuilderGetVerifyTime(builder
);
575 if (SecPathBuilderHasTemporalParentChecks(builder
) && !SecCertificateIsValid(certificate
, verifyDate
)) {
576 secinfo("async", "skipping CAIssuer fetch for expired %@", certificate
);
577 callback(context
, NULL
);
580 return SecCAIssuerCopyParents(certificate
, context
, callback
);
583 static bool SecCAIssuerCertificateSourceContains(SecCertificateSourceRef source
, SecCertificateRef certificate
) {
587 struct SecCertificateSource _kSecCAIssuerSource
= {
588 SecCAIssuerCertificateSourceCopyParents
,
590 SecCAIssuerCertificateSourceContains
593 const SecCertificateSourceRef kSecCAIssuerSource
= &_kSecCAIssuerSource
;
596 #include <Security/SecItemPriv.h>
598 // MARK: SecLegacyCertificateSource
599 /********************************************************
600 ********** SecLegacyCertificateSource object ***********
601 ********************************************************/
603 static bool SecLegacyCertificateSourceCopyParents(SecCertificateSourceRef source
, SecCertificateRef certificate
,
604 void *context
, SecCertificateSourceParents callback
) {
605 CFArrayRef parents
= SecItemCopyParentCertificates_osx(certificate
, NULL
);
606 callback(context
, parents
);
607 CFReleaseSafe(parents
);
611 static bool SecLegacyCertificateSourceContains(SecCertificateSourceRef source
, SecCertificateRef certificate
) {
612 SecCertificateRef cert
= SecItemCopyStoredCertificate(certificate
, NULL
);
613 bool result
= (cert
) ? true : false;
618 struct SecCertificateSource _kSecLegacyCertificateSource
= {
619 SecLegacyCertificateSourceCopyParents
,
621 SecLegacyCertificateSourceContains
624 const SecCertificateSourceRef kSecLegacyCertificateSource
= &_kSecLegacyCertificateSource
;
626 #endif /* SecLegacyCertificateSource */
630 // MARK: SecLegacyAnchorSource
631 /********************************************************
632 ************ SecLegacyAnchorSource object **************
633 ********************************************************/
635 static bool SecLegacyAnchorSourceCopyParents(SecCertificateSourceRef source
, SecCertificateRef certificate
,
636 void *context
, SecCertificateSourceParents callback
) {
637 CFMutableArrayRef anchors
= CFArrayCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeArrayCallBacks
);
638 CFArrayRef parents
= SecItemCopyParentCertificates_osx(certificate
, NULL
);
639 CFArrayRef trusted
= NULL
;
640 if (parents
== NULL
) {
643 /* Get the custom anchors which have been trusted in the user and admin domains.
644 * We don't need system domain roots here, since SecSystemAnchorSource provides those.
646 OSStatus status
= SecTrustSettingsCopyCertificatesForUserAdminDomains(&trusted
);
647 if (status
== errSecSuccess
&& trusted
) {
648 CFIndex index
, count
= CFArrayGetCount(parents
);
649 for (index
= 0; index
< count
; index
++) {
650 SecCertificateRef parent
= (SecCertificateRef
)CFArrayGetValueAtIndex(parents
, index
);
651 if (parent
&& CFArrayContainsValue(trusted
, CFRangeMake(0, CFArrayGetCount(trusted
)), parent
)) {
652 CFArrayAppendValue(anchors
, parent
);
658 callback(context
, anchors
);
659 CFReleaseSafe(anchors
);
660 CFReleaseSafe(parents
);
661 CFReleaseSafe(trusted
);
665 static CFArrayRef
SecLegacyAnchorSourceCopyUsageConstraints(SecCertificateSourceRef source
,
666 SecCertificateRef certificate
) {
667 CFArrayRef result
= NULL
;
668 CFArrayRef userTrustSettings
= NULL
, adminTrustSettings
= NULL
;
670 OSStatus status
= SecTrustSettingsCopyTrustSettings(certificate
,
671 kSecTrustSettingsDomainUser
,
673 if ((status
== errSecSuccess
) && (userTrustSettings
!= NULL
)) {
674 result
= CFRetain(userTrustSettings
);
677 status
= SecTrustSettingsCopyTrustSettings(certificate
,
678 kSecTrustSettingsDomainAdmin
,
679 &adminTrustSettings
);
680 /* user trust settings overrule admin trust settings */
681 if ((status
== errSecSuccess
) && (adminTrustSettings
!= NULL
) && (result
== NULL
)) {
682 result
= CFRetain(adminTrustSettings
);
685 CFReleaseNull(userTrustSettings
);
686 CFReleaseNull(adminTrustSettings
);
690 static bool SecLegacyAnchorSourceContains(SecCertificateSourceRef source
,
691 SecCertificateRef certificate
) {
692 if (certificate
== NULL
) {
695 CFArrayRef trusted
= NULL
;
697 OSStatus status
= SecTrustSettingsCopyCertificatesForUserAdminDomains(&trusted
);
698 if ((status
== errSecSuccess
) && (trusted
!= NULL
)) {
699 CFIndex index
, count
= CFArrayGetCount(trusted
);
700 for (index
= 0; index
< count
; index
++) {
701 SecCertificateRef anchor
= (SecCertificateRef
)CFArrayGetValueAtIndex(trusted
, index
);
702 if (anchor
&& CFEqual(anchor
, certificate
)) {
708 CFReleaseSafe(trusted
);
712 struct SecCertificateSource _kSecLegacyAnchorSource
= {
713 SecLegacyAnchorSourceCopyParents
,
714 SecLegacyAnchorSourceCopyUsageConstraints
,
715 SecLegacyAnchorSourceContains
718 const SecCertificateSourceRef kSecLegacyAnchorSource
= &_kSecLegacyAnchorSource
;
720 #endif /* SecLegacyAnchorSource */