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(
238 SecCertificateSourceRef source
, SecCertificateRef certificate
,
239 void *context
, SecCertificateSourceParents callback
) {
240 SecItemCertificateSourceRef msource
= (SecItemCertificateSourceRef
)source
;
241 CFDataRef normalizedIssuer
= SecCertificateGetNormalizedIssuerContent(certificate
);
243 CFErrorRef localError
= NULL
;
244 CFArrayRef results
= SecItemCopyParentCertificates_ios(normalizedIssuer
, msource
->accessGroups
, &localError
);
246 if (localError
&& (CFErrorGetCode(localError
) != errSecItemNotFound
)) {
247 secdebug("trust", "SecItemCopyParentCertificates_ios: %@", localError
);
249 CFReleaseSafe(localError
);
251 CFArrayRef certs
= SecItemCertificateSourceResultsPost(results
);
252 CFReleaseSafe(results
);
253 callback(context
, certs
);
254 CFReleaseSafe(certs
);
258 static bool SecItemCertificateSourceContains(SecCertificateSourceRef source
,
259 SecCertificateRef certificate
) {
260 SecItemCertificateSourceRef msource
= (SecItemCertificateSourceRef
)source
;
261 /* Look up a certificate by issuer and serial number. */
262 CFDataRef normalizedIssuer
= SecCertificateGetNormalizedIssuerContent(certificate
);
263 CFRetainSafe(normalizedIssuer
);
264 CFDataRef serialNumber
=
265 #if (TARGET_OS_MAC && !(TARGET_OS_EMBEDDED || TARGET_OS_IPHONE))
266 SecCertificateCopySerialNumber(certificate
, NULL
);
268 SecCertificateCopySerialNumber(certificate
);
270 CFErrorRef localError
= NULL
;
271 bool result
= SecItemCertificateExists(normalizedIssuer
, serialNumber
, msource
->accessGroups
, &localError
);
273 if (CFErrorGetCode(localError
) != errSecItemNotFound
) {
274 secdebug("trust", "SecItemCertificateExists_ios: %@", localError
);
276 CFReleaseSafe(localError
);
278 CFReleaseSafe(serialNumber
);
279 CFReleaseSafe(normalizedIssuer
);
283 SecCertificateSourceRef
SecItemCertificateSourceCreate(CFArrayRef accessGroups
) {
284 SecItemCertificateSourceRef result
= (SecItemCertificateSourceRef
)malloc(sizeof(*result
));
285 result
->base
.copyParents
= SecItemCertificateSourceCopyParents
;
286 result
->base
.copyUsageConstraints
= NULL
;
287 result
->base
.contains
= SecItemCertificateSourceContains
;
288 result
->accessGroups
= accessGroups
;
289 CFRetainSafe(accessGroups
);
290 return (SecCertificateSourceRef
)result
;
293 void SecItemCertificateSourceDestroy(SecCertificateSourceRef source
) {
294 SecItemCertificateSourceRef msource
= (SecItemCertificateSourceRef
)source
;
295 CFReleaseSafe(msource
->accessGroups
);
300 // MARK: SecSystemAnchorSource
301 /********************************************************
302 *********** SecSystemAnchorSource object ************
303 ********************************************************/
305 static bool SecSystemAnchorSourceCopyParents(
306 SecCertificateSourceRef source
, SecCertificateRef certificate
,
307 void *context
, SecCertificateSourceParents callback
) {
308 //#ifndef SECITEM_SHIM_OSX
309 CFArrayRef parents
= NULL
;
310 CFArrayRef anchors
= NULL
;
311 SecOTAPKIRef otapkiref
= NULL
;
313 CFDataRef nic
= SecCertificateGetNormalizedIssuerContent(certificate
);
314 /* 64 bits cast: the worst that can happen here is we truncate the length and match an actual anchor.
315 It does not matter since we would be returning the wrong anchors */
316 assert((unsigned long)CFDataGetLength(nic
)<UINT_MAX
); /* Debug check. correct as long as CFIndex is signed long */
318 otapkiref
= SecOTAPKICopyCurrentOTAPKIRef();
319 require_quiet(otapkiref
, errOut
);
320 anchors
= subject_to_anchors(nic
);
321 require_quiet(anchors
, errOut
);
322 parents
= CopyCertsFromIndices(anchors
);
325 callback(context
, parents
);
326 CFReleaseSafe(parents
);
327 CFReleaseSafe(otapkiref
);
328 //#endif // SECITEM_SHIM_OSX
332 static CFArrayRef
SecSystemAnchorSourceCopyUsageConstraints(SecCertificateSourceRef __unused source
,
333 SecCertificateRef __unused certificate
)
335 CFMutableArrayRef result
= NULL
;
336 CFMutableDictionaryRef options
= NULL
, strengthConstraints
= NULL
, trustRoot
= NULL
;
337 CFNumberRef trustResult
= NULL
;
339 require_quiet(options
= CFDictionaryCreateMutable(NULL
, 1,
340 &kCFTypeDictionaryKeyCallBacks
,
341 &kCFTypeDictionaryValueCallBacks
),
343 require_quiet(strengthConstraints
= CFDictionaryCreateMutable(NULL
, 1,
344 &kCFTypeDictionaryKeyCallBacks
,
345 &kCFTypeDictionaryValueCallBacks
),
347 require_quiet(trustRoot
= CFDictionaryCreateMutable(NULL
, 1,
348 &kCFTypeDictionaryKeyCallBacks
,
349 &kCFTypeDictionaryValueCallBacks
),
352 uint32_t temp
= kSecTrustSettingsResultTrustRoot
;
353 require_quiet(trustResult
= CFNumberCreate(NULL
, kCFNumberSInt32Type
, &temp
), out
);
354 CFDictionaryAddValue(trustRoot
, kSecTrustSettingsResult
, trustResult
);
356 CFDictionaryAddValue(options
, kSecPolicyCheckSystemTrustedWeakHash
, kCFBooleanTrue
);
357 CFDictionaryAddValue(options
, kSecPolicyCheckSystemTrustedWeakKey
, kCFBooleanTrue
);
358 CFDictionaryAddValue(strengthConstraints
, kSecTrustSettingsPolicyOptions
, options
);
360 require_quiet(result
= CFArrayCreateMutable(NULL
, 2, &kCFTypeArrayCallBacks
), out
);
361 CFArrayAppendValue(result
, strengthConstraints
);
362 CFArrayAppendValue(result
, trustRoot
);
365 CFReleaseNull(options
);
366 CFReleaseNull(trustResult
);
367 CFReleaseNull(trustRoot
);
368 CFReleaseNull(strengthConstraints
);
372 static bool SecSystemAnchorSourceContains(SecCertificateSourceRef source
,
373 SecCertificateRef certificate
) {
375 CFArrayRef anchors
= NULL
;
376 SecOTAPKIRef otapkiref
= NULL
;
377 CFArrayRef cert_datas
= NULL
;
379 CFDataRef nic
= SecCertificateGetNormalizedSubjectContent(certificate
);
380 /* 64 bits cast: the worst that can happen here is we truncate the length and match an actual anchor.
381 It does not matter since we would be returning the wrong anchors */
382 assert((unsigned long)CFDataGetLength(nic
)<UINT_MAX
); /* Debug check. correct as long as CFIndex is signed long */
384 otapkiref
= SecOTAPKICopyCurrentOTAPKIRef();
385 require_quiet(otapkiref
, errOut
);
386 anchors
= subject_to_anchors(nic
);
387 require_quiet(anchors
, errOut
);
388 cert_datas
= CopyCertDataFromIndices(anchors
);
389 require_quiet(cert_datas
, errOut
);
391 CFIndex cert_length
= SecCertificateGetLength(certificate
);
392 const UInt8
*cert_data_ptr
= SecCertificateGetBytePtr(certificate
);
394 CFIndex num_cert_datas
= CFArrayGetCount(cert_datas
);
395 for (CFIndex idx
= 0; idx
< num_cert_datas
; idx
++)
397 CFDataRef cert_data
= (CFDataRef
)CFArrayGetValueAtIndex(cert_datas
, idx
);
399 if (NULL
!= cert_data
)
401 if (CFGetTypeID(cert_data
) == CFDataGetTypeID())
403 CFIndex aCert_Length
= CFDataGetLength(cert_data
);
404 const UInt8
* aCert_Data_Ptr
= CFDataGetBytePtr(cert_data
);
406 if (aCert_Length
== cert_length
)
408 if (!memcmp(cert_data_ptr
, aCert_Data_Ptr
, cert_length
))
419 CFReleaseSafe(cert_datas
);
420 CFReleaseSafe(otapkiref
);
424 struct SecCertificateSource _kSecSystemAnchorSource
= {
425 SecSystemAnchorSourceCopyParents
,
426 SecSystemAnchorSourceCopyUsageConstraints
,
427 SecSystemAnchorSourceContains
430 const SecCertificateSourceRef kSecSystemAnchorSource
= &_kSecSystemAnchorSource
;
435 // MARK: SecUserAnchorSource
436 /********************************************************
437 ************* SecUserAnchorSource object ***************
438 ********************************************************/
439 static bool SecUserAnchorSourceCopyParents(SecCertificateSourceRef source
, SecCertificateRef certificate
,
440 void *context
, SecCertificateSourceParents callback
) {
441 CFArrayRef parents
= SecTrustStoreCopyParents(SecTrustStoreForDomain(kSecTrustStoreDomainUser
),
443 callback(context
, parents
);
444 CFReleaseSafe(parents
);
448 static CFArrayRef
SecUserAnchorSourceCopyUsageConstraints(SecCertificateSourceRef source
,
449 SecCertificateRef certificate
) {
450 CFDataRef digest
= SecCertificateGetSHA1Digest(certificate
);
453 CFArrayRef usageConstraints
= NULL
;
454 bool ok
= _SecTrustStoreCopyUsageConstraints(SecTrustStoreForDomain(kSecTrustStoreDomainUser
),
455 digest
, &usageConstraints
, NULL
);
457 return usageConstraints
;
459 CFReleaseNull(usageConstraints
);
464 static bool SecUserAnchorSourceContains(SecCertificateSourceRef source
,
465 SecCertificateRef certificate
) {
466 return SecTrustStoreContains(SecTrustStoreForDomain(kSecTrustStoreDomainUser
),
470 struct SecCertificateSource _kSecUserAnchorSource
= {
471 SecUserAnchorSourceCopyParents
,
472 SecUserAnchorSourceCopyUsageConstraints
,
473 SecUserAnchorSourceContains
476 const SecCertificateSourceRef kSecUserAnchorSource
= &_kSecUserAnchorSource
;
480 // MARK: SecMemoryCertificateSource
481 /********************************************************
482 ********** SecMemoryCertificateSource object ***********
483 ********************************************************/
484 struct SecMemoryCertificateSource
{
485 struct SecCertificateSource base
;
486 CFMutableSetRef certificates
;
487 CFMutableDictionaryRef subjects
;
489 typedef struct SecMemoryCertificateSource
*SecMemoryCertificateSourceRef
;
491 static bool SecMemoryCertificateSourceCopyParents(
492 SecCertificateSourceRef source
, SecCertificateRef certificate
,
493 void *context
, SecCertificateSourceParents callback
) {
494 SecMemoryCertificateSourceRef msource
=
495 (SecMemoryCertificateSourceRef
)source
;
496 CFDataRef normalizedIssuer
=
497 SecCertificateGetNormalizedIssuerContent(certificate
);
498 CFArrayRef parents
= (normalizedIssuer
) ? CFDictionaryGetValue(msource
->subjects
,
499 normalizedIssuer
) : NULL
;
500 /* FIXME filter parents by subjectID if certificate has an
501 authorityKeyIdentifier. */
502 secdebug("trust", "%@ parents -> %@", certificate
, parents
);
503 callback(context
, parents
);
507 static bool SecMemoryCertificateSourceContains(SecCertificateSourceRef source
,
508 SecCertificateRef certificate
) {
509 SecMemoryCertificateSourceRef msource
=
510 (SecMemoryCertificateSourceRef
)source
;
511 return CFSetContainsValue(msource
->certificates
, certificate
);
514 static void dictAddValueToArrayForKey(CFMutableDictionaryRef dict
,
515 const void *key
, const void *value
) {
519 CFMutableArrayRef values
=
520 (CFMutableArrayRef
)CFDictionaryGetValue(dict
, key
);
522 values
= CFArrayCreateMutable(kCFAllocatorDefault
, 0,
523 &kCFTypeArrayCallBacks
);
524 CFDictionaryAddValue(dict
, key
, values
);
529 CFArrayAppendValue(values
, value
);
532 static void SecMemoryCertificateSourceApplierFunction(const void *value
,
534 SecMemoryCertificateSourceRef msource
=
535 (SecMemoryCertificateSourceRef
)context
;
536 SecCertificateRef certificate
= (SecCertificateRef
)value
;
538 /* CFSet's API has no way to combine these 2 operations into 1 sadly. */
539 if (CFSetContainsValue(msource
->certificates
, certificate
))
541 CFSetAddValue(msource
->certificates
, certificate
);
543 CFDataRef key
= SecCertificateGetNormalizedSubjectContent(certificate
);
544 dictAddValueToArrayForKey(msource
->subjects
, key
, value
);
547 SecCertificateSourceRef
SecMemoryCertificateSourceCreate(CFArrayRef certificates
) {
548 SecMemoryCertificateSourceRef result
= (SecMemoryCertificateSourceRef
)
549 malloc(sizeof(*result
));
550 result
->base
.copyParents
= SecMemoryCertificateSourceCopyParents
;
551 result
->base
.copyUsageConstraints
= NULL
;
552 result
->base
.contains
= SecMemoryCertificateSourceContains
;
553 CFIndex count
= CFArrayGetCount(certificates
);
554 result
->certificates
= CFSetCreateMutable(kCFAllocatorDefault
, count
,
555 &kCFTypeSetCallBacks
);
556 result
->subjects
= CFDictionaryCreateMutable(kCFAllocatorDefault
,
557 count
, &kCFTypeDictionaryKeyCallBacks
,
558 &kCFTypeDictionaryValueCallBacks
);
559 CFRange range
= { 0, count
};
560 CFArrayApplyFunction(certificates
, range
,
561 SecMemoryCertificateSourceApplierFunction
, result
);
563 return (SecCertificateSourceRef
)result
;
566 void SecMemoryCertificateSourceDestroy(SecCertificateSourceRef source
) {
567 SecMemoryCertificateSourceRef msource
=
568 (SecMemoryCertificateSourceRef
)source
;
569 CFRelease(msource
->certificates
);
570 CFRelease(msource
->subjects
);
575 // MARK: SecCAIssuerCertificateSource
576 /********************************************************
577 ********* SecCAIssuerCertificateSource object **********
578 ********************************************************/
579 static bool SecCAIssuerCertificateSourceCopyParents(
580 SecCertificateSourceRef source
, SecCertificateRef certificate
,
581 void *context
, SecCertificateSourceParents callback
) {
582 /* Some expired certs have dead domains. Let's not check them. */
583 SecPathBuilderRef builder
= (SecPathBuilderRef
)context
;
584 CFAbsoluteTime verifyDate
= SecPathBuilderGetVerifyTime(builder
);
585 if (SecPathBuilderHasTemporalParentChecks(builder
) && !SecCertificateIsValid(certificate
, verifyDate
)) {
586 secinfo("async", "skipping CAIssuer fetch for expired %@", certificate
);
587 callback(context
, NULL
);
590 return SecCAIssuerCopyParents(certificate
, SecPathBuilderGetQueue(builder
), context
, callback
);
593 static bool SecCAIssuerCertificateSourceContains(
594 SecCertificateSourceRef source
, SecCertificateRef certificate
) {
598 struct SecCertificateSource _kSecCAIssuerSource
= {
599 SecCAIssuerCertificateSourceCopyParents
,
601 SecCAIssuerCertificateSourceContains
604 const SecCertificateSourceRef kSecCAIssuerSource
= &_kSecCAIssuerSource
;
607 #include <Security/SecItemPriv.h>
609 // MARK: SecLegacyCertificateSource
610 /********************************************************
611 ********** SecLegacyCertificateSource object ***********
612 ********************************************************/
614 static bool SecLegacyCertificateSourceCopyParents(
615 SecCertificateSourceRef source
, SecCertificateRef certificate
,
616 void *context
, SecCertificateSourceParents callback
) {
617 CFArrayRef parents
= SecItemCopyParentCertificates_osx(certificate
, NULL
);
618 callback(context
, parents
);
619 CFReleaseSafe(parents
);
623 static bool SecLegacyCertificateSourceContains(
624 SecCertificateSourceRef source
, SecCertificateRef certificate
) {
625 SecCertificateRef cert
= SecItemCopyStoredCertificate(certificate
, NULL
);
626 bool result
= (cert
) ? true : false;
631 struct SecCertificateSource _kSecLegacyCertificateSource
= {
632 SecLegacyCertificateSourceCopyParents
,
634 SecLegacyCertificateSourceContains
637 const SecCertificateSourceRef kSecLegacyCertificateSource
= &_kSecLegacyCertificateSource
;
639 #endif /* SecLegacyCertificateSource */
643 // MARK: SecLegacyAnchorSource
644 /********************************************************
645 ************ SecLegacyAnchorSource object **************
646 ********************************************************/
648 static bool SecLegacyAnchorSourceCopyParents(SecCertificateSourceRef source
, SecCertificateRef certificate
,
649 void *context
, SecCertificateSourceParents callback
) {
650 CFMutableArrayRef anchors
= CFArrayCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeArrayCallBacks
);
651 CFArrayRef parents
= SecItemCopyParentCertificates_osx(certificate
, NULL
);
652 CFArrayRef trusted
= NULL
;
653 if (parents
== NULL
) {
656 /* Get the custom anchors which have been trusted in the user and admin domains.
657 * We don't need system domain roots here, since SecSystemAnchorSource provides those.
659 OSStatus status
= SecTrustSettingsCopyCertificatesForUserAdminDomains(&trusted
);
660 if (status
== errSecSuccess
&& trusted
) {
661 CFIndex index
, count
= CFArrayGetCount(parents
);
662 for (index
= 0; index
< count
; index
++) {
663 SecCertificateRef parent
= (SecCertificateRef
)CFArrayGetValueAtIndex(parents
, index
);
664 if (parent
&& CFArrayContainsValue(trusted
, CFRangeMake(0, CFArrayGetCount(trusted
)), parent
)) {
665 CFArrayAppendValue(anchors
, parent
);
671 callback(context
, anchors
);
672 CFReleaseSafe(anchors
);
673 CFReleaseSafe(parents
);
674 CFReleaseSafe(trusted
);
678 static CFArrayRef
SecLegacyAnchorSourceCopyUsageConstraints(SecCertificateSourceRef source
,
679 SecCertificateRef certificate
) {
680 CFArrayRef result
= NULL
;
681 CFArrayRef userTrustSettings
= NULL
, adminTrustSettings
= NULL
;
683 OSStatus status
= SecTrustSettingsCopyTrustSettings(certificate
,
684 kSecTrustSettingsDomainUser
,
686 if ((status
== errSecSuccess
) && (userTrustSettings
!= NULL
)) {
687 result
= CFRetain(userTrustSettings
);
690 status
= SecTrustSettingsCopyTrustSettings(certificate
,
691 kSecTrustSettingsDomainAdmin
,
692 &adminTrustSettings
);
693 /* user trust settings overrule admin trust settings */
694 if ((status
== errSecSuccess
) && (adminTrustSettings
!= NULL
) && (result
== NULL
)) {
695 result
= CFRetain(adminTrustSettings
);
698 CFReleaseNull(userTrustSettings
);
699 CFReleaseNull(adminTrustSettings
);
703 static bool SecLegacyAnchorSourceContains(SecCertificateSourceRef source
,
704 SecCertificateRef certificate
) {
705 if (certificate
== NULL
) {
708 CFArrayRef trusted
= NULL
;
710 OSStatus status
= SecTrustSettingsCopyCertificatesForUserAdminDomains(&trusted
);
711 if ((status
== errSecSuccess
) && (trusted
!= NULL
)) {
712 CFIndex index
, count
= CFArrayGetCount(trusted
);
713 for (index
= 0; index
< count
; index
++) {
714 SecCertificateRef anchor
= (SecCertificateRef
)CFArrayGetValueAtIndex(trusted
, index
);
715 if (anchor
&& CFEqual(anchor
, certificate
)) {
721 CFReleaseSafe(trusted
);
725 struct SecCertificateSource _kSecLegacyAnchorSource
= {
726 SecLegacyAnchorSourceCopyParents
,
727 SecLegacyAnchorSourceCopyUsageConstraints
,
728 SecLegacyAnchorSourceContains
731 const SecCertificateSourceRef kSecLegacyAnchorSource
= &_kSecLegacyAnchorSource
;
733 #endif /* SecLegacyAnchorSource */