1/* 2 * Copyright (c) 2005,2011-2014 Apple Inc. All Rights Reserved. 3 * 4 * @APPLE_LICENSE_HEADER_START@ 5 * 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 11 * file. 12 * 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. 20 * 21 * @APPLE_LICENSE_HEADER_END@ 22 */ 23 24/* 25 * SecTrustSettings.cpp - Public interface for manipulation of Trust Settings. 26 * 27 */ 28 29#include "SecBridge.h" 30#include "SecTrustSettings.h" 31#include "SecTrustSettingsPriv.h" 32#include "TrustSettingsUtils.h" 33#include "TrustSettings.h" 34#include "TrustSettingsSchema.h" 35#include "TrustKeychains.h" 36#include "Trust.h" 37#include "SecKeychainPriv.h" 38#include "Globals.h" 39#include <security_utilities/threading.h> 40#include <security_utilities/globalizer.h> 41#include <security_utilities/errors.h> 42#include <security_cdsa_utilities/cssmerrors.h> 43#include <security_utilities/logging.h> 44#include <security_utilities/debugging.h> 45#include <security_utilities/simpleprefs.h> 46#include <securityd_client/dictionary.h> 47#include <securityd_client/ssclient.h> 48#include <assert.h> 49#include <vector> 50#include <CommonCrypto/CommonDigest.h> 51 52#define trustSettingsDbg(args...) secdebug("trustSettings", ## args) 53 54/* 55 * Ideally we'd like to implement our own lock to protect the state of the cert stores 56 * without grabbing the global Sec API lock, but we deal with SecCFObjects, so we'll have 57 * to bite the bullet and grab the big lock. We also have our own lock protecting the 58 * global trust settings cache which is also used by the keychain callback function 59 * (which does not grab the Sec API lock). 60 */ 61 62#define BEGIN_RCSAPI \ 63 OSStatus __secapiresult; \ 64 try { 65#define END_RCSAPI \ 66 __secapiresult=errSecSuccess; \ 67 } \ 68 catch (const MacOSError &err) { __secapiresult=err.osStatus(); } \ 69 catch (const CommonError &err) { __secapiresult=SecKeychainErrFromOSStatus(err.osStatus()); } \ 70 catch (const std::bad_alloc &) { __secapiresult=errSecAllocate; } \ 71 catch (...) { __secapiresult=errSecInternalComponent; } \ 72 return __secapiresult; 73 74#define END_RCSAPI0 \ 75 catch (...) {} \ 76 return; 77 78 79#pragma mark --- TrustSettings preferences --- 80 81/* 82 * If Colonel Klink wants to disable user-level Trust Settings, he'll have 83 * to restart the apps which will be affected after he does so. We are not 84 * going to consult system prefs every time we do a cert evaluation. We 85 * consult it once per process and cache the results here. 86 */ 87static bool tsUserTrustDisableValid = false; /* true once we consult prefs */ 88static bool tsUserTrustDisable = false; /* the cached value */ 89 90/* 91 * Determine whether user-level Trust Settings disabled. 92 */ 93static bool tsUserTrustSettingsDisabled() 94{ 95 if(tsUserTrustDisableValid) { 96 return tsUserTrustDisable; 97 } 98 tsUserTrustDisable = false; 99 100 Dictionary* dictionary = Dictionary::CreateDictionary(kSecTrustSettingsPrefsDomain, Dictionary::US_System); 101 if (dictionary) 102 { 103 auto_ptr<Dictionary> prefsDict(dictionary); 104 /* this returns false if the pref isn't there, just like we want */ 105 tsUserTrustDisable = prefsDict->getBoolValue(kSecTrustSettingsDisableUserTrustSettings); 106 } 107 108 tsUserTrustDisableValid = true; 109 return tsUserTrustDisable; 110} 111 112#pragma mark --- TrustSettings global cache --- 113 114/*** 115 *** cache submodule - keeps per-app copy of zero or one TrustSettings 116 *** for each domain. Used only by SecTrustSettingsEvaluateCert() 117 *** and SecTrustSettingsCopyQualifiedCerts(); results of 118 *** manipulation by public API functions are not cached. 119 ***/ 120 121/* 122 * API/client code has to hold this lock when doing anything with any of 123 * the TrustSettings maintained here. 124 * It's recursive to accomodate CodeSigning's need to do cert verification 125 * (while we evaluate app equivalence). 126 */ 127static ModuleNexus<RecursiveMutex> sutCacheLock; 128 129#define TRUST_SETTINGS_NUM_DOMAINS 3 130 131/* 132 * The three global TrustSettings. 133 * We rely on the fact the the domain enums start with 0; we use 134 * the domain value as an index into the following two arrays. 135 */ 136static TrustSettings *globalTrustSettings[TRUST_SETTINGS_NUM_DOMAINS] = 137 {NULL, NULL, NULL}; 138 139/* 140 * Indicates "the associated global here is currently valid; if there isn't a 141 * globalTrustSettings[domain], don't try to find one" 142 */ 143static bool globalTrustSettingsValid[TRUST_SETTINGS_NUM_DOMAINS] = 144 {false, false, false}; 145 146/* remember the fact that we've registered our KC callback */ 147static bool sutRegisteredCallback = false; 148 149static void tsRegisterCallback(); 150 151/* 152 * Assign global TrustSetting to new incoming value, which may be NULL. 153 * Caller holds sutCacheLock. 154 */ 155static void tsSetGlobalTrustSettings( 156 TrustSettings *ts, 157 SecTrustSettingsDomain domain) 158{ 159 assert(((int)domain >= 0) && ((int)domain < TRUST_SETTINGS_NUM_DOMAINS)); 160 161 trustSettingsDbg("tsSetGlobalTrustSettings domain %d: caching TS %p old TS %p", 162 (int)domain, ts, globalTrustSettings[domain]); 163 delete globalTrustSettings[domain]; 164 globalTrustSettings[domain] = ts; 165 globalTrustSettingsValid[domain] = ts ? true : false; 166 tsRegisterCallback(); 167} 168 169/* 170 * Obtain global TrustSettings for specified domain if it exists. 171 * Returns NULL if there is simply no TS for that domain. 172 * The TS, if returned, belongs to this cache module. 173 * Caller holds sutCacheLock. 174 */ 175static TrustSettings *tsGetGlobalTrustSettings( 176 SecTrustSettingsDomain domain) 177{ 178 assert(((int)domain >= 0) && ((int)domain < TRUST_SETTINGS_NUM_DOMAINS)); 179 180 if((domain == kSecTrustSettingsDomainUser) && tsUserTrustSettingsDisabled()) { 181 trustSettingsDbg("tsGetGlobalTrustSettings: skipping DISABLED user domain"); 182 return NULL; 183 } 184 185 if(globalTrustSettingsValid[domain]) { 186 // ready or not, use this 187 return globalTrustSettings[domain]; 188 } 189 assert(globalTrustSettings[domain] == NULL); 190 191 /* try to find one */ 192 OSStatus result = errSecSuccess; 193 TrustSettings *ts = NULL; 194 /* don't create; trim if found */ 195 result = TrustSettings::CreateTrustSettings(domain, CREATE_NO, TRIM_YES, ts); 196 if ( (domain != kSecTrustSettingsDomainSystem) 197 && (result == errSecInternalComponent)) { 198 /* 199 * Could not connect to ocspd to get the user/admin domain trust settings 200 * This happens in single user mode for example. 201 * Valid flag is set to false and continue. 202 */ 203 trustSettingsDbg("tsGetGlobalTrustSettings: could not connect to ocspd for domain (%d)",(int)domain); 204 globalTrustSettingsValid[domain] = false; 205 tsRegisterCallback(); 206 return NULL; 207 } 208 else if (result == errSecNoTrustSettings) { 209 /* 210 * No TrustSettings for this domain, actually a fairly common case. 211 * Optimize: don't bother trying this again. 212 */ 213 trustSettingsDbg("tsGetGlobalTrustSettings: flagging known NULL"); 214 globalTrustSettingsValid[domain] = true; 215 tsRegisterCallback(); 216 return NULL; 217 } 218 else if(result != errSecSuccess) { 219 /* gross error */ 220 MacOSError::throwMe(result); 221 } 222 223 tsSetGlobalTrustSettings(ts, domain); 224 return ts; 225} 226 227/* 228 * Purge TrustSettings cache. 229 * Called by Keychain Event callback and by our API functions that 230 * modify trust settings. 231 * Caller can NOT hold sutCacheLock. 232 */ 233static void tsPurgeCache() 234{ 235 int domain; 236 237 StLock<Mutex> _(sutCacheLock()); 238 trustSettingsDbg("tsPurgeCache"); 239 for(domain=0; domain<TRUST_SETTINGS_NUM_DOMAINS; domain++) { 240 tsSetGlobalTrustSettings(NULL, domain); 241 } 242} 243 244/* 245 * Keychain event callback function, for notification by other processes that 246 * user trust list(s) has/have changed. 247 */ 248static OSStatus tsTrustSettingsCallback ( 249 SecKeychainEvent keychainEvent, 250 SecKeychainCallbackInfo *info, 251 void *context) 252{ 253 trustSettingsDbg("tsTrustSettingsCallback, event %d", (int)keychainEvent); 254 if(keychainEvent != kSecTrustSettingsChangedEvent) { 255 /* should not happen, right? */ 256 return errSecSuccess; 257 } 258 if(info->pid == getpid()) { 259 /* 260 * Avoid dup cache invalidates: we already dealt with this event. 261 */ 262 trustSettingsDbg("cacheEventCallback: our pid, skipping"); 263 } 264 else { 265 tsPurgeCache(); 266 } 267 return errSecSuccess; 268} 269 270/* 271 * Ensure that we've registered for kSecTrustSettingsChangedEvent callbacks 272 */ 273static void tsRegisterCallback() 274{ 275 if(sutRegisteredCallback) { 276 return; 277 } 278 trustSettingsDbg("tsRegisterCallback: registering callback"); 279 OSStatus ortn = SecKeychainAddCallback(tsTrustSettingsCallback, 280 kSecTrustSettingsChangedEventMask, NULL); 281 if(ortn) { 282 trustSettingsDbg("tsRegisterCallback: SecKeychainAddCallback returned %d", (int)ortn); 283 /* Not sure how this could ever happen - maybe if there is no run loop active? */ 284 } 285 sutRegisteredCallback = true; 286} 287 288#pragma mark --- Static functions --- 289 290 291/* 292 * Called by API code when a trust list has changed; we notify other processes 293 * and purge our own cache. 294 */ 295static void tsTrustSettingsChanged() 296{ 297 tsPurgeCache(); 298 299 /* The only interesting data is our pid */ 300 NameValueDictionary nvd; 301 pid_t ourPid = getpid(); 302 nvd.Insert (new NameValuePair (PID_KEY, 303 CssmData (reinterpret_cast<void*>(&ourPid), sizeof (pid_t)))); 304 CssmData data; 305 nvd.Export (data); 306 307 trustSettingsDbg("tsTrustSettingsChanged: posting notification"); 308 SecurityServer::ClientSession cs (Allocator::standard(), Allocator::standard()); 309 cs.postNotification (SecurityServer::kNotificationDomainDatabase, 310 kSecTrustSettingsChangedEvent, data); 311 free (data.data ()); 312} 313 314/* 315 * Common code for SecTrustSettingsCopyTrustSettings(), 316 * SecTrustSettingsCopyModificationDate(). 317 */ 318static OSStatus tsCopyTrustSettings( 319 SecCertificateRef cert, 320 SecTrustSettingsDomain domain, 321 CFArrayRef *trustSettings, /* optionally RETURNED */ 322 CFDateRef *modDate) /* optionally RETURNED */ 323{ 324 BEGIN_RCSAPI 325 326 TS_REQUIRED(cert) 327 328 /* obtain fresh full copy from disk */ 329 OSStatus result; 330 TrustSettings* ts; 331 332 result = TrustSettings::CreateTrustSettings(domain, CREATE_NO, TRIM_NO, ts); 333 334 // rather than throw these results, just return them because we are at the top level 335 if (result == errSecNoTrustSettings) { 336 return errSecItemNotFound; 337 } 338 else if (result != errSecSuccess) { 339 return result; 340 } 341 342 auto_ptr<TrustSettings>_(ts); // make sure this gets deleted just in case something throws underneath 343 344 if(trustSettings) { 345 *trustSettings = ts->copyTrustSettings(cert); 346 } 347 if(modDate) { 348 *modDate = ts->copyModDate(cert); 349 } 350 351 END_RCSAPI 352} 353 354/* 355 * Common code for SecTrustSettingsCopyQualifiedCerts() and 356 * SecTrustSettingsCopyUnrestrictedRoots(). 357 */ 358static OSStatus tsCopyCertsCommon( 359 /* usage constraints, all optional */ 360 const CSSM_OID *policyOID, 361 const char *policyString, 362 SecTrustSettingsKeyUsage keyUsage, 363 /* constrain to only roots */ 364 bool onlyRoots, 365 /* per-domain enables */ 366 bool user, 367 bool admin, 368 bool system, 369 CFArrayRef *certArray) /* RETURNED */ 370{ 371 StLock<Mutex> _TC(sutCacheLock()); 372 StLock<Mutex> _TK(SecTrustKeychainsGetMutex()); 373 374 TS_REQUIRED(certArray) 375 376 /* this relies on the domain enums being numbered 0..2, user..system */ 377 bool domainEnable[3] = {user, admin, system}; 378 379 /* we'll retain it again before successful exit */ 380 CFRef<CFMutableArrayRef> outArray(CFArrayCreateMutable(NULL, 0, 381 &kCFTypeArrayCallBacks)); 382 383 /* 384 * Search all keychains - user's, System.keychain, system root store, 385 * system intermdiates as appropriate 386 */ 387 StorageManager::KeychainList keychains; 388 Keychain adminKc; 389 if(user) { 390 globals().storageManager.getSearchList(keychains); 391 } 392 if(user || admin) { 393 adminKc = globals().storageManager.make(ADMIN_CERT_STORE_PATH, false); 394 keychains.push_back(adminKc); 395 } 396 Keychain sysRootKc = globals().storageManager.make(SYSTEM_ROOT_STORE_PATH, false); 397 keychains.push_back(sysRootKc); 398 Keychain sysCertKc = globals().storageManager.make(SYSTEM_CERT_STORE_PATH, false); 399 keychains.push_back(sysCertKc); 400 401 assert(kSecTrustSettingsDomainUser == 0); 402 for(unsigned domain=0; domain<TRUST_SETTINGS_NUM_DOMAINS; domain++) { 403 if(!domainEnable[domain]) { 404 continue; 405 } 406 TrustSettings *ts = tsGetGlobalTrustSettings(domain); 407 if(ts == NULL) { 408 continue; 409 } 410 ts->findQualifiedCerts(keychains, 411 false, /* !findAll */ 412 onlyRoots, 413 policyOID, policyString, keyUsage, 414 outArray); 415 } 416 *certArray = outArray; 417 CFRetain(*certArray); 418 trustSettingsDbg("tsCopyCertsCommon: %ld certs found", 419 CFArrayGetCount(outArray)); 420 return errSecSuccess; 421} 422 423#pragma mark --- SPI functions --- 424 425 426/* 427 * Fundamental routine used by TP to ascertain status of one cert. 428 * 429 * Returns true in *foundMatchingEntry if a trust setting matching 430 * specific constraints was found for the cert. Returns true in 431 * *foundAnyEntry if any entry was found for the cert, even if it 432 * did not match the specified constraints. The TP uses this to 433 * optimize for the case where a cert is being evaluated for 434 * one type of usage, and then later for another type. If 435 * foundAnyEntry is false, the second evaluation need not occur. 436 * 437 * Returns the domain in which a setting was found in *foundDomain. 438 * 439 * Allowed errors applying to the specified cert evaluation 440 * are returned in a mallocd array in *allowedErrors and must 441 * be freed by caller. 442 * 443 * The design of the entire TrustSettings module is centered around 444 * optimizing the performance of this routine (security concerns 445 * aside, that is). It's why the per-cert dictionaries are stored 446 * as a dictionary, keyed off of the cert hash. It's why TrustSettings 447 * are cached in memory by tsGetGlobalTrustSettings(), and why those 448 * cached TrustSettings objects are 'trimmed' of dictionary fields 449 * which are not needed to verify a cert. 450 * 451 * The API functions which are used to manipulate Trust Settings 452 * are called infrequently and need not be particularly fast since 453 * they result in user interaction for authentication. Thus they do 454 * not use cached TrustSettings as this function does. 455 */ 456OSStatus SecTrustSettingsEvaluateCert( 457 CFStringRef certHashStr, 458 /* parameters describing the current cert evalaution */ 459 const CSSM_OID *policyOID, 460 const char *policyString, /* optional */ 461 uint32 policyStringLen, 462 SecTrustSettingsKeyUsage keyUsage, /* optional */ 463 bool isRootCert, /* for checking default setting */ 464 /* RETURNED values */ 465 SecTrustSettingsDomain *foundDomain, 466 CSSM_RETURN **allowedErrors, /* mallocd */ 467 uint32 *numAllowedErrors, 468 SecTrustSettingsResult *resultType, 469 bool *foundMatchingEntry, 470 bool *foundAnyEntry) 471{ 472 BEGIN_RCSAPI 473 474 StLock<Mutex> _(sutCacheLock()); 475 476 TS_REQUIRED(certHashStr) 477 TS_REQUIRED(foundDomain) 478 TS_REQUIRED(allowedErrors) 479 TS_REQUIRED(numAllowedErrors) 480 TS_REQUIRED(resultType) 481 TS_REQUIRED(foundMatchingEntry) 482 TS_REQUIRED(foundAnyEntry) 483 484 /* ensure a NULL_terminated string */ 485 auto_array<char> polStr; 486 if(policyString != NULL && policyStringLen > 0) { 487 polStr.allocate(policyStringLen + 1); 488 memmove(polStr.get(), policyString, policyStringLen); 489 if(policyString[policyStringLen - 1] != '\0') { 490 (polStr.get())[policyStringLen] = '\0'; 491 } 492 } 493 494 /* initial condition - this can grow if we inspect multiple TrustSettings */ 495 *allowedErrors = NULL; 496 *numAllowedErrors = 0; 497 498 /* 499 * This loop relies on the ordering of the SecTrustSettingsDomain enum: 500 * search user first, then admin, then system. 501 */ 502 assert(kSecTrustSettingsDomainAdmin == (kSecTrustSettingsDomainUser + 1)); 503 assert(kSecTrustSettingsDomainSystem == (kSecTrustSettingsDomainAdmin + 1)); 504 bool foundAny = false; 505 for(unsigned domain=kSecTrustSettingsDomainUser; 506 domain<=kSecTrustSettingsDomainSystem; 507 domain++) { 508 TrustSettings *ts = tsGetGlobalTrustSettings(domain); 509 if(ts == NULL) { 510 continue; 511 } 512 513 /* validate cert returns true if matching entry was found */ 514 bool foundAnyHere = false; 515 bool found = ts->evaluateCert(certHashStr, policyOID, 516 polStr.get(), keyUsage, isRootCert, 517 allowedErrors, numAllowedErrors, resultType, &foundAnyHere); 518 519 if(found) { 520 /* 521 * Note this, even though we may overwrite it later if this 522 * is an Unspecified entry and we find a definitive entry 523 * later 524 */ 525 *foundDomain = domain; 526 } 527 if(found && (*resultType != kSecTrustSettingsResultUnspecified)) { 528 trustSettingsDbg("SecTrustSettingsEvaluateCert: found in domain %d", domain); 529 *foundAnyEntry = true; 530 *foundMatchingEntry = true; 531 return errSecSuccess; 532 } 533 foundAny |= foundAnyHere; 534 } 535 trustSettingsDbg("SecTrustSettingsEvaluateCert: NOT FOUND"); 536 *foundAnyEntry = foundAny; 537 *foundMatchingEntry = false; 538 return errSecSuccess; 539 END_RCSAPI 540} 541 542/* 543 * Obtain trusted certs which match specified usage. 544 * Only certs with a SecTrustSettingsResult of 545 * kSecTrustSettingsResultTrustRoot or 546 * or kSecTrustSettingsResultTrustAsRoot will be returned. 547 * To be used by SecureTransport for its SSLSetTrustedRoots() call; 548 * I hope nothing else has to use this... 549 * Caller must CFRelease the returned CFArrayRef. 550 */ 551OSStatus SecTrustSettingsCopyQualifiedCerts( 552 const CSSM_OID *policyOID, 553 const char *policyString, /* optional */ 554 uint32 policyStringLen, 555 SecTrustSettingsKeyUsage keyUsage, /* optional */ 556 CFArrayRef *certArray) /* RETURNED */ 557{ 558 BEGIN_RCSAPI 559 560 /* ensure a NULL_terminated string */ 561 auto_array<char> polStr; 562 if(policyString != NULL) { 563 polStr.allocate(policyStringLen + 1); 564 memmove(polStr.get(), policyString, policyStringLen); 565 if(policyString[policyStringLen - 1] != '\0') { 566 (polStr.get())[policyStringLen] = '\0'; 567 } 568 } 569 570 return tsCopyCertsCommon(policyOID, polStr.get(), keyUsage, 571 false, /* !onlyRoots */ 572 true, true, true, /* all domains */ 573 certArray); 574 575 END_RCSAPI 576} 577 578/* 579 * Obtain unrestricted root certs fromt eh specified domain(s). 580 * Only returns roots with no usage constraints. 581 * Caller must CFRelease the returned CFArrayRef. 582 */ 583OSStatus SecTrustSettingsCopyUnrestrictedRoots( 584 Boolean user, 585 Boolean admin, 586 Boolean system, 587 CFArrayRef *certArray) /* RETURNED */ 588{ 589 BEGIN_RCSAPI 590 591 return tsCopyCertsCommon(NULL, NULL, NULL, /* no constraints */ 592 true, /* onlyRoots */ 593 user, admin, system, 594 certArray); 595 596 END_RCSAPI 597} 598 599static const char hexChars[16] = { 600 '0', '1', '2', '3', '4', '5', '6', '7', 601 '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' 602}; 603 604/* 605 * Obtain a string representing a cert's SHA1 digest. This string is 606 * the key used to look up per-cert trust settings in a TrustSettings record. 607 */ 608CFStringRef SecTrustSettingsCertHashStrFromCert( 609 SecCertificateRef certRef) 610{ 611 if(certRef == NULL) { 612 return NULL; 613 } 614 615 if(certRef == kSecTrustSettingsDefaultRootCertSetting) { 616 /* use this string instead of the cert hash as the dictionary key */ 617 trustSettingsDbg("SecTrustSettingsCertHashStrFromCert: DefaultSetting"); 618 return kSecTrustRecordDefaultRootCert; 619 } 620 621 CSSM_DATA certData; 622 OSStatus ortn = SecCertificateGetData(certRef, &certData); 623 if(ortn) { 624 return NULL; 625 } 626 return SecTrustSettingsCertHashStrFromData(certData.Data, certData.Length); 627} 628 629CFStringRef SecTrustSettingsCertHashStrFromData( 630 const void *cert, 631 size_t certLen) 632{ 633 unsigned char digest[CC_SHA1_DIGEST_LENGTH]; 634 char asciiDigest[(2 * CC_SHA1_DIGEST_LENGTH) + 1]; 635 unsigned dex; 636 char *outp = asciiDigest; 637 unsigned char *inp = digest; 638 639 if(cert == NULL) { 640 return NULL; 641 } 642 643 CC_SHA1(cert, (CC_LONG)certLen, digest); 644 645 for(dex=0; dex<CC_SHA1_DIGEST_LENGTH; dex++) { 646 unsigned c = *inp++; 647 outp[1] = hexChars[c & 0xf]; 648 c >>= 4; 649 outp[0] = hexChars[c]; 650 outp += 2; 651 } 652 *outp = 0; 653 return CFStringCreateWithCString(NULL, asciiDigest, kCFStringEncodingASCII); 654} 655 656/* 657 * Add a cert's TrustSettings to a non-persistent TrustSettings record. 658 * No locking or cache flushing here; it's all local to the TrustSettings 659 * we construct here. 660 */ 661OSStatus SecTrustSettingsSetTrustSettingsExternal( 662 CFDataRef settingsIn, /* optional */ 663 SecCertificateRef certRef, /* optional */ 664 CFTypeRef trustSettingsDictOrArray, /* optional */ 665 CFDataRef *settingsOut) /* RETURNED */ 666{ 667 BEGIN_RCSAPI 668 669 TS_REQUIRED(settingsOut) 670 671 OSStatus result; 672 TrustSettings* ts; 673 674 result = TrustSettings::CreateTrustSettings(kSecTrustSettingsDomainMemory, settingsIn, ts); 675 if (result != errSecSuccess) { 676 return result; 677 } 678 679 auto_ptr<TrustSettings>_(ts); 680 681 if(certRef != NULL) { 682 ts->setTrustSettings(certRef, trustSettingsDictOrArray); 683 } 684 *settingsOut = ts->createExternal(); 685 return errSecSuccess; 686 687 END_RCSAPI 688} 689 690#pragma mark --- API functions --- 691 692OSStatus SecTrustSettingsCopyTrustSettings( 693 SecCertificateRef certRef, 694 SecTrustSettingsDomain domain, 695 CFArrayRef *trustSettings) /* RETURNED */ 696{ 697 TS_REQUIRED(trustSettings) 698 699 OSStatus result = tsCopyTrustSettings(certRef, domain, trustSettings, NULL); 700 if (result == errSecSuccess && *trustSettings == NULL) { 701 result = errSecItemNotFound; /* documented result if no trust settings exist */ 702 } 703 return result; 704} 705 706OSStatus SecTrustSettingsCopyModificationDate( 707 SecCertificateRef certRef, 708 SecTrustSettingsDomain domain, 709 CFDateRef *modificationDate) /* RETURNED */ 710{ 711 TS_REQUIRED(modificationDate) 712 713 OSStatus result = tsCopyTrustSettings(certRef, domain, NULL, modificationDate); 714 if (result == errSecSuccess && *modificationDate == NULL) { 715 result = errSecItemNotFound; /* documented result if no trust settings exist */ 716 } 717 return result; 718} 719 720/* works with existing and with new cert */ 721OSStatus SecTrustSettingsSetTrustSettings( 722 SecCertificateRef certRef, 723 SecTrustSettingsDomain domain, 724 CFTypeRef trustSettingsDictOrArray) 725{ 726 BEGIN_RCSAPI 727 728 TS_REQUIRED(certRef) 729 730 if(domain == kSecTrustSettingsDomainSystem) { 731 return errSecDataNotModifiable; 732 } 733 734 OSStatus result; 735 TrustSettings* ts; 736 737 result = TrustSettings::CreateTrustSettings(domain, CREATE_YES, TRIM_NO, ts); 738 if (result != errSecSuccess) { 739 return result; 740 } 741 742 auto_ptr<TrustSettings>_(ts); 743 744 ts->setTrustSettings(certRef, trustSettingsDictOrArray); 745 ts->flushToDisk(); 746 tsTrustSettingsChanged(); 747 return errSecSuccess; 748 749 END_RCSAPI 750} 751 752OSStatus SecTrustSettingsRemoveTrustSettings( 753 SecCertificateRef cert, 754 SecTrustSettingsDomain domain) 755{ 756 BEGIN_RCSAPI 757 758 TS_REQUIRED(cert) 759 760 if(domain == kSecTrustSettingsDomainSystem) { 761 return errSecDataNotModifiable; 762 } 763 764 OSStatus result; 765 TrustSettings* ts; 766 767 result = TrustSettings::CreateTrustSettings(domain, CREATE_NO, TRIM_NO, ts); 768 if (result != errSecSuccess) { 769 return result; 770 } 771 772 auto_ptr<TrustSettings>_(ts); 773 774 /* deleteTrustSettings throws if record not found */ 775 trustSettingsDbg("SecTrustSettingsRemoveTrustSettings: deleting from domain %d", 776 (int)domain); 777 ts->deleteTrustSettings(cert); 778 ts->flushToDisk(); 779 tsTrustSettingsChanged(); 780 return errSecSuccess; 781 782 END_RCSAPI 783} 784 785/* get all certs listed in specified domain */ 786OSStatus SecTrustSettingsCopyCertificates( 787 SecTrustSettingsDomain domain, 788 CFArrayRef *certArray) 789{ 790 BEGIN_RCSAPI 791 792 TS_REQUIRED(certArray) 793 794 OSStatus result; 795 TrustSettings* ts; 796 797 result = TrustSettings::CreateTrustSettings(domain, CREATE_NO, TRIM_NO, ts); 798 if (result != errSecSuccess) { 799 return result; 800 } 801 802 auto_ptr<TrustSettings>_(ts); 803 804 CFMutableArrayRef outArray = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); 805 806 /* 807 * Keychains to search: user's search list, System.keychain, system root store, 808 * system intermdiates, as appropriate 809 */ 810 StorageManager::KeychainList keychains; 811 Keychain adminKc; 812 Keychain sysCertKc; 813 Keychain sysRootKc; 814 switch(domain) { 815 case kSecTrustSettingsDomainUser: 816 /* user search list */ 817 globals().storageManager.getSearchList(keychains); 818 /* drop thru to next case */ 819 case kSecTrustSettingsDomainAdmin: 820 /* admin certs in system keychain */ 821 adminKc = globals().storageManager.make(ADMIN_CERT_STORE_PATH, false); 822 keychains.push_back(adminKc); 823 /* system-wide intermediate certs */ 824 sysCertKc = globals().storageManager.make(SYSTEM_CERT_STORE_PATH, false); 825 keychains.push_back(sysCertKc); 826 /* drop thru to next case */ 827 case kSecTrustSettingsDomainSystem: 828 /* and, for all cases, immutable system root store */ 829 sysRootKc = globals().storageManager.make(SYSTEM_ROOT_STORE_PATH, false); 830 keychains.push_back(sysRootKc); 831 default: 832 /* already validated when we created the TrustSettings */ 833 break; 834 } 835 ts->findCerts(keychains, outArray); 836 if(CFArrayGetCount(outArray) == 0) { 837 CFRelease(outArray); 838 return errSecNoTrustSettings; 839 } 840 *certArray = outArray; 841 END_RCSAPI 842} 843 844/* 845 * Obtain an external, portable representation of the specified 846 * domain's TrustSettings. Caller must CFRelease the returned data. 847 */ 848OSStatus SecTrustSettingsCreateExternalRepresentation( 849 SecTrustSettingsDomain domain, 850 CFDataRef *trustSettings) 851{ 852 BEGIN_RCSAPI 853 854 TS_REQUIRED(trustSettings) 855 856 OSStatus result; 857 TrustSettings* ts; 858 859 result = TrustSettings::CreateTrustSettings(domain, CREATE_NO, TRIM_NO, ts); 860 if (result != errSecSuccess) { 861 return result; 862 } 863 864 auto_ptr<TrustSettings>_(ts); 865 866 *trustSettings = ts->createExternal(); 867 return errSecSuccess; 868 869 END_RCSAPI 870} 871 872/* 873 * Import trust settings, obtained via SecTrustSettingsCreateExternalRepresentation, 874 * into the specified domain. 875 */ 876OSStatus SecTrustSettingsImportExternalRepresentation( 877 SecTrustSettingsDomain domain, 878 CFDataRef trustSettings) /* optional - NULL means empty settings */ 879{ 880 BEGIN_RCSAPI 881 882 if(domain == kSecTrustSettingsDomainSystem) { 883 return errSecDataNotModifiable; 884 } 885 886 OSStatus result; 887 TrustSettings* ts; 888 889 result = TrustSettings::CreateTrustSettings(domain, trustSettings, ts); 890 if (result != errSecSuccess) { 891 return result; 892 } 893 894 auto_ptr<TrustSettings>_(ts); 895 896 ts->flushToDisk(); 897 tsTrustSettingsChanged(); 898 return errSecSuccess; 899 900 END_RCSAPI 901} 902 903