2  * Copyright (c) 2005,2011-2016 Apple Inc. All Rights Reserved. 
   4  * @APPLE_LICENSE_HEADER_START@ 
   6  * This file contains Original Code and/or Modifications of Original Code 
   7  * as defined in and that are subject to the Apple Public Source License 
   8  * Version 2.0 (the 'License'). You may not use this file except in 
   9  * compliance with the License. Please obtain a copy of the License at 
  10  * http://www.opensource.apple.com/apsl/ and read it before using this 
  13  * The Original Code and all software distributed under the License are 
  14  * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 
  15  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 
  16  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 
  17  * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 
  18  * Please see the License for the specific language governing rights and 
  19  * limitations under the License. 
  21  * @APPLE_LICENSE_HEADER_END@ 
  25  * SecTrustSettings.cpp - Public interface for manipulation of Trust Settings. 
  29 #include "SecBridge.h" 
  30 #include "SecCertificatePriv.h" 
  31 #include "SecTrustSettings.h" 
  32 #include "SecTrustSettingsPriv.h" 
  33 #include "SecTrustSettingsCertificates.h" 
  34 #include "TrustSettingsUtils.h" 
  35 #include "TrustSettings.h" 
  36 #include "TrustSettingsSchema.h" 
  37 #include "TrustKeychains.h" 
  39 #include "SecKeychainPriv.h" 
  41 #include <security_utilities/threading.h> 
  42 #include <security_utilities/globalizer.h> 
  43 #include <security_utilities/errors.h> 
  44 #include <security_cdsa_utilities/cssmerrors.h> 
  45 #include <security_utilities/logging.h> 
  46 #include <security_utilities/debugging.h> 
  47 #include <security_utilities/simpleprefs.h> 
  48 #include <securityd_client/dictionary.h> 
  49 #include <securityd_client/ssclient.h> 
  55 #include <CommonCrypto/CommonDigest.h> 
  56 #include <CoreFoundation/CFPreferences.h> 
  57 #include <utilities/SecCFRelease.h> 
  59 #define trustSettingsDbg(args...)       secinfo("trustSettings", ## args) 
  62  * Ideally we'd like to implement our own lock to protect the state of the cert stores 
  63  * without grabbing the global Sec API lock, but we deal with SecCFObjects, so we'll have 
  64  * to bite the bullet and grab the big lock. We also have our own lock protecting the 
  65  * global trust settings cache which is also used by the keychain callback function 
  66  * (which does not grab the Sec API lock). 
  69 #define BEGIN_RCSAPI    \ 
  70         OSStatus __secapiresult; \ 
  73                 __secapiresult=errSecSuccess; \ 
  75         catch (const MacOSError &err) { __secapiresult=err.osStatus(); } \ 
  76         catch (const CommonError &err) { __secapiresult=SecKeychainErrFromOSStatus(err.osStatus()); } \ 
  77         catch (const std::bad_alloc &) { __secapiresult=errSecAllocate; } \ 
  78         catch (...) { __secapiresult=errSecInternalComponent; } \ 
  79         return __secapiresult; 
  86 #pragma mark --- TrustSettings preferences --- 
  89  * If Colonel Klink wants to disable user-level Trust Settings, he'll have 
  90  * to restart the apps which will be affected after he does so. We are not 
  91  * going to consult system prefs every time we do a cert evaluation. We 
  92  * consult it once per process and cache the results here. 
  94 static bool tsUserTrustDisableValid 
= false;    /* true once we consult prefs */ 
  95 static bool tsUserTrustDisable 
= false;                 /* the cached value */ 
  98  * Determine whether user-level Trust Settings disabled. 
 100 static bool tsUserTrustSettingsDisabled() 
 102         if(tsUserTrustDisableValid
) { 
 103                 return tsUserTrustDisable
; 
 105         tsUserTrustDisable 
= false; 
 107         Dictionary
* dictionary 
= Dictionary::CreateDictionary(kSecTrustSettingsPrefsDomain
, Dictionary::US_System
); 
 110                 auto_ptr
<Dictionary
> prefsDict(dictionary
); 
 111                 /* this returns false if the pref isn't there, just like we want */ 
 112                 tsUserTrustDisable 
= prefsDict
->getBoolValue(kSecTrustSettingsDisableUserTrustSettings
); 
 115         tsUserTrustDisableValid 
= true; 
 116         return tsUserTrustDisable
; 
 119 #pragma mark --- TrustSettings global cache --- 
 122  *** cache submodule - keeps per-app copy of zero or one TrustSettings 
 123  ***                               for each domain. Used only by SecTrustSettingsEvaluateCert() 
 124  ***                               and SecTrustSettingsCopyQualifiedCerts(); results of 
 125  ***                               manipulation by public API functions are not cached. 
 129  * API/client code has to hold this lock when doing anything with any of 
 130  * the TrustSettings maintained here. 
 131  * It's recursive to accomodate CodeSigning's need to do cert verification 
 132  * (while we evaluate app equivalence). 
 134 static ModuleNexus
<RecursiveMutex
> sutCacheLock
; 
 136 #define TRUST_SETTINGS_NUM_DOMAINS              3 
 139  * The three global TrustSettings. 
 140  * We rely on the fact the the domain enums start with 0; we use 
 141  * the domain value as an index into the following two arrays. 
 143 static TrustSettings 
*globalTrustSettings
[TRUST_SETTINGS_NUM_DOMAINS
] = 
 147  * Indicates "the associated global here is currently valid; if there isn't a 
 148  * globalTrustSettings[domain], don't try to find one" 
 150 static bool globalTrustSettingsValid
[TRUST_SETTINGS_NUM_DOMAINS
] = 
 151                 {false, false, false}; 
 153 /* remember the fact that we've registered our KC callback */ 
 154 static bool sutRegisteredCallback 
= false; 
 156 static void tsRegisterCallback(); 
 159  * Assign global TrustSetting to new incoming value, which may be NULL. 
 160  * Caller holds sutCacheLock. 
 162 static void tsSetGlobalTrustSettings( 
 164         SecTrustSettingsDomain domain
) 
 166         assert(((int)domain 
>= 0) && ((int)domain 
< TRUST_SETTINGS_NUM_DOMAINS
)); 
 168         trustSettingsDbg("tsSetGlobalTrustSettings domain %d: caching TS %p old TS %p", 
 169                 (int)domain
, ts
, globalTrustSettings
[domain
]); 
 170         delete globalTrustSettings
[domain
]; 
 171         globalTrustSettings
[domain
] = ts
; 
 172         globalTrustSettingsValid
[domain
] = ts 
? true : false; 
 173         tsRegisterCallback(); 
 177  * Obtain global TrustSettings for specified domain if it exists. 
 178  * Returns NULL if there is simply no TS for that domain. 
 179  * The TS, if returned, belongs to this cache module. 
 180  * Caller holds sutCacheLock. 
 182 static TrustSettings 
*tsGetGlobalTrustSettings( 
 183         SecTrustSettingsDomain domain
) 
 185         assert(((int)domain 
>= 0) && ((int)domain 
< TRUST_SETTINGS_NUM_DOMAINS
)); 
 187         if((domain 
== kSecTrustSettingsDomainUser
) && tsUserTrustSettingsDisabled()) { 
 188                 trustSettingsDbg("tsGetGlobalTrustSettings: skipping DISABLED user domain"); 
 192         if(globalTrustSettingsValid
[domain
]) { 
 193                 // ready or not, use this 
 194                 return globalTrustSettings
[domain
]; 
 196         assert(globalTrustSettings
[domain
] == NULL
); 
 198         /* try to find one */ 
 199         OSStatus result 
= errSecSuccess
; 
 200         TrustSettings 
*ts 
= NULL
; 
 201         /* don't create; trim if found */ 
 202         result 
= TrustSettings::CreateTrustSettings(domain
, CREATE_NO
, TRIM_YES
, ts
); 
 203     if (   (domain 
!= kSecTrustSettingsDomainSystem
) 
 204         && (result 
== errSecInternalComponent
)) { 
 206          * Could not connect to ocspd to get the user/admin domain trust settings 
 207          * This happens in single user mode for example. 
 208          * Valid flag is set to false and continue. 
 210         trustSettingsDbg("tsGetGlobalTrustSettings: could not connect to ocspd for domain (%d)",(int)domain
); 
 211         globalTrustSettingsValid
[domain
] = false; 
 212         tsRegisterCallback(); 
 215     else if (result 
== errSecNoTrustSettings
) { 
 217                  * No TrustSettings for this domain, actually a fairly common case. 
 218                  * Optimize: don't bother trying this again. 
 220                 trustSettingsDbg("tsGetGlobalTrustSettings: flagging known NULL"); 
 221                 globalTrustSettingsValid
[domain
] = true; 
 222                 tsRegisterCallback(); 
 225     else if(result 
!= errSecSuccess
) { 
 227         MacOSError::throwMe(result
); 
 230         tsSetGlobalTrustSettings(ts
, domain
); 
 235  * Purge TrustSettings cache. 
 236  * Called by Keychain Event callback and by our API functions that 
 237  * modify trust settings. 
 238  * Caller can NOT hold sutCacheLock. 
 240 static void tsPurgeCache() 
 244         StLock
<Mutex
>   _(sutCacheLock()); 
 245         trustSettingsDbg("tsPurgeCache"); 
 246         for(domain
=0; domain
<TRUST_SETTINGS_NUM_DOMAINS
; domain
++) { 
 247                 tsSetGlobalTrustSettings(NULL
, (SecTrustSettingsDomain
) domain
); 
 252  * Keychain event callback function, for notification by other processes that 
 253  * user trust list(s) has/have changed. 
 255 static OSStatus 
tsTrustSettingsCallback ( 
 256    SecKeychainEvent keychainEvent
, 
 257    SecKeychainCallbackInfo 
*info
, 
 260         trustSettingsDbg("tsTrustSettingsCallback, event %d", (int)keychainEvent
); 
 261         if(keychainEvent 
!= kSecTrustSettingsChangedEvent
) { 
 262                 /* should not happen, right? */ 
 263                 return errSecSuccess
; 
 265         if(info
->pid 
== getpid()) { 
 267                  * Avoid dup cache invalidates: we already dealt with this event. 
 269                 trustSettingsDbg("cacheEventCallback: our pid, skipping"); 
 274         return errSecSuccess
; 
 278  * Ensure that we've registered for kSecTrustSettingsChangedEvent callbacks 
 280 static void tsRegisterCallback() 
 282         if(sutRegisteredCallback
) { 
 285         trustSettingsDbg("tsRegisterCallback: registering callback"); 
 286         OSStatus ortn 
= SecKeychainAddCallback(tsTrustSettingsCallback
, 
 287                 kSecTrustSettingsChangedEventMask
, NULL
); 
 289                 trustSettingsDbg("tsRegisterCallback: SecKeychainAddCallback returned %d", (int)ortn
); 
 290                 /* Not sure how this could ever happen - maybe if there is no run loop active? */ 
 292         sutRegisteredCallback 
= true; 
 295 #pragma mark --- Static functions --- 
 299  * Called by API code when a trust list has changed; we notify other processes 
 300  * and purge our own cache. 
 302 static void tsTrustSettingsChanged() 
 306         /* The only interesting data is our pid */ 
 307         NameValueDictionary nvd
; 
 308         pid_t ourPid 
= getpid(); 
 309         nvd
.Insert (new NameValuePair (PID_KEY
, 
 310                 CssmData (reinterpret_cast<void*>(&ourPid
), sizeof (pid_t
)))); 
 314         trustSettingsDbg("tsTrustSettingsChanged: posting notification"); 
 315         SecurityServer::ClientSession 
cs (Allocator::standard(), Allocator::standard()); 
 316         cs
.postNotification (SecurityServer::kNotificationDomainDatabase
, 
 317                 kSecTrustSettingsChangedEvent
, data
); 
 322  * Common code for SecTrustSettingsCopyTrustSettings(), 
 323  * SecTrustSettingsCopyModificationDate(). 
 325 static OSStatus 
tsCopyTrustSettings( 
 326         SecCertificateRef cert
, 
 327         SecTrustSettingsDomain domain
, 
 328         CFArrayRef 
*trustSettings
,              /* optionally RETURNED */ 
 329         CFDateRef 
*modDate
)                             /* optionally RETURNED */ 
 335         /* obtain fresh full copy from disk */ 
 339         result 
= TrustSettings::CreateTrustSettings(domain
, CREATE_NO
, TRIM_NO
, ts
); 
 341         // rather than throw these results, just return them because we are at the top level 
 342         if (result 
== errSecNoTrustSettings
) { 
 343                 return errSecItemNotFound
; 
 345         else if (result 
!= errSecSuccess
) { 
 349         auto_ptr
<TrustSettings
>_(ts
); // make sure this gets deleted just in case something throws underneath 
 352                 *trustSettings 
= ts
->copyTrustSettings(cert
); 
 355                 *modDate 
= ts
->copyModDate(cert
); 
 361 static void tsAddConditionalCerts(CFMutableArrayRef certArray
); 
 364  * Common code for SecTrustSettingsCopyQualifiedCerts() and 
 365  * SecTrustSettingsCopyUnrestrictedRoots(). 
 367 static OSStatus 
tsCopyCertsCommon( 
 368         /* usage constraints, all optional */ 
 369         const CSSM_OID                  
*policyOID
, 
 370         const char                              *policyString
, 
 371         SecTrustSettingsKeyUsage keyUsage
, 
 372         /* constrain to only roots */ 
 374         /* per-domain enables */ 
 378         CFArrayRef                              
*certArray
)             /* RETURNED */ 
 380         StLock
<Mutex
> _TC(sutCacheLock()); 
 381         StLock
<Mutex
> _TK(SecTrustKeychainsGetMutex()); 
 383         TS_REQUIRED(certArray
) 
 385         /* this relies on the domain enums being numbered 0..2, user..system */ 
 386         bool domainEnable
[3] = {user
, admin
, system
}; 
 388         /* we'll retain it again before successful exit */ 
 389         CFRef
<CFMutableArrayRef
> outArray(CFArrayCreateMutable(NULL
, 0, 
 390                 &kCFTypeArrayCallBacks
)); 
 393          * Search all keychains - user's keychain list, System.keychain, 
 394          * and system root store 
 396         StorageManager::KeychainList keychains
; 
 399                 globals().storageManager
.getSearchList(keychains
); 
 402                 adminKc 
= globals().storageManager
.make(ADMIN_CERT_STORE_PATH
, false); 
 403                 keychains
.push_back(adminKc
); 
 405         Keychain sysRootKc 
= globals().storageManager
.make(SYSTEM_ROOT_STORE_PATH
, false); 
 406         keychains
.push_back(sysRootKc
); 
 408         assert(kSecTrustSettingsDomainUser 
== 0); 
 409         for(unsigned domain
=0; domain
<TRUST_SETTINGS_NUM_DOMAINS
; domain
++) { 
 410                 if(!domainEnable
[domain
]) { 
 413                 TrustSettings 
*ts 
= tsGetGlobalTrustSettings((SecTrustSettingsDomain
)domain
); 
 417                 ts
->findQualifiedCerts(keychains
, 
 418                         false,          /* !findAll */ 
 420                         policyOID
, policyString
, keyUsage
, 
 424                 tsAddConditionalCerts(outArray
); 
 426         *certArray 
= outArray
; 
 427         CFRetain(*certArray
); 
 428         trustSettingsDbg("tsCopyCertsCommon: %ld certs found", 
 429                 CFArrayGetCount(outArray
)); 
 430         return errSecSuccess
; 
 433 static void tsAddConditionalCerts(CFMutableArrayRef certArray
) 
 435 #if TARGET_OS_MAC && !TARGET_IPHONE_SIMULATOR && !TARGET_OS_IPHONE && !TARGET_OS_NANO 
 436         struct certmap_entry_s 
{ 
 437                 CFStringRef bundleId
; 
 439                 const CFIndex length
; 
 441         typedef struct certmap_entry_s certmap_entry_t
; 
 443         CFBundleRef bundle 
= CFBundleGetMainBundle(); 
 444         CFStringRef bundleIdentifier 
= (bundle
) ? CFBundleGetIdentifier(bundle
) : NULL
; 
 445         if (!bundleIdentifier 
|| !certArray
) { return; } 
 447         // conditionally include 1024-bit compatibility roots for specific apps 
 448         const certmap_entry_t certmap
[] = { 
 449                 { CFSTR("com.autodesk.AdSSO"), _GTECyberTrustGlobalRootCA
, sizeof(_GTECyberTrustGlobalRootCA
) }, // rdar://25916338 
 450                 { CFSTR("com.clo3d.MD5"), _ThawtePremiumServerCA
, sizeof(_ThawtePremiumServerCA
) }, // rdar://26281864 
 453         unsigned int i
, certmaplen 
= sizeof(certmap
) / sizeof(certmap_entry_t
); 
 454         for (i
=0; i
<certmaplen
; i
++) { 
 455                 if (CFStringCompare(bundleIdentifier
, certmap
[i
].bundleId
, 0) == kCFCompareEqualTo
) { 
 456                         SecCertificateRef cert 
= SecCertificateCreateWithBytes(NULL
, certmap
[i
].data
, certmap
[i
].length
); 
 457                         if (!cert
) { continue; } 
 458                         CFArrayAppendValue(certArray
, cert
); 
 464         // this function is a no-op on iOS platforms 
 469 #pragma mark --- SPI functions --- 
 473  * Fundamental routine used by TP to ascertain status of one cert. 
 475  * Returns true in *foundMatchingEntry if a trust setting matching 
 476  * specific constraints was found for the cert. Returns true in 
 477  * *foundAnyEntry if any entry was found for the cert, even if it 
 478  * did not match the specified constraints. The TP uses this to 
 479  * optimize for the case where a cert is being evaluated for 
 480  * one type of usage, and then later for another type. If 
 481  * foundAnyEntry is false, the second evaluation need not occur. 
 483  * Returns the domain in which a setting was found in *foundDomain. 
 485  * Allowed errors applying to the specified cert evaluation 
 486  * are returned in a mallocd array in *allowedErrors and must 
 487  * be freed by caller. 
 489  * The design of the entire TrustSettings module is centered around 
 490  * optimizing the performance of this routine (security concerns 
 491  * aside, that is). It's why the per-cert dictionaries are stored 
 492  * as a dictionary, keyed off of the cert hash. It's why TrustSettings 
 493  * are cached in memory by tsGetGlobalTrustSettings(), and why those 
 494  * cached TrustSettings objects are 'trimmed' of dictionary fields 
 495  * which are not needed to verify a cert. 
 497  * The API functions which are used to manipulate Trust Settings 
 498  * are called infrequently and need not be particularly fast since 
 499  * they result in user interaction for authentication. Thus they do 
 500  * not use cached TrustSettings as this function does. 
 502 OSStatus 
SecTrustSettingsEvaluateCert( 
 503         CFStringRef                             certHashStr
, 
 504         /* parameters describing the current cert evalaution */ 
 505         const CSSM_OID                  
*policyOID
, 
 506         const char                              *policyString
,          /* optional */ 
 507         uint32                                  policyStringLen
, 
 508         SecTrustSettingsKeyUsage keyUsage
,                      /* optional */ 
 509         bool                                    isRootCert
,                     /* for checking default setting */ 
 510         /* RETURNED values */ 
 511         SecTrustSettingsDomain  
*foundDomain
, 
 512         CSSM_RETURN                             
**allowedErrors
,        /* mallocd */ 
 513         uint32                                  
*numAllowedErrors
, 
 514         SecTrustSettingsResult  
*resultType
, 
 515         bool                                    *foundMatchingEntry
, 
 520         StLock
<Mutex
>   _(sutCacheLock()); 
 522         TS_REQUIRED(certHashStr
) 
 523         TS_REQUIRED(foundDomain
) 
 524         TS_REQUIRED(allowedErrors
) 
 525         TS_REQUIRED(numAllowedErrors
) 
 526         TS_REQUIRED(resultType
) 
 527         TS_REQUIRED(foundMatchingEntry
) 
 528         TS_REQUIRED(foundAnyEntry
) 
 530         /* ensure a NULL_terminated string */ 
 531         auto_array
<char> polStr
; 
 532         if(policyString 
!= NULL 
&& policyStringLen 
> 0) { 
 533                 polStr
.allocate(policyStringLen 
+ 1); 
 534                 memmove(polStr
.get(), policyString
, policyStringLen
); 
 535                 if(policyString
[policyStringLen 
- 1] != '\0') { 
 536                         (polStr
.get())[policyStringLen
] = '\0'; 
 540         /* initial condition - this can grow if we inspect multiple TrustSettings */ 
 541         *allowedErrors 
= NULL
; 
 542         *numAllowedErrors 
= 0; 
 545          * This loop relies on the ordering of the SecTrustSettingsDomain enum: 
 546          * search user first, then admin, then system. 
 548         assert(kSecTrustSettingsDomainAdmin 
== (kSecTrustSettingsDomainUser 
+ 1)); 
 549         assert(kSecTrustSettingsDomainSystem 
== (kSecTrustSettingsDomainAdmin 
+ 1)); 
 550         bool foundAny 
= false; 
 551         for(unsigned domain
=kSecTrustSettingsDomainUser
; 
 552                              domain
<=kSecTrustSettingsDomainSystem
; 
 554                 TrustSettings 
*ts 
= tsGetGlobalTrustSettings((SecTrustSettingsDomain
)domain
); 
 559                 /* validate cert returns true if matching entry was found */ 
 560                 bool foundAnyHere 
= false; 
 561                 bool found 
= ts
->evaluateCert(certHashStr
, policyOID
, 
 562                         polStr
.get(), keyUsage
, isRootCert
, 
 563                         allowedErrors
, numAllowedErrors
, resultType
, &foundAnyHere
); 
 567                          * Note this, even though we may overwrite it later if this 
 568                          * is an Unspecified entry and we find a definitive entry 
 571                         *foundDomain 
= (SecTrustSettingsDomain
)domain
; 
 573                 if(found 
&& (*resultType 
!= kSecTrustSettingsResultUnspecified
)) { 
 574                         trustSettingsDbg("SecTrustSettingsEvaluateCert: found in domain %d", domain
); 
 575                         *foundAnyEntry 
= true; 
 576                         *foundMatchingEntry 
= true; 
 577                         return errSecSuccess
; 
 579                 foundAny 
|= foundAnyHere
; 
 581         trustSettingsDbg("SecTrustSettingsEvaluateCert: NOT FOUND"); 
 582         *foundAnyEntry 
= foundAny
; 
 583         *foundMatchingEntry 
= false; 
 584         return errSecSuccess
; 
 589  * Obtain trusted certs which match specified usage. 
 590  * Only certs with a SecTrustSettingsResult of 
 591  * kSecTrustSettingsResultTrustRoot or 
 592  * or kSecTrustSettingsResultTrustAsRoot will be returned. 
 593  * To be used by SecureTransport for its SSLSetTrustedRoots() call; 
 594  * I hope nothing else has to use this... 
 595  * Caller must CFRelease the returned CFArrayRef. 
 597 OSStatus 
SecTrustSettingsCopyQualifiedCerts( 
 598         const CSSM_OID                          
*policyOID
, 
 599         const char                                      *policyString
,          /* optional */ 
 600         uint32                                          policyStringLen
, 
 601         SecTrustSettingsKeyUsage        keyUsage
,                       /* optional */ 
 602         CFArrayRef                                      
*certArray
)                     /* RETURNED */ 
 606         /* ensure a NULL_terminated string */ 
 607         auto_array
<char> polStr
; 
 608         if(policyString 
!= NULL
) { 
 609                 polStr
.allocate(policyStringLen 
+ 1); 
 610                 memmove(polStr
.get(), policyString
, policyStringLen
); 
 611                 if(policyString
[policyStringLen 
- 1] != '\0') { 
 612                         (polStr
.get())[policyStringLen
] = '\0'; 
 616         return tsCopyCertsCommon(policyOID
, polStr
.get(), keyUsage
, 
 617                 false,                          /* !onlyRoots */ 
 618                 true, true, true,       /* all domains */ 
 625  * Obtain unrestricted root certs from the specified domain(s). 
 626  * Only returns roots with no usage constraints. 
 627  * Caller must CFRelease the returned CFArrayRef. 
 629 OSStatus 
SecTrustSettingsCopyUnrestrictedRoots( 
 633         CFArrayRef                              
*certArray
)             /* RETURNED */ 
 637         OSStatus status 
= tsCopyCertsCommon(NULL
, NULL
, NULL
,   /* no constraints */ 
 638                 true,                           /* onlyRoots */ 
 647 static const char hexChars
[16] = { 
 648         '0', '1', '2', '3', '4', '5', '6', '7', 
 649         '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' 
 653  * Obtain a string representing a cert's SHA1 digest. This string is 
 654  * the key used to look up per-cert trust settings in a TrustSettings record. 
 656 CFStringRef 
SecTrustSettingsCertHashStrFromCert( 
 657         SecCertificateRef certRef
) 
 659         if(certRef 
== NULL
) { 
 663         if(certRef 
== kSecTrustSettingsDefaultRootCertSetting
) { 
 664                 /* use this string instead of the cert hash as the dictionary key */ 
 665                 trustSettingsDbg("SecTrustSettingsCertHashStrFromCert: DefaultSetting"); 
 666         secerror("Caller passed kSecTrustSettingsDefaultRootCertSetting. This constant is deprecated and no longer affects the behavior of the system."); 
 667                 return kSecTrustRecordDefaultRootCert
; 
 671         OSStatus ortn 
= SecCertificateGetData(certRef
, &certData
); 
 675         return SecTrustSettingsCertHashStrFromData(certData
.Data
, certData
.Length
); 
 678 CFStringRef 
SecTrustSettingsCertHashStrFromData( 
 682         unsigned char digest
[CC_SHA1_DIGEST_LENGTH
]; 
 683         char asciiDigest
[(2 * CC_SHA1_DIGEST_LENGTH
) + 1]; 
 685         char *outp 
= asciiDigest
; 
 686         unsigned char *inp 
= digest
; 
 692         CC_SHA1(cert
, (CC_LONG
)certLen
, digest
); 
 694         for(dex
=0; dex
<CC_SHA1_DIGEST_LENGTH
; dex
++) { 
 696                 outp
[1] = hexChars
[c 
& 0xf]; 
 698                 outp
[0] = hexChars
[c
]; 
 702         return CFStringCreateWithCString(NULL
, asciiDigest
, kCFStringEncodingASCII
); 
 706  * Add a cert's TrustSettings to a non-persistent TrustSettings record. 
 707  * No locking or cache flushing here; it's all local to the TrustSettings 
 710 OSStatus 
SecTrustSettingsSetTrustSettingsExternal( 
 711         CFDataRef                       settingsIn
,                                     /* optional */ 
 712         SecCertificateRef       certRef
,                                        /* optional */ 
 713         CFTypeRef                       trustSettingsDictOrArray
,       /* optional */ 
 714         CFDataRef                       
*settingsOut
)                           /* RETURNED */ 
 718         TS_REQUIRED(settingsOut
) 
 723         result 
= TrustSettings::CreateTrustSettings((SecTrustSettingsDomain
)kSecTrustSettingsDomainMemory
, settingsIn
, ts
); 
 724         if (result 
!= errSecSuccess
) { 
 728         auto_ptr
<TrustSettings
>_(ts
); 
 730         if(certRef 
!= NULL
) { 
 731                 ts
->setTrustSettings(certRef
, trustSettingsDictOrArray
); 
 733         *settingsOut 
= ts
->createExternal(); 
 734         return errSecSuccess
; 
 739 #pragma mark --- API functions --- 
 741 OSStatus 
SecTrustSettingsCopyTrustSettings( 
 742         SecCertificateRef certRef
, 
 743         SecTrustSettingsDomain domain
, 
 744         CFArrayRef 
*trustSettings
)                              /* RETURNED */ 
 747         TS_REQUIRED(trustSettings
) 
 749         OSStatus result 
= tsCopyTrustSettings(certRef
, domain
, trustSettings
, NULL
); 
 750         if (result 
== errSecSuccess 
&& *trustSettings 
== NULL
) { 
 751                 result 
= errSecItemNotFound
; /* documented result if no trust settings exist */ 
 756 OSStatus 
SecTrustSettingsCopyModificationDate( 
 757         SecCertificateRef               certRef
, 
 758         SecTrustSettingsDomain  domain
, 
 759         CFDateRef                               
*modificationDate
)      /* RETURNED */ 
 762         TS_REQUIRED(modificationDate
) 
 764         OSStatus result 
= tsCopyTrustSettings(certRef
, domain
, NULL
, modificationDate
); 
 765         if (result 
== errSecSuccess 
&& *modificationDate 
== NULL
) { 
 766                 result 
= errSecItemNotFound
; /* documented result if no trust settings exist */ 
 771 /* works with existing and with new cert */ 
 772 OSStatus 
SecTrustSettingsSetTrustSettings( 
 773         SecCertificateRef certRef
, 
 774         SecTrustSettingsDomain domain
, 
 775         CFTypeRef trustSettingsDictOrArray
) 
 781         if(domain 
== kSecTrustSettingsDomainSystem
) { 
 782                 return errSecDataNotModifiable
; 
 788         result 
= TrustSettings::CreateTrustSettings(domain
, CREATE_YES
, TRIM_NO
, ts
); 
 789         if (result 
!= errSecSuccess
) { 
 793         auto_ptr
<TrustSettings
>_(ts
); 
 795         ts
->setTrustSettings(certRef
, trustSettingsDictOrArray
); 
 797         tsTrustSettingsChanged(); 
 798         return errSecSuccess
; 
 803 OSStatus 
SecTrustSettingsRemoveTrustSettings( 
 804         SecCertificateRef cert
, 
 805         SecTrustSettingsDomain domain
) 
 811         if(domain 
== kSecTrustSettingsDomainSystem
) { 
 812                 return errSecDataNotModifiable
; 
 818         result 
= TrustSettings::CreateTrustSettings(domain
, CREATE_NO
, TRIM_NO
, ts
); 
 819         if (result 
!= errSecSuccess
) { 
 823         auto_ptr
<TrustSettings
>_(ts
); 
 825         /* deleteTrustSettings throws if record not found */ 
 826         trustSettingsDbg("SecTrustSettingsRemoveTrustSettings: deleting from domain %d", 
 828         ts
->deleteTrustSettings(cert
); 
 830         tsTrustSettingsChanged(); 
 831         return errSecSuccess
; 
 836 /* get all certs listed in specified domain */ 
 837 OSStatus 
SecTrustSettingsCopyCertificates( 
 838         SecTrustSettingsDomain  domain
, 
 839         CFArrayRef                              
*certArray
) 
 843         TS_REQUIRED(certArray
) 
 848         result 
= TrustSettings::CreateTrustSettings(domain
, CREATE_NO
, TRIM_NO
, ts
); 
 849         if (result 
!= errSecSuccess
) { 
 853         auto_ptr
<TrustSettings
>_(ts
); 
 855         CFMutableArrayRef outArray 
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
); 
 858          * Keychains to search: user's search list, System.keychain, system root store 
 860         StorageManager::KeychainList keychains
; 
 864                 case kSecTrustSettingsDomainUser
: 
 865                         /* user search list */ 
 866                         globals().storageManager
.getSearchList(keychains
); 
 867                         /* drop thru to next case */ 
 868                 case kSecTrustSettingsDomainAdmin
: 
 869                         /* admin certs in system keychain */ 
 870                         adminKc 
= globals().storageManager
.make(ADMIN_CERT_STORE_PATH
, false); 
 871                         keychains
.push_back(adminKc
); 
 872                         /* drop thru to next case */ 
 873                 case kSecTrustSettingsDomainSystem
: 
 874                         /* and, for all cases, immutable system root store */ 
 875                         sysRootKc 
= globals().storageManager
.make(SYSTEM_ROOT_STORE_PATH
, false); 
 876                         keychains
.push_back(sysRootKc
); 
 878                         /* already validated when we created the TrustSettings */ 
 881         ts
->findCerts(keychains
, outArray
); 
 882         if(CFArrayGetCount(outArray
) == 0) { 
 884                 return errSecNoTrustSettings
; 
 886         if (kSecTrustSettingsDomainSystem 
== domain
) { 
 887                 tsAddConditionalCerts(outArray
); 
 889         *certArray 
= outArray
; 
 893 static CFArrayRef gUserAdminCerts 
= NULL
; 
 894 static bool gUserAdminCertsCacheBuilt 
= false; 
 895 static ReadWriteLock gUserAdminCertsLock
; 
 897 void SecTrustSettingsPurgeUserAdminCertsCache(void) { 
 898     StReadWriteLock 
_(gUserAdminCertsLock
, StReadWriteLock::Write
); 
 899     CFReleaseNull(gUserAdminCerts
); 
 900     gUserAdminCertsCacheBuilt 
= false; 
 903 OSStatus 
SecTrustSettingsCopyCertificatesForUserAdminDomains( 
 904                                                              CFArrayRef  
*certArray
) 
 906     TS_REQUIRED(certArray
); 
 907     OSStatus result 
= errSecSuccess
; 
 909     { /* Hold the read lock for the check */ 
 910         StReadWriteLock 
_(gUserAdminCertsLock
, StReadWriteLock::Read
); 
 911         if (gUserAdminCertsCacheBuilt
) { 
 912             if (gUserAdminCerts
) { 
 913                 *certArray 
= (CFArrayRef
)CFRetain(gUserAdminCerts
); 
 914                 return errSecSuccess
; 
 916                 return errSecNoTrustSettings
; 
 921     /* There were no cached results. We'll have to recreate them. */ 
 922     CFMutableArrayRef outArray 
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
); 
 924         return errSecAllocate
; 
 927     CFArrayRef userTrusted 
= NULL
, adminTrusted 
= NULL
; 
 928     OSStatus userStatus 
= SecTrustSettingsCopyCertificates(kSecTrustSettingsDomainUser
, &userTrusted
); 
 929     if ((userStatus 
== errSecSuccess
) && (userTrusted 
!= NULL
)) { 
 930         CFArrayAppendArray(outArray
, userTrusted
, CFRangeMake(0, CFArrayGetCount(userTrusted
))); 
 931         CFRelease(userTrusted
); 
 934     OSStatus adminStatus 
= SecTrustSettingsCopyCertificates(kSecTrustSettingsDomainAdmin
, &adminTrusted
); 
 935     if ((adminStatus 
== errSecSuccess
) && (adminTrusted 
!= NULL
)) { 
 936         CFArrayAppendArray(outArray
, adminTrusted
, CFRangeMake(0, CFArrayGetCount(adminTrusted
))); 
 937         CFRelease(adminTrusted
); 
 940     /* Lack of trust settings for a domain results in an error above. Only fail 
 941      * if we weren't able to get trust settings for both domains. */ 
 942     if (userStatus 
!= errSecSuccess 
&& adminStatus 
!= errSecSuccess
) { 
 946     if (result 
!= errSecSuccess 
&& outArray
) { 
 951     *certArray 
= outArray
; 
 953     /* For valid results, update the global cache */ 
 954     if (result 
== errSecSuccess 
|| result 
== errSecNoTrustSettings
) { 
 955         StReadWriteLock 
_(gUserAdminCertsLock
, StReadWriteLock::Write
); 
 956         CFReleaseNull(gUserAdminCerts
); 
 957         gUserAdminCerts 
= (CFArrayRef
)CFRetainSafe(outArray
); 
 958         gUserAdminCertsCacheBuilt 
= true; 
 965  * Obtain an external, portable representation of the specified 
 966  * domain's TrustSettings. Caller must CFRelease the returned data. 
 968 OSStatus 
SecTrustSettingsCreateExternalRepresentation( 
 969         SecTrustSettingsDomain  domain
, 
 970         CFDataRef                               
*trustSettings
) 
 974         TS_REQUIRED(trustSettings
) 
 979         result 
= TrustSettings::CreateTrustSettings(domain
, CREATE_NO
, TRIM_NO
, ts
); 
 980         if (result 
!= errSecSuccess
) { 
 984         auto_ptr
<TrustSettings
>_(ts
); 
 986         *trustSettings 
= ts
->createExternal(); 
 987         return errSecSuccess
; 
 993  * Import trust settings, obtained via SecTrustSettingsCreateExternalRepresentation, 
 994  * into the specified domain. 
 996 OSStatus 
SecTrustSettingsImportExternalRepresentation( 
 997         SecTrustSettingsDomain  domain
, 
 998         CFDataRef                               trustSettings
)          /* optional - NULL means empty settings */ 
1002         if(domain 
== kSecTrustSettingsDomainSystem
) { 
1003                 return errSecDataNotModifiable
; 
1009         result 
= TrustSettings::CreateTrustSettings(domain
, trustSettings
, ts
); 
1010         if (result 
!= errSecSuccess
) { 
1014         auto_ptr
<TrustSettings
>_(ts
); 
1017         tsTrustSettingsChanged(); 
1018         return errSecSuccess
;