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
;
420 // MARK: SecUserAnchorSource
421 /********************************************************
422 ************* SecUserAnchorSource object ***************
423 ********************************************************/
424 static bool SecUserAnchorSourceCopyParents(SecCertificateSourceRef source
, SecCertificateRef certificate
,
425 void *context
, SecCertificateSourceParents callback
) {
426 CFArrayRef parents
= SecTrustStoreCopyParents(SecTrustStoreForDomain(kSecTrustStoreDomainUser
),
428 callback(context
, parents
);
429 CFReleaseSafe(parents
);
433 static CFArrayRef
SecUserAnchorSourceCopyUsageConstraints(SecCertificateSourceRef source
,
434 SecCertificateRef certificate
) {
435 CFDataRef digest
= SecCertificateGetSHA1Digest(certificate
);
438 CFArrayRef usageConstraints
= NULL
;
439 bool ok
= _SecTrustStoreCopyUsageConstraints(SecTrustStoreForDomain(kSecTrustStoreDomainUser
),
440 digest
, &usageConstraints
, NULL
);
442 return usageConstraints
;
444 CFReleaseNull(usageConstraints
);
449 static bool SecUserAnchorSourceContains(SecCertificateSourceRef source
,
450 SecCertificateRef certificate
) {
451 return SecTrustStoreContains(SecTrustStoreForDomain(kSecTrustStoreDomainUser
),
455 struct SecCertificateSource _kSecUserAnchorSource
= {
456 SecUserAnchorSourceCopyParents
,
457 SecUserAnchorSourceCopyUsageConstraints
,
458 SecUserAnchorSourceContains
461 const SecCertificateSourceRef kSecUserAnchorSource
= &_kSecUserAnchorSource
;
464 // MARK: SecMemoryCertificateSource
465 /********************************************************
466 ********** SecMemoryCertificateSource object ***********
467 ********************************************************/
468 struct SecMemoryCertificateSource
{
469 struct SecCertificateSource base
;
470 CFMutableSetRef certificates
;
471 CFMutableDictionaryRef subjects
;
473 typedef struct SecMemoryCertificateSource
*SecMemoryCertificateSourceRef
;
475 static bool SecMemoryCertificateSourceCopyParents(SecCertificateSourceRef source
, SecCertificateRef certificate
,
476 void *context
, SecCertificateSourceParents callback
) {
477 SecMemoryCertificateSourceRef msource
=
478 (SecMemoryCertificateSourceRef
)source
;
479 CFDataRef normalizedIssuer
=
480 SecCertificateGetNormalizedIssuerContent(certificate
);
481 CFArrayRef parents
= (normalizedIssuer
) ? CFDictionaryGetValue(msource
->subjects
,
482 normalizedIssuer
) : NULL
;
483 /* FIXME filter parents by subjectID if certificate has an
484 authorityKeyIdentifier. */
485 secdebug("trust", "%@ parents -> %@", certificate
, parents
);
486 callback(context
, parents
);
490 static bool SecMemoryCertificateSourceContains(SecCertificateSourceRef source
,
491 SecCertificateRef certificate
) {
492 SecMemoryCertificateSourceRef msource
=
493 (SecMemoryCertificateSourceRef
)source
;
494 return CFSetContainsValue(msource
->certificates
, certificate
);
497 static void dictAddValueToArrayForKey(CFMutableDictionaryRef dict
,
498 const void *key
, const void *value
) {
502 CFMutableArrayRef values
=
503 (CFMutableArrayRef
)CFDictionaryGetValue(dict
, key
);
505 values
= CFArrayCreateMutable(kCFAllocatorDefault
, 0,
506 &kCFTypeArrayCallBacks
);
507 CFDictionaryAddValue(dict
, key
, values
);
512 CFArrayAppendValue(values
, value
);
515 static void SecMemoryCertificateSourceApplierFunction(const void *value
, void *context
) {
516 SecMemoryCertificateSourceRef msource
=
517 (SecMemoryCertificateSourceRef
)context
;
518 SecCertificateRef certificate
= (SecCertificateRef
)value
;
520 /* CFSet's API has no way to combine these 2 operations into 1 sadly. */
521 if (CFSetContainsValue(msource
->certificates
, certificate
))
523 CFSetAddValue(msource
->certificates
, certificate
);
525 CFDataRef key
= SecCertificateGetNormalizedSubjectContent(certificate
);
526 dictAddValueToArrayForKey(msource
->subjects
, key
, value
);
529 SecCertificateSourceRef
SecMemoryCertificateSourceCreate(CFArrayRef certificates
) {
530 SecMemoryCertificateSourceRef result
= (SecMemoryCertificateSourceRef
)
531 malloc(sizeof(*result
));
532 result
->base
.copyParents
= SecMemoryCertificateSourceCopyParents
;
533 result
->base
.copyUsageConstraints
= NULL
;
534 result
->base
.contains
= SecMemoryCertificateSourceContains
;
535 CFIndex count
= CFArrayGetCount(certificates
);
536 result
->certificates
= CFSetCreateMutable(kCFAllocatorDefault
, count
,
537 &kCFTypeSetCallBacks
);
538 result
->subjects
= CFDictionaryCreateMutable(kCFAllocatorDefault
,
539 count
, &kCFTypeDictionaryKeyCallBacks
,
540 &kCFTypeDictionaryValueCallBacks
);
541 CFRange range
= { 0, count
};
542 CFArrayApplyFunction(certificates
, range
,
543 SecMemoryCertificateSourceApplierFunction
, result
);
545 return (SecCertificateSourceRef
)result
;
548 void SecMemoryCertificateSourceDestroy(SecCertificateSourceRef source
) {
549 SecMemoryCertificateSourceRef msource
=
550 (SecMemoryCertificateSourceRef
)source
;
551 CFRelease(msource
->certificates
);
552 CFRelease(msource
->subjects
);
557 // MARK: SecCAIssuerCertificateSource
558 /********************************************************
559 ********* SecCAIssuerCertificateSource object **********
560 ********************************************************/
561 static bool SecCAIssuerCertificateSourceCopyParents(SecCertificateSourceRef source
, SecCertificateRef certificate
,
562 void *context
, SecCertificateSourceParents callback
) {
563 /* Some expired certs have dead domains. Let's not check them. */
564 SecPathBuilderRef builder
= (SecPathBuilderRef
)context
;
565 CFAbsoluteTime verifyDate
= SecPathBuilderGetVerifyTime(builder
);
566 if (SecPathBuilderHasTemporalParentChecks(builder
) && !SecCertificateIsValid(certificate
, verifyDate
)) {
567 secinfo("async", "skipping CAIssuer fetch for expired %@", certificate
);
568 callback(context
, NULL
);
571 return SecCAIssuerCopyParents(certificate
, context
, callback
);
574 static bool SecCAIssuerCertificateSourceContains(SecCertificateSourceRef source
, SecCertificateRef certificate
) {
578 struct SecCertificateSource _kSecCAIssuerSource
= {
579 SecCAIssuerCertificateSourceCopyParents
,
581 SecCAIssuerCertificateSourceContains
584 const SecCertificateSourceRef kSecCAIssuerSource
= &_kSecCAIssuerSource
;
587 #include <Security/SecItemPriv.h>
589 // MARK: SecLegacyCertificateSource
590 /********************************************************
591 ********** SecLegacyCertificateSource object ***********
592 ********************************************************/
594 static bool SecLegacyCertificateSourceCopyParents(SecCertificateSourceRef source
, SecCertificateRef certificate
,
595 void *context
, SecCertificateSourceParents callback
) {
596 CFArrayRef parents
= SecItemCopyParentCertificates_osx(certificate
, NULL
);
597 callback(context
, parents
);
598 CFReleaseSafe(parents
);
602 static bool SecLegacyCertificateSourceContains(SecCertificateSourceRef source
, SecCertificateRef certificate
) {
603 SecCertificateRef cert
= SecItemCopyStoredCertificate(certificate
, NULL
);
604 bool result
= (cert
) ? true : false;
609 struct SecCertificateSource _kSecLegacyCertificateSource
= {
610 SecLegacyCertificateSourceCopyParents
,
612 SecLegacyCertificateSourceContains
615 const SecCertificateSourceRef kSecLegacyCertificateSource
= &_kSecLegacyCertificateSource
;
617 #endif /* SecLegacyCertificateSource */
621 // MARK: SecLegacyAnchorSource
622 /********************************************************
623 ************ SecLegacyAnchorSource object **************
624 ********************************************************/
626 static bool SecLegacyAnchorSourceCopyParents(SecCertificateSourceRef source
, SecCertificateRef certificate
,
627 void *context
, SecCertificateSourceParents callback
) {
628 CFMutableArrayRef anchors
= CFArrayCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeArrayCallBacks
);
629 CFArrayRef trusted
= NULL
;
630 CFDataRef normalizedIssuer
= SecCertificateCopyNormalizedIssuerSequence(certificate
);
631 if (!normalizedIssuer
) {
635 /* Get the custom anchors which have been trusted in the user and admin domains.
636 * We don't need system domain roots here, since SecSystemAnchorSource provides those.
638 OSStatus status
= SecTrustSettingsCopyCertificatesForUserAdminDomains(&trusted
);
639 if (status
== errSecSuccess
&& trusted
) {
640 CFIndex index
, count
= CFArrayGetCount(trusted
);
641 for (index
= 0; index
< count
; index
++) {
642 SecCertificateRef potentialParent
= (SecCertificateRef
)CFArrayGetValueAtIndex(trusted
, index
);
643 CFDataRef normalizedSubject
= SecCertificateCopyNormalizedSubjectSequence(potentialParent
);
644 if (CFEqualSafe(normalizedIssuer
, normalizedSubject
)) {
645 CFArrayAppendValue(anchors
, potentialParent
);
647 CFReleaseSafe(normalizedSubject
);
652 callback(context
, anchors
);
653 CFReleaseSafe(anchors
);
654 CFReleaseSafe(trusted
);
655 CFReleaseSafe(normalizedIssuer
);
659 static CFArrayRef
SecLegacyAnchorSourceCopyUsageConstraints(SecCertificateSourceRef source
,
660 SecCertificateRef certificate
) {
661 CFArrayRef result
= NULL
;
662 CFArrayRef userTrustSettings
= NULL
, adminTrustSettings
= NULL
;
664 OSStatus status
= SecTrustSettingsCopyTrustSettings_Cached(certificate
,
665 kSecTrustSettingsDomainAdmin
,
666 &adminTrustSettings
);
667 if ((status
== errSecSuccess
) && (adminTrustSettings
!= NULL
)) {
668 /* admin trust settings overrule user trust settings (rdar://37052515) */
669 return adminTrustSettings
;
672 status
= SecTrustSettingsCopyTrustSettings_Cached(certificate
,
673 kSecTrustSettingsDomainUser
,
675 if (status
== errSecSuccess
) {
676 result
= CFRetainSafe(userTrustSettings
);
679 CFReleaseNull(userTrustSettings
);
680 CFReleaseNull(adminTrustSettings
);
684 static bool SecLegacyAnchorSourceContains(SecCertificateSourceRef source
,
685 SecCertificateRef certificate
) {
686 if (certificate
== NULL
) {
690 if (SecTrustSettingsUserAdminDomainsContain(certificate
)) {
693 CFArrayRef trusted
= NULL
;
695 OSStatus status
= SecTrustSettingsCopyCertificatesForUserAdminDomains(&trusted
);
696 if ((status
== errSecSuccess
) && (trusted
!= NULL
)) {
697 if ((CFArrayGetCount(trusted
) > 0) && CFGetTypeID(CFArrayGetValueAtIndex(trusted
, 0)) != CFGetTypeID(certificate
)) {
698 /* This fallback should only happen if trustd and the Security framework are using different SecCertificate TypeIDs.
699 * This occurs in TrustTests where we rebuild SecCertificate.c for code coverage purposes, so we end up with
700 * two registered SecCertificate types. So we'll make a SecCertificate of our type. */
701 CFIndex index
, count
= CFArrayGetCount(trusted
);
702 for (index
= 0; index
< count
; index
++) {
703 SecCertificateRef anchor
= (SecCertificateRef
)CFRetainSafe(CFArrayGetValueAtIndex(trusted
, index
));
704 if (anchor
&& (CFGetTypeID(anchor
) != CFGetTypeID(certificate
))) {
705 SecCertificateRef temp
= SecCertificateCreateWithBytes(NULL
, SecCertificateGetBytePtr(anchor
), SecCertificateGetLength(anchor
));
706 CFAssignRetained(anchor
, temp
);
708 if (anchor
&& CFEqual(anchor
, certificate
)) {
711 CFReleaseNull(anchor
);
717 CFReleaseSafe(trusted
);
724 struct SecCertificateSource _kSecLegacyAnchorSource
= {
725 SecLegacyAnchorSourceCopyParents
,
726 SecLegacyAnchorSourceCopyUsageConstraints
,
727 SecLegacyAnchorSourceContains
730 const SecCertificateSourceRef kSecLegacyAnchorSource
= &_kSecLegacyAnchorSource
;
732 #endif /* SecLegacyAnchorSource */