2 * Copyright (c) 2016 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>
39 #include <utilities/debugging.h>
40 #include <utilities/SecCFWrappers.h>
42 #include <securityd/SecTrustServer.h>
43 #include <securityd/SecItemServer.h>
44 #include <securityd/SecTrustStoreServer.h>
45 #include <securityd/SecCAIssuerRequest.h>
47 #include "OTATrustUtilities.h"
48 #include "SecCertificateSource.h"
50 /********************************************************
51 ***************** OTA Trust support ********************
52 ********************************************************/
55 //#ifndef SECITEM_SHIM_OSX
57 static CFArrayRef
subject_to_anchors(CFDataRef nic
);
58 static CFArrayRef
CopyCertsFromIndices(CFArrayRef offsets
);
60 static CFArrayRef
subject_to_anchors(CFDataRef nic
)
62 CFArrayRef result
= NULL
;
69 SecOTAPKIRef otapkiref
= SecOTAPKICopyCurrentOTAPKIRef();
70 if (NULL
== otapkiref
)
75 CFDictionaryRef lookupTable
= SecOTAPKICopyAnchorLookupTable(otapkiref
);
78 if (NULL
== lookupTable
)
83 unsigned char subject_digest
[CC_SHA1_DIGEST_LENGTH
];
84 memset(subject_digest
, 0, CC_SHA1_DIGEST_LENGTH
);
86 (void)CC_SHA1(CFDataGetBytePtr(nic
), (CC_LONG
)CFDataGetLength(nic
), subject_digest
);
87 CFDataRef sha1Digest
= CFDataCreateWithBytesNoCopy(kCFAllocatorDefault
, subject_digest
, CC_SHA1_DIGEST_LENGTH
, kCFAllocatorNull
);
90 result
= (CFArrayRef
)CFDictionaryGetValue(lookupTable
, sha1Digest
);
91 CFReleaseSafe(lookupTable
);
92 CFReleaseSafe(sha1Digest
);
97 static CFArrayRef
CopyCertDataFromIndices(CFArrayRef offsets
)
99 CFMutableArrayRef result
= NULL
;
101 SecOTAPKIRef otapkiref
= SecOTAPKICopyCurrentOTAPKIRef();
102 if (NULL
== otapkiref
)
107 const char* anchorTable
= SecOTAPKIGetAnchorTable(otapkiref
);
108 if (NULL
== anchorTable
)
110 CFReleaseSafe(otapkiref
);
114 CFIndex num_offsets
= CFArrayGetCount(offsets
);
116 result
= CFArrayCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeArrayCallBacks
);
118 for (CFIndex idx
= 0; idx
< num_offsets
; idx
++)
120 CFNumberRef offset
= (CFNumberRef
)CFArrayGetValueAtIndex(offsets
, idx
);
121 uint32_t offset_value
= 0;
122 if (CFNumberGetValue(offset
, kCFNumberSInt32Type
, &offset_value
))
124 char* pDataPtr
= (char *)(anchorTable
+ offset_value
);
125 //int32_t record_length = *((int32_t * )pDataPtr);
126 //record_length = record_length;
127 pDataPtr
+= sizeof(uint32_t);
129 int32_t cert_data_length
= *((int32_t * )pDataPtr
);
130 pDataPtr
+= sizeof(uint32_t);
132 CFDataRef cert_data
= CFDataCreateWithBytesNoCopy(kCFAllocatorDefault
, (const UInt8
*)pDataPtr
,
133 cert_data_length
, kCFAllocatorNull
);
134 if (NULL
!= cert_data
)
136 CFArrayAppendValue(result
, cert_data
);
137 CFReleaseSafe(cert_data
);
141 CFReleaseSafe(otapkiref
);
145 static CFArrayRef
CopyCertsFromIndices(CFArrayRef offsets
)
147 CFMutableArrayRef result
= NULL
;
149 CFArrayRef cert_data_array
= CopyCertDataFromIndices(offsets
);
151 if (NULL
!= cert_data_array
)
153 result
= CFArrayCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeArrayCallBacks
);
154 CFIndex num_cert_datas
= CFArrayGetCount(cert_data_array
);
155 for (CFIndex idx
= 0; idx
< num_cert_datas
; idx
++)
157 CFDataRef cert_data
= (CFDataRef
)CFArrayGetValueAtIndex(cert_data_array
, idx
);
158 if (NULL
!= cert_data
)
160 SecCertificateRef cert
= SecCertificateCreateWithData(kCFAllocatorDefault
, cert_data
);
163 CFArrayAppendValue(result
, cert
);
168 CFRelease(cert_data_array
);
173 //#endif // SECITEM_SHIM_OSX
175 /********************************************************
176 *************** END OTA Trust support ******************
177 ********************************************************/
179 /********************************************************
180 ************ SecCertificateSource object ***************
181 ********************************************************/
183 bool SecCertificateSourceCopyParents(SecCertificateSourceRef source
,
184 SecCertificateRef certificate
,
185 void *context
, SecCertificateSourceParents callback
) {
186 return source
->copyParents(source
, certificate
, context
, callback
);
189 CFArrayRef
SecCertificateSourceCopyUsageConstraints(SecCertificateSourceRef source
,
190 SecCertificateRef certificate
) {
191 if (source
->copyUsageConstraints
) {
192 return source
->copyUsageConstraints(source
, certificate
);
198 bool SecCertificateSourceContains(SecCertificateSourceRef source
,
199 SecCertificateRef certificate
) {
200 return source
->contains(source
, certificate
);
204 // MARK: SecItemCertificateSource
205 /********************************************************
206 *********** SecItemCertificateSource object ************
207 ********************************************************/
208 struct SecItemCertificateSource
{
209 struct SecCertificateSource base
;
210 CFArrayRef accessGroups
;
212 typedef struct SecItemCertificateSource
*SecItemCertificateSourceRef
;
214 static CF_RETURNS_RETAINED CFArrayRef _Nullable
SecItemCertificateSourceResultsPost(CFTypeRef raw_results
) {
215 CFMutableArrayRef result
= NULL
;
216 if (isArray(raw_results
)) {
217 result
= CFArrayCreateMutable(kCFAllocatorDefault
, CFArrayGetCount(raw_results
), &kCFTypeArrayCallBacks
);
218 CFArrayForEach(raw_results
, ^(const void *value
) {
219 SecCertificateRef cert
= SecCertificateCreateWithData(kCFAllocatorDefault
, value
);
221 CFArrayAppendValue(result
, cert
);
225 } else if (isData(raw_results
)) {
226 result
= CFArrayCreateMutable(kCFAllocatorDefault
, CFArrayGetCount(raw_results
), &kCFTypeArrayCallBacks
);
227 SecCertificateRef cert
= SecCertificateCreateWithData(kCFAllocatorDefault
, (CFDataRef
)raw_results
);
229 CFArrayAppendValue(result
, cert
);
236 static bool SecItemCertificateSourceCopyParents(
237 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 CFDataRef serialNumber
=
264 #if (TARGET_OS_MAC && !(TARGET_OS_EMBEDDED || TARGET_OS_IPHONE))
265 SecCertificateCopySerialNumber(certificate
, NULL
);
267 SecCertificateCopySerialNumber(certificate
);
269 CFErrorRef localError
= NULL
;
270 bool result
= SecItemCertificateExists(normalizedIssuer
, serialNumber
, msource
->accessGroups
, &localError
);
272 if (CFErrorGetCode(localError
) != errSecItemNotFound
) {
273 secdebug("trust", "SecItemCertificateExists_ios: %@", localError
);
275 CFReleaseSafe(localError
);
277 CFReleaseSafe(serialNumber
);
278 CFReleaseSafe(normalizedIssuer
);
282 SecCertificateSourceRef
SecItemCertificateSourceCreate(CFArrayRef accessGroups
) {
283 SecItemCertificateSourceRef result
= (SecItemCertificateSourceRef
)malloc(sizeof(*result
));
284 result
->base
.copyParents
= SecItemCertificateSourceCopyParents
;
285 result
->base
.copyUsageConstraints
= NULL
;
286 result
->base
.contains
= SecItemCertificateSourceContains
;
287 result
->accessGroups
= accessGroups
;
288 CFRetainSafe(accessGroups
);
289 return (SecCertificateSourceRef
)result
;
292 void SecItemCertificateSourceDestroy(SecCertificateSourceRef source
) {
293 SecItemCertificateSourceRef msource
= (SecItemCertificateSourceRef
)source
;
294 CFReleaseSafe(msource
->accessGroups
);
299 // MARK: SecSystemAnchorSource
300 /********************************************************
301 *********** SecSystemAnchorSource object ************
302 ********************************************************/
304 static bool SecSystemAnchorSourceCopyParents(
305 SecCertificateSourceRef source
, SecCertificateRef certificate
,
306 void *context
, SecCertificateSourceParents callback
) {
307 //#ifndef SECITEM_SHIM_OSX
308 CFArrayRef parents
= NULL
;
309 CFArrayRef anchors
= NULL
;
310 SecOTAPKIRef otapkiref
= NULL
;
312 CFDataRef nic
= SecCertificateGetNormalizedIssuerContent(certificate
);
313 /* 64 bits cast: the worst that can happen here is we truncate the length and match an actual anchor.
314 It does not matter since we would be returning the wrong anchors */
315 assert((unsigned long)CFDataGetLength(nic
)<UINT_MAX
); /* Debug check. correct as long as CFIndex is signed long */
317 otapkiref
= SecOTAPKICopyCurrentOTAPKIRef();
318 require_quiet(otapkiref
, errOut
);
319 anchors
= subject_to_anchors(nic
);
320 require_quiet(anchors
, errOut
);
321 parents
= CopyCertsFromIndices(anchors
);
324 callback(context
, parents
);
325 CFReleaseSafe(parents
);
326 CFReleaseSafe(otapkiref
);
327 //#endif // SECITEM_SHIM_OSX
331 static CFArrayRef
SecSystemAnchorSourceCopyUsageConstraints(SecCertificateSourceRef __unused source
,
332 SecCertificateRef __unused certificate
)
334 CFMutableArrayRef result
= NULL
;
335 CFMutableDictionaryRef options
= NULL
, strengthConstraints
= NULL
, trustRoot
= NULL
;
336 CFNumberRef trustResult
= NULL
;
338 require_quiet(options
= CFDictionaryCreateMutable(NULL
, 1,
339 &kCFTypeDictionaryKeyCallBacks
,
340 &kCFTypeDictionaryValueCallBacks
),
342 require_quiet(strengthConstraints
= CFDictionaryCreateMutable(NULL
, 1,
343 &kCFTypeDictionaryKeyCallBacks
,
344 &kCFTypeDictionaryValueCallBacks
),
346 require_quiet(trustRoot
= CFDictionaryCreateMutable(NULL
, 1,
347 &kCFTypeDictionaryKeyCallBacks
,
348 &kCFTypeDictionaryValueCallBacks
),
351 uint32_t temp
= kSecTrustSettingsResultTrustRoot
;
352 require_quiet(trustResult
= CFNumberCreate(NULL
, kCFNumberSInt32Type
, &temp
), out
);
353 CFDictionaryAddValue(trustRoot
, kSecTrustSettingsResult
, trustResult
);
355 CFDictionaryAddValue(options
, kSecPolicyCheckSystemTrustedWeakHash
, kCFBooleanTrue
);
356 CFDictionaryAddValue(options
, kSecPolicyCheckSystemTrustedWeakKey
, kCFBooleanTrue
);
357 CFDictionaryAddValue(strengthConstraints
, kSecTrustSettingsPolicyOptions
, options
);
359 require_quiet(result
= CFArrayCreateMutable(NULL
, 2, &kCFTypeArrayCallBacks
), out
);
360 CFArrayAppendValue(result
, strengthConstraints
);
361 CFArrayAppendValue(result
, trustRoot
);
364 CFReleaseNull(options
);
365 CFReleaseNull(trustResult
);
366 CFReleaseNull(trustRoot
);
367 CFReleaseNull(strengthConstraints
);
371 static bool SecSystemAnchorSourceContains(SecCertificateSourceRef source
,
372 SecCertificateRef certificate
) {
374 CFArrayRef anchors
= NULL
;
375 SecOTAPKIRef otapkiref
= NULL
;
376 CFArrayRef cert_datas
= NULL
;
378 CFDataRef nic
= SecCertificateGetNormalizedSubjectContent(certificate
);
379 /* 64 bits cast: the worst that can happen here is we truncate the length and match an actual anchor.
380 It does not matter since we would be returning the wrong anchors */
381 assert((unsigned long)CFDataGetLength(nic
)<UINT_MAX
); /* Debug check. correct as long as CFIndex is signed long */
383 otapkiref
= SecOTAPKICopyCurrentOTAPKIRef();
384 require_quiet(otapkiref
, errOut
);
385 anchors
= subject_to_anchors(nic
);
386 require_quiet(anchors
, errOut
);
387 cert_datas
= CopyCertDataFromIndices(anchors
);
388 require_quiet(cert_datas
, errOut
);
390 CFIndex cert_length
= SecCertificateGetLength(certificate
);
391 const UInt8
*cert_data_ptr
= SecCertificateGetBytePtr(certificate
);
393 CFIndex num_cert_datas
= CFArrayGetCount(cert_datas
);
394 for (CFIndex idx
= 0; idx
< num_cert_datas
; idx
++)
396 CFDataRef cert_data
= (CFDataRef
)CFArrayGetValueAtIndex(cert_datas
, idx
);
398 if (NULL
!= cert_data
)
400 if (CFGetTypeID(cert_data
) == CFDataGetTypeID())
402 CFIndex aCert_Length
= CFDataGetLength(cert_data
);
403 const UInt8
* aCert_Data_Ptr
= CFDataGetBytePtr(cert_data
);
405 if (aCert_Length
== cert_length
)
407 if (!memcmp(cert_data_ptr
, aCert_Data_Ptr
, cert_length
))
418 CFReleaseSafe(cert_datas
);
419 CFReleaseSafe(otapkiref
);
423 struct SecCertificateSource _kSecSystemAnchorSource
= {
424 SecSystemAnchorSourceCopyParents
,
425 SecSystemAnchorSourceCopyUsageConstraints
,
426 SecSystemAnchorSourceContains
429 const SecCertificateSourceRef kSecSystemAnchorSource
= &_kSecSystemAnchorSource
;
434 // MARK: SecUserAnchorSource
435 /********************************************************
436 ************* SecUserAnchorSource object ***************
437 ********************************************************/
438 static bool SecUserAnchorSourceCopyParents(SecCertificateSourceRef source
, SecCertificateRef certificate
,
439 void *context
, SecCertificateSourceParents callback
) {
440 CFArrayRef parents
= SecTrustStoreCopyParents(SecTrustStoreForDomain(kSecTrustStoreDomainUser
),
442 callback(context
, parents
);
443 CFReleaseSafe(parents
);
447 static CFArrayRef
SecUserAnchorSourceCopyUsageConstraints(SecCertificateSourceRef source
,
448 SecCertificateRef certificate
) {
449 CFDataRef digest
= SecCertificateGetSHA1Digest(certificate
);
452 CFArrayRef usageConstraints
= NULL
;
453 bool ok
= _SecTrustStoreCopyUsageConstraints(SecTrustStoreForDomain(kSecTrustStoreDomainUser
),
454 digest
, &usageConstraints
, NULL
);
456 return usageConstraints
;
458 CFReleaseNull(usageConstraints
);
463 static bool SecUserAnchorSourceContains(SecCertificateSourceRef source
,
464 SecCertificateRef certificate
) {
465 return SecTrustStoreContains(SecTrustStoreForDomain(kSecTrustStoreDomainUser
),
469 struct SecCertificateSource _kSecUserAnchorSource
= {
470 SecUserAnchorSourceCopyParents
,
471 SecUserAnchorSourceCopyUsageConstraints
,
472 SecUserAnchorSourceContains
475 const SecCertificateSourceRef kSecUserAnchorSource
= &_kSecUserAnchorSource
;
479 // MARK: SecMemoryCertificateSource
480 /********************************************************
481 ********** SecMemoryCertificateSource object ***********
482 ********************************************************/
483 struct SecMemoryCertificateSource
{
484 struct SecCertificateSource base
;
485 CFMutableSetRef certificates
;
486 CFMutableDictionaryRef subjects
;
488 typedef struct SecMemoryCertificateSource
*SecMemoryCertificateSourceRef
;
490 static bool SecMemoryCertificateSourceCopyParents(
491 SecCertificateSourceRef source
, SecCertificateRef certificate
,
492 void *context
, SecCertificateSourceParents callback
) {
493 SecMemoryCertificateSourceRef msource
=
494 (SecMemoryCertificateSourceRef
)source
;
495 CFDataRef normalizedIssuer
=
496 SecCertificateGetNormalizedIssuerContent(certificate
);
497 CFArrayRef parents
= (normalizedIssuer
) ? CFDictionaryGetValue(msource
->subjects
,
498 normalizedIssuer
) : NULL
;
499 /* FIXME filter parents by subjectID if certificate has an
500 authorityKeyIdentifier. */
501 secdebug("trust", "%@ parents -> %@", certificate
, parents
);
502 callback(context
, parents
);
506 static bool SecMemoryCertificateSourceContains(SecCertificateSourceRef source
,
507 SecCertificateRef certificate
) {
508 SecMemoryCertificateSourceRef msource
=
509 (SecMemoryCertificateSourceRef
)source
;
510 return CFSetContainsValue(msource
->certificates
, certificate
);
513 static void dictAddValueToArrayForKey(CFMutableDictionaryRef dict
,
514 const void *key
, const void *value
) {
518 CFMutableArrayRef values
=
519 (CFMutableArrayRef
)CFDictionaryGetValue(dict
, key
);
521 values
= CFArrayCreateMutable(kCFAllocatorDefault
, 0,
522 &kCFTypeArrayCallBacks
);
523 CFDictionaryAddValue(dict
, key
, values
);
528 CFArrayAppendValue(values
, value
);
531 static void SecMemoryCertificateSourceApplierFunction(const void *value
,
533 SecMemoryCertificateSourceRef msource
=
534 (SecMemoryCertificateSourceRef
)context
;
535 SecCertificateRef certificate
= (SecCertificateRef
)value
;
537 /* CFSet's API has no way to combine these 2 operations into 1 sadly. */
538 if (CFSetContainsValue(msource
->certificates
, certificate
))
540 CFSetAddValue(msource
->certificates
, certificate
);
542 CFDataRef key
= SecCertificateGetNormalizedSubjectContent(certificate
);
543 dictAddValueToArrayForKey(msource
->subjects
, key
, value
);
546 SecCertificateSourceRef
SecMemoryCertificateSourceCreate(CFArrayRef certificates
) {
547 SecMemoryCertificateSourceRef result
= (SecMemoryCertificateSourceRef
)
548 malloc(sizeof(*result
));
549 result
->base
.copyParents
= SecMemoryCertificateSourceCopyParents
;
550 result
->base
.copyUsageConstraints
= NULL
;
551 result
->base
.contains
= SecMemoryCertificateSourceContains
;
552 CFIndex count
= CFArrayGetCount(certificates
);
553 result
->certificates
= CFSetCreateMutable(kCFAllocatorDefault
, count
,
554 &kCFTypeSetCallBacks
);
555 result
->subjects
= CFDictionaryCreateMutable(kCFAllocatorDefault
,
556 count
, &kCFTypeDictionaryKeyCallBacks
,
557 &kCFTypeDictionaryValueCallBacks
);
558 CFRange range
= { 0, count
};
559 CFArrayApplyFunction(certificates
, range
,
560 SecMemoryCertificateSourceApplierFunction
, result
);
562 return (SecCertificateSourceRef
)result
;
565 void SecMemoryCertificateSourceDestroy(SecCertificateSourceRef source
) {
566 SecMemoryCertificateSourceRef msource
=
567 (SecMemoryCertificateSourceRef
)source
;
568 CFRelease(msource
->certificates
);
569 CFRelease(msource
->subjects
);
574 // MARK: SecCAIssuerCertificateSource
575 /********************************************************
576 ********* SecCAIssuerCertificateSource object **********
577 ********************************************************/
578 static bool SecCAIssuerCertificateSourceCopyParents(
579 SecCertificateSourceRef source
, SecCertificateRef certificate
,
580 void *context
, SecCertificateSourceParents callback
) {
581 return SecCAIssuerCopyParents(certificate
, SecPathBuilderGetQueue((SecPathBuilderRef
)context
), context
, callback
);
584 static bool SecCAIssuerCertificateSourceContains(
585 SecCertificateSourceRef source
, SecCertificateRef certificate
) {
589 struct SecCertificateSource _kSecCAIssuerSource
= {
590 SecCAIssuerCertificateSourceCopyParents
,
592 SecCAIssuerCertificateSourceContains
595 const SecCertificateSourceRef kSecCAIssuerSource
= &_kSecCAIssuerSource
;
598 #include <Security/SecItemPriv.h>
600 // MARK: SecLegacyCertificateSource
601 /********************************************************
602 ********** SecLegacyCertificateSource object ***********
603 ********************************************************/
605 static bool SecLegacyCertificateSourceCopyParents(
606 SecCertificateSourceRef source
, SecCertificateRef certificate
,
607 void *context
, SecCertificateSourceParents callback
) {
608 CFArrayRef parents
= SecItemCopyParentCertificates_osx(certificate
, NULL
);
609 callback(context
, parents
);
610 CFReleaseSafe(parents
);
614 static bool SecLegacyCertificateSourceContains(
615 SecCertificateSourceRef source
, SecCertificateRef certificate
) {
616 SecCertificateRef cert
= SecItemCopyStoredCertificate(certificate
, NULL
);
617 bool result
= (cert
) ? true : false;
622 struct SecCertificateSource _kSecLegacyCertificateSource
= {
623 SecLegacyCertificateSourceCopyParents
,
625 SecLegacyCertificateSourceContains
628 const SecCertificateSourceRef kSecLegacyCertificateSource
= &_kSecLegacyCertificateSource
;
630 #endif /* SecLegacyCertificateSource */
634 // MARK: SecLegacyAnchorSource
635 /********************************************************
636 ************ SecLegacyAnchorSource object **************
637 ********************************************************/
639 static bool SecLegacyAnchorSourceCopyParents(SecCertificateSourceRef source
, SecCertificateRef certificate
,
640 void *context
, SecCertificateSourceParents callback
) {
641 CFMutableArrayRef anchors
= CFArrayCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeArrayCallBacks
);
642 CFArrayRef parents
= SecItemCopyParentCertificates_osx(certificate
, NULL
);
643 CFArrayRef trusted
= NULL
;
644 if (parents
== NULL
) {
647 /* Get the custom anchors which have been trusted in the user and admin domains.
648 * We don't need system domain roots here, since SecSystemAnchorSource provides those.
650 OSStatus status
= SecTrustSettingsCopyCertificatesForUserAdminDomains(&trusted
);
651 if (status
== errSecSuccess
&& trusted
) {
652 CFIndex index
, count
= CFArrayGetCount(parents
);
653 for (index
= 0; index
< count
; index
++) {
654 SecCertificateRef parent
= (SecCertificateRef
)CFArrayGetValueAtIndex(parents
, index
);
655 if (parent
&& CFArrayContainsValue(trusted
, CFRangeMake(0, CFArrayGetCount(trusted
)), parent
)) {
656 CFArrayAppendValue(anchors
, parent
);
662 callback(context
, anchors
);
663 CFReleaseSafe(anchors
);
664 CFReleaseSafe(parents
);
665 CFReleaseSafe(trusted
);
669 static CFArrayRef
SecLegacyAnchorSourceCopyUsageConstraints(SecCertificateSourceRef source
,
670 SecCertificateRef certificate
) {
671 CFArrayRef result
= NULL
;
672 CFArrayRef userTrustSettings
= NULL
, adminTrustSettings
= NULL
;
674 OSStatus status
= SecTrustSettingsCopyTrustSettings(certificate
,
675 kSecTrustSettingsDomainUser
,
677 if ((status
== errSecSuccess
) && (userTrustSettings
!= NULL
)) {
678 result
= CFRetain(userTrustSettings
);
681 status
= SecTrustSettingsCopyTrustSettings(certificate
,
682 kSecTrustSettingsDomainAdmin
,
683 &adminTrustSettings
);
684 /* user trust settings overrule admin trust settings */
685 if ((status
== errSecSuccess
) && (adminTrustSettings
!= NULL
) && (result
== NULL
)) {
686 result
= CFRetain(adminTrustSettings
);
689 CFReleaseNull(userTrustSettings
);
690 CFReleaseNull(adminTrustSettings
);
694 static bool SecLegacyAnchorSourceContains(SecCertificateSourceRef source
,
695 SecCertificateRef certificate
) {
696 if (certificate
== NULL
) {
699 CFArrayRef trusted
= NULL
;
701 OSStatus status
= SecTrustSettingsCopyCertificatesForUserAdminDomains(&trusted
);
702 if ((status
== errSecSuccess
) && (trusted
!= NULL
)) {
703 CFIndex index
, count
= CFArrayGetCount(trusted
);
704 for (index
= 0; index
< count
; index
++) {
705 SecCertificateRef anchor
= (SecCertificateRef
)CFArrayGetValueAtIndex(trusted
, index
);
706 if (anchor
&& CFEqual(anchor
, certificate
)) {
712 CFReleaseSafe(trusted
);
716 struct SecCertificateSource _kSecLegacyAnchorSource
= {
717 SecLegacyAnchorSourceCopyParents
,
718 SecLegacyAnchorSourceCopyUsageConstraints
,
719 SecLegacyAnchorSourceContains
722 const SecCertificateSourceRef kSecLegacyAnchorSource
= &_kSecLegacyAnchorSource
;
724 #endif /* SecLegacyAnchorSource */