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
);