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