2 * Copyright (c) 2002-2010 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@
27 #include <security_keychain/Trust.h>
28 #include <security_keychain/TrustSettingsSchema.h>
29 #include <security_cdsa_utilities/cssmdates.h>
30 #include <security_utilities/cfutilities.h>
31 #include <CoreFoundation/CoreFoundation.h>
32 #include <Security/SecCertificate.h>
33 #include <Security/SecTrust.h>
34 #include "SecBridge.h"
35 #include "TrustAdditions.h"
36 #include "TrustKeychains.h"
39 using namespace Security
;
40 using namespace KeychainCore
;
43 // Translate CFDataRef to CssmData. The output shares the input's buffer.
45 static inline CssmData
cfData(CFDataRef data
)
47 return CssmData(const_cast<UInt8
*>(CFDataGetBytePtr(data
)),
48 CFDataGetLength(data
));
52 // Convert a SecPointer to a CF object.
54 static SecCertificateRef
55 convert(const SecPointer
<Certificate
> &certificate
)
61 // For now, we use a global TrustStore
63 ModuleNexus
<TrustStore
> Trust::gStore
;
65 #pragma mark -- TrustKeychains --
67 static const CSSM_DL_DB_HANDLE nullCSSMDLDBHandle
= {0,};
69 // TrustKeychains maintains a global reference to standard system keychains,
70 // to avoid having them be opened anew for each Trust instance.
77 CSSM_DL_DB_HANDLE
rootStoreHandle() { return mRootStore
? mRootStore
->database()->handle() : nullCSSMDLDBHandle
; }
78 CSSM_DL_DB_HANDLE
systemKcHandle() { return mSystem
? mSystem
->database()->handle() : nullCSSMDLDBHandle
; }
79 Keychain
&rootStore() { return mRootStore
; }
80 Keychain
&systemKc() { return mSystem
; }
87 // Singleton maintaining open references to standard system keychains,
88 // to avoid having them be opened anew every time SecTrust is used.
91 static ModuleNexus
<TrustKeychains
> trustKeychains
;
92 static ModuleNexus
<RecursiveMutex
> trustKeychainsMutex
;
94 TrustKeychains::TrustKeychains() :
95 mRootStore(globals().storageManager
.make(SYSTEM_ROOT_STORE_PATH
, false)),
96 mSystem(globals().storageManager
.make(ADMIN_CERT_STORE_PATH
, false))
100 RecursiveMutex
& SecTrustKeychainsGetMutex()
102 return trustKeychainsMutex();
105 #pragma mark -- Trust --
107 // Construct a Trust object with suitable defaults.
108 // Use setters for additional arguments before calling evaluate().
110 Trust::Trust(CFTypeRef certificates
, CFTypeRef policies
)
111 : mTP(gGuidAppleX509TP
), mAction(CSSM_TP_ACTION_DEFAULT
),
112 mCerts(cfArrayize(certificates
)), mPolicies(cfArrayize(policies
)),
113 mResult(kSecTrustResultInvalid
), mUsingTrustSettings(false),
114 mAnchorPolicy(useAnchorsDefault
), mSearchLibsSet(false),
115 mSearchLibs(NULL
), mMutex(Mutex::recursive
)
121 // Clean up a Trust object
133 // Get searchLibs (a vector of Keychain objects);
134 // normally initialized to default search list
136 StorageManager::KeychainList
& Trust::searchLibs(bool init
)
139 mSearchLibs
= new StorageManager::KeychainList
;
141 globals().storageManager
.getSearchList(*mSearchLibs
);
149 // Set searchLibs to provided vector of Keychain objects
151 void Trust::searchLibs(StorageManager::KeychainList
&libs
)
153 searchLibs(false) = libs
;
154 mSearchLibsSet
= true;
159 // Retrieve the last TP evaluation result, if any
161 CSSM_TP_VERIFY_CONTEXT_RESULT_PTR
Trust::cssmResult()
163 if (mResult
== kSecTrustResultInvalid
)
164 MacOSError::throwMe(errSecTrustNotAvailable
);
169 // SecCertificateRef -> CssmData
170 CssmData
cfCertificateData(SecCertificateRef certificate
)
172 return Certificate::required(certificate
)->data();
175 // SecPolicyRef -> CssmField (CFDataRef/NULL or oid/value of a SecPolicy)
176 CssmField
cfField(SecPolicyRef item
)
178 SecPointer
<Policy
> policy
= Policy::required(SecPolicyRef(item
));
179 return CssmField(policy
->oid(), policy
->value());
182 // SecKeychain -> CssmDlDbHandle
183 CSSM_DL_DB_HANDLE
cfKeychain(SecKeychainRef ref
)
185 Keychain keychain
= KeychainImpl::required(ref
);
186 return keychain
->database()->handle();
190 void showCertSKID(const void *value
, void *context
);
194 // Here's the big "E" - evaluation.
195 // We build most of the CSSM-layer input structures dynamically right here;
196 // they will auto-destruct when we're done. The output structures are kept
197 // around (in our data members) for later analysis.
198 // Note that evaluate() can be called repeatedly, so we must be careful to
199 // dispose of prior results.
201 void Trust::evaluate(bool disableEV
)
203 bool isEVCandidate
=false;
204 // begin evaluation block with stack-based mutex
206 StLock
<Mutex
>_(mMutex
);
207 // if we have evaluated before, release prior result
210 // determine whether the leaf certificate is an EV candidate
211 CFArrayRef allowedAnchors
= allowedEVRootsForLeafCertificate(mCerts
);
212 CFArrayRef filteredCerts
= NULL
;
213 isEVCandidate
= (allowedAnchors
&& !disableEV
) ? true : false;
215 secdebug("evTrust", "Trust::evaluate() certificate is EV candidate");
216 filteredCerts
= potentialEVChainWithCertificates(mCerts
);
217 mCerts
= filteredCerts
;
219 secdebug("evTrust", "Trust::evaluate() performing standard evaluation");
221 filteredCerts
= CFArrayCreateMutableCopy(NULL
, 0, mCerts
);
224 allowedAnchors
= CFArrayCreateMutableCopy(NULL
, 0, mAnchors
);
227 // retain these certs as long as we potentially could have results involving them
228 // (note that assignment to a CFRef type performs an implicit retain)
229 mAllowedAnchors
= allowedAnchors
;
230 mFilteredCerts
= filteredCerts
;
233 CFRelease(allowedAnchors
);
235 CFRelease(filteredCerts
);
239 secdebug("trusteval", "Trust::evaluate: anchors: %ld", CFArrayGetCount(mAllowedAnchors
));
241 CFArrayApplyFunction(mAllowedAnchors
, CFRangeMake(0, CFArrayGetCount(mAllowedAnchors
)), showCertSKID
, NULL
);
245 // set default search list from user's default, if caller did not explicitly supply it
246 if(!mSearchLibsSet
) {
247 globals().storageManager
.getSearchList(searchLibs());
248 mSearchLibsSet
= true;
251 // build the target cert group
252 CFToVector
<CssmData
, SecCertificateRef
, cfCertificateData
> subjects(mFilteredCerts
);
253 CertGroup
subjectCertGroup(CSSM_CERT_X_509v3
,
254 CSSM_CERT_ENCODING_BER
, CSSM_CERTGROUP_DATA
);
255 subjectCertGroup
.count() = subjects
;
256 subjectCertGroup
.blobCerts() = subjects
;
258 // build a TP_VERIFY_CONTEXT, a veritable nightmare of a data structure
259 TPBuildVerifyContext
context(mAction
);
262 * Guarantee *some* action data...
263 * NOTE this only works with the local X509 TP. When this module can deal
264 * with other TPs, this must be revisited.
266 CSSM_APPLE_TP_ACTION_DATA localActionData
;
267 memset(&localActionData
, 0, sizeof(localActionData
));
268 CssmData
localActionCData((uint8
*)&localActionData
, sizeof(localActionData
));
269 CSSM_APPLE_TP_ACTION_DATA
*actionDataP
= &localActionData
;
271 context
.actionData() = cfData(mActionData
);
272 actionDataP
= (CSSM_APPLE_TP_ACTION_DATA
*)context
.actionData().data();
275 context
.actionData() = localActionCData
;
279 // always check trust settings if caller did not provide explicit trust anchors
280 actionDataP
->ActionFlags
|= CSSM_TP_ACTION_TRUST_SETTINGS
;
283 if (policySpecified(mPolicies
, CSSMOID_APPLE_TP_SSL
)) {
284 // enable network cert fetch for SSL only: <rdar://7422356>
285 actionDataP
->ActionFlags
|= CSSM_TP_ACTION_FETCH_CERT_FROM_NET
;
289 * Policies (one at least, please).
290 * For revocation policies, see if any have been explicitly specified...
292 CFMutableArrayRef allPolicies
= NULL
;
293 uint32 numSpecAdded
= 0;
294 uint32 numPrefAdded
= 0;
295 bool requirePerCert
= (actionDataP
->ActionFlags
& CSSM_TP_ACTION_REQUIRE_REV_PER_CERT
);
296 if (isEVCandidate
|| requirePerCert
) {
297 // force revocation checking for this evaluation
298 secdebug("evTrust", "Trust::evaluate() forcing OCSP/CRL revocation checking");
299 allPolicies
= forceRevocationPolicies(numPrefAdded
, context
.allocator
, requirePerCert
);
301 else if (mAnchors
&& (CFArrayGetCount(mAnchors
)==0) && (searchLibs().size()==0)) {
302 // caller explicitly provided empty anchors and no keychain list;
303 // override global revocation check setting for this evaluation
304 allPolicies
= NULL
; // use only mPolicies
306 else if(!(revocationPolicySpecified(mPolicies
))) {
308 * None specified in mPolicies; see if any specified via SPI.
310 allPolicies
= addSpecifiedRevocationPolicies(numSpecAdded
, context
.allocator
);
311 if(allPolicies
== NULL
) {
313 * None there; try preferences.
315 allPolicies
= Trust::addPreferenceRevocationPolicies(numPrefAdded
,
320 if(allPolicies
== NULL
) {
321 allPolicies
= CFMutableArrayRef(CFArrayRef(mPolicies
));
323 orderRevocationPolicies(allPolicies
);
324 CFToVector
<CssmField
, SecPolicyRef
, cfField
> policies(allPolicies
);
325 if (policies
.empty())
326 MacOSError::throwMe(CSSMERR_TP_INVALID_POLICY_IDENTIFIERS
);
327 context
.setPolicies(policies
, policies
);
329 // anchor certificates (if caller provides them, or if cert requires EV)
330 CFCopyRef
<CFArrayRef
> anchors(mAllowedAnchors
);
331 CFToVector
<CssmData
, SecCertificateRef
, cfCertificateData
> roots(anchors
);
333 // no anchor certificates were provided;
334 // built-in anchors will be trusted unless explicitly disabled.
335 mUsingTrustSettings
= (mAnchorPolicy
< useAnchorsOnly
);
336 secdebug("userTrust", "Trust::evaluate() %s",
337 (mUsingTrustSettings
) ? "using UserTrust" : "has no trusted anchors!");
340 // anchor certificates were provided;
341 // built-in anchors will NOT also be trusted unless explicitly enabled.
342 mUsingTrustSettings
= (mAnchorPolicy
== useAnchorsAndBuiltIns
);
343 secdebug("userTrust", "Trust::evaluate() using %s %s anchors",
344 (mUsingTrustSettings
) ? "UserTrust AND" : "only",
345 (isEVCandidate
) ? "EV" : "caller");
346 context
.anchors(roots
, roots
);
349 // dlDbList (keychain list)
350 vector
<CSSM_DL_DB_HANDLE
> dlDbList
;
352 StLock
<Mutex
> _(SecTrustKeychainsGetMutex());
353 StorageManager::KeychainList
& list
= searchLibs();
354 for (StorageManager::KeychainList::const_iterator it
= list
.begin();
355 it
!= list
.end(); it
++)
359 // For the purpose of looking up intermediate certificates to establish trust,
360 // do not include the network-based LDAP or DotMac pseudo-keychains. (The only
361 // time the network should be consulted for certificates is if there is an AIA
362 // extension with a specific URL, which will be handled by the TP code.)
363 CSSM_DL_DB_HANDLE dldbHandle
= (*it
)->database()->handle();
364 if (dldbHandle
.DLHandle
) {
366 CSSM_RETURN crtn
= CSSM_GetModuleGUIDFromHandle(dldbHandle
.DLHandle
, &guid
);
367 if (crtn
== CSSM_OK
) {
368 if ((memcmp(&guid
, &gGuidAppleLDAPDL
, sizeof(CSSM_GUID
))==0) ||
369 (memcmp(&guid
, &gGuidAppleDotMacDL
, sizeof(CSSM_GUID
))==0)) {
370 continue; // don't add to dlDbList
374 // This DB is OK to search for intermediate certificates.
375 dlDbList
.push_back(dldbHandle
);
381 if(mUsingTrustSettings
) {
382 /* Append system anchors for use with Trust Settings */
384 CSSM_DL_DB_HANDLE rootStoreHandle
= trustKeychains().rootStoreHandle();
385 if (rootStoreHandle
.DBHandle
)
386 dlDbList
.push_back(rootStoreHandle
);
387 actionDataP
->ActionFlags
|= CSSM_TP_ACTION_TRUST_SETTINGS
;
390 // no root store or system keychain; don't use trust settings but continue
391 mUsingTrustSettings
= false;
394 CSSM_DL_DB_HANDLE systemKcHandle
= trustKeychains().systemKcHandle();
395 if (systemKcHandle
.DBHandle
)
396 dlDbList
.push_back(systemKcHandle
);
399 /* Oh well, at least we got the root store DB */
402 context
.setDlDbList(dlDbList
.size(), &dlDbList
[0]);
408 CssmUniformDate(static_cast<CFDateRef
>(mVerifyTime
)).convertTo(
409 timeString
, sizeof(timeString
));
410 context
.time(timeString
);
413 // to avoid keychain open/close thrashing, hold a copy of the search list
414 StorageManager::KeychainList
*holdSearchList
= NULL
;
415 if (searchLibs().size() > 0) {
416 holdSearchList
= new StorageManager::KeychainList
;
417 globals().storageManager
.getSearchList(*holdSearchList
);
422 mTP
->certGroupVerify(subjectCertGroup
, context
, &mTpResult
);
424 } catch (CommonError
&err
) {
425 mTpReturn
= err
.osStatus();
426 secdebug("trusteval", "certGroupVerify exception: %d", (int)mTpReturn
);
428 mResult
= diagnoseOutcome();
430 // see if we can use the evidence
431 if (mTpResult
.count() > 0
432 && mTpResult
[0].form() == CSSM_EVIDENCE_FORM_APPLE_HEADER
433 && mTpResult
[0].as
<CSSM_TP_APPLE_EVIDENCE_HEADER
>()->Version
== CSSM_TP_APPLE_EVIDENCE_VERSION
434 && mTpResult
.count() == 3
435 && mTpResult
[1].form() == CSSM_EVIDENCE_FORM_APPLE_CERTGROUP
436 && mTpResult
[2].form() == CSSM_EVIDENCE_FORM_APPLE_CERT_INFO
) {
437 evaluateUserTrust(*mTpResult
[1].as
<CertGroup
>(),
438 mTpResult
[2].as
<CSSM_TP_APPLE_EVIDENCE_INFO
>(), anchors
);
440 // unexpected evidence information. Can't use it
441 secdebug("trusteval", "unexpected evidence ignored");
444 /* do post-processing for the evaluated certificate chain */
445 CFArrayRef fullChain
= makeCFArray(convert
, mCertChain
);
446 CFDictionaryRef etResult
= extendedTrustResults(fullChain
, mResult
, mTpReturn
, isEVCandidate
);
447 mExtendedResult
= etResult
; // assignment to CFRef type is an implicit retain
452 CFRelease(fullChain
);
455 /* Clean up Policies we created implicitly */
457 freeSpecifiedRevocationPolicies(allPolicies
, numSpecAdded
, context
.allocator
);
460 Trust::freePreferenceRevocationPolicies(allPolicies
, numPrefAdded
, context
.allocator
);
463 if (holdSearchList
) {
464 delete holdSearchList
;
465 holdSearchList
= NULL
;
467 } // end evaluation block with mutex; releases all temporary allocations in this scope
470 if (isEVCandidate
&& mResult
== kSecTrustResultRecoverableTrustFailure
&&
471 isRevocationServerMetaError(mTpReturn
)) {
472 // re-do the evaluation, this time disabling EV
477 // CSSM_RETURN values that map to kSecTrustResultRecoverableTrustFailure.
478 static const CSSM_RETURN recoverableErrors
[] =
480 CSSMERR_TP_INVALID_ANCHOR_CERT
,
481 CSSMERR_TP_NOT_TRUSTED
,
482 CSSMERR_TP_VERIFICATION_FAILURE
,
483 CSSMERR_TP_VERIFY_ACTION_FAILED
,
484 CSSMERR_TP_INVALID_CERTIFICATE
,
485 CSSMERR_TP_INVALID_REQUEST_INPUTS
,
486 CSSMERR_TP_CERT_EXPIRED
,
487 CSSMERR_TP_CERT_NOT_VALID_YET
,
488 CSSMERR_TP_CERTIFICATE_CANT_OPERATE
,
489 CSSMERR_TP_INVALID_CERT_AUTHORITY
,
490 CSSMERR_APPLETP_INCOMPLETE_REVOCATION_CHECK
,
491 CSSMERR_APPLETP_HOSTNAME_MISMATCH
,
492 CSSMERR_TP_VERIFY_ACTION_FAILED
,
493 CSSMERR_APPLETP_SMIME_EMAIL_ADDRS_NOT_FOUND
,
494 CSSMERR_APPLETP_SMIME_NO_EMAIL_ADDRS
,
495 CSSMERR_APPLETP_SMIME_BAD_EXT_KEY_USE
,
496 CSSMERR_APPLETP_CS_BAD_CERT_CHAIN_LENGTH
,
497 CSSMERR_APPLETP_CS_NO_BASIC_CONSTRAINTS
,
498 CSSMERR_APPLETP_CS_BAD_PATH_LENGTH
,
499 CSSMERR_APPLETP_CS_NO_EXTENDED_KEY_USAGE
,
500 CSSMERR_APPLETP_INVALID_EXTENDED_KEY_USAGE
,
501 CSSMERR_APPLETP_CODE_SIGN_DEVELOPMENT
,
502 CSSMERR_APPLETP_RS_BAD_CERT_CHAIN_LENGTH
,
503 CSSMERR_APPLETP_UNKNOWN_CRITICAL_EXTEN
,
504 CSSMERR_APPLETP_CRL_NOT_FOUND
,
505 CSSMERR_APPLETP_CRL_SERVER_DOWN
,
506 CSSMERR_APPLETP_CRL_NOT_VALID_YET
,
507 CSSMERR_APPLETP_OCSP_UNAVAILABLE
,
508 CSSMERR_APPLETP_INCOMPLETE_REVOCATION_CHECK
,
509 CSSMERR_APPLETP_NETWORK_FAILURE
,
510 CSSMERR_APPLETP_OCSP_RESP_TRY_LATER
,
512 #define NUM_RECOVERABLE_ERRORS (sizeof(recoverableErrors) / sizeof(CSSM_RETURN))
515 // Classify the TP outcome in terms of a SecTrustResultType
517 SecTrustResultType
Trust::diagnoseOutcome()
519 StLock
<Mutex
>_(mMutex
);
521 uint32 chainLength
= 0;
522 if (mTpResult
.count() == 3 &&
523 mTpResult
[1].form() == CSSM_EVIDENCE_FORM_APPLE_CERTGROUP
&&
524 mTpResult
[2].form() == CSSM_EVIDENCE_FORM_APPLE_CERT_INFO
)
526 const CertGroup
&chain
= *mTpResult
[1].as
<CertGroup
>();
527 chainLength
= chain
.count();
531 case noErr
: // peachy
532 if (mUsingTrustSettings
)
536 const CSSM_TP_APPLE_EVIDENCE_INFO
*infoList
= mTpResult
[2].as
<CSSM_TP_APPLE_EVIDENCE_INFO
>();
537 const TPEvidenceInfo
&info
= TPEvidenceInfo::overlay(infoList
[chainLength
-1]);
538 const CSSM_TP_APPLE_CERT_STATUS resultCertStatus
= info
.status();
539 bool hasUserDomainTrust
= ((resultCertStatus
& CSSM_CERT_STATUS_TRUST_SETTINGS_TRUST
) &&
540 (resultCertStatus
& CSSM_CERT_STATUS_TRUST_SETTINGS_FOUND_USER
));
541 bool hasAdminDomainTrust
= ((resultCertStatus
& CSSM_CERT_STATUS_TRUST_SETTINGS_TRUST
) &&
542 (resultCertStatus
& CSSM_CERT_STATUS_TRUST_SETTINGS_FOUND_ADMIN
));
543 if (hasUserDomainTrust
|| hasAdminDomainTrust
)
545 return kSecTrustResultProceed
; // explicitly allowed
549 return kSecTrustResultUnspecified
; // cert evaluates OK
550 case CSSMERR_TP_INVALID_CERTIFICATE
: // bad certificate
551 return kSecTrustResultFatalTrustFailure
;
552 case CSSMERR_APPLETP_TRUST_SETTING_DENY
: // authoritative denial
553 return kSecTrustResultDeny
;
558 // a known list of returns maps to kSecTrustResultRecoverableTrustFailure
559 const CSSM_RETURN
*errp
=recoverableErrors
;
560 for(unsigned dex
=0; dex
<NUM_RECOVERABLE_ERRORS
; dex
++, errp
++) {
561 if(*errp
== mTpReturn
) {
562 return kSecTrustResultRecoverableTrustFailure
;
565 return kSecTrustResultOtherError
; // unknown
570 // Assuming a good evidence chain, check user trust
571 // settings and set mResult accordingly.
573 void Trust::evaluateUserTrust(const CertGroup
&chain
,
574 const CSSM_TP_APPLE_EVIDENCE_INFO
*infoList
, CFCopyRef
<CFArrayRef
> anchors
)
576 StLock
<Mutex
>_(mMutex
);
577 // extract cert chain as Certificate objects
578 mCertChain
.resize(chain
.count());
579 for (uint32 n
= 0; n
< mCertChain
.size(); n
++) {
580 const TPEvidenceInfo
&info
= TPEvidenceInfo::overlay(infoList
[n
]);
581 if (info
.recordId()) {
582 Keychain keychain
= keychainByDLDb(info
.DlDbHandle
);
583 DbUniqueRecord
uniqueId(keychain
->database()->newDbUniqueRecord());
584 secdebug("trusteval", "evidence %lu from keychain \"%s\"", (unsigned long)n
, keychain
->name());
585 *static_cast<CSSM_DB_UNIQUE_RECORD_PTR
*>(uniqueId
) = info
.UniqueRecord
;
586 uniqueId
->activate(); // transfers ownership
587 Item ii
= keychain
->item(CSSM_DL_DB_RECORD_X509_CERTIFICATE
, uniqueId
);
588 Certificate
* cert
= dynamic_cast<Certificate
*>(ii
.get());
590 CssmError::throwMe(CSSMERR_CSSM_INVALID_POINTER
);
592 mCertChain
[n
] = cert
;
593 } else if (info
.status(CSSM_CERT_STATUS_IS_IN_INPUT_CERTS
)) {
594 secdebug("trusteval", "evidence %lu from input cert %lu", (unsigned long)n
, (unsigned long)info
.index());
595 assert(info
.index() < uint32(CFArrayGetCount(mCerts
)));
596 SecCertificateRef cert
= SecCertificateRef(CFArrayGetValueAtIndex(mCerts
,
598 mCertChain
[n
] = Certificate::required(cert
);
599 } else if (info
.status(CSSM_CERT_STATUS_IS_IN_ANCHORS
)) {
600 secdebug("trusteval", "evidence %lu from anchor cert %lu", (unsigned long)n
, (unsigned long)info
.index());
601 assert(info
.index() < uint32(CFArrayGetCount(anchors
)));
602 SecCertificateRef cert
= SecCertificateRef(CFArrayGetValueAtIndex(anchors
,
604 mCertChain
[n
] = Certificate::required(cert
);
606 // unknown source; make a new Certificate for it
607 secdebug("trusteval", "evidence %lu from unknown source", (unsigned long)n
);
609 new Certificate(chain
.blobCerts()[n
],
610 CSSM_CERT_X_509v3
, CSSM_CERT_ENCODING_BER
);
614 // now walk the chain, leaf-to-root, checking for user settings
615 TrustStore
&store
= gStore();
616 SecPointer
<Policy
> policy
=
617 Policy::required(SecPolicyRef(CFArrayGetValueAtIndex(mPolicies
, 0)));
618 for (mResultIndex
= 0;
619 mResult
== kSecTrustResultUnspecified
&& mResultIndex
< mCertChain
.size();
621 if (!mCertChain
[mResultIndex
]) {
625 mResult
= store
.find(mCertChain
[mResultIndex
], policy
, searchLibs());
626 secdebug("trusteval", "trustResult=%lu from cert %lu", mResult
, (unsigned long)mResultIndex
);
632 // Release TP evidence information.
633 // This information is severely under-defined by CSSM, so we proceed
635 // (a) If the evidence matches an Apple-defined pattern, use specific
636 // knowledge of that format.
637 // (b) Otherwise, assume that the void * are flat blocks of memory.
639 void Trust::releaseTPEvidence(TPVerifyResult
&result
, Allocator
&allocator
)
641 if (result
.count() > 0) { // something to do
642 if (result
[0].form() == CSSM_EVIDENCE_FORM_APPLE_HEADER
) {
643 // Apple defined evidence form -- use intimate knowledge
644 if (result
[0].as
<CSSM_TP_APPLE_EVIDENCE_HEADER
>()->Version
== CSSM_TP_APPLE_EVIDENCE_VERSION
645 && result
.count() == 3
646 && result
[1].form() == CSSM_EVIDENCE_FORM_APPLE_CERTGROUP
647 && result
[2].form() == CSSM_EVIDENCE_FORM_APPLE_CERT_INFO
) {
649 CertGroup
& certs
= *result
[1].as
<CertGroup
>();
650 CSSM_TP_APPLE_EVIDENCE_INFO
*evidence
= result
[2].as
<CSSM_TP_APPLE_EVIDENCE_INFO
>();
651 uint32 count
= certs
.count();
652 allocator
.free(result
[0].data()); // just a struct
653 certs
.destroy(allocator
); // certgroup contents
654 allocator
.free(result
[1].data()); // the CertGroup itself
655 for (uint32 n
= 0; n
< count
; n
++)
656 allocator
.free(evidence
[n
].StatusCodes
);
657 allocator
.free(result
[2].data()); // array of (flat) info structs
659 secdebug("trusteval", "unrecognized Apple TP evidence format");
660 // drop it -- better leak than kill
663 // unknown format -- blindly assume flat blobs
664 secdebug("trusteval", "destroying unknown TP evidence format");
665 for (uint32 n
= 0; n
< result
.count(); n
++)
667 allocator
.free(result
[n
].data());
671 allocator
.free (result
.Evidence
);
677 // Clear evaluation results unless state is initial (invalid)
679 void Trust::clearResults()
681 StLock
<Mutex
>_(mMutex
);
682 if (mResult
!= kSecTrustResultInvalid
) {
683 releaseTPEvidence(mTpResult
, mTP
.allocator());
684 mResult
= kSecTrustResultInvalid
;
690 // Build evidence information
692 void Trust::buildEvidence(CFArrayRef
&certChain
, TPEvidenceInfo
* &statusChain
)
694 StLock
<Mutex
>_(mMutex
);
695 if (mResult
== kSecTrustResultInvalid
)
696 MacOSError::throwMe(errSecTrustNotAvailable
);
697 certChain
= mEvidenceReturned
=
698 makeCFArray(convert
, mCertChain
);
699 if(mTpResult
.count() >= 3) {
700 statusChain
= mTpResult
[2].as
<TPEvidenceInfo
>();
709 // Return extended result dictionary
711 void Trust::extendedResult(CFDictionaryRef
&result
)
713 if (mResult
== kSecTrustResultInvalid
)
714 MacOSError::throwMe(errSecTrustNotAvailable
);
716 CFRetain(mExtendedResult
); // retain before handing out to caller
717 result
= mExtendedResult
;
722 // Return properties array (a CFDictionaryRef for each certificate in chain)
724 CFArrayRef
Trust::properties()
726 // Builds and returns an array which the caller must release.
727 StLock
<Mutex
>_(mMutex
);
728 CFMutableArrayRef properties
= CFArrayCreateMutable(NULL
, 0,
729 &kCFTypeArrayCallBacks
);
730 if (mResult
== kSecTrustResultInvalid
) // chain not built or evaluated
733 // Walk the chain from leaf to anchor, building properties dictionaries
734 for (uint32 idx
=0; idx
< mCertChain
.size(); idx
++) {
735 CFMutableDictionaryRef dict
= CFDictionaryCreateMutable(NULL
, 0,
736 &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
738 CFStringRef title
= NULL
;
739 mCertChain
[idx
]->inferLabel(false, &title
);
741 CFDictionarySetValue(dict
, (const void *)kSecPropertyTypeTitle
, (const void *)title
);
744 if (idx
== 0 && mTpReturn
!= noErr
) {
745 CFStringRef error
= SecCopyErrorMessageString(mTpReturn
, NULL
);
747 CFDictionarySetValue(dict
, (const void *)kSecPropertyTypeError
, (const void *)error
);
751 CFArrayAppendValue(properties
, (const void *)dict
);
761 //* ===========================================================================
762 //* We need a way to compare two CSSM_DL_DB_HANDLEs WITHOUT using a operator
764 //* ===========================================================================
765 bool Compare_CSSM_DL_DB_HANDLE(const CSSM_DL_DB_HANDLE
&h1
, const CSSM_DL_DB_HANDLE
&h2
)
767 return (h1
.DLHandle
== h2
.DLHandle
&& h1
.DBHandle
== h2
.DBHandle
);
773 // Given a DL_DB_HANDLE, locate the Keychain object (from the search list)
775 Keychain
Trust::keychainByDLDb(const CSSM_DL_DB_HANDLE
&handle
)
777 StLock
<Mutex
>_(mMutex
);
778 StorageManager::KeychainList
& list
= searchLibs();
779 for (StorageManager::KeychainList::const_iterator it
= list
.begin();
780 it
!= list
.end(); it
++)
785 if (Compare_CSSM_DL_DB_HANDLE((*it
)->database()->handle(), handle
))
792 if(mUsingTrustSettings
) {
794 if(Compare_CSSM_DL_DB_HANDLE(trustKeychains().rootStoreHandle(), handle
)) {
795 return trustKeychains().rootStore();
797 if(Compare_CSSM_DL_DB_HANDLE(trustKeychains().systemKcHandle(), handle
)) {
798 return trustKeychains().systemKc();
802 /* one of those is missing; proceed */
806 // could not find in search list - internal error
808 // we now throw an error here rather than assert and silently fail. That way our application won't crash...
809 MacOSError::throwMe(errSecInternal
);