2 * Copyright (c) 2002-2014 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@
25 #include "SecTrustPriv.h"
27 #include <security_keychain/SecTrustSettingsPriv.h>
28 #include "SecBridge.h"
29 #include "SecInternal.h"
30 #include "SecInternalP.h"
31 #include "SecTrustSettings.h"
32 #include "SecCertificatePriv.h"
33 #include "SecCertificateP.h"
34 #include "SecCertificatePrivP.h"
35 #include <security_utilities/cfutilities.h>
36 #include <security_utilities/cfmunge.h>
37 #include <CoreFoundation/CoreFoundation.h>
39 // forward declarations
40 CFArrayRef
SecTrustCopyDetails(SecTrustRef trust
);
41 static CFDictionaryRef
SecTrustGetExceptionForCertificateAtIndex(SecTrustRef trust
, CFIndex ix
);
42 static void SecTrustCheckException(const void *key
, const void *value
, void *context
);
44 typedef struct SecTrustCheckExceptionContext
{
45 CFDictionaryRef exception
;
46 bool exceptionNotFound
;
47 } SecTrustCheckExceptionContext
;
49 // public trust result constants
50 CFTypeRef kSecTrustEvaluationDate
= CFSTR("TrustEvaluationDate");
51 CFTypeRef kSecTrustExtendedValidation
= CFSTR("TrustExtendedValidation");
52 CFTypeRef kSecTrustOrganizationName
= CFSTR("Organization");
53 CFTypeRef kSecTrustResultValue
= CFSTR("TrustResultValue");
54 CFTypeRef kSecTrustRevocationChecked
= CFSTR("TrustRevocationChecked");
55 CFTypeRef kSecTrustRevocationValidUntilDate
= CFSTR("TrustExpirationDate");
56 CFTypeRef kSecTrustResultDetails
= CFSTR("TrustResultDetails");
61 CFTypeID
SecTrustGetTypeID(void)
65 return gTypes().Trust
.typeID
;
67 END_SECAPI1(_kCFRuntimeNotATypeID
)
72 // Sec* API bridge functions
74 OSStatus
SecTrustCreateWithCertificates(
75 CFTypeRef certificates
,
77 SecTrustRef
*trustRef
)
81 *trustRef
= (new Trust(certificates
, policies
))->handle();
86 SecTrustSetPolicies(SecTrustRef trustRef
, CFTypeRef policies
)
89 Trust::required(trustRef
)->policies(policies
);
94 SecTrustSetOptions(SecTrustRef trustRef
, SecTrustOptionFlags options
)
97 CSSM_APPLE_TP_ACTION_DATA actionData
= {
98 CSSM_APPLE_TP_ACTION_VERSION
,
99 (CSSM_APPLE_TP_ACTION_FLAGS
)options
101 Trust
*trust
= Trust::required(trustRef
);
102 CFDataRef actionDataRef
= CFDataCreate(NULL
,
103 (const UInt8
*)&actionData
,
104 (CFIndex
)sizeof(CSSM_APPLE_TP_ACTION_DATA
));
105 trust
->action(CSSM_TP_ACTION_DEFAULT
);
106 trust
->actionData(actionDataRef
);
107 if (actionDataRef
) CFRelease(actionDataRef
);
111 OSStatus
SecTrustSetParameters(
112 SecTrustRef trustRef
,
113 CSSM_TP_ACTION action
,
114 CFDataRef actionData
)
117 Trust
*trust
= Trust::required(trustRef
);
118 trust
->action(action
);
119 trust
->actionData(actionData
);
124 OSStatus
SecTrustSetAnchorCertificates(SecTrustRef trust
, CFArrayRef anchorCertificates
)
127 Trust::required(trust
)->anchors(anchorCertificates
);
131 OSStatus
SecTrustSetAnchorCertificatesOnly(SecTrustRef trust
, Boolean anchorCertificatesOnly
)
134 Trust::AnchorPolicy policy
= (anchorCertificatesOnly
) ? Trust::useAnchorsOnly
: Trust::useAnchorsAndBuiltIns
;
135 Trust::required(trust
)->anchorPolicy(policy
);
139 OSStatus
SecTrustSetKeychains(SecTrustRef trust
, CFTypeRef keychainOrArray
)
142 StorageManager::KeychainList keychains
;
143 // avoid unnecessary global initializations if an empty array is passed in
144 if (!( (keychainOrArray
!= NULL
) &&
145 (CFGetTypeID(keychainOrArray
) == CFArrayGetTypeID()) &&
146 (CFArrayGetCount((CFArrayRef
)keychainOrArray
) == 0) )) {
147 globals().storageManager
.optionalSearchList(keychainOrArray
, keychains
);
149 Trust::required(trust
)->searchLibs(keychains
);
154 OSStatus
SecTrustSetVerifyDate(SecTrustRef trust
, CFDateRef verifyDate
)
157 Trust::required(trust
)->time(verifyDate
);
162 CFAbsoluteTime
SecTrustGetVerifyTime(SecTrustRef trust
)
164 CFAbsoluteTime verifyTime
= 0;
165 OSStatus __secapiresult
= errSecSuccess
;
167 CFRef
<CFDateRef
> verifyDate
= Trust::required(trust
)->time();
168 verifyTime
= CFDateGetAbsoluteTime(verifyDate
);
170 catch (const MacOSError
&err
) { __secapiresult
=err
.osStatus(); }
171 catch (const CommonError
&err
) { __secapiresult
=SecKeychainErrFromOSStatus(err
.osStatus()); }
172 catch (const std::bad_alloc
&) { __secapiresult
=errSecAllocate
; }
173 catch (...) { __secapiresult
=errSecInternalComponent
; }
178 OSStatus
SecTrustEvaluate(SecTrustRef trust
, SecTrustResultType
*resultP
)
180 SecTrustResultType trustResult
= kSecTrustResultInvalid
;
181 CFArrayRef exceptions
= NULL
;
182 OSStatus __secapiresult
= errSecSuccess
;
184 Trust
*trustObj
= Trust::required(trust
);
185 trustObj
->evaluate();
186 trustResult
= trustObj
->result();
187 exceptions
= trustObj
->exceptions();
189 catch (const MacOSError
&err
) { __secapiresult
=err
.osStatus(); }
190 catch (const CommonError
&err
) { __secapiresult
=SecKeychainErrFromOSStatus(err
.osStatus()); }
191 catch (const std::bad_alloc
&) { __secapiresult
=errSecAllocate
; }
192 catch (...) { __secapiresult
=errSecInternalComponent
; }
194 if (__secapiresult
) {
195 return __secapiresult
;
198 /* post-process trust result based on exceptions */
199 if (trustResult
== kSecTrustResultUnspecified
) {
200 /* If leaf is in exceptions -> proceed, otherwise unspecified. */
201 if (SecTrustGetExceptionForCertificateAtIndex(trust
, 0))
202 trustResult
= kSecTrustResultProceed
;
204 else if (trustResult
== kSecTrustResultRecoverableTrustFailure
&& exceptions
) {
205 /* If we have exceptions get details and match to exceptions. */
206 CFArrayRef details
= SecTrustCopyDetails(trust
);
208 CFIndex pathLength
= CFArrayGetCount(details
);
209 struct SecTrustCheckExceptionContext context
= {};
211 for (ix
= 0; ix
< pathLength
; ++ix
) {
212 CFDictionaryRef detail
= (CFDictionaryRef
)CFArrayGetValueAtIndex(details
, ix
);
213 // if ((ix == 0) && CFDictionaryContainsKey(detail, kSecPolicyCheckBlackListedLeaf))
214 // trustResult = kSecTrustResultFatalTrustFailure;
215 context
.exception
= SecTrustGetExceptionForCertificateAtIndex(trust
, ix
);
216 CFDictionaryApplyFunction(detail
, SecTrustCheckException
, &context
);
217 if (context
.exceptionNotFound
) {
221 if (!context
.exceptionNotFound
)
222 trustResult
= kSecTrustResultProceed
;
227 secdebug("SecTrustEvaluate", "SecTrustEvaluate trust result = %d", (int)trustResult
);
229 *resultP
= trustResult
;
231 return __secapiresult
;
234 OSStatus
SecTrustEvaluateAsync(SecTrustRef trust
,
235 dispatch_queue_t queue
, SecTrustCallback result
)
238 dispatch_async(queue
, ^{
240 Trust
*trustObj
= Trust::required(trust
);
241 trustObj
->evaluate();
242 SecTrustResultType trustResult
= trustObj
->result();
243 result(trust
, trustResult
);
246 result(trust
, kSecTrustResultInvalid
);
253 // Construct the "official" result evidence and return it
255 OSStatus
SecTrustGetResult(
256 SecTrustRef trustRef
,
257 SecTrustResultType
*result
,
258 CFArrayRef
*certChain
, CSSM_TP_APPLE_EVIDENCE_INFO
**statusChain
)
261 Trust
*trust
= Trust::required(trustRef
);
263 *result
= trust
->result();
264 if (certChain
&& statusChain
)
265 trust
->buildEvidence(*certChain
, TPEvidenceInfo::overlayVar(*statusChain
));
270 // Retrieve result of trust evaluation only
272 OSStatus
SecTrustGetTrustResult(SecTrustRef trustRef
,
273 SecTrustResultType
*result
)
276 Trust
*trust
= Trust::required(trustRef
);
277 if (result
) *result
= trust
->result();
282 // Retrieve extended validation trust results
284 OSStatus
SecTrustCopyExtendedResult(SecTrustRef trust
, CFDictionaryRef
*result
)
287 Trust
*trustObj
= Trust::required(trust
);
290 trustObj
->extendedResult(*result
);
295 // Retrieve CSSM-level information for those who want to dig down
297 OSStatus
SecTrustGetCssmResult(SecTrustRef trust
, CSSM_TP_VERIFY_CONTEXT_RESULT_PTR
*result
)
300 Required(result
) = Trust::required(trust
)->cssmResult();
305 // Retrieve CSSM_LEVEL TP return code
307 OSStatus
SecTrustGetCssmResultCode(SecTrustRef trustRef
, OSStatus
*result
)
310 Trust
*trust
= Trust::required(trustRef
);
311 if (trust
->result() == kSecTrustResultInvalid
)
314 Required(result
) = trust
->cssmResultCode();
318 OSStatus
SecTrustGetTPHandle(SecTrustRef trust
, CSSM_TP_HANDLE
*handle
)
321 Required(handle
) = Trust::required(trust
)->getTPHandle();
325 OSStatus
SecTrustCopyPolicies(SecTrustRef trust
, CFArrayRef
*policies
)
328 CFArrayRef currentPolicies
= Trust::required(trust
)->policies();
329 if (currentPolicies
!= NULL
)
331 CFRetain(currentPolicies
);
334 Required(policies
) = currentPolicies
;
338 OSStatus
SecTrustSetNetworkFetchAllowed(SecTrustRef trust
, Boolean allowFetch
)
341 Trust
*trustObj
= Trust::required(trust
);
342 Trust::NetworkPolicy netPolicy
= (allowFetch
) ?
343 Trust::useNetworkEnabled
: Trust::useNetworkDisabled
;
344 trustObj
->networkPolicy(netPolicy
);
348 OSStatus
SecTrustGetNetworkFetchAllowed(SecTrustRef trust
, Boolean
*allowFetch
)
351 Boolean allowed
= false;
352 Trust
*trustObj
= Trust::required(trust
);
353 Trust::NetworkPolicy netPolicy
= trustObj
->networkPolicy();
354 if (netPolicy
== Trust::useNetworkDefault
) {
355 // network fetch is enabled by default for SSL only
356 allowed
= trustObj
->policySpecified(trustObj
->policies(), CSSMOID_APPLE_TP_SSL
);
358 // caller has explicitly set the network policy
359 allowed
= (netPolicy
== Trust::useNetworkEnabled
);
361 Required(allowFetch
) = allowed
;
365 OSStatus
SecTrustSetOCSPResponse(SecTrustRef trust
, CFTypeRef responseData
)
368 Trust::required(trust
)->responses(responseData
);
372 OSStatus
SecTrustCopyCustomAnchorCertificates(SecTrustRef trust
, CFArrayRef
*anchorCertificates
)
375 CFArrayRef customAnchors
= Trust::required(trust
)->anchors();
376 Required(anchorCertificates
) = (customAnchors
) ?
377 (const CFArrayRef
)CFRetain(customAnchors
) : (const CFArrayRef
)NULL
;
382 // Get the user's default anchor certificate set
384 OSStatus
SecTrustCopyAnchorCertificates(CFArrayRef
*anchorCertificates
)
388 return SecTrustSettingsCopyUnrestrictedRoots(
389 true, true, true, /* all domains */
396 SecKeyRef
SecTrustCopyPublicKey(SecTrustRef trust
)
398 SecKeyRef pubKey
= NULL
;
399 CFArrayRef certChain
= NULL
;
400 CFArrayRef evidenceChain
= NULL
;
401 CSSM_TP_APPLE_EVIDENCE_INFO
*statusChain
= NULL
;
402 OSStatus __secapiresult
= errSecSuccess
;
404 Trust
*trustObj
= Trust::required(trust
);
405 if (trustObj
->result() == kSecTrustResultInvalid
) {
406 // Trust hasn't been evaluated; attempt to retrieve public key from leaf.
407 SecCertificateRef cert
= SecTrustGetCertificateAtIndex(trust
, 0);
408 __secapiresult
= SecCertificateCopyPublicKey(cert
, &pubKey
);
412 // Otherwise, we must evaluate first.
413 trustObj
->evaluate();
414 if (trustObj
->result() == kSecTrustResultInvalid
) {
415 MacOSError::throwMe(errSecTrustNotAvailable
);
418 if (trustObj
->evidence() == nil
) {
419 trustObj
->buildEvidence(certChain
, TPEvidenceInfo::overlayVar(statusChain
));
421 evidenceChain
= trustObj
->evidence();
423 catch (const MacOSError
&err
) { __secapiresult
=err
.osStatus(); }
424 catch (const CommonError
&err
) { __secapiresult
=SecKeychainErrFromOSStatus(err
.osStatus()); }
425 catch (const std::bad_alloc
&) { __secapiresult
=errSecAllocate
; }
426 catch (...) { __secapiresult
=errSecInternalComponent
; }
429 CFRelease(certChain
);
432 if (CFArrayGetCount(evidenceChain
) > 0) {
433 SecCertificateRef cert
= (SecCertificateRef
) CFArrayGetValueAtIndex(evidenceChain
, 0);
434 __secapiresult
= SecCertificateCopyPublicKey(cert
, &pubKey
);
436 // do not release evidenceChain, as it is owned by the trust object.
442 CFIndex
SecTrustGetCertificateCount(SecTrustRef trust
)
444 CFIndex chainLen
= 0;
445 CFArrayRef certChain
= NULL
;
446 CFArrayRef evidenceChain
= NULL
;
447 CSSM_TP_APPLE_EVIDENCE_INFO
*statusChain
= NULL
;
448 OSStatus __secapiresult
= errSecSuccess
;
450 Trust
*trustObj
= Trust::required(trust
);
451 if (trustObj
->result() == kSecTrustResultInvalid
) {
452 trustObj
->evaluate();
453 if (trustObj
->result() == kSecTrustResultInvalid
)
454 MacOSError::throwMe(errSecTrustNotAvailable
);
456 if (trustObj
->evidence() == nil
)
457 trustObj
->buildEvidence(certChain
, TPEvidenceInfo::overlayVar(statusChain
));
458 evidenceChain
= trustObj
->evidence();
460 catch (const MacOSError
&err
) { __secapiresult
=err
.osStatus(); }
461 catch (const CommonError
&err
) { __secapiresult
=SecKeychainErrFromOSStatus(err
.osStatus()); }
462 catch (const std::bad_alloc
&) { __secapiresult
=errSecAllocate
; }
463 catch (...) { __secapiresult
=errSecInternalComponent
; }
466 CFRelease(certChain
);
469 chainLen
= CFArrayGetCount(evidenceChain
); // don't release, trust object owns it.
475 SecCertificateRef
SecTrustGetCertificateAtIndex(SecTrustRef trust
, CFIndex ix
)
477 SecCertificateRef certificate
= NULL
;
478 CFArrayRef certChain
= NULL
;
479 CFArrayRef evidenceChain
= NULL
;
480 CSSM_TP_APPLE_EVIDENCE_INFO
*statusChain
= NULL
;
481 OSStatus __secapiresult
= errSecSuccess
;
483 Trust
*trustObj
= Trust::required(trust
);
484 if (trustObj
->result() == kSecTrustResultInvalid
) {
485 // If caller is asking for the leaf, we can return it without
486 // having to evaluate the entire chain. Note that we don't retain
487 // the cert as it's owned by the trust and this is a 'Get' API.
489 CFArrayRef certs
= trustObj
->certificates();
490 if (certs
&& (CFArrayGetCount(certs
) > 0)) {
491 certificate
= (SecCertificateRef
) CFArrayGetValueAtIndex(certs
, 0);
497 // Otherwise, we must evaluate first.
498 trustObj
->evaluate();
499 if (trustObj
->result() == kSecTrustResultInvalid
) {
500 MacOSError::throwMe(errSecTrustNotAvailable
);
503 if (trustObj
->evidence() == nil
) {
504 trustObj
->buildEvidence(certChain
, TPEvidenceInfo::overlayVar(statusChain
));
506 evidenceChain
= trustObj
->evidence();
508 catch (const MacOSError
&err
) { __secapiresult
=err
.osStatus(); }
509 catch (const CommonError
&err
) { __secapiresult
=SecKeychainErrFromOSStatus(err
.osStatus()); }
510 catch (const std::bad_alloc
&) { __secapiresult
=errSecAllocate
; }
511 catch (...) { __secapiresult
=errSecInternalComponent
; }
514 CFRelease(certChain
);
517 if (ix
< CFArrayGetCount(evidenceChain
)) {
518 certificate
= (SecCertificateRef
) CFArrayGetValueAtIndex(evidenceChain
, ix
);
519 // note: we do not retain this certificate. The assumption here is
520 // that the certificate is retained by the trust object, so it is
521 // valid unil the trust is released (or until re-evaluated.)
522 // also note: we do not release the evidenceChain, as it is owned
523 // by the trust object.
530 static CFStringRef kSecCertificateDetailSHA1Digest
= CFSTR("SHA1Digest");
531 static CFStringRef kSecCertificateDetailStatusCodes
= CFSTR("StatusCodes");
534 _AppendStatusCode(CFMutableArrayRef array
, OSStatus statusCode
)
538 SInt32 num
= statusCode
;
539 CFNumberRef numRef
= CFNumberCreate(NULL
, kCFNumberSInt32Type
, &num
);
542 CFArrayAppendValue(array
, numRef
);
546 CFArrayRef
SecTrustCopyDetails(SecTrustRef trust
)
548 // This function returns an array of dictionaries, one per certificate,
549 // holding status info for each certificate in the evaluated chain.
551 CFIndex count
, chainLen
= 0;
552 CFArrayRef certChain
= NULL
;
553 CFMutableArrayRef details
= NULL
;
554 CSSM_TP_APPLE_EVIDENCE_INFO
*statusChain
= NULL
;
555 OSStatus __secapiresult
= errSecSuccess
;
557 Trust
*trustObj
= Trust::required(trust
);
558 if (trustObj
->result() == kSecTrustResultInvalid
) {
559 trustObj
->evaluate();
560 if (trustObj
->result() == kSecTrustResultInvalid
)
561 MacOSError::throwMe(errSecTrustNotAvailable
);
563 trustObj
->buildEvidence(certChain
, TPEvidenceInfo::overlayVar(statusChain
));
565 catch (const MacOSError
&err
) { __secapiresult
=err
.osStatus(); }
566 catch (const CommonError
&err
) { __secapiresult
=SecKeychainErrFromOSStatus(err
.osStatus()); }
567 catch (const std::bad_alloc
&) { __secapiresult
=errSecAllocate
; }
568 catch (...) { __secapiresult
=errSecInternalComponent
; }
571 chainLen
= CFArrayGetCount(certChain
);
572 CFRelease(certChain
);
575 details
= CFArrayCreateMutable(NULL
, chainLen
, &kCFTypeArrayCallBacks
);
576 for (count
= 0; count
< chainLen
; count
++) {
577 CFMutableDictionaryRef certDict
= CFDictionaryCreateMutable(kCFAllocatorDefault
,
578 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
579 CFMutableArrayRef statusCodes
= CFArrayCreateMutable(kCFAllocatorDefault
,
580 0, &kCFTypeArrayCallBacks
);
581 CSSM_TP_APPLE_EVIDENCE_INFO
*evInfo
= &statusChain
[count
];
582 CSSM_TP_APPLE_CERT_STATUS statBits
= evInfo
->StatusBits
;
584 // translate status bits
585 if (statBits
& CSSM_CERT_STATUS_EXPIRED
)
586 _AppendStatusCode(statusCodes
, errSecCertificateExpired
);
587 if (statBits
& CSSM_CERT_STATUS_NOT_VALID_YET
)
588 _AppendStatusCode(statusCodes
, errSecCertificateNotValidYet
);
589 if (statBits
& CSSM_CERT_STATUS_TRUST_SETTINGS_DENY
)
590 _AppendStatusCode(statusCodes
, errSecTrustSettingDeny
);
592 // translate status codes
594 for (i
= 0; i
< evInfo
->NumStatusCodes
; i
++) {
595 CSSM_RETURN scode
= evInfo
->StatusCodes
[i
];
596 _AppendStatusCode(statusCodes
, (OSStatus
)scode
);
599 CFDictionarySetValue(certDict
, kSecCertificateDetailStatusCodes
, statusCodes
);
600 CFRelease(statusCodes
);
601 CFArrayAppendValue(details
, certDict
);
608 static CFDictionaryRef
SecTrustGetExceptionForCertificateAtIndex(SecTrustRef trust
, CFIndex ix
)
610 CFArrayRef exceptions
= NULL
;
611 OSStatus __secapiresult
= errSecSuccess
;
613 exceptions
= Trust::required(trust
)->exceptions();
615 catch (const MacOSError
&err
) { __secapiresult
=err
.osStatus(); }
616 catch (const CommonError
&err
) { __secapiresult
=SecKeychainErrFromOSStatus(err
.osStatus()); }
617 catch (const std::bad_alloc
&) { __secapiresult
=errSecAllocate
; }
618 catch (...) { __secapiresult
=errSecInternalComponent
; }
620 if (!exceptions
|| ix
>= CFArrayGetCount(exceptions
))
622 CFDictionaryRef exception
= (CFDictionaryRef
)CFArrayGetValueAtIndex(exceptions
, ix
);
623 if (CFGetTypeID(exception
) != CFDictionaryGetTypeID())
626 SecCertificateRef certificate
= SecTrustGetCertificateAtIndex(trust
, ix
);
630 /* If the exception contains the current certificate's sha1Digest in the
631 kSecCertificateDetailSHA1Digest key then we use it otherwise we ignore it. */
632 CFDataRef sha1Digest
= SecCertificateGetSHA1Digest(certificate
);
633 CFTypeRef digestValue
= CFDictionaryGetValue(exception
, kSecCertificateDetailSHA1Digest
);
634 if (!digestValue
|| !CFEqual(sha1Digest
, digestValue
))
640 static void SecTrustCheckException(const void *key
, const void *value
, void *context
)
642 struct SecTrustCheckExceptionContext
*cec
= (struct SecTrustCheckExceptionContext
*)context
;
643 if (cec
->exception
) {
644 CFTypeRef exceptionValue
= CFDictionaryGetValue(cec
->exception
, key
);
645 if (!exceptionValue
|| !CFEqual(value
, exceptionValue
)) {
646 cec
->exceptionNotFound
= true;
649 cec
->exceptionNotFound
= true;
654 CFDataRef
SecTrustCopyExceptions(SecTrustRef trust
)
656 CFArrayRef details
= SecTrustCopyDetails(trust
);
657 CFIndex pathLength
= details
? CFArrayGetCount(details
) : 0;
658 CFMutableArrayRef exceptions
= CFArrayCreateMutable(kCFAllocatorDefault
,
659 pathLength
, &kCFTypeArrayCallBacks
);
661 for (ix
= 0; ix
< pathLength
; ++ix
) {
662 CFDictionaryRef detail
= (CFDictionaryRef
)CFArrayGetValueAtIndex(details
, ix
);
663 CFIndex detailCount
= CFDictionaryGetCount(detail
);
664 CFMutableDictionaryRef exception
;
665 if (ix
== 0 || detailCount
> 0) {
666 exception
= CFDictionaryCreateMutableCopy(kCFAllocatorDefault
,
667 detailCount
+ 1, detail
);
668 SecCertificateRef certificate
= SecTrustGetCertificateAtIndex(trust
, ix
);
669 CFDataRef digest
= SecCertificateGetSHA1Digest(certificate
);
671 CFDictionaryAddValue(exception
, kSecCertificateDetailSHA1Digest
, digest
);
674 /* Add empty exception dictionaries for non leaf certs which have no exceptions
677 exception
= (CFMutableDictionaryRef
)CFDictionaryCreate(kCFAllocatorDefault
,
679 &kCFTypeDictionaryKeyCallBacks
,
680 &kCFTypeDictionaryValueCallBacks
);
682 CFArrayAppendValue(exceptions
, exception
);
683 CFReleaseNull(exception
);
685 CFReleaseSafe(details
);
687 /* Remove any trailing empty dictionaries to save even more space (we skip the leaf
688 since it will never be empty). */
689 for (ix
= pathLength
; ix
-- > 1;) {
690 CFDictionaryRef exception
= (CFDictionaryRef
)CFArrayGetValueAtIndex(exceptions
, ix
);
691 if (CFDictionaryGetCount(exception
) == 0) {
692 CFArrayRemoveValueAtIndex(exceptions
, ix
);
698 CFDataRef encodedExceptions
= CFPropertyListCreateData(kCFAllocatorDefault
,
699 exceptions
, kCFPropertyListBinaryFormat_v1_0
, 0, NULL
);
700 CFRelease(exceptions
);
702 return encodedExceptions
;
706 bool SecTrustSetExceptions(SecTrustRef trust
, CFDataRef encodedExceptions
)
708 CFArrayRef exceptions
;
709 exceptions
= (CFArrayRef
)CFPropertyListCreateWithData(kCFAllocatorDefault
,
710 encodedExceptions
, kCFPropertyListImmutable
, NULL
, NULL
);
711 if (exceptions
&& CFGetTypeID(exceptions
) != CFArrayGetTypeID()) {
712 CFRelease(exceptions
);
716 OSStatus __secapiresult
= errSecSuccess
;
718 Trust::required(trust
)->exceptions(exceptions
);
720 catch (const MacOSError
&err
) { __secapiresult
=err
.osStatus(); }
721 catch (const CommonError
&err
) { __secapiresult
=SecKeychainErrFromOSStatus(err
.osStatus()); }
722 catch (const std::bad_alloc
&) { __secapiresult
=errSecAllocate
; }
723 catch (...) { __secapiresult
=errSecInternalComponent
; }
725 /* If there is a valid exception entry for our current leaf we're golden. */
726 if (SecTrustGetExceptionForCertificateAtIndex(trust
, 0))
729 /* The passed in exceptions didn't match our current leaf, so we discard it. */
731 Trust::required(trust
)->exceptions(NULL
);
732 __secapiresult
= errSecSuccess
;
734 catch (const MacOSError
&err
) { __secapiresult
=err
.osStatus(); }
735 catch (const CommonError
&err
) { __secapiresult
=SecKeychainErrFromOSStatus(err
.osStatus()); }
736 catch (const std::bad_alloc
&) { __secapiresult
=errSecAllocate
; }
737 catch (...) { __secapiresult
=errSecInternalComponent
; }
744 SecTrustCopyResult(SecTrustRef trust
)
746 CFDictionaryRef result
= NULL
;
748 result
= Trust::required(trust
)->results();
749 // merge details into result
750 CFArrayRef details
= SecTrustCopyDetails(trust
);
752 CFDictionarySetValue((CFMutableDictionaryRef
)result
,
753 kSecTrustResultDetails
, details
);
768 SecTrustCopyProperties(SecTrustRef trust
)
770 /* can't use SECAPI macros, since this function does not return OSStatus */
771 CFArrayRef result
= NULL
;
773 result
= Trust::required(trust
)->properties();
785 /* deprecated in 10.5 */
786 OSStatus
SecTrustGetCSSMAnchorCertificates(const CSSM_DATA
**cssmAnchors
,
787 uint32
*cssmAnchorCount
)
791 Trust::gStore().getCssmRootCertificates(certs
);
792 Required(cssmAnchors
) = certs
.blobCerts();
793 Required(cssmAnchorCount
) = certs
.count();
799 // Get and set user trust settings. Deprecated in 10.5.
800 // User Trust getter, deprecated, works as it always has.
802 OSStatus
SecTrustGetUserTrust(SecCertificateRef certificate
,
803 SecPolicyRef policy
, SecTrustUserSetting
*trustSetting
)
806 StorageManager::KeychainList searchList
;
807 globals().storageManager
.getSearchList(searchList
);
808 Required(trustSetting
) = Trust::gStore().find(
809 Certificate::required(certificate
),
810 Policy::required(policy
),
816 // The public setter, also deprecated; it maps to the appropriate
817 // Trust Settings call if possible, else throws errSecUnimplemented.
819 OSStatus
SecTrustSetUserTrust(SecCertificateRef certificate
,
820 SecPolicyRef policy
, SecTrustUserSetting trustSetting
)
822 SecTrustSettingsResult tsResult
= kSecTrustSettingsResultInvalid
;
826 Policy::required(policy
);
827 switch(trustSetting
) {
828 case kSecTrustResultProceed
:
829 /* different SecTrustSettingsResult depending in root-ness */
830 ortn
= SecCertificateIsSelfSigned(certificate
, &isRoot
);
835 tsResult
= kSecTrustSettingsResultTrustRoot
;
838 tsResult
= kSecTrustSettingsResultTrustAsRoot
;
841 case kSecTrustResultDeny
:
842 tsResult
= kSecTrustSettingsResultDeny
;
845 return errSecUnimplemented
;
848 /* make a usage constraints dictionary */
849 CFRef
<CFMutableDictionaryRef
> usageDict(CFDictionaryCreateMutable(NULL
,
850 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
));
851 CFDictionaryAddValue(usageDict
, kSecTrustSettingsPolicy
, policy
);
852 if(tsResult
!= kSecTrustSettingsResultTrustRoot
) {
853 /* skip if we're specifying the default */
854 SInt32 result
= tsResult
;
855 CFNumberRef cfNum
= CFNumberCreate(NULL
, kCFNumberSInt32Type
, &result
);
856 CFDictionarySetValue(usageDict
, kSecTrustSettingsResult
, cfNum
);
859 return SecTrustSettingsSetTrustSettings(certificate
, kSecTrustSettingsDomainUser
,
864 // This one is the now-private version of what SecTrustSetUserTrust() used to
865 // be. The public API can no longer manipulate User Trust settings, only
868 OSStatus
SecTrustSetUserTrustLegacy(SecCertificateRef certificate
,
869 SecPolicyRef policy
, SecTrustUserSetting trustSetting
)
872 switch (trustSetting
) {
873 case kSecTrustResultProceed
:
874 case kSecTrustResultConfirm
:
875 case kSecTrustResultDeny
:
876 case kSecTrustResultUnspecified
:
879 MacOSError::throwMe(errSecInvalidTrustSetting
);
881 Trust::gStore().assign(
882 Certificate::required(certificate
),
883 Policy::required(policy
),
888 /* SecGetAppleTPHandle - @@@NOT EXPORTED YET; copied from SecurityInterface,
889 but could be useful in the future.
893 SecGetAppleTPHandle()
896 return TP(gGuidAppleX509TP)->handle();