1 // Copyright (c) 2011 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 #endif 20 21 #include <vector> 22 23 #include "base/environment.h" 24 #include "base/file_path.h" 25 #include "base/file_util.h" 26 #include "base/lazy_instance.h" 27 #include "base/logging.h" 28 #include "base/memory/scoped_ptr.h" 29 #include "base/native_library.h" 30 #include "base/stringprintf.h" 31 #include "base/threading/thread_restrictions.h" 32 #include "crypto/scoped_nss_types.h" 33 34 // USE_NSS means we use NSS for everything crypto-related. If USE_NSS is not 35 // defined, such as on Mac and Windows, we use NSS for SSL only -- we don't 36 // use NSS for crypto or certificate verification, and we don't use the NSS 37 // certificate and key databases. 38 #if defined(USE_NSS) 39 #include "base/synchronization/lock.h" 40 #include "crypto/crypto_module_blocking_password_delegate.h" 41 #endif // defined(USE_NSS) 42 43 namespace crypto { 44 45 namespace { 46 47 #if defined(OS_CHROMEOS) 48 const char kNSSDatabaseName[] = "Real NSS database"; 49 50 // Constants for loading opencryptoki. 51 const char kOpencryptokiModuleName[] = "opencryptoki"; 52 const char kOpencryptokiPath[] = "/usr/lib/opencryptoki/libopencryptoki.so"; 53 54 // Fake certificate authority database used for testing. 55 static const FilePath::CharType kReadOnlyCertDB[] = 56 FILE_PATH_LITERAL("/etc/fake_root_ca/nssdb"); 57 #endif // defined(OS_CHROMEOS) 58 59 std::string GetNSSErrorMessage() { 60 std::string result; 61 if (PR_GetErrorTextLength()) { 62 scoped_array<char> error_text(new char[PR_GetErrorTextLength() + 1]); 63 PRInt32 copied = PR_GetErrorText(error_text.get()); 64 result = std::string(error_text.get(), copied); 65 } else { 66 result = StringPrintf("NSS error code: %d", PR_GetError()); 67 } 68 return result; 69 } 70 71 #if defined(USE_NSS) 72 FilePath GetDefaultConfigDirectory() { 73 FilePath dir = file_util::GetHomeDir(); 74 if (dir.empty()) { 75 LOG(ERROR) << "Failed to get home directory."; 76 return dir; 77 } 78 dir = dir.AppendASCII(".pki").AppendASCII("nssdb"); 79 if (!file_util::CreateDirectory(dir)) { 80 LOG(ERROR) << "Failed to create ~/.pki/nssdb directory."; 81 dir.clear(); 82 } 83 return dir; 84 } 85 86 // On non-chromeos platforms, return the default config directory. 87 // On chromeos, return a read-only directory with fake root CA certs for testing 88 // (which will not exist on non-testing images). These root CA certs are used 89 // by the local Google Accounts server mock we use when testing our login code. 90 // If this directory is not present, NSS_Init() will fail. It is up to the 91 // caller to failover to NSS_NoDB_Init() at that point. 92 FilePath GetInitialConfigDirectory() { 93 #if defined(OS_CHROMEOS) 94 return FilePath(kReadOnlyCertDB); 95 #else 96 return GetDefaultConfigDirectory(); 97 #endif // defined(OS_CHROMEOS) 98 } 99 100 // This callback for NSS forwards all requests to a caller-specified 101 // CryptoModuleBlockingPasswordDelegate object. 102 char* PKCS11PasswordFunc(PK11SlotInfo* slot, PRBool retry, void* arg) { 103 #if defined(OS_CHROMEOS) 104 // If we get asked for a password for the TPM, then return the 105 // well known password we use, as long as the TPM slot has been 106 // initialized. 107 if (crypto::IsTPMTokenReady()) { 108 std::string token_name; 109 std::string user_pin; 110 crypto::GetTPMTokenInfo(&token_name, &user_pin); 111 if (PK11_GetTokenName(slot) == token_name) 112 return PORT_Strdup(user_pin.c_str()); 113 } 114 #endif 115 crypto::CryptoModuleBlockingPasswordDelegate* delegate = 116 reinterpret_cast<crypto::CryptoModuleBlockingPasswordDelegate*>(arg); 117 if (delegate) { 118 bool cancelled = false; 119 std::string password = delegate->RequestPassword(PK11_GetTokenName(slot), 120 retry != PR_FALSE, 121 &cancelled); 122 if (cancelled) 123 return NULL; 124 char* result = PORT_Strdup(password.c_str()); 125 password.replace(0, password.size(), password.size(), 0); 126 return result; 127 } 128 DLOG(ERROR) << "PK11 password requested with NULL arg"; 129 return NULL; 130 } 131 132 // NSS creates a local cache of the sqlite database if it detects that the 133 // filesystem the database is on is much slower than the local disk. The 134 // detection doesn't work with the latest versions of sqlite, such as 3.6.22 135 // (NSS bug https://bugzilla.mozilla.org/show_bug.cgi?id=578561). So we set 136 // the NSS environment variable NSS_SDB_USE_CACHE to "yes" to override NSS's 137 // detection when database_dir is on NFS. See http://crbug.com/48585. 138 // 139 // TODO(wtc): port this function to other USE_NSS platforms. It is defined 140 // only for OS_LINUX simply because the statfs structure is OS-specific. 141 // 142 // Because this function sets an environment variable it must be run before we 143 // go multi-threaded. 144 void UseLocalCacheOfNSSDatabaseIfNFS(const FilePath& database_dir) { 145 #if defined(OS_LINUX) 146 struct statfs buf; 147 if (statfs(database_dir.value().c_str(), &buf) == 0) { 148 if (buf.f_type == NFS_SUPER_MAGIC) { 149 scoped_ptr<base::Environment> env(base::Environment::Create()); 150 const char* use_cache_env_var = "NSS_SDB_USE_CACHE"; 151 if (!env->HasVar(use_cache_env_var)) 152 env->SetVar(use_cache_env_var, "yes"); 153 } 154 } 155 #endif // defined(OS_LINUX) 156 } 157 158 // A helper class that acquires the SECMOD list read lock while the 159 // AutoSECMODListReadLock is in scope. 160 class AutoSECMODListReadLock { 161 public: 162 AutoSECMODListReadLock() 163 : lock_(SECMOD_GetDefaultModuleListLock()) { 164 SECMOD_GetReadLock(lock_); 165 } 166 167 ~AutoSECMODListReadLock() { 168 SECMOD_ReleaseReadLock(lock_); 169 } 170 171 private: 172 SECMODListLock* lock_; 173 DISALLOW_COPY_AND_ASSIGN(AutoSECMODListReadLock); 174 }; 175 176 PK11SlotInfo* FindSlotWithTokenName(const std::string& token_name) { 177 AutoSECMODListReadLock auto_lock; 178 SECMODModuleList* head = SECMOD_GetDefaultModuleList(); 179 for (SECMODModuleList* item = head; item != NULL; item = item->next) { 180 int slot_count = item->module->loaded ? item->module->slotCount : 0; 181 for (int i = 0; i < slot_count; i++) { 182 PK11SlotInfo* slot = item->module->slots[i]; 183 if (PK11_GetTokenName(slot) == token_name) 184 return PK11_ReferenceSlot(slot); 185 } 186 } 187 return NULL; 188 } 189 190 #endif // defined(USE_NSS) 191 192 // A singleton to initialize/deinitialize NSPR. 193 // Separate from the NSS singleton because we initialize NSPR on the UI thread. 194 // Now that we're leaking the singleton, we could merge back with the NSS 195 // singleton. 196 class NSPRInitSingleton { 197 private: 198 friend struct base::DefaultLazyInstanceTraits<NSPRInitSingleton>; 199 200 NSPRInitSingleton() { 201 PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0); 202 } 203 204 // NOTE(willchan): We don't actually execute this code since we leak NSS to 205 // prevent non-joinable threads from using NSS after it's already been shut 206 // down. 207 ~NSPRInitSingleton() { 208 PL_ArenaFinish(); 209 PRStatus prstatus = PR_Cleanup(); 210 if (prstatus != PR_SUCCESS) { 211 LOG(ERROR) << "PR_Cleanup failed; was NSPR initialized on wrong thread?"; 212 } 213 } 214 }; 215 216 base::LazyInstance<NSPRInitSingleton, 217 base::LeakyLazyInstanceTraits<NSPRInitSingleton> > 218 g_nspr_singleton(base::LINKER_INITIALIZED); 219 220 class NSSInitSingleton { 221 public: 222 #if defined(OS_CHROMEOS) 223 void OpenPersistentNSSDB() { 224 if (!chromeos_user_logged_in_) { 225 // GetDefaultConfigDirectory causes us to do blocking IO on UI thread. 226 // Temporarily allow it until we fix http://crbug.com/70119 227 base::ThreadRestrictions::ScopedAllowIO allow_io; 228 chromeos_user_logged_in_ = true; 229 230 // This creates another DB slot in NSS that is read/write, unlike 231 // the fake root CA cert DB and the "default" crypto key 232 // provider, which are still read-only (because we initialized 233 // NSS before we had a cryptohome mounted). 234 software_slot_ = OpenUserDB(GetDefaultConfigDirectory(), 235 kNSSDatabaseName); 236 } 237 } 238 239 void EnableTPMTokenForNSS(TPMTokenInfoDelegate* info_delegate) { 240 CHECK(info_delegate); 241 tpm_token_info_delegate_.reset(info_delegate); 242 // Try to load once to avoid jank later. Ignore the return value, 243 // because if it fails we will try again later. 244 EnsureTPMTokenReady(); 245 } 246 247 void GetTPMTokenInfo(std::string* token_name, std::string* user_pin) { 248 tpm_token_info_delegate_->GetTokenInfo(token_name, user_pin); 249 } 250 251 bool IsTPMTokenReady() { 252 return tpm_slot_ != NULL; 253 } 254 255 PK11SlotInfo* GetTPMSlot() { 256 std::string token_name; 257 GetTPMTokenInfo(&token_name, NULL); 258 return FindSlotWithTokenName(token_name); 259 } 260 #endif // defined(OS_CHROMEOS) 261 262 263 bool OpenTestNSSDB(const FilePath& path, const char* description) { 264 test_slot_ = OpenUserDB(path, description); 265 return !!test_slot_; 266 } 267 268 void CloseTestNSSDB() { 269 if (test_slot_) { 270 SECStatus status = SECMOD_CloseUserDB(test_slot_); 271 if (status != SECSuccess) 272 LOG(ERROR) << "SECMOD_CloseUserDB failed: " << PORT_GetError(); 273 PK11_FreeSlot(test_slot_); 274 test_slot_ = NULL; 275 } 276 } 277 278 PK11SlotInfo* GetPublicNSSKeySlot() { 279 if (test_slot_) 280 return PK11_ReferenceSlot(test_slot_); 281 if (software_slot_) 282 return PK11_ReferenceSlot(software_slot_); 283 return PK11_GetInternalKeySlot(); 284 } 285 286 PK11SlotInfo* GetPrivateNSSKeySlot() { 287 if (test_slot_) 288 return PK11_ReferenceSlot(test_slot_); 289 290 #if defined(OS_CHROMEOS) 291 // Make sure that if EnableTPMTokenForNSS has been called that we 292 // have successfully loaded opencryptoki. 293 if (tpm_token_info_delegate_.get() != NULL) { 294 if (EnsureTPMTokenReady()) { 295 return PK11_ReferenceSlot(tpm_slot_); 296 } else { 297 // If we were supposed to get the hardware token, but were 298 // unable to, return NULL rather than fall back to sofware. 299 return NULL; 300 } 301 } 302 #endif 303 // If we weren't supposed to enable the TPM for NSS, then return 304 // the software slot. 305 if (software_slot_) 306 return PK11_ReferenceSlot(software_slot_); 307 return PK11_GetInternalKeySlot(); 308 } 309 310 #if defined(USE_NSS) 311 base::Lock* write_lock() { 312 return &write_lock_; 313 } 314 #endif // defined(USE_NSS) 315 316 // This method is used to force NSS to be initialized without a DB. 317 // Call this method before NSSInitSingleton() is constructed. 318 static void ForceNoDBInit() { 319 force_nodb_init_ = true; 320 } 321 322 private: 323 friend struct base::DefaultLazyInstanceTraits<NSSInitSingleton>; 324 325 NSSInitSingleton() 326 : opencryptoki_module_(NULL), 327 software_slot_(NULL), 328 test_slot_(NULL), 329 tpm_slot_(NULL), 330 root_(NULL), 331 chromeos_user_logged_in_(false) { 332 EnsureNSPRInit(); 333 334 // We *must* have NSS >= 3.12.3. See bug 26448. 335 COMPILE_ASSERT( 336 (NSS_VMAJOR == 3 && NSS_VMINOR == 12 && NSS_VPATCH >= 3) || 337 (NSS_VMAJOR == 3 && NSS_VMINOR > 12) || 338 (NSS_VMAJOR > 3), 339 nss_version_check_failed); 340 // Also check the run-time NSS version. 341 // NSS_VersionCheck is a >= check, not strict equality. 342 if (!NSS_VersionCheck("3.12.3")) { 343 // It turns out many people have misconfigured NSS setups, where 344 // their run-time NSPR doesn't match the one their NSS was compiled 345 // against. So rather than aborting, complain loudly. 346 LOG(ERROR) << "NSS_VersionCheck(\"3.12.3\") failed. " 347 "We depend on NSS >= 3.12.3, and this error is not fatal " 348 "only because many people have busted NSS setups (for " 349 "example, using the wrong version of NSPR). " 350 "Please upgrade to the latest NSS and NSPR, and if you " 351 "still get this error, contact your distribution " 352 "maintainer."; 353 } 354 355 SECStatus status = SECFailure; 356 bool nodb_init = force_nodb_init_; 357 358 #if !defined(USE_NSS) 359 // Use the system certificate store, so initialize NSS without database. 360 nodb_init = true; 361 #endif 362 363 if (nodb_init) { 364 status = NSS_NoDB_Init(NULL); 365 if (status != SECSuccess) { 366 LOG(ERROR) << "Error initializing NSS without a persistent " 367 "database: " << GetNSSErrorMessage(); 368 } 369 } else { 370 #if defined(USE_NSS) 371 FilePath database_dir = GetInitialConfigDirectory(); 372 if (!database_dir.empty()) { 373 // This duplicates the work which should have been done in 374 // EarlySetupForNSSInit. However, this function is idempotent so 375 // there's no harm done. 376 UseLocalCacheOfNSSDatabaseIfNFS(database_dir); 377 378 // Initialize with a persistent database (likely, ~/.pki/nssdb). 379 // Use "sql:" which can be shared by multiple processes safely. 380 std::string nss_config_dir = 381 StringPrintf("sql:%s", database_dir.value().c_str()); 382 #if defined(OS_CHROMEOS) 383 status = NSS_Init(nss_config_dir.c_str()); 384 #else 385 status = NSS_InitReadWrite(nss_config_dir.c_str()); 386 #endif 387 if (status != SECSuccess) { 388 LOG(ERROR) << "Error initializing NSS with a persistent " 389 "database (" << nss_config_dir 390 << "): " << GetNSSErrorMessage(); 391 } 392 } 393 if (status != SECSuccess) { 394 VLOG(1) << "Initializing NSS without a persistent database."; 395 status = NSS_NoDB_Init(NULL); 396 if (status != SECSuccess) { 397 LOG(ERROR) << "Error initializing NSS without a persistent " 398 "database: " << GetNSSErrorMessage(); 399 return; 400 } 401 } 402 403 PK11_SetPasswordFunc(PKCS11PasswordFunc); 404 405 // If we haven't initialized the password for the NSS databases, 406 // initialize an empty-string password so that we don't need to 407 // log in. 408 PK11SlotInfo* slot = PK11_GetInternalKeySlot(); 409 if (slot) { 410 // PK11_InitPin may write to the keyDB, but no other thread can use NSS 411 // yet, so we don't need to lock. 412 if (PK11_NeedUserInit(slot)) 413 PK11_InitPin(slot, NULL, NULL); 414 PK11_FreeSlot(slot); 415 } 416 417 root_ = InitDefaultRootCerts(); 418 #endif // defined(USE_NSS) 419 } 420 } 421 422 // NOTE(willchan): We don't actually execute this code since we leak NSS to 423 // prevent non-joinable threads from using NSS after it's already been shut 424 // down. 425 ~NSSInitSingleton() { 426 if (tpm_slot_) { 427 PK11_FreeSlot(tpm_slot_); 428 tpm_slot_ = NULL; 429 } 430 if (software_slot_) { 431 SECMOD_CloseUserDB(software_slot_); 432 PK11_FreeSlot(software_slot_); 433 software_slot_ = NULL; 434 } 435 CloseTestNSSDB(); 436 if (root_) { 437 SECMOD_UnloadUserModule(root_); 438 SECMOD_DestroyModule(root_); 439 root_ = NULL; 440 } 441 if (opencryptoki_module_) { 442 SECMOD_UnloadUserModule(opencryptoki_module_); 443 SECMOD_DestroyModule(opencryptoki_module_); 444 opencryptoki_module_ = NULL; 445 } 446 447 SECStatus status = NSS_Shutdown(); 448 if (status != SECSuccess) { 449 // We VLOG(1) because this failure is relatively harmless (leaking, but 450 // we're shutting down anyway). 451 VLOG(1) << "NSS_Shutdown failed; see http://crbug.com/4609"; 452 } 453 } 454 455 #if defined(USE_NSS) 456 // Load nss's built-in root certs. 457 SECMODModule* InitDefaultRootCerts() { 458 SECMODModule* root = LoadModule("Root Certs", "libnssckbi.so", NULL); 459 if (root) 460 return root; 461 462 // Aw, snap. Can't find/load root cert shared library. 463 // This will make it hard to talk to anybody via https. 464 NOTREACHED(); 465 return NULL; 466 } 467 468 // Load the given module for this NSS session. 469 SECMODModule* LoadModule(const char* name, 470 const char* library_path, 471 const char* params) { 472 std::string modparams = StringPrintf( 473 "name=\"%s\" library=\"%s\" %s", 474 name, library_path, params ? params : ""); 475 476 // Shouldn't need to const_cast here, but SECMOD doesn't properly 477 // declare input string arguments as const. Bug 478 // https://bugzilla.mozilla.org/show_bug.cgi?id=642546 was filed 479 // on NSS codebase to address this. 480 SECMODModule* module = SECMOD_LoadUserModule( 481 const_cast<char*>(modparams.c_str()), NULL, PR_FALSE); 482 if (!module) { 483 LOG(ERROR) << "Error loading " << name << " module into NSS: " 484 << GetNSSErrorMessage(); 485 return NULL; 486 } 487 return module; 488 } 489 #endif 490 491 static PK11SlotInfo* OpenUserDB(const FilePath& path, 492 const char* description) { 493 const std::string modspec = 494 StringPrintf("configDir='sql:%s' tokenDescription='%s'", 495 path.value().c_str(), description); 496 PK11SlotInfo* db_slot = SECMOD_OpenUserDB(modspec.c_str()); 497 if (db_slot) { 498 if (PK11_NeedUserInit(db_slot)) 499 PK11_InitPin(db_slot, NULL, NULL); 500 } 501 else { 502 LOG(ERROR) << "Error opening persistent database (" << modspec 503 << "): " << GetNSSErrorMessage(); 504 } 505 return db_slot; 506 } 507 508 #if defined(OS_CHROMEOS) 509 // This is called whenever we want to make sure opencryptoki is 510 // properly loaded, because it can fail shortly after the initial 511 // login while the PINs are being initialized, and we want to retry 512 // if this happens. 513 bool EnsureTPMTokenReady() { 514 // If EnableTPMTokenForNSS hasn't been called, or if everything is 515 // already initialized, then this call succeeds. 516 if (tpm_token_info_delegate_.get() == NULL || 517 (opencryptoki_module_ && tpm_slot_)) { 518 return true; 519 } 520 521 if (tpm_token_info_delegate_->IsTokenReady()) { 522 // This tries to load the opencryptoki module so NSS can talk to 523 // the hardware TPM. 524 if (!opencryptoki_module_) { 525 opencryptoki_module_ = LoadModule( 526 kOpencryptokiModuleName, 527 kOpencryptokiPath, 528 // trustOrder=100 -- means it'll select this as the most 529 // trusted slot for the mechanisms it provides. 530 // slotParams=... -- selects RSA as the only mechanism, and only 531 // asks for the password when necessary (instead of every 532 // time, or after a timeout). 533 "trustOrder=100 slotParams=(1={slotFlags=[RSA] askpw=only})"); 534 } 535 if (opencryptoki_module_) { 536 // If this gets set, then we'll use the TPM for certs with 537 // private keys, otherwise we'll fall back to the software 538 // implementation. 539 tpm_slot_ = GetTPMSlot(); 540 return tpm_slot_ != NULL; 541 } 542 } 543 return false; 544 } 545 #endif 546 547 // If this is set to true NSS is forced to be initialized without a DB. 548 static bool force_nodb_init_; 549 550 #if defined(OS_CHROMEOS) 551 scoped_ptr<TPMTokenInfoDelegate> tpm_token_info_delegate_; 552 #endif 553 554 SECMODModule* opencryptoki_module_; 555 PK11SlotInfo* software_slot_; 556 PK11SlotInfo* test_slot_; 557 PK11SlotInfo* tpm_slot_; 558 SECMODModule* root_; 559 bool chromeos_user_logged_in_; 560 #if defined(USE_NSS) 561 // TODO(davidben): When https://bugzilla.mozilla.org/show_bug.cgi?id=564011 562 // is fixed, we will no longer need the lock. 563 base::Lock write_lock_; 564 #endif // defined(USE_NSS) 565 }; 566 567 // static 568 bool NSSInitSingleton::force_nodb_init_ = false; 569 570 base::LazyInstance<NSSInitSingleton, 571 base::LeakyLazyInstanceTraits<NSSInitSingleton> > 572 g_nss_singleton(base::LINKER_INITIALIZED); 573 574 } // namespace 575 576 #if defined(USE_NSS) 577 void EarlySetupForNSSInit() { 578 FilePath database_dir = GetInitialConfigDirectory(); 579 if (!database_dir.empty()) 580 UseLocalCacheOfNSSDatabaseIfNFS(database_dir); 581 } 582 #endif 583 584 void EnsureNSPRInit() { 585 g_nspr_singleton.Get(); 586 } 587 588 void EnsureNSSInit() { 589 // Initializing SSL causes us to do blocking IO. 590 // Temporarily allow it until we fix 591 // http://code.google.com/p/chromium/issues/detail?id=59847 592 base::ThreadRestrictions::ScopedAllowIO allow_io; 593 g_nss_singleton.Get(); 594 } 595 596 void ForceNSSNoDBInit() { 597 NSSInitSingleton::ForceNoDBInit(); 598 } 599 600 void DisableNSSForkCheck() { 601 scoped_ptr<base::Environment> env(base::Environment::Create()); 602 env->SetVar("NSS_STRICT_NOFORK", "DISABLED"); 603 } 604 605 void LoadNSSLibraries() { 606 // Some NSS libraries are linked dynamically so load them here. 607 #if defined(USE_NSS) 608 // Try to search for multiple directories to load the libraries. 609 std::vector<FilePath> paths; 610 611 // Use relative path to Search PATH for the library files. 612 paths.push_back(FilePath()); 613 614 // For Debian derivaties NSS libraries are located here. 615 paths.push_back(FilePath("/usr/lib/nss")); 616 617 // A list of library files to load. 618 std::vector<std::string> libs; 619 libs.push_back("libsoftokn3.so"); 620 libs.push_back("libfreebl3.so"); 621 622 // For each combination of library file and path, check for existence and 623 // then load. 624 size_t loaded = 0; 625 for (size_t i = 0; i < libs.size(); ++i) { 626 for (size_t j = 0; j < paths.size(); ++j) { 627 FilePath path = paths[j].Append(libs[i]); 628 base::NativeLibrary lib = base::LoadNativeLibrary(path, NULL); 629 if (lib) { 630 ++loaded; 631 break; 632 } 633 } 634 } 635 636 if (loaded == libs.size()) { 637 VLOG(3) << "NSS libraries loaded."; 638 } else { 639 LOG(WARNING) << "Failed to load NSS libraries."; 640 } 641 #endif 642 } 643 644 bool CheckNSSVersion(const char* version) { 645 return !!NSS_VersionCheck(version); 646 } 647 648 #if defined(USE_NSS) 649 bool OpenTestNSSDB(const FilePath& path, const char* description) { 650 return g_nss_singleton.Get().OpenTestNSSDB(path, description); 651 } 652 653 void CloseTestNSSDB() { 654 g_nss_singleton.Get().CloseTestNSSDB(); 655 } 656 657 base::Lock* GetNSSWriteLock() { 658 return g_nss_singleton.Get().write_lock(); 659 } 660 661 AutoNSSWriteLock::AutoNSSWriteLock() : lock_(GetNSSWriteLock()) { 662 // May be NULL if the lock is not needed in our version of NSS. 663 if (lock_) 664 lock_->Acquire(); 665 } 666 667 AutoNSSWriteLock::~AutoNSSWriteLock() { 668 if (lock_) { 669 lock_->AssertAcquired(); 670 lock_->Release(); 671 } 672 } 673 #endif // defined(USE_NSS) 674 675 #if defined(OS_CHROMEOS) 676 void OpenPersistentNSSDB() { 677 g_nss_singleton.Get().OpenPersistentNSSDB(); 678 } 679 680 TPMTokenInfoDelegate::TPMTokenInfoDelegate() {} 681 TPMTokenInfoDelegate::~TPMTokenInfoDelegate() {} 682 683 void EnableTPMTokenForNSS(TPMTokenInfoDelegate* info_delegate) { 684 g_nss_singleton.Get().EnableTPMTokenForNSS(info_delegate); 685 } 686 687 void GetTPMTokenInfo(std::string* token_name, std::string* user_pin) { 688 g_nss_singleton.Get().GetTPMTokenInfo(token_name, user_pin); 689 } 690 691 bool IsTPMTokenReady() { 692 return g_nss_singleton.Get().IsTPMTokenReady(); 693 } 694 695 #endif // defined(OS_CHROMEOS) 696 697 // TODO(port): Implement this more simply. We can convert by subtracting an 698 // offset (the difference between NSPR's and base::Time's epochs). 699 base::Time PRTimeToBaseTime(PRTime prtime) { 700 PRExplodedTime prxtime; 701 PR_ExplodeTime(prtime, PR_GMTParameters, &prxtime); 702 703 base::Time::Exploded exploded; 704 exploded.year = prxtime.tm_year; 705 exploded.month = prxtime.tm_month + 1; 706 exploded.day_of_week = prxtime.tm_wday; 707 exploded.day_of_month = prxtime.tm_mday; 708 exploded.hour = prxtime.tm_hour; 709 exploded.minute = prxtime.tm_min; 710 exploded.second = prxtime.tm_sec; 711 exploded.millisecond = prxtime.tm_usec / 1000; 712 713 return base::Time::FromUTCExploded(exploded); 714 } 715 716 PK11SlotInfo* GetPublicNSSKeySlot() { 717 return g_nss_singleton.Get().GetPublicNSSKeySlot(); 718 } 719 720 PK11SlotInfo* GetPrivateNSSKeySlot() { 721 return g_nss_singleton.Get().GetPrivateNSSKeySlot(); 722 } 723 724 } // namespace crypto 725