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 "trust/trustd/SecTrustServer.h"
44 #include "keychain/securityd/SecItemServer.h"
45 #include "trust/trustd/SecTrustStoreServer.h"
46 #include "trust/trustd/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 CFArrayRef parents
= NULL
;
302 CFArrayRef anchors
= NULL
;
304 CFDataRef nic
= SecCertificateGetNormalizedIssuerContent(certificate
);
305 /* 64 bits cast: the worst that can happen here is we truncate the length and match an actual anchor.
306 It does not matter since we would be returning the wrong anchors */
307 assert((unsigned long)CFDataGetLength(nic
)<UINT_MAX
); /* Debug check. correct as long as CFIndex is signed long */
309 anchors
= subject_to_anchors(nic
);
310 require_quiet(anchors
, errOut
);
311 parents
= CopyCertsFromIndices(anchors
);
314 callback(context
, parents
);
315 CFReleaseSafe(parents
);
319 static CFArrayRef
SecSystemAnchorSourceCopyUsageConstraints(SecCertificateSourceRef __unused source
,
320 SecCertificateRef __unused certificate
)
322 CFMutableArrayRef result
= NULL
;
323 CFMutableDictionaryRef options
= NULL
, strengthConstraints
= NULL
, trustRoot
= NULL
;
324 CFNumberRef trustResult
= NULL
;
326 require_quiet(options
= CFDictionaryCreateMutable(NULL
, 1,
327 &kCFTypeDictionaryKeyCallBacks
,
328 &kCFTypeDictionaryValueCallBacks
),
330 require_quiet(strengthConstraints
= CFDictionaryCreateMutable(NULL
, 1,
331 &kCFTypeDictionaryKeyCallBacks
,
332 &kCFTypeDictionaryValueCallBacks
),
334 require_quiet(trustRoot
= CFDictionaryCreateMutable(NULL
, 1,
335 &kCFTypeDictionaryKeyCallBacks
,
336 &kCFTypeDictionaryValueCallBacks
),
339 uint32_t temp
= kSecTrustSettingsResultTrustRoot
;
340 require_quiet(trustResult
= CFNumberCreate(NULL
, kCFNumberSInt32Type
, &temp
), out
);
341 CFDictionaryAddValue(trustRoot
, kSecTrustSettingsResult
, trustResult
);
343 CFDictionaryAddValue(options
, kSecPolicyCheckSystemTrustedWeakHash
, kCFBooleanTrue
);
344 CFDictionaryAddValue(options
, kSecPolicyCheckSystemTrustedWeakKey
, kCFBooleanTrue
);
345 CFDictionaryAddValue(strengthConstraints
, kSecTrustSettingsPolicyOptions
, options
);
347 require_quiet(result
= CFArrayCreateMutable(NULL
, 2, &kCFTypeArrayCallBacks
), out
);
348 CFArrayAppendValue(result
, strengthConstraints
);
349 CFArrayAppendValue(result
, trustRoot
);
352 CFReleaseNull(options
);
353 CFReleaseNull(trustResult
);
354 CFReleaseNull(trustRoot
);
355 CFReleaseNull(strengthConstraints
);
359 static bool SecSystemAnchorSourceContains(SecCertificateSourceRef source
,
360 SecCertificateRef certificate
) {
362 CFArrayRef anchors
= NULL
;
363 SecOTAPKIRef otapkiref
= NULL
;
364 CFArrayRef cert_datas
= NULL
;
366 CFDataRef nic
= SecCertificateGetNormalizedSubjectContent(certificate
);
367 /* 64 bits cast: the worst that can happen here is we truncate the length and match an actual anchor.
368 It does not matter since we would be returning the wrong anchors */
369 assert((unsigned long)CFDataGetLength(nic
)<UINT_MAX
); /* Debug check. correct as long as CFIndex is signed long */
371 otapkiref
= SecOTAPKICopyCurrentOTAPKIRef();
372 require_quiet(otapkiref
, errOut
);
373 anchors
= subject_to_anchors(nic
);
374 require_quiet(anchors
, errOut
);
375 cert_datas
= CopyCertDataFromIndices(anchors
);
376 require_quiet(cert_datas
, errOut
);
378 CFIndex cert_length
= SecCertificateGetLength(certificate
);
379 const UInt8
*cert_data_ptr
= SecCertificateGetBytePtr(certificate
);
381 CFIndex num_cert_datas
= CFArrayGetCount(cert_datas
);
382 for (CFIndex idx
= 0; idx
< num_cert_datas
; idx
++)
384 CFDataRef cert_data
= (CFDataRef
)CFArrayGetValueAtIndex(cert_datas
, idx
);
386 if (NULL
!= cert_data
)
388 if (CFGetTypeID(cert_data
) == CFDataGetTypeID())
390 CFIndex aCert_Length
= CFDataGetLength(cert_data
);
391 const UInt8
* aCert_Data_Ptr
= CFDataGetBytePtr(cert_data
);
393 if (aCert_Length
== cert_length
)
395 if (!memcmp(cert_data_ptr
, aCert_Data_Ptr
, cert_length
))
406 CFReleaseSafe(cert_datas
);
407 CFReleaseSafe(otapkiref
);
411 struct SecCertificateSource _kSecSystemAnchorSource
= {
412 SecSystemAnchorSourceCopyParents
,
413 SecSystemAnchorSourceCopyUsageConstraints
,
414 SecSystemAnchorSourceContains
417 const SecCertificateSourceRef kSecSystemAnchorSource
= &_kSecSystemAnchorSource
;
422 // MARK: SecUserAnchorSource
423 /********************************************************
424 ************* SecUserAnchorSource object ***************
425 ********************************************************/
426 static bool SecUserAnchorSourceCopyParents(SecCertificateSourceRef source
, SecCertificateRef certificate
,
427 void *context
, SecCertificateSourceParents callback
) {
428 CFArrayRef parents
= SecTrustStoreCopyParents(SecTrustStoreForDomain(kSecTrustStoreDomainUser
),
430 callback(context
, parents
);
431 CFReleaseSafe(parents
);
435 static CFArrayRef
SecUserAnchorSourceCopyUsageConstraints(SecCertificateSourceRef source
,
436 SecCertificateRef certificate
) {
437 CFDataRef digest
= SecCertificateGetSHA1Digest(certificate
);
440 CFArrayRef usageConstraints
= NULL
;
441 bool ok
= _SecTrustStoreCopyUsageConstraints(SecTrustStoreForDomain(kSecTrustStoreDomainUser
),
442 digest
, &usageConstraints
, NULL
);
444 return usageConstraints
;
446 CFReleaseNull(usageConstraints
);
451 static bool SecUserAnchorSourceContains(SecCertificateSourceRef source
,
452 SecCertificateRef certificate
) {
453 return SecTrustStoreContains(SecTrustStoreForDomain(kSecTrustStoreDomainUser
),
457 struct SecCertificateSource _kSecUserAnchorSource
= {
458 SecUserAnchorSourceCopyParents
,
459 SecUserAnchorSourceCopyUsageConstraints
,
460 SecUserAnchorSourceContains
463 const SecCertificateSourceRef kSecUserAnchorSource
= &_kSecUserAnchorSource
;
467 // MARK: SecMemoryCertificateSource
468 /********************************************************
469 ********** SecMemoryCertificateSource object ***********
470 ********************************************************/
471 struct SecMemoryCertificateSource
{
472 struct SecCertificateSource base
;
473 CFMutableSetRef certificates
;
474 CFMutableDictionaryRef subjects
;
476 typedef struct SecMemoryCertificateSource
*SecMemoryCertificateSourceRef
;
478 static bool SecMemoryCertificateSourceCopyParents(SecCertificateSourceRef source
, SecCertificateRef certificate
,
479 void *context
, SecCertificateSourceParents callback
) {
480 SecMemoryCertificateSourceRef msource
=
481 (SecMemoryCertificateSourceRef
)source
;
482 CFDataRef normalizedIssuer
=
483 SecCertificateGetNormalizedIssuerContent(certificate
);
484 CFArrayRef parents
= (normalizedIssuer
) ? CFDictionaryGetValue(msource
->subjects
,
485 normalizedIssuer
) : NULL
;
486 /* FIXME filter parents by subjectID if certificate has an
487 authorityKeyIdentifier. */
488 secdebug("trust", "%@ parents -> %@", certificate
, parents
);
489 callback(context
, parents
);
493 static bool SecMemoryCertificateSourceContains(SecCertificateSourceRef source
,
494 SecCertificateRef certificate
) {
495 SecMemoryCertificateSourceRef msource
=
496 (SecMemoryCertificateSourceRef
)source
;
497 return CFSetContainsValue(msource
->certificates
, certificate
);
500 static void dictAddValueToArrayForKey(CFMutableDictionaryRef dict
,
501 const void *key
, const void *value
) {
505 CFMutableArrayRef values
=
506 (CFMutableArrayRef
)CFDictionaryGetValue(dict
, key
);
508 values
= CFArrayCreateMutable(kCFAllocatorDefault
, 0,
509 &kCFTypeArrayCallBacks
);
510 CFDictionaryAddValue(dict
, key
, values
);
515 CFArrayAppendValue(values
, value
);
518 static void SecMemoryCertificateSourceApplierFunction(const void *value
, void *context
) {
519 SecMemoryCertificateSourceRef msource
=
520 (SecMemoryCertificateSourceRef
)context
;
521 SecCertificateRef certificate
= (SecCertificateRef
)value
;
523 /* CFSet's API has no way to combine these 2 operations into 1 sadly. */
524 if (CFSetContainsValue(msource
->certificates
, certificate
))
526 CFSetAddValue(msource
->certificates
, certificate
);
528 CFDataRef key
= SecCertificateGetNormalizedSubjectContent(certificate
);
529 dictAddValueToArrayForKey(msource
->subjects
, key
, value
);
532 SecCertificateSourceRef
SecMemoryCertificateSourceCreate(CFArrayRef certificates
) {
533 SecMemoryCertificateSourceRef result
= (SecMemoryCertificateSourceRef
)
534 malloc(sizeof(*result
));
535 result
->base
.copyParents
= SecMemoryCertificateSourceCopyParents
;
536 result
->base
.copyUsageConstraints
= NULL
;
537 result
->base
.contains
= SecMemoryCertificateSourceContains
;
538 CFIndex count
= CFArrayGetCount(certificates
);
539 result
->certificates
= CFSetCreateMutable(kCFAllocatorDefault
, count
,
540 &kCFTypeSetCallBacks
);
541 result
->subjects
= CFDictionaryCreateMutable(kCFAllocatorDefault
,
542 count
, &kCFTypeDictionaryKeyCallBacks
,
543 &kCFTypeDictionaryValueCallBacks
);
544 CFRange range
= { 0, count
};
545 CFArrayApplyFunction(certificates
, range
,
546 SecMemoryCertificateSourceApplierFunction
, result
);
548 return (SecCertificateSourceRef
)result
;
551 void SecMemoryCertificateSourceDestroy(SecCertificateSourceRef source
) {
552 SecMemoryCertificateSourceRef msource
=
553 (SecMemoryCertificateSourceRef
)source
;
554 CFRelease(msource
->certificates
);
555 CFRelease(msource
->subjects
);
560 // MARK: SecCAIssuerCertificateSource
561 /********************************************************
562 ********* SecCAIssuerCertificateSource object **********
563 ********************************************************/
564 static bool SecCAIssuerCertificateSourceCopyParents(SecCertificateSourceRef source
, SecCertificateRef certificate
,
565 void *context
, SecCertificateSourceParents callback
) {
566 /* Some expired certs have dead domains. Let's not check them. */
567 SecPathBuilderRef builder
= (SecPathBuilderRef
)context
;
568 CFAbsoluteTime verifyDate
= SecPathBuilderGetVerifyTime(builder
);
569 if (SecPathBuilderHasTemporalParentChecks(builder
) && !SecCertificateIsValid(certificate
, verifyDate
)) {
570 secinfo("async", "skipping CAIssuer fetch for expired %@", certificate
);
571 callback(context
, NULL
);
574 return SecCAIssuerCopyParents(certificate
, context
, callback
);
577 static bool SecCAIssuerCertificateSourceContains(SecCertificateSourceRef source
, SecCertificateRef certificate
) {
581 struct SecCertificateSource _kSecCAIssuerSource
= {
582 SecCAIssuerCertificateSourceCopyParents
,
584 SecCAIssuerCertificateSourceContains
587 const SecCertificateSourceRef kSecCAIssuerSource
= &_kSecCAIssuerSource
;
590 #include <Security/SecItemPriv.h>
592 // MARK: SecLegacyCertificateSource
593 /********************************************************
594 ********** SecLegacyCertificateSource object ***********
595 ********************************************************/
597 static bool SecLegacyCertificateSourceCopyParents(SecCertificateSourceRef source
, SecCertificateRef certificate
,
598 void *context
, SecCertificateSourceParents callback
) {
599 CFArrayRef parents
= SecItemCopyParentCertificates_osx(certificate
, NULL
);
600 callback(context
, parents
);
601 CFReleaseSafe(parents
);
605 static bool SecLegacyCertificateSourceContains(SecCertificateSourceRef source
, SecCertificateRef certificate
) {
606 SecCertificateRef cert
= SecItemCopyStoredCertificate(certificate
, NULL
);
607 bool result
= (cert
) ? true : false;
612 struct SecCertificateSource _kSecLegacyCertificateSource
= {
613 SecLegacyCertificateSourceCopyParents
,
615 SecLegacyCertificateSourceContains
618 const SecCertificateSourceRef kSecLegacyCertificateSource
= &_kSecLegacyCertificateSource
;
620 #endif /* SecLegacyCertificateSource */
624 // MARK: SecLegacyAnchorSource
625 /********************************************************
626 ************ SecLegacyAnchorSource object **************
627 ********************************************************/
629 static bool SecLegacyAnchorSourceCopyParents(SecCertificateSourceRef source
, SecCertificateRef certificate
,
630 void *context
, SecCertificateSourceParents callback
) {
631 CFMutableArrayRef anchors
= CFArrayCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeArrayCallBacks
);
632 CFArrayRef parents
= SecItemCopyParentCertificates_osx(certificate
, NULL
);
633 CFArrayRef trusted
= NULL
;
634 if (parents
== NULL
) {
637 /* Get the custom anchors which have been trusted in the user and admin domains.
638 * We don't need system domain roots here, since SecSystemAnchorSource provides those.
640 OSStatus status
= SecTrustSettingsCopyCertificatesForUserAdminDomains(&trusted
);
641 if (status
== errSecSuccess
&& trusted
) {
642 CFIndex index
, count
= CFArrayGetCount(parents
);
643 for (index
= 0; index
< count
; index
++) {
644 SecCertificateRef parent
= (SecCertificateRef
)CFArrayGetValueAtIndex(parents
, index
);
645 if (parent
&& CFArrayContainsValue(trusted
, CFRangeMake(0, CFArrayGetCount(trusted
)), parent
)) {
646 CFArrayAppendValue(anchors
, parent
);
652 callback(context
, anchors
);
653 CFReleaseSafe(anchors
);
654 CFReleaseSafe(parents
);
655 CFReleaseSafe(trusted
);
659 static CFArrayRef
SecLegacyAnchorSourceCopyUsageConstraints(SecCertificateSourceRef source
,
660 SecCertificateRef certificate
) {
661 CFArrayRef result
= NULL
;
662 CFArrayRef userTrustSettings
= NULL
, adminTrustSettings
= NULL
;
664 OSStatus status
= SecTrustSettingsCopyTrustSettings(certificate
,
665 kSecTrustSettingsDomainUser
,
667 if ((status
== errSecSuccess
) && (userTrustSettings
!= NULL
)) {
668 result
= CFRetain(userTrustSettings
);
671 status
= SecTrustSettingsCopyTrustSettings(certificate
,
672 kSecTrustSettingsDomainAdmin
,
673 &adminTrustSettings
);
674 /* user trust settings overrule admin trust settings */
675 if ((status
== errSecSuccess
) && (adminTrustSettings
!= NULL
) && (result
== NULL
)) {
676 result
= CFRetain(adminTrustSettings
);
679 CFReleaseNull(userTrustSettings
);
680 CFReleaseNull(adminTrustSettings
);
684 static bool SecLegacyAnchorSourceContains(SecCertificateSourceRef source
,
685 SecCertificateRef certificate
) {
686 if (certificate
== NULL
) {
689 CFArrayRef trusted
= NULL
;
691 OSStatus status
= SecTrustSettingsCopyCertificatesForUserAdminDomains(&trusted
);
692 if ((status
== errSecSuccess
) && (trusted
!= NULL
)) {
693 CFIndex index
, count
= CFArrayGetCount(trusted
);
694 for (index
= 0; index
< count
; index
++) {
695 SecCertificateRef anchor
= (SecCertificateRef
)CFRetainSafe(CFArrayGetValueAtIndex(trusted
, index
));
696 if (anchor
&& (CFGetTypeID(anchor
) != CFGetTypeID(certificate
))) {
697 /* This should only happen if trustd and the Security framework are using different SecCertificate TypeIDs.
698 * This occurs in TrustTests where we rebuild SecCertificate.c for code coverage purposes, so we end up with
699 * two registered SecCertificate types. So we'll make a SecCertificate of our type. */
700 SecCertificateRef temp
= SecCertificateCreateWithBytes(NULL
, SecCertificateGetBytePtr(anchor
), SecCertificateGetLength(anchor
));
701 CFAssignRetained(anchor
, temp
);
703 if (anchor
&& CFEqual(anchor
, certificate
)) {
706 CFReleaseNull(anchor
);
712 CFReleaseSafe(trusted
);
716 struct SecCertificateSource _kSecLegacyAnchorSource
= {
717 SecLegacyAnchorSourceCopyParents
,
718 SecLegacyAnchorSourceCopyUsageConstraints
,
719 SecLegacyAnchorSourceContains
722 const SecCertificateSourceRef kSecLegacyAnchorSource
= &_kSecLegacyAnchorSource
;
724 #endif /* SecLegacyAnchorSource */