nss_util.cc revision 5821806d5e7f356e8fa4b058a389a808ea183019
1// Copyright (c) 2012 The Chromium Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#include "crypto/nss_util.h" 6#include "crypto/nss_util_internal.h" 7 8#include <nss.h> 9#include <plarena.h> 10#include <prerror.h> 11#include <prinit.h> 12#include <prtime.h> 13#include <pk11pub.h> 14#include <secmod.h> 15 16#if defined(OS_LINUX) 17#include <linux/nfs_fs.h> 18#include <sys/vfs.h> 19#elif defined(OS_OPENBSD) 20#include <sys/mount.h> 21#include <sys/param.h> 22#endif 23 24#include <vector> 25 26#include "base/environment.h" 27#include "base/file_path.h" 28#include "base/file_util.h" 29#include "base/lazy_instance.h" 30#include "base/logging.h" 31#include "base/memory/scoped_ptr.h" 32#include "base/native_library.h" 33#include "base/scoped_temp_dir.h" 34#include "base/stringprintf.h" 35#include "base/threading/thread_restrictions.h" 36#include "build/build_config.h" 37 38#if defined(OS_CHROMEOS) 39#include "crypto/symmetric_key.h" 40#endif 41 42// USE_NSS means we use NSS for everything crypto-related. If USE_NSS is not 43// defined, such as on Mac and Windows, we use NSS for SSL only -- we don't 44// use NSS for crypto or certificate verification, and we don't use the NSS 45// certificate and key databases. 46#if defined(USE_NSS) 47#include "base/synchronization/lock.h" 48#include "crypto/crypto_module_blocking_password_delegate.h" 49#endif // defined(USE_NSS) 50 51namespace crypto { 52 53namespace { 54 55#if defined(OS_CHROMEOS) 56const char kNSSDatabaseName[] = "Real NSS database"; 57 58// Constants for loading the Chrome OS TPM-backed PKCS #11 library. 59const char kChapsModuleName[] = "Chaps"; 60const char kChapsPath[] = "libchaps.so"; 61 62// Fake certificate authority database used for testing. 63static const FilePath::CharType kReadOnlyCertDB[] = 64 FILE_PATH_LITERAL("/etc/fake_root_ca/nssdb"); 65#endif // defined(OS_CHROMEOS) 66 67std::string GetNSSErrorMessage() { 68 std::string result; 69 if (PR_GetErrorTextLength()) { 70 scoped_array<char> error_text(new char[PR_GetErrorTextLength() + 1]); 71 PRInt32 copied = PR_GetErrorText(error_text.get()); 72 result = std::string(error_text.get(), copied); 73 } else { 74 result = StringPrintf("NSS error code: %d", PR_GetError()); 75 } 76 return result; 77} 78 79#if defined(USE_NSS) 80FilePath GetDefaultConfigDirectory() { 81 FilePath dir = file_util::GetHomeDir(); 82 if (dir.empty()) { 83 LOG(ERROR) << "Failed to get home directory."; 84 return dir; 85 } 86 dir = dir.AppendASCII(".pki").AppendASCII("nssdb"); 87 if (!file_util::CreateDirectory(dir)) { 88 LOG(ERROR) << "Failed to create " << dir.value() << " directory."; 89 dir.clear(); 90 } 91 return dir; 92} 93 94#if defined(OS_CHROMEOS) 95// Supplemental user key id. 96unsigned char kSupplementalUserKeyId[] = { 97 0xCC, 0x13, 0x19, 0xDE, 0x75, 0x5E, 0xFE, 0xFA, 98 0x5E, 0x71, 0xD4, 0xA6, 0xFB, 0x00, 0x00, 0xCC 99}; 100#endif // defined(OS_CHROMEOS) 101 102 103// On non-chromeos platforms, return the default config directory. 104// On chromeos, return a read-only directory with fake root CA certs for testing 105// (which will not exist on non-testing images). These root CA certs are used 106// by the local Google Accounts server mock we use when testing our login code. 107// If this directory is not present, NSS_Init() will fail. It is up to the 108// caller to failover to NSS_NoDB_Init() at that point. 109FilePath GetInitialConfigDirectory() { 110#if defined(OS_CHROMEOS) 111 return FilePath(kReadOnlyCertDB); 112#else 113 return GetDefaultConfigDirectory(); 114#endif // defined(OS_CHROMEOS) 115} 116 117// This callback for NSS forwards all requests to a caller-specified 118// CryptoModuleBlockingPasswordDelegate object. 119char* PKCS11PasswordFunc(PK11SlotInfo* slot, PRBool retry, void* arg) { 120#if defined(OS_CHROMEOS) 121 // If we get asked for a password for the TPM, then return the 122 // well known password we use, as long as the TPM slot has been 123 // initialized. 124 if (crypto::IsTPMTokenReady()) { 125 std::string token_name; 126 std::string user_pin; 127 crypto::GetTPMTokenInfo(&token_name, &user_pin); 128 if (PK11_GetTokenName(slot) == token_name) 129 return PORT_Strdup(user_pin.c_str()); 130 } 131#endif 132 crypto::CryptoModuleBlockingPasswordDelegate* delegate = 133 reinterpret_cast<crypto::CryptoModuleBlockingPasswordDelegate*>(arg); 134 if (delegate) { 135 bool cancelled = false; 136 std::string password = delegate->RequestPassword(PK11_GetTokenName(slot), 137 retry != PR_FALSE, 138 &cancelled); 139 if (cancelled) 140 return NULL; 141 char* result = PORT_Strdup(password.c_str()); 142 password.replace(0, password.size(), password.size(), 0); 143 return result; 144 } 145 DLOG(ERROR) << "PK11 password requested with NULL arg"; 146 return NULL; 147} 148 149// NSS creates a local cache of the sqlite database if it detects that the 150// filesystem the database is on is much slower than the local disk. The 151// detection doesn't work with the latest versions of sqlite, such as 3.6.22 152// (NSS bug https://bugzilla.mozilla.org/show_bug.cgi?id=578561). So we set 153// the NSS environment variable NSS_SDB_USE_CACHE to "yes" to override NSS's 154// detection when database_dir is on NFS. See http://crbug.com/48585. 155// 156// TODO(wtc): port this function to other USE_NSS platforms. It is defined 157// only for OS_LINUX and OS_OPENBSD simply because the statfs structure 158// is OS-specific. 159// 160// Because this function sets an environment variable it must be run before we 161// go multi-threaded. 162void UseLocalCacheOfNSSDatabaseIfNFS(const FilePath& database_dir) { 163#if defined(OS_LINUX) || defined(OS_OPENBSD) 164 struct statfs buf; 165 if (statfs(database_dir.value().c_str(), &buf) == 0) { 166#if defined(OS_LINUX) 167 if (buf.f_type == NFS_SUPER_MAGIC) { 168#elif defined(OS_OPENBSD) 169 if (strcmp(buf.f_fstypename, MOUNT_NFS) == 0) { 170#endif 171 scoped_ptr<base::Environment> env(base::Environment::Create()); 172 const char* use_cache_env_var = "NSS_SDB_USE_CACHE"; 173 if (!env->HasVar(use_cache_env_var)) 174 env->SetVar(use_cache_env_var, "yes"); 175 } 176 } 177#endif // defined(OS_LINUX) || defined(OS_OPENBSD) 178} 179 180PK11SlotInfo* FindSlotWithTokenName(const std::string& token_name) { 181 AutoSECMODListReadLock auto_lock; 182 SECMODModuleList* head = SECMOD_GetDefaultModuleList(); 183 for (SECMODModuleList* item = head; item != NULL; item = item->next) { 184 int slot_count = item->module->loaded ? item->module->slotCount : 0; 185 for (int i = 0; i < slot_count; i++) { 186 PK11SlotInfo* slot = item->module->slots[i]; 187 if (PK11_GetTokenName(slot) == token_name) 188 return PK11_ReferenceSlot(slot); 189 } 190 } 191 return NULL; 192} 193 194#endif // defined(USE_NSS) 195 196// A singleton to initialize/deinitialize NSPR. 197// Separate from the NSS singleton because we initialize NSPR on the UI thread. 198// Now that we're leaking the singleton, we could merge back with the NSS 199// singleton. 200class NSPRInitSingleton { 201 private: 202 friend struct base::DefaultLazyInstanceTraits<NSPRInitSingleton>; 203 204 NSPRInitSingleton() { 205 PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0); 206 } 207 208 // NOTE(willchan): We don't actually execute this code since we leak NSS to 209 // prevent non-joinable threads from using NSS after it's already been shut 210 // down. 211 ~NSPRInitSingleton() { 212 PL_ArenaFinish(); 213 PRStatus prstatus = PR_Cleanup(); 214 if (prstatus != PR_SUCCESS) 215 LOG(ERROR) << "PR_Cleanup failed; was NSPR initialized on wrong thread?"; 216 } 217}; 218 219base::LazyInstance<NSPRInitSingleton>::Leaky 220 g_nspr_singleton = LAZY_INSTANCE_INITIALIZER; 221 222// This is a LazyInstance so that it will be deleted automatically when the 223// unittest exits. NSSInitSingleton is a LeakySingleton, so it would not be 224// deleted if it were a regular member. 225base::LazyInstance<ScopedTempDir> g_test_nss_db_dir = LAZY_INSTANCE_INITIALIZER; 226 227class NSSInitSingleton { 228 public: 229#if defined(OS_CHROMEOS) 230 void OpenPersistentNSSDB() { 231 if (!chromeos_user_logged_in_) { 232 // GetDefaultConfigDirectory causes us to do blocking IO on UI thread. 233 // Temporarily allow it until we fix http://crbug.com/70119 234 base::ThreadRestrictions::ScopedAllowIO allow_io; 235 chromeos_user_logged_in_ = true; 236 237 // This creates another DB slot in NSS that is read/write, unlike 238 // the fake root CA cert DB and the "default" crypto key 239 // provider, which are still read-only (because we initialized 240 // NSS before we had a cryptohome mounted). 241 software_slot_ = OpenUserDB(GetDefaultConfigDirectory(), 242 kNSSDatabaseName); 243 } 244 } 245 246 void EnableTPMTokenForNSS() { 247 tpm_token_enabled_for_nss_ = true; 248 } 249 250 bool InitializeTPMToken(const std::string& token_name, 251 const std::string& user_pin) { 252 // If EnableTPMTokenForNSS hasn't been called, return false. 253 if (!tpm_token_enabled_for_nss_) 254 return false; 255 256 // If everything is already initialized, then return true. 257 if (chaps_module_ && tpm_slot_) 258 return true; 259 260 tpm_token_name_ = token_name; 261 tpm_user_pin_ = user_pin; 262 263 // This tries to load the Chaps module so NSS can talk to the hardware 264 // TPM. 265 if (!chaps_module_) { 266 chaps_module_ = LoadModule( 267 kChapsModuleName, 268 kChapsPath, 269 // For more details on these parameters, see: 270 // https://developer.mozilla.org/en/PKCS11_Module_Specs 271 // slotFlags=[PublicCerts] -- Certificates and public keys can be 272 // read from this slot without requiring a call to C_Login. 273 // askpw=only -- Only authenticate to the token when necessary. 274 "NSS=\"slotParams=(0={slotFlags=[PublicCerts] askpw=only})\""); 275 } 276 if (chaps_module_){ 277 // If this gets set, then we'll use the TPM for certs with 278 // private keys, otherwise we'll fall back to the software 279 // implementation. 280 tpm_slot_ = GetTPMSlot(); 281 282 return tpm_slot_ != NULL; 283 } 284 return false; 285 } 286 287 void GetTPMTokenInfo(std::string* token_name, std::string* user_pin) { 288 if (!tpm_token_enabled_for_nss_) { 289 LOG(ERROR) << "GetTPMTokenInfo called before TPM Token is ready."; 290 return; 291 } 292 if (token_name) 293 *token_name = tpm_token_name_; 294 if (user_pin) 295 *user_pin = tpm_user_pin_; 296 } 297 298 bool IsTPMTokenReady() { 299 return tpm_slot_ != NULL; 300 } 301 302 PK11SlotInfo* GetTPMSlot() { 303 std::string token_name; 304 GetTPMTokenInfo(&token_name, NULL); 305 return FindSlotWithTokenName(token_name); 306 } 307 308 SymmetricKey* GetSupplementalUserKey() { 309 DCHECK(chromeos_user_logged_in_); 310 311 PK11SlotInfo* slot = NULL; 312 PK11SymKey* key = NULL; 313 SECItem keyID; 314 CK_MECHANISM_TYPE type = CKM_AES_ECB; 315 316 slot = GetPublicNSSKeySlot(); 317 if (!slot) 318 goto done; 319 320 if (PK11_Authenticate(slot, PR_TRUE, NULL) != SECSuccess) 321 goto done; 322 323 keyID.type = siBuffer; 324 keyID.data = kSupplementalUserKeyId; 325 keyID.len = static_cast<int>(sizeof(kSupplementalUserKeyId)); 326 327 // Find/generate AES key. 328 key = PK11_FindFixedKey(slot, type, &keyID, NULL); 329 if (!key) { 330 const int kKeySizeInBytes = 32; 331 key = PK11_TokenKeyGen(slot, type, NULL, 332 kKeySizeInBytes, 333 &keyID, PR_TRUE, NULL); 334 } 335 336 done: 337 if (slot) 338 PK11_FreeSlot(slot); 339 340 return key ? SymmetricKey::CreateFromKey(key) : NULL; 341 } 342#endif // defined(OS_CHROMEOS) 343 344 345 bool OpenTestNSSDB() { 346 if (test_slot_) 347 return true; 348 if (!g_test_nss_db_dir.Get().CreateUniqueTempDir()) 349 return false; 350 test_slot_ = OpenUserDB(g_test_nss_db_dir.Get().path(), "Test DB"); 351 return !!test_slot_; 352 } 353 354 void CloseTestNSSDB() { 355 if (test_slot_) { 356 SECStatus status = SECMOD_CloseUserDB(test_slot_); 357 if (status != SECSuccess) 358 PLOG(ERROR) << "SECMOD_CloseUserDB failed: " << PORT_GetError(); 359 PK11_FreeSlot(test_slot_); 360 test_slot_ = NULL; 361 ignore_result(g_test_nss_db_dir.Get().Delete()); 362 } 363 } 364 365 PK11SlotInfo* GetPublicNSSKeySlot() { 366 if (test_slot_) 367 return PK11_ReferenceSlot(test_slot_); 368 if (software_slot_) 369 return PK11_ReferenceSlot(software_slot_); 370 return PK11_GetInternalKeySlot(); 371 } 372 373 PK11SlotInfo* GetPrivateNSSKeySlot() { 374 if (test_slot_) 375 return PK11_ReferenceSlot(test_slot_); 376 377#if defined(OS_CHROMEOS) 378 if (tpm_token_enabled_for_nss_) { 379 if (IsTPMTokenReady()) { 380 return PK11_ReferenceSlot(tpm_slot_); 381 } else { 382 // If we were supposed to get the hardware token, but were 383 // unable to, return NULL rather than fall back to sofware. 384 return NULL; 385 } 386 } 387#endif 388 // If we weren't supposed to enable the TPM for NSS, then return 389 // the software slot. 390 if (software_slot_) 391 return PK11_ReferenceSlot(software_slot_); 392 return PK11_GetInternalKeySlot(); 393 } 394 395#if defined(USE_NSS) 396 base::Lock* write_lock() { 397 return &write_lock_; 398 } 399#endif // defined(USE_NSS) 400 401 // This method is used to force NSS to be initialized without a DB. 402 // Call this method before NSSInitSingleton() is constructed. 403 static void ForceNoDBInit() { 404 force_nodb_init_ = true; 405 } 406 407 private: 408 friend struct base::DefaultLazyInstanceTraits<NSSInitSingleton>; 409 410 NSSInitSingleton() 411 : tpm_token_enabled_for_nss_(false), 412 chaps_module_(NULL), 413 software_slot_(NULL), 414 test_slot_(NULL), 415 tpm_slot_(NULL), 416 root_(NULL), 417 chromeos_user_logged_in_(false) { 418 EnsureNSPRInit(); 419 420 // We *must* have NSS >= 3.12.3. See bug 26448. 421 COMPILE_ASSERT( 422 (NSS_VMAJOR == 3 && NSS_VMINOR == 12 && NSS_VPATCH >= 3) || 423 (NSS_VMAJOR == 3 && NSS_VMINOR > 12) || 424 (NSS_VMAJOR > 3), 425 nss_version_check_failed); 426 // Also check the run-time NSS version. 427 // NSS_VersionCheck is a >= check, not strict equality. 428 if (!NSS_VersionCheck("3.12.3")) { 429 // It turns out many people have misconfigured NSS setups, where 430 // their run-time NSPR doesn't match the one their NSS was compiled 431 // against. So rather than aborting, complain loudly. 432 LOG(ERROR) << "NSS_VersionCheck(\"3.12.3\") failed. " 433 "We depend on NSS >= 3.12.3, and this error is not fatal " 434 "only because many people have busted NSS setups (for " 435 "example, using the wrong version of NSPR). " 436 "Please upgrade to the latest NSS and NSPR, and if you " 437 "still get this error, contact your distribution " 438 "maintainer."; 439 } 440 441 SECStatus status = SECFailure; 442 bool nodb_init = force_nodb_init_; 443 444#if !defined(USE_NSS) 445 // Use the system certificate store, so initialize NSS without database. 446 nodb_init = true; 447#endif 448 449 if (nodb_init) { 450 status = NSS_NoDB_Init(NULL); 451 if (status != SECSuccess) { 452 LOG(ERROR) << "Error initializing NSS without a persistent " 453 "database: " << GetNSSErrorMessage(); 454 } 455#if defined(OS_IOS) 456 root_ = InitDefaultRootCerts(); 457#endif // defined(OS_IOS) 458 } else { 459#if defined(USE_NSS) 460 FilePath database_dir = GetInitialConfigDirectory(); 461 if (!database_dir.empty()) { 462 // This duplicates the work which should have been done in 463 // EarlySetupForNSSInit. However, this function is idempotent so 464 // there's no harm done. 465 UseLocalCacheOfNSSDatabaseIfNFS(database_dir); 466 467 // Initialize with a persistent database (likely, ~/.pki/nssdb). 468 // Use "sql:" which can be shared by multiple processes safely. 469 std::string nss_config_dir = 470 StringPrintf("sql:%s", database_dir.value().c_str()); 471#if defined(OS_CHROMEOS) 472 status = NSS_Init(nss_config_dir.c_str()); 473#else 474 status = NSS_InitReadWrite(nss_config_dir.c_str()); 475#endif 476 if (status != SECSuccess) { 477 LOG(ERROR) << "Error initializing NSS with a persistent " 478 "database (" << nss_config_dir 479 << "): " << GetNSSErrorMessage(); 480 } 481 } 482 if (status != SECSuccess) { 483 VLOG(1) << "Initializing NSS without a persistent database."; 484 status = NSS_NoDB_Init(NULL); 485 if (status != SECSuccess) { 486 LOG(ERROR) << "Error initializing NSS without a persistent " 487 "database: " << GetNSSErrorMessage(); 488 return; 489 } 490 } 491 492 PK11_SetPasswordFunc(PKCS11PasswordFunc); 493 494 // If we haven't initialized the password for the NSS databases, 495 // initialize an empty-string password so that we don't need to 496 // log in. 497 PK11SlotInfo* slot = PK11_GetInternalKeySlot(); 498 if (slot) { 499 // PK11_InitPin may write to the keyDB, but no other thread can use NSS 500 // yet, so we don't need to lock. 501 if (PK11_NeedUserInit(slot)) 502 PK11_InitPin(slot, NULL, NULL); 503 PK11_FreeSlot(slot); 504 } 505 506 root_ = InitDefaultRootCerts(); 507 508 // MD5 certificate signatures are disabled by default in NSS 3.14. 509 // Enable MD5 certificate signatures until we figure out how to deal 510 // with the weak certificate signature unit tests. 511 NSS_SetAlgorithmPolicy(SEC_OID_MD5, NSS_USE_ALG_IN_CERT_SIGNATURE, 0); 512#endif // defined(USE_NSS) 513 } 514 } 515 516 // NOTE(willchan): We don't actually execute this code since we leak NSS to 517 // prevent non-joinable threads from using NSS after it's already been shut 518 // down. 519 ~NSSInitSingleton() { 520 if (tpm_slot_) { 521 PK11_FreeSlot(tpm_slot_); 522 tpm_slot_ = NULL; 523 } 524 if (software_slot_) { 525 SECMOD_CloseUserDB(software_slot_); 526 PK11_FreeSlot(software_slot_); 527 software_slot_ = NULL; 528 } 529 CloseTestNSSDB(); 530 if (root_) { 531 SECMOD_UnloadUserModule(root_); 532 SECMOD_DestroyModule(root_); 533 root_ = NULL; 534 } 535 if (chaps_module_) { 536 SECMOD_UnloadUserModule(chaps_module_); 537 SECMOD_DestroyModule(chaps_module_); 538 chaps_module_ = NULL; 539 } 540 541 SECStatus status = NSS_Shutdown(); 542 if (status != SECSuccess) { 543 // We VLOG(1) because this failure is relatively harmless (leaking, but 544 // we're shutting down anyway). 545 VLOG(1) << "NSS_Shutdown failed; see http://crbug.com/4609"; 546 } 547 } 548 549#if defined(USE_NSS) || defined(OS_IOS) 550 // Load nss's built-in root certs. 551 SECMODModule* InitDefaultRootCerts() { 552 SECMODModule* root = LoadModule("Root Certs", "libnssckbi.so", NULL); 553 if (root) 554 return root; 555 556 // Aw, snap. Can't find/load root cert shared library. 557 // This will make it hard to talk to anybody via https. 558 NOTREACHED(); 559 return NULL; 560 } 561 562 // Load the given module for this NSS session. 563 SECMODModule* LoadModule(const char* name, 564 const char* library_path, 565 const char* params) { 566 std::string modparams = StringPrintf( 567 "name=\"%s\" library=\"%s\" %s", 568 name, library_path, params ? params : ""); 569 570 // Shouldn't need to const_cast here, but SECMOD doesn't properly 571 // declare input string arguments as const. Bug 572 // https://bugzilla.mozilla.org/show_bug.cgi?id=642546 was filed 573 // on NSS codebase to address this. 574 SECMODModule* module = SECMOD_LoadUserModule( 575 const_cast<char*>(modparams.c_str()), NULL, PR_FALSE); 576 if (!module) { 577 LOG(ERROR) << "Error loading " << name << " module into NSS: " 578 << GetNSSErrorMessage(); 579 return NULL; 580 } 581 return module; 582 } 583#endif 584 585 static PK11SlotInfo* OpenUserDB(const FilePath& path, 586 const char* description) { 587 const std::string modspec = 588 StringPrintf("configDir='sql:%s' tokenDescription='%s'", 589 path.value().c_str(), description); 590 PK11SlotInfo* db_slot = SECMOD_OpenUserDB(modspec.c_str()); 591 if (db_slot) { 592 if (PK11_NeedUserInit(db_slot)) 593 PK11_InitPin(db_slot, NULL, NULL); 594 } 595 else { 596 LOG(ERROR) << "Error opening persistent database (" << modspec 597 << "): " << GetNSSErrorMessage(); 598 } 599 return db_slot; 600 } 601 602 // If this is set to true NSS is forced to be initialized without a DB. 603 static bool force_nodb_init_; 604 605 bool tpm_token_enabled_for_nss_; 606 std::string tpm_token_name_; 607 std::string tpm_user_pin_; 608 SECMODModule* chaps_module_; 609 PK11SlotInfo* software_slot_; 610 PK11SlotInfo* test_slot_; 611 PK11SlotInfo* tpm_slot_; 612 SECMODModule* root_; 613 bool chromeos_user_logged_in_; 614#if defined(USE_NSS) 615 // TODO(davidben): When https://bugzilla.mozilla.org/show_bug.cgi?id=564011 616 // is fixed, we will no longer need the lock. 617 base::Lock write_lock_; 618#endif // defined(USE_NSS) 619}; 620 621// static 622bool NSSInitSingleton::force_nodb_init_ = false; 623 624base::LazyInstance<NSSInitSingleton>::Leaky 625 g_nss_singleton = LAZY_INSTANCE_INITIALIZER; 626} // namespace 627 628#if defined(USE_NSS) 629void EarlySetupForNSSInit() { 630 FilePath database_dir = GetInitialConfigDirectory(); 631 if (!database_dir.empty()) 632 UseLocalCacheOfNSSDatabaseIfNFS(database_dir); 633} 634#endif 635 636void EnsureNSPRInit() { 637 g_nspr_singleton.Get(); 638} 639 640void EnsureNSSInit() { 641 // Initializing SSL causes us to do blocking IO. 642 // Temporarily allow it until we fix 643 // http://code.google.com/p/chromium/issues/detail?id=59847 644 base::ThreadRestrictions::ScopedAllowIO allow_io; 645 g_nss_singleton.Get(); 646} 647 648void ForceNSSNoDBInit() { 649 NSSInitSingleton::ForceNoDBInit(); 650} 651 652void DisableNSSForkCheck() { 653 scoped_ptr<base::Environment> env(base::Environment::Create()); 654 env->SetVar("NSS_STRICT_NOFORK", "DISABLED"); 655} 656 657void LoadNSSLibraries() { 658 // Some NSS libraries are linked dynamically so load them here. 659#if defined(USE_NSS) 660 // Try to search for multiple directories to load the libraries. 661 std::vector<FilePath> paths; 662 663 // Use relative path to Search PATH for the library files. 664 paths.push_back(FilePath()); 665 666 // For Debian derivatives NSS libraries are located here. 667 paths.push_back(FilePath("/usr/lib/nss")); 668 669 // Ubuntu 11.10 (Oneiric) places the libraries here. 670#if defined(ARCH_CPU_X86_64) 671 paths.push_back(FilePath("/usr/lib/x86_64-linux-gnu/nss")); 672#elif defined(ARCH_CPU_X86) 673 paths.push_back(FilePath("/usr/lib/i386-linux-gnu/nss")); 674#elif defined(ARCH_CPU_ARMEL) 675 paths.push_back(FilePath("/usr/lib/arm-linux-gnueabi/nss")); 676#endif 677 678 // A list of library files to load. 679 std::vector<std::string> libs; 680 libs.push_back("libsoftokn3.so"); 681 libs.push_back("libfreebl3.so"); 682 683 // For each combination of library file and path, check for existence and 684 // then load. 685 size_t loaded = 0; 686 for (size_t i = 0; i < libs.size(); ++i) { 687 for (size_t j = 0; j < paths.size(); ++j) { 688 FilePath path = paths[j].Append(libs[i]); 689 base::NativeLibrary lib = base::LoadNativeLibrary(path, NULL); 690 if (lib) { 691 ++loaded; 692 break; 693 } 694 } 695 } 696 697 if (loaded == libs.size()) { 698 VLOG(3) << "NSS libraries loaded."; 699 } else { 700 LOG(ERROR) << "Failed to load NSS libraries."; 701 } 702#endif 703} 704 705bool CheckNSSVersion(const char* version) { 706 return !!NSS_VersionCheck(version); 707} 708 709#if defined(USE_NSS) 710ScopedTestNSSDB::ScopedTestNSSDB() 711 : is_open_(g_nss_singleton.Get().OpenTestNSSDB()) { 712} 713 714ScopedTestNSSDB::~ScopedTestNSSDB() { 715 // TODO(mattm): Close the dababase once NSS 3.14 is required, 716 // which fixes https://bugzilla.mozilla.org/show_bug.cgi?id=588269 717 // Resource leaks are suppressed. http://crbug.com/156433 . 718} 719 720base::Lock* GetNSSWriteLock() { 721 return g_nss_singleton.Get().write_lock(); 722} 723 724AutoNSSWriteLock::AutoNSSWriteLock() : lock_(GetNSSWriteLock()) { 725 // May be NULL if the lock is not needed in our version of NSS. 726 if (lock_) 727 lock_->Acquire(); 728} 729 730AutoNSSWriteLock::~AutoNSSWriteLock() { 731 if (lock_) { 732 lock_->AssertAcquired(); 733 lock_->Release(); 734 } 735} 736 737AutoSECMODListReadLock::AutoSECMODListReadLock() 738 : lock_(SECMOD_GetDefaultModuleListLock()) { 739 SECMOD_GetReadLock(lock_); 740 } 741 742AutoSECMODListReadLock::~AutoSECMODListReadLock() { 743 SECMOD_ReleaseReadLock(lock_); 744} 745 746#endif // defined(USE_NSS) 747 748#if defined(OS_CHROMEOS) 749void OpenPersistentNSSDB() { 750 g_nss_singleton.Get().OpenPersistentNSSDB(); 751} 752 753void EnableTPMTokenForNSS() { 754 g_nss_singleton.Get().EnableTPMTokenForNSS(); 755} 756 757void GetTPMTokenInfo(std::string* token_name, std::string* user_pin) { 758 g_nss_singleton.Get().GetTPMTokenInfo(token_name, user_pin); 759} 760 761bool IsTPMTokenReady() { 762 return g_nss_singleton.Get().IsTPMTokenReady(); 763} 764 765bool InitializeTPMToken(const std::string& token_name, 766 const std::string& user_pin) { 767 return g_nss_singleton.Get().InitializeTPMToken(token_name, user_pin); 768} 769 770SymmetricKey* GetSupplementalUserKey() { 771 return g_nss_singleton.Get().GetSupplementalUserKey(); 772} 773#endif // defined(OS_CHROMEOS) 774 775base::Time PRTimeToBaseTime(PRTime prtime) { 776 return base::Time::FromInternalValue( 777 prtime + base::Time::UnixEpoch().ToInternalValue()); 778} 779 780PRTime BaseTimeToPRTime(base::Time time) { 781 return time.ToInternalValue() - base::Time::UnixEpoch().ToInternalValue(); 782} 783 784PK11SlotInfo* GetPublicNSSKeySlot() { 785 return g_nss_singleton.Get().GetPublicNSSKeySlot(); 786} 787 788PK11SlotInfo* GetPrivateNSSKeySlot() { 789 return g_nss_singleton.Get().GetPrivateNSSKeySlot(); 790} 791 792} // namespace crypto 793