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