2  * Copyright (c) 2002-2015 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" 
  37 #include <security_cdsa_client/dlclient.h> 
  40 using namespace Security
; 
  41 using namespace KeychainCore
; 
  44 // Translate CFDataRef to CssmData. The output shares the input's buffer. 
  46 static inline CssmData 
cfData(CFDataRef data
) 
  48     return CssmData(const_cast<UInt8 
*>(CFDataGetBytePtr(data
)), 
  49         CFDataGetLength(data
)); 
  53 // Convert a SecPointer to a CF object. 
  55 static SecCertificateRef
 
  56 convert(const SecPointer
<Certificate
> &certificate
) 
  62 // For now, we use a global TrustStore 
  64 ModuleNexus
<TrustStore
> Trust::gStore
; 
  66 #pragma mark -- TrustKeychains -- 
  68 static const CSSM_DL_DB_HANDLE nullCSSMDLDBHandle 
= {0,}; 
  70 // TrustKeychains maintains a global reference to standard system keychains, 
  71 // to avoid having them be opened anew for each Trust instance. 
  78         CSSM_DL_DB_HANDLE       
rootStoreHandle()       { return mRootStoreHandle
; } 
  79         CSSM_DL_DB_HANDLE       
systemKcHandle()        { return mSystem 
? mSystem
->database()->handle() : nullCSSMDLDBHandle
; } 
  80         Keychain                        
&systemKc()                     { return mSystem
; } 
  81         Keychain                        
&rootStore()            { return *mRootStore
; } 
  87         CSSM_DL_DB_HANDLE       mRootStoreHandle
; 
  92 // Singleton maintaining open references to standard system keychains, 
  93 // to avoid having them be opened anew every time SecTrust is used. 
  96 static ModuleNexus
<TrustKeychains
> trustKeychains
; 
  97 static ModuleNexus
<RecursiveMutex
> trustKeychainsMutex
; 
  99 extern "C" bool GetServerMode(); 
 101 TrustKeychains::TrustKeychains() : 
 102         mRootStoreHandle(nullCSSMDLDBHandle
), 
 103         mSystem(globals().storageManager
.make(ADMIN_CERT_STORE_PATH
, false)) 
 105         if (GetServerMode()) // in server mode?  Don't make a keychain for the root store 
 107                 mRootStoreDL 
= new DL(gGuidAppleFileDL
), 
 108                 mRootStoreDb 
= new Db(*mRootStoreDL
, SYSTEM_ROOT_STORE_PATH
), 
 109                 (*mRootStoreDb
)->activate(); 
 110                 mRootStoreHandle 
= (*mRootStoreDb
)->handle(); 
 114                 mRootStore 
= new Keychain(globals().storageManager
.make(SYSTEM_ROOT_STORE_PATH
, false)); 
 115                 (*mRootStore
)->database()->activate(); 
 116                 mRootStoreHandle 
= (*mRootStore
)->database()->handle(); 
 120 RecursiveMutex
& SecTrustKeychainsGetMutex() 
 122         return trustKeychainsMutex(); 
 125 #pragma mark -- Trust -- 
 127 // Construct a Trust object with suitable defaults. 
 128 // Use setters for additional arguments before calling evaluate(). 
 130 Trust::Trust(CFTypeRef certificates
, CFTypeRef policies
) 
 131     : mTP(gGuidAppleX509TP
), mAction(CSSM_TP_ACTION_DEFAULT
), 
 132       mCerts(cfArrayize(certificates
)), mPolicies(cfArrayize(policies
)), 
 133       mSearchLibs(NULL
), mSearchLibsSet(false), mResult(kSecTrustResultInvalid
), 
 134       mUsingTrustSettings(false), mAnchorPolicy(useAnchorsDefault
), mMutex(Mutex::recursive
) 
 137                 mPolicies
.take(CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
)); 
 143 // Clean up a Trust object 
 157 // Get searchLibs (a vector of Keychain objects); 
 158 // normally initialized to default search list 
 160 StorageManager::KeychainList
& Trust::searchLibs(bool init
) 
 163                 mSearchLibs 
= new StorageManager::KeychainList
; 
 165                         globals().storageManager
.getSearchList(*mSearchLibs
); 
 173 // Set searchLibs to provided vector of Keychain objects 
 175 void Trust::searchLibs(StorageManager::KeychainList 
&libs
) 
 177         searchLibs(false) = libs
; 
 178         mSearchLibsSet 
= true; 
 183 // Retrieve the last TP evaluation result, if any 
 185 CSSM_TP_VERIFY_CONTEXT_RESULT_PTR 
Trust::cssmResult() 
 187         if (mResult 
== kSecTrustResultInvalid
) 
 188                 MacOSError::throwMe(errSecTrustNotAvailable
); 
 193 // SecCertificateRef -> CssmData 
 195 CssmData 
cfCertificateData(SecCertificateRef certificate
) 
 197     return Certificate::required(certificate
)->data(); 
 200 // SecPolicyRef -> CssmField (CFDataRef/NULL or oid/value of a SecPolicy) 
 202 CssmField 
cfField(SecPolicyRef item
) 
 204         SecPointer
<Policy
> policy 
= Policy::required(SecPolicyRef(item
)); 
 205     return CssmField(policy
->oid(), policy
->value()); 
 208 // SecKeychain -> CssmDlDbHandle 
 211 CSSM_DL_DB_HANDLE 
cfKeychain(SecKeychainRef ref
) 
 213         Keychain keychain 
= KeychainImpl::required(ref
); 
 214         return keychain
->database()->handle(); 
 219 void showCertSKID(const void *value
, void *context
); 
 223 // Here's the big "E" - evaluation. 
 224 // We build most of the CSSM-layer input structures dynamically right here; 
 225 // they will auto-destruct when we're done. The output structures are kept 
 226 // around (in our data members) for later analysis. 
 227 // Note that evaluate() can be called repeatedly, so we must be careful to 
 228 // dispose of prior results. 
 230 void Trust::evaluate(bool disableEV
) 
 232         bool isEVCandidate
=false; 
 233         // begin evaluation block with stack-based mutex 
 235         StLock
<Mutex
>_(mMutex
); 
 236         // if we have evaluated before, release prior result 
 239         // determine whether the leaf certificate is an EV candidate 
 240         CFArrayRef allowedAnchors 
= NULL
; 
 242                 allowedAnchors 
= allowedEVRootsForLeafCertificate(mCerts
); 
 243                 isEVCandidate 
= (allowedAnchors 
!= NULL
); 
 245         CFArrayRef filteredCerts 
= NULL
; 
 247                 secdebug("evTrust", "Trust::evaluate() certificate is EV candidate"); 
 248                 filteredCerts 
= potentialEVChainWithCertificates(mCerts
); 
 249                 mCerts 
= filteredCerts
; 
 251                 secdebug("evTrust", "Trust::evaluate() performing standard evaluation"); 
 253                         filteredCerts 
= CFArrayCreateMutableCopy(NULL
, 0, mCerts
); 
 256                         allowedAnchors 
= CFArrayCreateMutableCopy(NULL
, 0, mAnchors
); 
 259         // retain these certs as long as we potentially could have results involving them 
 260         // (note that assignment to a CFRef type performs an implicit retain) 
 261         mAllowedAnchors 
= allowedAnchors
; 
 262         mFilteredCerts 
= filteredCerts
; 
 265                 CFRelease(allowedAnchors
); 
 267                 CFRelease(filteredCerts
); 
 271                 secdebug("trusteval", "Trust::evaluate: anchors: %ld", CFArrayGetCount(mAllowedAnchors
)); 
 273                 CFArrayApplyFunction(mAllowedAnchors
, CFRangeMake(0, CFArrayGetCount(mAllowedAnchors
)), showCertSKID
, NULL
); 
 277         // set default search list from user's default, if caller did not explicitly supply it 
 278         if(!mSearchLibsSet
) { 
 279                 globals().storageManager
.getSearchList(searchLibs()); 
 280                 mSearchLibsSet 
= true; 
 283     // build the target cert group 
 284     CFToVector
<CssmData
, SecCertificateRef
, cfCertificateData
> subjects(mFilteredCerts
); 
 285     CertGroup 
subjectCertGroup(CSSM_CERT_X_509v3
, 
 286             CSSM_CERT_ENCODING_BER
, CSSM_CERTGROUP_DATA
); 
 287     subjectCertGroup
.count() = subjects
; 
 288     subjectCertGroup
.blobCerts() = subjects
; 
 290     // build a TP_VERIFY_CONTEXT, a veritable nightmare of a data structure 
 291     TPBuildVerifyContext 
context(mAction
); 
 294          * Guarantee *some* action data... 
 295          * NOTE this only works with the local X509 TP. When this module can deal 
 296          * with other TPs, this must be revisited. 
 298         CSSM_APPLE_TP_ACTION_DATA localActionData
; 
 299         memset(&localActionData
, 0, sizeof(localActionData
)); 
 300         CssmData 
localActionCData((uint8 
*)&localActionData
, sizeof(localActionData
)); 
 301         CSSM_APPLE_TP_ACTION_DATA 
*actionDataP 
= &localActionData
; 
 303                 context
.actionData() = cfData(mActionData
); 
 304                 actionDataP 
= (CSSM_APPLE_TP_ACTION_DATA 
*)context
.actionData().data(); 
 307                 context
.actionData() = localActionCData
; 
 310         bool hasSSLPolicy 
= policySpecified(mPolicies
, CSSMOID_APPLE_TP_SSL
); 
 311         bool hasEAPPolicy 
= policySpecified(mPolicies
, CSSMOID_APPLE_TP_EAP
); 
 314                 // always check trust settings if caller did not provide explicit trust anchors 
 315                 actionDataP
->ActionFlags 
|= CSSM_TP_ACTION_TRUST_SETTINGS
; 
 318         if (mNetworkPolicy 
== useNetworkDefault
) { 
 320                         // enable network cert fetch for SSL only: <rdar://7422356> 
 321                         actionDataP
->ActionFlags 
|= CSSM_TP_ACTION_FETCH_CERT_FROM_NET
; 
 324         else if (mNetworkPolicy 
== useNetworkEnabled
) 
 325                 actionDataP
->ActionFlags 
|= CSSM_TP_ACTION_FETCH_CERT_FROM_NET
; 
 326         else if (mNetworkPolicy 
== useNetworkDisabled
) 
 327                 actionDataP
->ActionFlags 
&= ~(CSSM_TP_ACTION_FETCH_CERT_FROM_NET
); 
 329         if (policySpecified(mPolicies
, CSSMOID_APPLE_TP_ESCROW_SERVICE
)) { 
 330                 // ignore expiration dates, per rdar://21943474 
 331                 actionDataP
->ActionFlags 
|= (CSSM_TP_ACTION_ALLOW_EXPIRED 
| 
 332                         CSSM_TP_ACTION_ALLOW_EXPIRED_ROOT
); 
 336          * Policies (one at least, please). 
 337          * For revocation policies, see if any have been explicitly specified... 
 339         CFMutableArrayRef allPolicies 
= NULL
; 
 340         uint32 numRevocationAdded 
= 0; 
 341         bool requirePerCert 
= (actionDataP
->ActionFlags 
& CSSM_TP_ACTION_REQUIRE_REV_PER_CERT
); 
 343         // If a new unified revocation policy was explicitly specified, 
 344         // convert into old-style individual OCSP and CRL policies. 
 345         // Note that the caller could configure revocation policy options 
 346         // to explicitly disable both methods, so 0 policies might be added, 
 347         // in which case we must no longer consider the cert an EV candidate. 
 349         allPolicies 
= convertRevocationPolicy(numRevocationAdded
, context
.allocator
); 
 351                 // caller has explicitly set the revocation policy they want to use 
 352                 secdebug("evTrust", "Trust::evaluate() using explicit revocation policy (%d)", 
 354                 if (numRevocationAdded 
== 0) 
 355                         isEVCandidate 
= false; 
 357         else if (mAnchors 
&& (CFArrayGetCount(mAnchors
)==0) && (searchLibs().size()==0)) { 
 358                 // caller explicitly provided empty anchors and no keychain list, 
 359                 // and did not explicitly specify the revocation policy; 
 360                 // override global revocation check setting for this evaluation 
 361                 secdebug("evTrust", "Trust::evaluate() has empty anchors and no keychains"); 
 362                 allPolicies 
= NULL
; // use only mPolicies 
 363                 isEVCandidate 
= false; 
 365         else if (isEVCandidate 
|| requirePerCert
) { 
 366                 // force revocation checking for this evaluation 
 367                 secdebug("evTrust", "Trust::evaluate() forcing OCSP/CRL revocation check"); 
 368                 allPolicies 
= forceRevocationPolicies(true, requirePerCert
, 
 369                         numRevocationAdded
, context
.allocator
, requirePerCert
); 
 371         else if(!(revocationPolicySpecified(mPolicies
))) { 
 372                 // none specified in mPolicies; try preferences 
 373                 allPolicies 
= addPreferenceRevocationPolicies(!(hasSSLPolicy 
|| hasEAPPolicy
), 
 374                         !(hasSSLPolicy 
|| hasEAPPolicy
), numRevocationAdded
, context
.allocator
); 
 376         if (allPolicies 
== NULL
) { 
 377                 // use mPolicies; no revocation checking will be performed 
 378                 secdebug("evTrust", "Trust::evaluate() will not perform revocation check"); 
 379                 CFIndex numPolicies 
= CFArrayGetCount(mPolicies
); 
 380                 CFAllocatorRef allocator 
= CFGetAllocator(mPolicies
); 
 381                 allPolicies 
= CFArrayCreateMutableCopy(allocator
, numPolicies
, mPolicies
); 
 383         orderRevocationPolicies(allPolicies
); 
 384     CFToVector
<CssmField
, SecPolicyRef
, cfField
> policies(allPolicies
); 
 386         // error exit here if empty policies are not supported 
 387     if (policies
.empty()) 
 388         MacOSError::throwMe(CSSMERR_TP_INVALID_POLICY_IDENTIFIERS
); 
 390     context
.setPolicies(policies
, policies
); 
 392         // anchor certificates (if caller provides them, or if cert requires EV) 
 393         CFCopyRef
<CFArrayRef
> anchors(mAllowedAnchors
); 
 394         CFToVector
<CssmData
, SecCertificateRef
, cfCertificateData
> roots(anchors
); 
 396                 // no anchor certificates were provided; 
 397                 // built-in anchors will be trusted unless explicitly disabled. 
 398                 mUsingTrustSettings 
= (mAnchorPolicy 
< useAnchorsOnly
); 
 399                 secdebug("userTrust", "Trust::evaluate() %s", 
 400                                  (mUsingTrustSettings
) ? "using UserTrust" : "has no trusted anchors!"); 
 403                 // anchor certificates were provided; 
 404                 // built-in anchors will NOT also be trusted unless explicitly enabled. 
 405                 mUsingTrustSettings 
= (mAnchorPolicy 
== useAnchorsAndBuiltIns
); 
 406                 secdebug("userTrust", "Trust::evaluate() using %s %s anchors", 
 407                                  (mUsingTrustSettings
) ? "UserTrust AND" : "only", 
 408                                  (isEVCandidate
) ? "EV" : "caller"); 
 409                 context
.anchors(roots
, roots
); 
 412         // dlDbList (keychain list) 
 413         vector
<CSSM_DL_DB_HANDLE
> dlDbList
; 
 415                 StLock
<Mutex
> _(SecTrustKeychainsGetMutex()); 
 416                 StorageManager::KeychainList
& list 
= searchLibs(); 
 417                 for (StorageManager::KeychainList::const_iterator it 
= list
.begin(); 
 418                                 it 
!= list
.end(); it
++) 
 422                                 // For the purpose of looking up intermediate certificates to establish trust, 
 423                                 // do not include the network-based LDAP or DotMac pseudo-keychains. (The only 
 424                                 // time the network should be consulted for certificates is if there is an AIA 
 425                                 // extension with a specific URL, which will be handled by the TP code.) 
 426                                 CSSM_DL_DB_HANDLE dldbHandle 
= (*it
)->database()->handle(); 
 427                                 if (dldbHandle
.DLHandle
) { 
 429                                         CSSM_RETURN crtn 
= CSSM_GetModuleGUIDFromHandle(dldbHandle
.DLHandle
, &guid
); 
 430                                         if (crtn 
== CSSM_OK
) { 
 431                                                 if ((memcmp(&guid
, &gGuidAppleLDAPDL
, sizeof(CSSM_GUID
))==0) || 
 432                                                         (memcmp(&guid
, &gGuidAppleDotMacDL
, sizeof(CSSM_GUID
))==0)) { 
 433                                                         continue; // don't add to dlDbList 
 437                                 // This DB is OK to search for intermediate certificates. 
 438                                 dlDbList
.push_back(dldbHandle
); 
 444                 if(mUsingTrustSettings
) { 
 445                         /* Append system anchors for use with Trust Settings */ 
 447                 CSSM_DL_DB_HANDLE rootStoreHandle 
= trustKeychains().rootStoreHandle(); 
 448                 if (rootStoreHandle
.DBHandle
) 
 449                     dlDbList
.push_back(rootStoreHandle
); 
 450                                 actionDataP
->ActionFlags 
|= CSSM_TP_ACTION_TRUST_SETTINGS
; 
 453                                 // no root store or system keychain; don't use trust settings but continue 
 454                                 mUsingTrustSettings 
= false; 
 457                 CSSM_DL_DB_HANDLE systemKcHandle 
= trustKeychains().systemKcHandle(); 
 458                 if (systemKcHandle
.DBHandle
) 
 459                     dlDbList
.push_back(systemKcHandle
); 
 462                                 /* Oh well, at least we got the root store DB */ 
 465                 context
.setDlDbList((uint32
)dlDbList
.size(), &dlDbList
[0]); 
 471         CssmUniformDate(static_cast<CFDateRef
>(mVerifyTime
)).convertTo( 
 472                         timeString
, sizeof(timeString
)); 
 473         context
.time(timeString
); 
 476         // to avoid keychain open/close thrashing, hold a copy of the search list 
 477         StorageManager::KeychainList 
*holdSearchList 
= NULL
; 
 478         if (searchLibs().size() > 0) { 
 479                 holdSearchList 
= new StorageManager::KeychainList
; 
 480                 globals().storageManager
.getSearchList(*holdSearchList
); 
 485         mTP
->certGroupVerify(subjectCertGroup
, context
, &mTpResult
); 
 486         mTpReturn 
= errSecSuccess
; 
 487     } catch (CommonError 
&err
) { 
 488         mTpReturn 
= err
.osStatus(); 
 489         secdebug("trusteval", "certGroupVerify exception: %d", (int)mTpReturn
); 
 491     mResult 
= diagnoseOutcome(); 
 493     // see if we can use the evidence 
 494     if (mTpResult
.count() > 0 
 495             && mTpResult
[0].form() == CSSM_EVIDENCE_FORM_APPLE_HEADER
 
 496             && mTpResult
[0].as
<CSSM_TP_APPLE_EVIDENCE_HEADER
>()->Version 
== CSSM_TP_APPLE_EVIDENCE_VERSION
 
 497             && mTpResult
.count() == 3 
 498             && mTpResult
[1].form() == CSSM_EVIDENCE_FORM_APPLE_CERTGROUP
 
 499             && mTpResult
[2].form() == CSSM_EVIDENCE_FORM_APPLE_CERT_INFO
) { 
 500         evaluateUserTrust(*mTpResult
[1].as
<CertGroup
>(), 
 501             mTpResult
[2].as
<CSSM_TP_APPLE_EVIDENCE_INFO
>(), anchors
); 
 503         // unexpected evidence information. Can't use it 
 504         secdebug("trusteval", "unexpected evidence ignored"); 
 507         /* do post-processing for the evaluated certificate chain */ 
 508         CFArrayRef fullChain 
= makeCFArray(convert
, mCertChain
); 
 509         CFDictionaryRef etResult 
= extendedTrustResults(fullChain
, mResult
, mTpReturn
, isEVCandidate
); 
 510         mExtendedResult 
= etResult
; // assignment to CFRef type is an implicit retain 
 515                 CFRelease(fullChain
); 
 519                 /* clean up revocation policies we created implicitly */ 
 520                 if(numRevocationAdded
) { 
 521                         freeAddedRevocationPolicyData(allPolicies
, numRevocationAdded
, context
.allocator
); 
 523                 CFRelease(allPolicies
); 
 526         if (holdSearchList
) { 
 527                 delete holdSearchList
; 
 528                 holdSearchList 
= NULL
; 
 530         } // end evaluation block with mutex; releases all temporary allocations in this scope 
 533         if (isEVCandidate 
&& mResult 
== kSecTrustResultRecoverableTrustFailure 
&& 
 534                 (mTpReturn 
== CSSMERR_TP_NOT_TRUSTED 
|| isRevocationServerMetaError(mTpReturn
))) { 
 535                 // re-do the evaluation, this time disabling EV 
 540 // CSSM_RETURN values that map to kSecTrustResultRecoverableTrustFailure. 
 541 static const CSSM_RETURN recoverableErrors
[] = 
 543         CSSMERR_TP_INVALID_ANCHOR_CERT
, 
 544         CSSMERR_TP_NOT_TRUSTED
, 
 545         CSSMERR_TP_VERIFICATION_FAILURE
, 
 546         CSSMERR_TP_VERIFY_ACTION_FAILED
, 
 547         CSSMERR_TP_INVALID_REQUEST_INPUTS
, 
 548         CSSMERR_TP_CERT_EXPIRED
, 
 549         CSSMERR_TP_CERT_NOT_VALID_YET
, 
 550         CSSMERR_TP_CERTIFICATE_CANT_OPERATE
, 
 551         CSSMERR_TP_INVALID_CERT_AUTHORITY
, 
 552         CSSMERR_APPLETP_INCOMPLETE_REVOCATION_CHECK
, 
 553         CSSMERR_APPLETP_HOSTNAME_MISMATCH
, 
 554         CSSMERR_TP_VERIFY_ACTION_FAILED
, 
 555         CSSMERR_APPLETP_SMIME_EMAIL_ADDRS_NOT_FOUND
, 
 556         CSSMERR_APPLETP_SMIME_NO_EMAIL_ADDRS
, 
 557         CSSMERR_APPLETP_SMIME_BAD_EXT_KEY_USE
, 
 558         CSSMERR_APPLETP_CS_BAD_CERT_CHAIN_LENGTH
, 
 559         CSSMERR_APPLETP_CS_NO_BASIC_CONSTRAINTS
, 
 560         CSSMERR_APPLETP_CS_BAD_PATH_LENGTH
, 
 561         CSSMERR_APPLETP_CS_NO_EXTENDED_KEY_USAGE
, 
 562         CSSMERR_APPLETP_INVALID_EXTENDED_KEY_USAGE
, 
 563         CSSMERR_APPLETP_CODE_SIGN_DEVELOPMENT
, 
 564         CSSMERR_APPLETP_RS_BAD_CERT_CHAIN_LENGTH
, 
 565         CSSMERR_APPLETP_UNKNOWN_CRITICAL_EXTEN
, 
 566         CSSMERR_APPLETP_CRL_NOT_FOUND
, 
 567         CSSMERR_APPLETP_CRL_SERVER_DOWN
, 
 568         CSSMERR_APPLETP_CRL_NOT_VALID_YET
, 
 569         CSSMERR_APPLETP_OCSP_UNAVAILABLE
, 
 570         CSSMERR_APPLETP_INCOMPLETE_REVOCATION_CHECK
, 
 571         CSSMERR_APPLETP_NETWORK_FAILURE
, 
 572         CSSMERR_APPLETP_OCSP_RESP_TRY_LATER
, 
 573         CSSMERR_APPLETP_IDENTIFIER_MISSING
, 
 575 #define NUM_RECOVERABLE_ERRORS  (sizeof(recoverableErrors) / sizeof(CSSM_RETURN)) 
 578 // Classify the TP outcome in terms of a SecTrustResultType 
 580 SecTrustResultType 
Trust::diagnoseOutcome() 
 582         StLock
<Mutex
>_(mMutex
); 
 584         uint32 chainLength 
= 0; 
 585         if (mTpResult
.count() == 3 && 
 586                 mTpResult
[1].form() == CSSM_EVIDENCE_FORM_APPLE_CERTGROUP 
&& 
 587                 mTpResult
[2].form() == CSSM_EVIDENCE_FORM_APPLE_CERT_INFO
) 
 589                 const CertGroup 
&chain 
= *mTpResult
[1].as
<CertGroup
>(); 
 590                 chainLength 
= chain
.count(); 
 594     case errSecSuccess
:                                                                 // peachy 
 595                 if (mUsingTrustSettings
) 
 599                                 const CSSM_TP_APPLE_EVIDENCE_INFO 
*infoList 
= mTpResult
[2].as
<CSSM_TP_APPLE_EVIDENCE_INFO
>(); 
 600                                 const TPEvidenceInfo 
&info 
= TPEvidenceInfo::overlay(infoList
[chainLength
-1]); 
 601                                 const CSSM_TP_APPLE_CERT_STATUS resultCertStatus 
= info
.status(); 
 602                                 bool hasUserDomainTrust 
= ((resultCertStatus 
& CSSM_CERT_STATUS_TRUST_SETTINGS_TRUST
) && 
 603                                                 (resultCertStatus 
& CSSM_CERT_STATUS_TRUST_SETTINGS_FOUND_USER
)); 
 604                                 bool hasAdminDomainTrust 
= ((resultCertStatus 
& CSSM_CERT_STATUS_TRUST_SETTINGS_TRUST
) && 
 605                                                 (resultCertStatus 
& CSSM_CERT_STATUS_TRUST_SETTINGS_FOUND_ADMIN
)); 
 606                                 if (hasUserDomainTrust 
|| hasAdminDomainTrust
) 
 608                                         return kSecTrustResultProceed
;          // explicitly allowed 
 612                 return kSecTrustResultUnspecified
;              // cert evaluates OK 
 613     case CSSMERR_TP_INVALID_CERTIFICATE
:                // bad certificate 
 614         return kSecTrustResultFatalTrustFailure
; 
 615         case CSSMERR_APPLETP_TRUST_SETTING_DENY
:        // authoritative denial 
 616                 return kSecTrustResultDeny
; 
 621         // a known list of returns maps to kSecTrustResultRecoverableTrustFailure 
 622         const CSSM_RETURN 
*errp
=recoverableErrors
; 
 623         for(unsigned dex
=0; dex
<NUM_RECOVERABLE_ERRORS
; dex
++, errp
++) { 
 624                 if(*errp 
== mTpReturn
) { 
 625                         return kSecTrustResultRecoverableTrustFailure
; 
 628         return kSecTrustResultOtherError
;                       // unknown 
 633 // Assuming a good evidence chain, check user trust 
 634 // settings and set mResult accordingly. 
 636 void Trust::evaluateUserTrust(const CertGroup 
&chain
, 
 637     const CSSM_TP_APPLE_EVIDENCE_INFO 
*infoList
, CFCopyRef
<CFArrayRef
> anchors
) 
 639         StLock
<Mutex
>_(mMutex
); 
 640     // extract cert chain as Certificate objects 
 641     mCertChain
.resize(chain
.count()); 
 642     for (uint32 n 
= 0; n 
< mCertChain
.size(); n
++) { 
 643         const TPEvidenceInfo 
&info 
= TPEvidenceInfo::overlay(infoList
[n
]); 
 644         if (info
.recordId()) { 
 645                         Keychain keychain 
= keychainByDLDb(info
.DlDbHandle
); 
 646                         DbUniqueRecord 
uniqueId(keychain
->database()->newDbUniqueRecord()); 
 647                         secdebug("trusteval", "evidence %lu from keychain \"%s\"", (unsigned long)n
, keychain
->name()); 
 648                         *static_cast<CSSM_DB_UNIQUE_RECORD_PTR 
*>(uniqueId
) = info
.UniqueRecord
; 
 649                         uniqueId
->activate(); // transfers ownership 
 650                         Item ii 
= keychain
->item(CSSM_DL_DB_RECORD_X509_CERTIFICATE
, uniqueId
); 
 651                         Certificate
* cert 
= dynamic_cast<Certificate
*>(ii
.get()); 
 653                                 CssmError::throwMe(CSSMERR_CSSM_INVALID_POINTER
); 
 655                         mCertChain
[n
] = cert
; 
 656         } else if (info
.status(CSSM_CERT_STATUS_IS_IN_INPUT_CERTS
)) { 
 657             secdebug("trusteval", "evidence %lu from input cert %lu", (unsigned long)n
, (unsigned long)info
.index()); 
 658             assert(info
.index() < uint32(CFArrayGetCount(mCerts
))); 
 659             SecCertificateRef cert 
= SecCertificateRef(CFArrayGetValueAtIndex(mCerts
, 
 661             mCertChain
[n
] = Certificate::required(cert
); 
 662         } else if (info
.status(CSSM_CERT_STATUS_IS_IN_ANCHORS
)) { 
 663             secdebug("trusteval", "evidence %lu from anchor cert %lu", (unsigned long)n
, (unsigned long)info
.index()); 
 664             assert(info
.index() < uint32(CFArrayGetCount(anchors
))); 
 665             SecCertificateRef cert 
= SecCertificateRef(CFArrayGetValueAtIndex(anchors
, 
 667             mCertChain
[n
] = Certificate::required(cert
); 
 669             // unknown source; make a new Certificate for it 
 670             secdebug("trusteval", "evidence %lu from unknown source", (unsigned long)n
); 
 672                 new Certificate(chain
.blobCerts()[n
], 
 673                                         CSSM_CERT_X_509v3
, CSSM_CERT_ENCODING_BER
); 
 677     // now walk the chain, leaf-to-root, checking for user settings 
 678         TrustStore 
&store 
= gStore(); 
 679         SecPointer
<Policy
> policy 
= (CFArrayGetCount(mPolicies
)) ? 
 680                 Policy::required(SecPolicyRef(CFArrayGetValueAtIndex(mPolicies
, 0))) : NULL
; 
 681         for (mResultIndex 
= 0; 
 682                         mResult 
== kSecTrustResultUnspecified 
&& mResultIndex 
< mCertChain
.size() && policy
; 
 684                 if (!mCertChain
[mResultIndex
]) { 
 688                 mResult 
= store
.find(mCertChain
[mResultIndex
], policy
, searchLibs()); 
 689                 secdebug("trusteval", "trustResult=%d from cert %d", (int)mResult
, (int)mResultIndex
); 
 695 // Release TP evidence information. 
 696 // This information is severely under-defined by CSSM, so we proceed 
 698 //  (a) If the evidence matches an Apple-defined pattern, use specific 
 699 //      knowledge of that format. 
 700 //  (b) Otherwise, assume that the void * are flat blocks of memory. 
 702 void Trust::releaseTPEvidence(TPVerifyResult 
&result
, Allocator 
&allocator
) 
 704         if (result
.count() > 0) {       // something to do 
 705                 if (result
[0].form() == CSSM_EVIDENCE_FORM_APPLE_HEADER
) { 
 706                         // Apple defined evidence form -- use intimate knowledge 
 707                         if (result
[0].as
<CSSM_TP_APPLE_EVIDENCE_HEADER
>()->Version 
== CSSM_TP_APPLE_EVIDENCE_VERSION
 
 708                                 && result
.count() == 3 
 709                                 && result
[1].form() == CSSM_EVIDENCE_FORM_APPLE_CERTGROUP
 
 710                                 && result
[2].form() == CSSM_EVIDENCE_FORM_APPLE_CERT_INFO
) { 
 712                                 CertGroup
& certs 
= *result
[1].as
<CertGroup
>(); 
 713                                 CSSM_TP_APPLE_EVIDENCE_INFO 
*evidence 
= result
[2].as
<CSSM_TP_APPLE_EVIDENCE_INFO
>(); 
 714                                 uint32 count 
= certs
.count(); 
 715                                 allocator
.free(result
[0].data());       // just a struct 
 716                                 certs
.destroy(allocator
);               // certgroup contents 
 717                                 allocator
.free(result
[1].data());       // the CertGroup itself 
 718                                 for (uint32 n 
= 0; n 
< count
; n
++) 
 719                                         allocator
.free(evidence
[n
].StatusCodes
); 
 720                                 allocator
.free(result
[2].data());       // array of (flat) info structs 
 722                                 secdebug("trusteval", "unrecognized Apple TP evidence format"); 
 723                                 // drop it -- better leak than kill 
 726                         // unknown format -- blindly assume flat blobs 
 727                         secdebug("trusteval", "destroying unknown TP evidence format"); 
 728                         for (uint32 n 
= 0; n 
< result
.count(); n
++) 
 730                                 allocator
.free(result
[n
].data()); 
 734                 allocator
.free (result
.Evidence
); 
 740 // Clear evaluation results unless state is initial (invalid) 
 742 void Trust::clearResults() 
 744         StLock
<Mutex
>_(mMutex
); 
 745         if (mResult 
!= kSecTrustResultInvalid
) { 
 746                 releaseTPEvidence(mTpResult
, mTP
.allocator()); 
 747                 mResult 
= kSecTrustResultInvalid
; 
 753 // Build evidence information 
 755 void Trust::buildEvidence(CFArrayRef 
&certChain
, TPEvidenceInfo 
* &statusChain
) 
 757         StLock
<Mutex
>_(mMutex
); 
 758         if (mResult 
== kSecTrustResultInvalid
) 
 759                 MacOSError::throwMe(errSecTrustNotAvailable
); 
 760     certChain 
= mEvidenceReturned 
= 
 761         makeCFArray(convert
, mCertChain
); 
 762         if(mTpResult
.count() >= 3) { 
 763                 statusChain 
= mTpResult
[2].as
<TPEvidenceInfo
>(); 
 772 // Return extended result dictionary 
 774 void Trust::extendedResult(CFDictionaryRef 
&result
) 
 776         if (mResult 
== kSecTrustResultInvalid
) 
 777                 MacOSError::throwMe(errSecTrustNotAvailable
); 
 779                 CFRetain(mExtendedResult
); // retain before handing out to caller 
 780     result 
= mExtendedResult
; 
 785 // Return properties array (a CFDictionaryRef for each certificate in chain) 
 787 CFArrayRef 
Trust::properties() 
 789         // Builds and returns an array which the caller must release. 
 790         StLock
<Mutex
>_(mMutex
); 
 791         CFMutableArrayRef properties 
= CFArrayCreateMutable(NULL
, 0, 
 792                 &kCFTypeArrayCallBacks
); 
 793         if (mResult 
== kSecTrustResultInvalid
) // chain not built or evaluated 
 796         /* Get evidence pointer */ 
 797         CSSM_TP_APPLE_EVIDENCE_INFO 
*evidence 
= NULL
; 
 798         uint32 evidenceChainLen 
= 0; 
 799         if (mTpResult
.count() > 0) { 
 800                 if (mTpResult
[0].form() == CSSM_EVIDENCE_FORM_APPLE_HEADER
) { 
 801                         if (mTpResult
[0].as
<CSSM_TP_APPLE_EVIDENCE_HEADER
>()->Version 
== CSSM_TP_APPLE_EVIDENCE_VERSION
 
 802                                 && mTpResult
.count() == 3 
 803                                 && mTpResult
[1].form() == CSSM_EVIDENCE_FORM_APPLE_CERTGROUP
 
 804                                 && mTpResult
[2].form() == CSSM_EVIDENCE_FORM_APPLE_CERT_INFO
) { 
 806                                 CertGroup
& certs 
= *mTpResult
[1].as
<CertGroup
>(); 
 807                                 evidence 
= mTpResult
[2].as
<CSSM_TP_APPLE_EVIDENCE_INFO
>(); 
 808                                 evidenceChainLen 
= certs
.count(); 
 813         // Walk the chain from leaf to anchor, building properties dictionaries 
 814         for (uint32 idx
=0; idx 
< mCertChain
.size(); idx
++) { 
 815                 CFMutableDictionaryRef dict 
= CFDictionaryCreateMutable(NULL
, 0, 
 816                         &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
); 
 818                         CFStringRef title 
= NULL
; 
 819                         mCertChain
[idx
]->inferLabel(false, &title
); 
 821                                 CFDictionarySetValue(dict
, (const void *)kSecPropertyTypeTitle
, (const void *)title
); 
 824                         if (idx 
== 0 && mTpReturn 
!= errSecSuccess
) { 
 825                                 CFStringRef error 
= SecCopyErrorMessageString(mTpReturn
, NULL
); 
 827                                         CFDictionarySetValue(dict
, (const void *)kSecPropertyTypeError
, (const void *)error
); 
 831                         if (idx 
< evidenceChainLen
) { 
 832                                 uint32 numCodes 
= evidence
[idx
].NumStatusCodes
; 
 833                                 sint32 reason 
= evidence
[idx
].StatusCodes
[numCodes
]; // stored at end of status codes array 
 835                                         CFNumberRef cfreason 
= CFNumberCreate(kCFAllocatorDefault
, kCFNumberSInt32Type
, &reason
); 
 837                                                 CFDictionarySetValue(dict
, (const void *)kSecTrustRevocationReason
, (const void *)cfreason
); 
 842                         CFArrayAppendValue(properties
, (const void *)dict
); 
 851 // Return dictionary of evaluation results 
 853 CFDictionaryRef 
Trust::results() 
 855         // Builds and returns a dictionary which the caller must release. 
 856         StLock
<Mutex
>_(mMutex
); 
 857         CFMutableDictionaryRef results 
= CFDictionaryCreateMutable(NULL
, 0, 
 858                         &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
); 
 860         // kSecTrustResultValue 
 861         CFNumberRef numValue 
= CFNumberCreate(NULL
, kCFNumberSInt32Type
, &mResult
); 
 863                 CFDictionarySetValue(results
, (const void *)kSecTrustResultValue
, (const void *)numValue
); 
 866         if (mResult 
== kSecTrustResultInvalid 
|| !mExtendedResult
) 
 867                 return results
; // we have nothing more to add 
 869         // kSecTrustEvaluationDate 
 870         CFTypeRef evaluationDate
; 
 871         if (CFDictionaryGetValueIfPresent(mExtendedResult
, kSecTrustEvaluationDate
, &evaluationDate
)) 
 872                 CFDictionarySetValue(results
, (const void *)kSecTrustEvaluationDate
, (const void *)evaluationDate
); 
 874         // kSecTrustExtendedValidation, kSecTrustOrganizationName 
 875         CFTypeRef organizationName
; 
 876         if (CFDictionaryGetValueIfPresent(mExtendedResult
, kSecEVOrganizationName
, &organizationName
)) { 
 877                 CFDictionarySetValue(results
, (const void *)kSecTrustOrganizationName
, (const void *)organizationName
); 
 878                 CFDictionarySetValue(results
, (const void *)kSecTrustExtendedValidation
, (const void *)kCFBooleanTrue
); 
 881         // kSecTrustRevocationChecked, kSecTrustRevocationValidUntilDate 
 882         CFTypeRef expirationDate
; 
 883         if (CFDictionaryGetValueIfPresent(mExtendedResult
, kSecTrustExpirationDate
, &expirationDate
)) { 
 884                 CFDictionarySetValue(results
, (const void *)kSecTrustRevocationValidUntilDate
, (const void *)expirationDate
); 
 885                 CFDictionarySetValue(results
, (const void *)kSecTrustRevocationChecked
, (const void *)kCFBooleanTrue
); 
 893 //* =========================================================================== 
 894 //* We need a way to compare two CSSM_DL_DB_HANDLEs WITHOUT using a operator 
 896 //* =========================================================================== 
 898 bool Compare_CSSM_DL_DB_HANDLE(const CSSM_DL_DB_HANDLE 
&h1
, const CSSM_DL_DB_HANDLE 
&h2
) 
 900     return (h1
.DLHandle 
== h2
.DLHandle 
&& h1
.DBHandle 
== h2
.DBHandle
); 
 906 // Given a DL_DB_HANDLE, locate the Keychain object (from the search list) 
 908 Keychain 
Trust::keychainByDLDb(const CSSM_DL_DB_HANDLE 
&handle
) 
 910         StLock
<Mutex
>_(mMutex
); 
 911         StorageManager::KeychainList
& list 
= searchLibs(); 
 912         for (StorageManager::KeychainList::const_iterator it 
= list
.begin(); 
 913                         it 
!= list
.end(); it
++) 
 918                         if (Compare_CSSM_DL_DB_HANDLE((*it
)->database()->handle(), handle
)) 
 925         if(mUsingTrustSettings
) { 
 927                         if(Compare_CSSM_DL_DB_HANDLE(trustKeychains().rootStoreHandle(), handle
)) { 
 928                                 return trustKeychains().rootStore(); 
 930                         if(Compare_CSSM_DL_DB_HANDLE(trustKeychains().systemKcHandle(), handle
)) { 
 931                                 return trustKeychains().systemKc(); 
 935                         /* one of those is missing; proceed */ 
 939         // could not find in search list - internal error 
 941         // we now throw an error here rather than assert and silently fail.  That way our application won't crash... 
 942         MacOSError::throwMe(errSecInternal
);