Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "crypto/nss_util.h" | 5 #include "crypto/nss_util.h" |
| 6 #include "crypto/nss_util_internal.h" | 6 #include "crypto/nss_util_internal.h" |
| 7 | 7 |
| 8 #include <nss.h> | 8 #include <nss.h> |
| 9 #include <pk11pub.h> | 9 #include <pk11pub.h> |
| 10 #include <plarena.h> | 10 #include <plarena.h> |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 43 #include "base/threading/worker_pool.h" | 43 #include "base/threading/worker_pool.h" |
| 44 #include "build/build_config.h" | 44 #include "build/build_config.h" |
| 45 | 45 |
| 46 // USE_NSS means we use NSS for everything crypto-related. If USE_NSS is not | 46 // USE_NSS means we use NSS for everything crypto-related. If USE_NSS is not |
| 47 // defined, such as on Mac and Windows, we use NSS for SSL only -- we don't | 47 // defined, such as on Mac and Windows, we use NSS for SSL only -- we don't |
| 48 // use NSS for crypto or certificate verification, and we don't use the NSS | 48 // use NSS for crypto or certificate verification, and we don't use the NSS |
| 49 // certificate and key databases. | 49 // certificate and key databases. |
| 50 #if defined(USE_NSS) | 50 #if defined(USE_NSS) |
| 51 #include "base/synchronization/lock.h" | 51 #include "base/synchronization/lock.h" |
| 52 #include "crypto/nss_crypto_module_delegate.h" | 52 #include "crypto/nss_crypto_module_delegate.h" |
| 53 #include "crypto/scoped_test_nss_db.h" | |
| 53 #endif // defined(USE_NSS) | 54 #endif // defined(USE_NSS) |
| 54 | 55 |
| 55 namespace crypto { | 56 namespace crypto { |
| 56 | 57 |
| 57 namespace { | 58 namespace { |
| 58 | 59 |
| 59 #if defined(OS_CHROMEOS) | 60 #if defined(OS_CHROMEOS) |
| 60 const char kUserNSSDatabaseName[] = "UserNSSDB"; | 61 const char kUserNSSDatabaseName[] = "UserNSSDB"; |
| 61 | 62 |
| 62 // Constants for loading the Chrome OS TPM-backed PKCS #11 library. | 63 // Constants for loading the Chrome OS TPM-backed PKCS #11 library. |
| (...skipping 128 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 191 PL_ArenaFinish(); | 192 PL_ArenaFinish(); |
| 192 PRStatus prstatus = PR_Cleanup(); | 193 PRStatus prstatus = PR_Cleanup(); |
| 193 if (prstatus != PR_SUCCESS) | 194 if (prstatus != PR_SUCCESS) |
| 194 LOG(ERROR) << "PR_Cleanup failed; was NSPR initialized on wrong thread?"; | 195 LOG(ERROR) << "PR_Cleanup failed; was NSPR initialized on wrong thread?"; |
| 195 } | 196 } |
| 196 }; | 197 }; |
| 197 | 198 |
| 198 base::LazyInstance<NSPRInitSingleton>::Leaky | 199 base::LazyInstance<NSPRInitSingleton>::Leaky |
| 199 g_nspr_singleton = LAZY_INSTANCE_INITIALIZER; | 200 g_nspr_singleton = LAZY_INSTANCE_INITIALIZER; |
| 200 | 201 |
| 201 // This is a LazyInstance so that it will be deleted automatically when the | |
| 202 // unittest exits. NSSInitSingleton is a LeakySingleton, so it would not be | |
| 203 // deleted if it were a regular member. | |
| 204 base::LazyInstance<base::ScopedTempDir> g_test_nss_db_dir = | |
| 205 LAZY_INSTANCE_INITIALIZER; | |
| 206 | |
| 207 // Force a crash with error info on NSS_NoDB_Init failure. | 202 // Force a crash with error info on NSS_NoDB_Init failure. |
| 208 void CrashOnNSSInitFailure() { | 203 void CrashOnNSSInitFailure() { |
| 209 int nss_error = PR_GetError(); | 204 int nss_error = PR_GetError(); |
| 210 int os_error = PR_GetOSError(); | 205 int os_error = PR_GetOSError(); |
| 211 base::debug::Alias(&nss_error); | 206 base::debug::Alias(&nss_error); |
| 212 base::debug::Alias(&os_error); | 207 base::debug::Alias(&os_error); |
| 213 LOG(ERROR) << "Error initializing NSS without a persistent database: " | 208 LOG(ERROR) << "Error initializing NSS without a persistent database: " |
| 214 << GetNSSErrorMessage(); | 209 << GetNSSErrorMessage(); |
| 215 LOG(FATAL) << "nss_error=" << nss_error << ", os_error=" << os_error; | 210 LOG(FATAL) << "nss_error=" << nss_error << ", os_error=" << os_error; |
| 216 } | 211 } |
| (...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 280 public: | 275 public: |
| 281 #if defined(OS_CHROMEOS) | 276 #if defined(OS_CHROMEOS) |
| 282 // Used with PostTaskAndReply to pass handles to worker thread and back. | 277 // Used with PostTaskAndReply to pass handles to worker thread and back. |
| 283 struct TPMModuleAndSlot { | 278 struct TPMModuleAndSlot { |
| 284 explicit TPMModuleAndSlot(SECMODModule* init_chaps_module) | 279 explicit TPMModuleAndSlot(SECMODModule* init_chaps_module) |
| 285 : chaps_module(init_chaps_module), tpm_slot(NULL) {} | 280 : chaps_module(init_chaps_module), tpm_slot(NULL) {} |
| 286 SECMODModule* chaps_module; | 281 SECMODModule* chaps_module; |
| 287 PK11SlotInfo* tpm_slot; | 282 PK11SlotInfo* tpm_slot; |
| 288 }; | 283 }; |
| 289 | 284 |
| 290 PK11SlotInfo* OpenPersistentNSSDBForPath(const std::string& db_name, | 285 ScopedPK11Slot OpenPersistentNSSDBForPath(const std::string& db_name, |
| 291 const base::FilePath& path) { | 286 const base::FilePath& path) { |
| 292 DCHECK(thread_checker_.CalledOnValidThread()); | 287 DCHECK(thread_checker_.CalledOnValidThread()); |
| 293 // NSS is allowed to do IO on the current thread since dispatching | 288 // NSS is allowed to do IO on the current thread since dispatching |
| 294 // to a dedicated thread would still have the affect of blocking | 289 // to a dedicated thread would still have the affect of blocking |
| 295 // the current thread, due to NSS's internal locking requirements | 290 // the current thread, due to NSS's internal locking requirements |
| 296 base::ThreadRestrictions::ScopedAllowIO allow_io; | 291 base::ThreadRestrictions::ScopedAllowIO allow_io; |
| 297 | 292 |
| 298 base::FilePath nssdb_path = path.AppendASCII(".pki").AppendASCII("nssdb"); | 293 base::FilePath nssdb_path = path.AppendASCII(".pki").AppendASCII("nssdb"); |
| 299 if (!base::CreateDirectory(nssdb_path)) { | 294 if (!base::CreateDirectory(nssdb_path)) { |
| 300 LOG(ERROR) << "Failed to create " << nssdb_path.value() << " directory."; | 295 LOG(ERROR) << "Failed to create " << nssdb_path.value() << " directory."; |
| 301 return NULL; | 296 return ScopedPK11Slot(); |
| 302 } | 297 } |
| 303 return OpenUserDB(nssdb_path, db_name); | 298 return OpenSoftwareNSSDB(nssdb_path, db_name); |
| 304 } | 299 } |
| 305 | 300 |
| 306 void EnableTPMTokenForNSS() { | 301 void EnableTPMTokenForNSS() { |
| 307 DCHECK(thread_checker_.CalledOnValidThread()); | 302 DCHECK(thread_checker_.CalledOnValidThread()); |
| 308 | 303 |
| 309 // If this gets set, then we'll use the TPM for certs with | 304 // If this gets set, then we'll use the TPM for certs with |
| 310 // private keys, otherwise we'll fall back to the software | 305 // private keys, otherwise we'll fall back to the software |
| 311 // implementation. | 306 // implementation. |
| 312 tpm_token_enabled_for_nss_ = true; | 307 tpm_token_enabled_for_nss_ = true; |
| 313 } | 308 } |
| (...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 386 | 381 |
| 387 void OnInitializedTPMTokenAndSystemSlot( | 382 void OnInitializedTPMTokenAndSystemSlot( |
| 388 const base::Callback<void(bool)>& callback, | 383 const base::Callback<void(bool)>& callback, |
| 389 scoped_ptr<TPMModuleAndSlot> tpm_args) { | 384 scoped_ptr<TPMModuleAndSlot> tpm_args) { |
| 390 DCHECK(thread_checker_.CalledOnValidThread()); | 385 DCHECK(thread_checker_.CalledOnValidThread()); |
| 391 DVLOG(2) << "Loaded chaps: " << !!tpm_args->chaps_module | 386 DVLOG(2) << "Loaded chaps: " << !!tpm_args->chaps_module |
| 392 << ", got tpm slot: " << !!tpm_args->tpm_slot; | 387 << ", got tpm slot: " << !!tpm_args->tpm_slot; |
| 393 | 388 |
| 394 chaps_module_ = tpm_args->chaps_module; | 389 chaps_module_ = tpm_args->chaps_module; |
| 395 tpm_slot_ = tpm_args->tpm_slot; | 390 tpm_slot_ = tpm_args->tpm_slot; |
| 396 if (!chaps_module_ && test_slot_) { | 391 if (!chaps_module_ && test_system_slot_) { |
| 397 // chromeos_unittests try to test the TPM initialization process. If we | 392 // chromeos_unittests try to test the TPM initialization process. If we |
| 398 // have a test DB open, pretend that it is the TPM slot. | 393 // have a test DB open, pretend that it is the TPM slot. |
| 399 tpm_slot_ = PK11_ReferenceSlot(test_slot_); | 394 tpm_slot_ = PK11_ReferenceSlot(test_system_slot_.get()); |
| 400 } | 395 } |
| 401 initializing_tpm_token_ = false; | 396 initializing_tpm_token_ = false; |
| 402 | 397 |
| 403 if (tpm_slot_) { | 398 if (tpm_slot_) { |
| 404 TPMReadyCallbackList callback_list; | 399 TPMReadyCallbackList callback_list; |
| 405 callback_list.swap(tpm_ready_callback_list_); | 400 callback_list.swap(tpm_ready_callback_list_); |
| 406 for (TPMReadyCallbackList::iterator i = callback_list.begin(); | 401 for (TPMReadyCallbackList::iterator i = callback_list.begin(); |
| 407 i != callback_list.end(); | 402 i != callback_list.end(); |
| 408 ++i) { | 403 ++i) { |
| 409 (*i).Run(); | 404 (*i).Run(); |
| (...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 456 const std::string& email, | 451 const std::string& email, |
| 457 const std::string& username_hash, | 452 const std::string& username_hash, |
| 458 const base::FilePath& path) { | 453 const base::FilePath& path) { |
| 459 DCHECK(thread_checker_.CalledOnValidThread()); | 454 DCHECK(thread_checker_.CalledOnValidThread()); |
| 460 if (chromeos_user_map_.find(username_hash) != chromeos_user_map_.end()) { | 455 if (chromeos_user_map_.find(username_hash) != chromeos_user_map_.end()) { |
| 461 // This user already exists in our mapping. | 456 // This user already exists in our mapping. |
| 462 DVLOG(2) << username_hash << " already initialized."; | 457 DVLOG(2) << username_hash << " already initialized."; |
| 463 return false; | 458 return false; |
| 464 } | 459 } |
| 465 | 460 |
| 466 // If test slot is set, slot getter methods will short circuit | |
| 467 // checking |chromeos_user_map_|, so there is nothing left to be | |
| 468 // initialized. | |
| 469 if (test_slot_) | |
| 470 return false; | |
| 471 | |
| 472 DVLOG(2) << "Opening NSS DB " << path.value(); | 461 DVLOG(2) << "Opening NSS DB " << path.value(); |
| 473 std::string db_name = base::StringPrintf( | 462 std::string db_name = base::StringPrintf( |
| 474 "%s %s", kUserNSSDatabaseName, username_hash.c_str()); | 463 "%s %s", kUserNSSDatabaseName, username_hash.c_str()); |
| 475 ScopedPK11Slot public_slot(OpenPersistentNSSDBForPath(db_name, path)); | 464 ScopedPK11Slot public_slot(OpenPersistentNSSDBForPath(db_name, path)); |
| 476 chromeos_user_map_[username_hash] = | 465 chromeos_user_map_[username_hash] = |
| 477 new ChromeOSUserData(public_slot.Pass()); | 466 new ChromeOSUserData(public_slot.Pass()); |
| 478 return true; | 467 return true; |
| 479 } | 468 } |
| 480 | 469 |
| 481 bool ShouldInitializeTPMForChromeOSUser(const std::string& username_hash) { | 470 bool ShouldInitializeTPMForChromeOSUser(const std::string& username_hash) { |
| (...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 544 | 533 |
| 545 ScopedPK11Slot GetPublicSlotForChromeOSUser( | 534 ScopedPK11Slot GetPublicSlotForChromeOSUser( |
| 546 const std::string& username_hash) { | 535 const std::string& username_hash) { |
| 547 DCHECK(thread_checker_.CalledOnValidThread()); | 536 DCHECK(thread_checker_.CalledOnValidThread()); |
| 548 | 537 |
| 549 if (username_hash.empty()) { | 538 if (username_hash.empty()) { |
| 550 DVLOG(2) << "empty username_hash"; | 539 DVLOG(2) << "empty username_hash"; |
| 551 return ScopedPK11Slot(); | 540 return ScopedPK11Slot(); |
| 552 } | 541 } |
| 553 | 542 |
| 554 if (test_slot_) { | |
| 555 DVLOG(2) << "returning test_slot_ for " << username_hash; | |
| 556 return ScopedPK11Slot(PK11_ReferenceSlot(test_slot_)); | |
| 557 } | |
| 558 | |
| 559 if (chromeos_user_map_.find(username_hash) == chromeos_user_map_.end()) { | 543 if (chromeos_user_map_.find(username_hash) == chromeos_user_map_.end()) { |
| 560 LOG(ERROR) << username_hash << " not initialized."; | 544 LOG(ERROR) << username_hash << " not initialized."; |
| 561 return ScopedPK11Slot(); | 545 return ScopedPK11Slot(); |
| 562 } | 546 } |
| 563 return chromeos_user_map_[username_hash]->GetPublicSlot(); | 547 return chromeos_user_map_[username_hash]->GetPublicSlot(); |
| 564 } | 548 } |
| 565 | 549 |
| 566 ScopedPK11Slot GetPrivateSlotForChromeOSUser( | 550 ScopedPK11Slot GetPrivateSlotForChromeOSUser( |
| 567 const std::string& username_hash, | 551 const std::string& username_hash, |
| 568 const base::Callback<void(ScopedPK11Slot)>& callback) { | 552 const base::Callback<void(ScopedPK11Slot)>& callback) { |
| 569 DCHECK(thread_checker_.CalledOnValidThread()); | 553 DCHECK(thread_checker_.CalledOnValidThread()); |
| 570 | 554 |
| 571 if (username_hash.empty()) { | 555 if (username_hash.empty()) { |
| 572 DVLOG(2) << "empty username_hash"; | 556 DVLOG(2) << "empty username_hash"; |
| 573 if (!callback.is_null()) { | 557 if (!callback.is_null()) { |
| 574 base::MessageLoop::current()->PostTask( | 558 base::MessageLoop::current()->PostTask( |
| 575 FROM_HERE, base::Bind(callback, base::Passed(ScopedPK11Slot()))); | 559 FROM_HERE, base::Bind(callback, base::Passed(ScopedPK11Slot()))); |
| 576 } | 560 } |
| 577 return ScopedPK11Slot(); | 561 return ScopedPK11Slot(); |
| 578 } | 562 } |
| 579 | 563 |
| 580 DCHECK(chromeos_user_map_.find(username_hash) != chromeos_user_map_.end()); | 564 DCHECK(chromeos_user_map_.find(username_hash) != chromeos_user_map_.end()); |
| 581 | 565 |
| 582 if (test_slot_) { | |
| 583 DVLOG(2) << "returning test_slot_ for " << username_hash; | |
| 584 return ScopedPK11Slot(PK11_ReferenceSlot(test_slot_)); | |
| 585 } | |
| 586 | |
| 587 return chromeos_user_map_[username_hash]->GetPrivateSlot(callback); | 566 return chromeos_user_map_[username_hash]->GetPrivateSlot(callback); |
| 588 } | 567 } |
| 589 | 568 |
| 590 void CloseTestChromeOSUser(const std::string& username_hash) { | 569 void CloseChromeOSUserForTesting(const std::string& username_hash) { |
| 591 DCHECK(thread_checker_.CalledOnValidThread()); | 570 DCHECK(thread_checker_.CalledOnValidThread()); |
| 592 ChromeOSUserMap::iterator i = chromeos_user_map_.find(username_hash); | 571 ChromeOSUserMap::iterator i = chromeos_user_map_.find(username_hash); |
| 593 DCHECK(i != chromeos_user_map_.end()); | 572 DCHECK(i != chromeos_user_map_.end()); |
| 594 delete i->second; | 573 delete i->second; |
| 595 chromeos_user_map_.erase(i); | 574 chromeos_user_map_.erase(i); |
| 596 } | 575 } |
| 576 | |
| 577 void SetTestSystemKeySlot(ScopedPK11Slot slot) { | |
| 578 // Ensure that a previous value of test_system_slot_ is not overwritten. | |
| 579 // Unsetting, i.e. setting a NULL, however is allowed. | |
| 580 DCHECK(!slot || !test_system_slot_); | |
| 581 test_system_slot_ = slot.Pass(); | |
| 582 } | |
| 597 #endif // defined(OS_CHROMEOS) | 583 #endif // defined(OS_CHROMEOS) |
| 598 | 584 |
| 599 | 585 #if !defined(OS_CHROMEOS) |
| 600 bool OpenTestNSSDB() { | |
| 601 DCHECK(thread_checker_.CalledOnValidThread()); | |
| 602 // NSS is allowed to do IO on the current thread since dispatching | |
| 603 // to a dedicated thread would still have the affect of blocking | |
| 604 // the current thread, due to NSS's internal locking requirements | |
| 605 base::ThreadRestrictions::ScopedAllowIO allow_io; | |
| 606 | |
| 607 if (test_slot_) | |
| 608 return true; | |
| 609 if (!g_test_nss_db_dir.Get().CreateUniqueTempDir()) | |
| 610 return false; | |
| 611 test_slot_ = OpenUserDB(g_test_nss_db_dir.Get().path(), kTestTPMTokenName); | |
| 612 return !!test_slot_; | |
| 613 } | |
| 614 | |
| 615 void CloseTestNSSDB() { | |
| 616 DCHECK(thread_checker_.CalledOnValidThread()); | |
| 617 // NSS is allowed to do IO on the current thread since dispatching | |
| 618 // to a dedicated thread would still have the affect of blocking | |
| 619 // the current thread, due to NSS's internal locking requirements | |
| 620 base::ThreadRestrictions::ScopedAllowIO allow_io; | |
| 621 | |
| 622 if (!test_slot_) | |
| 623 return; | |
| 624 SECStatus status = SECMOD_CloseUserDB(test_slot_); | |
| 625 if (status != SECSuccess) | |
| 626 PLOG(ERROR) << "SECMOD_CloseUserDB failed: " << PORT_GetError(); | |
| 627 PK11_FreeSlot(test_slot_); | |
| 628 test_slot_ = NULL; | |
| 629 ignore_result(g_test_nss_db_dir.Get().Delete()); | |
| 630 } | |
| 631 | |
| 632 PK11SlotInfo* GetPersistentNSSKeySlot() { | 586 PK11SlotInfo* GetPersistentNSSKeySlot() { |
| 633 // TODO(mattm): Change to DCHECK when callers have been fixed. | 587 // TODO(mattm): Change to DCHECK when callers have been fixed. |
| 634 if (!thread_checker_.CalledOnValidThread()) { | 588 if (!thread_checker_.CalledOnValidThread()) { |
| 635 DVLOG(1) << "Called on wrong thread.\n" | 589 DVLOG(1) << "Called on wrong thread.\n" |
| 636 << base::debug::StackTrace().ToString(); | 590 << base::debug::StackTrace().ToString(); |
| 637 } | 591 } |
| 638 | 592 |
| 639 if (test_slot_) | |
| 640 return PK11_ReferenceSlot(test_slot_); | |
| 641 return PK11_GetInternalKeySlot(); | 593 return PK11_GetInternalKeySlot(); |
| 642 } | 594 } |
| 595 #endif | |
| 643 | 596 |
| 644 #if defined(OS_CHROMEOS) | 597 #if defined(OS_CHROMEOS) |
| 645 PK11SlotInfo* GetSystemNSSKeySlot() { | 598 PK11SlotInfo* GetSystemNSSKeySlot() { |
| 646 DCHECK(thread_checker_.CalledOnValidThread()); | 599 DCHECK(thread_checker_.CalledOnValidThread()); |
| 647 | 600 |
| 648 if (test_slot_) | |
| 649 return PK11_ReferenceSlot(test_slot_); | |
| 650 | |
| 651 // TODO(mattm): chromeos::TPMTokenloader always calls | 601 // TODO(mattm): chromeos::TPMTokenloader always calls |
| 652 // InitializeTPMTokenAndSystemSlot with slot 0. If the system slot is | 602 // InitializeTPMTokenAndSystemSlot with slot 0. If the system slot is |
| 653 // disabled, tpm_slot_ will be the first user's slot instead. Can that be | 603 // disabled, tpm_slot_ will be the first user's slot instead. Can that be |
| 654 // detected and return NULL instead? | 604 // detected and return NULL instead? |
| 655 if (tpm_token_enabled_for_nss_ && IsTPMTokenReady(base::Closure())) | 605 if (tpm_token_enabled_for_nss_ && IsTPMTokenReady(base::Closure())) |
| 656 return PK11_ReferenceSlot(tpm_slot_); | 606 return PK11_ReferenceSlot(tpm_slot_); |
| 657 // If we were supposed to get the hardware token, but were | 607 // If we were supposed to get the hardware token, but were |
| 658 // unable to, return NULL rather than fall back to sofware. | 608 // unable to, return NULL rather than fall back to sofware. |
| 659 return NULL; | 609 return NULL; |
| 660 } | 610 } |
| (...skipping 11 matching lines...) Expand all Loading... | |
| 672 force_nodb_init_ = true; | 622 force_nodb_init_ = true; |
| 673 } | 623 } |
| 674 | 624 |
| 675 private: | 625 private: |
| 676 friend struct base::DefaultLazyInstanceTraits<NSSInitSingleton>; | 626 friend struct base::DefaultLazyInstanceTraits<NSSInitSingleton>; |
| 677 | 627 |
| 678 NSSInitSingleton() | 628 NSSInitSingleton() |
| 679 : tpm_token_enabled_for_nss_(false), | 629 : tpm_token_enabled_for_nss_(false), |
| 680 initializing_tpm_token_(false), | 630 initializing_tpm_token_(false), |
| 681 chaps_module_(NULL), | 631 chaps_module_(NULL), |
| 682 test_slot_(NULL), | |
| 683 tpm_slot_(NULL), | 632 tpm_slot_(NULL), |
| 684 root_(NULL) { | 633 root_(NULL) { |
| 685 base::TimeTicks start_time = base::TimeTicks::Now(); | 634 base::TimeTicks start_time = base::TimeTicks::Now(); |
| 686 | 635 |
| 687 // It's safe to construct on any thread, since LazyInstance will prevent any | 636 // It's safe to construct on any thread, since LazyInstance will prevent any |
| 688 // other threads from accessing until the constructor is done. | 637 // other threads from accessing until the constructor is done. |
| 689 thread_checker_.DetachFromThread(); | 638 thread_checker_.DetachFromThread(); |
| 690 | 639 |
| 691 DisableAESNIIfNeeded(); | 640 DisableAESNIIfNeeded(); |
| 692 | 641 |
| (...skipping 101 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 794 // prevent non-joinable threads from using NSS after it's already been shut | 743 // prevent non-joinable threads from using NSS after it's already been shut |
| 795 // down. | 744 // down. |
| 796 ~NSSInitSingleton() { | 745 ~NSSInitSingleton() { |
| 797 #if defined(OS_CHROMEOS) | 746 #if defined(OS_CHROMEOS) |
| 798 STLDeleteValues(&chromeos_user_map_); | 747 STLDeleteValues(&chromeos_user_map_); |
| 799 #endif | 748 #endif |
| 800 if (tpm_slot_) { | 749 if (tpm_slot_) { |
| 801 PK11_FreeSlot(tpm_slot_); | 750 PK11_FreeSlot(tpm_slot_); |
| 802 tpm_slot_ = NULL; | 751 tpm_slot_ = NULL; |
| 803 } | 752 } |
| 804 CloseTestNSSDB(); | |
| 805 if (root_) { | 753 if (root_) { |
| 806 SECMOD_UnloadUserModule(root_); | 754 SECMOD_UnloadUserModule(root_); |
| 807 SECMOD_DestroyModule(root_); | 755 SECMOD_DestroyModule(root_); |
| 808 root_ = NULL; | 756 root_ = NULL; |
| 809 } | 757 } |
| 810 if (chaps_module_) { | 758 if (chaps_module_) { |
| 811 SECMOD_UnloadUserModule(chaps_module_); | 759 SECMOD_UnloadUserModule(chaps_module_); |
| 812 SECMOD_DestroyModule(chaps_module_); | 760 SECMOD_DestroyModule(chaps_module_); |
| 813 chaps_module_ = NULL; | 761 chaps_module_ = NULL; |
| 814 } | 762 } |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 856 if (!module->loaded) { | 804 if (!module->loaded) { |
| 857 LOG(ERROR) << "After loading " << name << ", loaded==false: " | 805 LOG(ERROR) << "After loading " << name << ", loaded==false: " |
| 858 << GetNSSErrorMessage(); | 806 << GetNSSErrorMessage(); |
| 859 SECMOD_DestroyModule(module); | 807 SECMOD_DestroyModule(module); |
| 860 return NULL; | 808 return NULL; |
| 861 } | 809 } |
| 862 return module; | 810 return module; |
| 863 } | 811 } |
| 864 #endif | 812 #endif |
| 865 | 813 |
| 866 static PK11SlotInfo* OpenUserDB(const base::FilePath& path, | |
| 867 const std::string& description) { | |
| 868 const std::string modspec = | |
| 869 base::StringPrintf("configDir='sql:%s' tokenDescription='%s'", | |
| 870 path.value().c_str(), | |
| 871 description.c_str()); | |
| 872 PK11SlotInfo* db_slot = SECMOD_OpenUserDB(modspec.c_str()); | |
| 873 if (db_slot) { | |
| 874 if (PK11_NeedUserInit(db_slot)) | |
| 875 PK11_InitPin(db_slot, NULL, NULL); | |
| 876 } else { | |
| 877 LOG(ERROR) << "Error opening persistent database (" << modspec | |
| 878 << "): " << GetNSSErrorMessage(); | |
| 879 } | |
| 880 return db_slot; | |
| 881 } | |
| 882 | |
| 883 static void DisableAESNIIfNeeded() { | 814 static void DisableAESNIIfNeeded() { |
| 884 if (NSS_VersionCheck("3.15") && !NSS_VersionCheck("3.15.4")) { | 815 if (NSS_VersionCheck("3.15") && !NSS_VersionCheck("3.15.4")) { |
| 885 // Some versions of NSS have a bug that causes AVX instructions to be | 816 // Some versions of NSS have a bug that causes AVX instructions to be |
| 886 // used without testing whether XSAVE is enabled by the operating system. | 817 // used without testing whether XSAVE is enabled by the operating system. |
| 887 // In order to work around this, we disable AES-NI in NSS when we find | 818 // In order to work around this, we disable AES-NI in NSS when we find |
| 888 // that |has_avx()| is false (which includes the XSAVE test). See | 819 // that |has_avx()| is false (which includes the XSAVE test). See |
| 889 // https://bugzilla.mozilla.org/show_bug.cgi?id=940794 | 820 // https://bugzilla.mozilla.org/show_bug.cgi?id=940794 |
| 890 base::CPU cpu; | 821 base::CPU cpu; |
| 891 | 822 |
| 892 if (cpu.has_avx_hardware() && !cpu.has_avx()) { | 823 if (cpu.has_avx_hardware() && !cpu.has_avx()) { |
| 893 base::Environment::Create()->SetVar("NSS_DISABLE_HW_AES", "1"); | 824 base::Environment::Create()->SetVar("NSS_DISABLE_HW_AES", "1"); |
| 894 } | 825 } |
| 895 } | 826 } |
| 896 } | 827 } |
| 897 | 828 |
| 898 // If this is set to true NSS is forced to be initialized without a DB. | 829 // If this is set to true NSS is forced to be initialized without a DB. |
| 899 static bool force_nodb_init_; | 830 static bool force_nodb_init_; |
| 900 | 831 |
| 901 bool tpm_token_enabled_for_nss_; | 832 bool tpm_token_enabled_for_nss_; |
| 902 bool initializing_tpm_token_; | 833 bool initializing_tpm_token_; |
| 903 typedef std::vector<base::Closure> TPMReadyCallbackList; | 834 typedef std::vector<base::Closure> TPMReadyCallbackList; |
| 904 TPMReadyCallbackList tpm_ready_callback_list_; | 835 TPMReadyCallbackList tpm_ready_callback_list_; |
| 905 SECMODModule* chaps_module_; | 836 SECMODModule* chaps_module_; |
| 906 PK11SlotInfo* test_slot_; | |
| 907 PK11SlotInfo* tpm_slot_; | 837 PK11SlotInfo* tpm_slot_; |
| 908 SECMODModule* root_; | 838 SECMODModule* root_; |
| 909 #if defined(OS_CHROMEOS) | 839 #if defined(OS_CHROMEOS) |
| 910 typedef std::map<std::string, ChromeOSUserData*> ChromeOSUserMap; | 840 typedef std::map<std::string, ChromeOSUserData*> ChromeOSUserMap; |
| 911 ChromeOSUserMap chromeos_user_map_; | 841 ChromeOSUserMap chromeos_user_map_; |
| 842 ScopedPK11Slot test_system_slot_; | |
| 912 #endif | 843 #endif |
| 913 #if defined(USE_NSS) | 844 #if defined(USE_NSS) |
| 914 // TODO(davidben): When https://bugzilla.mozilla.org/show_bug.cgi?id=564011 | 845 // TODO(davidben): When https://bugzilla.mozilla.org/show_bug.cgi?id=564011 |
| 915 // is fixed, we will no longer need the lock. | 846 // is fixed, we will no longer need the lock. |
| 916 base::Lock write_lock_; | 847 base::Lock write_lock_; |
| 917 #endif // defined(USE_NSS) | 848 #endif // defined(USE_NSS) |
| 918 | 849 |
| 919 base::ThreadChecker thread_checker_; | 850 base::ThreadChecker thread_checker_; |
| 920 }; | 851 }; |
| 921 | 852 |
| 922 // static | 853 // static |
| 923 bool NSSInitSingleton::force_nodb_init_ = false; | 854 bool NSSInitSingleton::force_nodb_init_ = false; |
| 924 | 855 |
| 925 base::LazyInstance<NSSInitSingleton>::Leaky | 856 base::LazyInstance<NSSInitSingleton>::Leaky |
| 926 g_nss_singleton = LAZY_INSTANCE_INITIALIZER; | 857 g_nss_singleton = LAZY_INSTANCE_INITIALIZER; |
| 927 } // namespace | 858 } // namespace |
| 928 | 859 |
| 929 const char kTestTPMTokenName[] = "Test DB"; | 860 #if defined(USE_NSS) |
| 861 ScopedPK11Slot OpenSoftwareNSSDB(const base::FilePath& path, | |
| 862 const std::string& description) { | |
| 863 const std::string modspec = | |
| 864 base::StringPrintf("configDir='sql:%s' tokenDescription='%s'", | |
| 865 path.value().c_str(), | |
| 866 description.c_str()); | |
| 867 PK11SlotInfo* db_slot = SECMOD_OpenUserDB(modspec.c_str()); | |
| 868 if (db_slot) { | |
| 869 if (PK11_NeedUserInit(db_slot)) | |
| 870 PK11_InitPin(db_slot, NULL, NULL); | |
| 871 } else { | |
| 872 LOG(ERROR) << "Error opening persistent database (" << modspec | |
| 873 << "): " << GetNSSErrorMessage(); | |
| 874 } | |
| 875 return ScopedPK11Slot(db_slot); | |
| 876 } | |
| 930 | 877 |
| 931 #if defined(USE_NSS) | |
| 932 void EarlySetupForNSSInit() { | 878 void EarlySetupForNSSInit() { |
| 933 base::FilePath database_dir = GetInitialConfigDirectory(); | 879 base::FilePath database_dir = GetInitialConfigDirectory(); |
| 934 if (!database_dir.empty()) | 880 if (!database_dir.empty()) |
| 935 UseLocalCacheOfNSSDatabaseIfNFS(database_dir); | 881 UseLocalCacheOfNSSDatabaseIfNFS(database_dir); |
| 936 } | 882 } |
| 937 #endif | 883 #endif |
| 938 | 884 |
| 939 void EnsureNSPRInit() { | 885 void EnsureNSPRInit() { |
| 940 g_nspr_singleton.Get(); | 886 g_nspr_singleton.Get(); |
| 941 } | 887 } |
| (...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1020 LOG(ERROR) << "Failed to load NSS libraries."; | 966 LOG(ERROR) << "Failed to load NSS libraries."; |
| 1021 } | 967 } |
| 1022 #endif // defined(USE_NSS) | 968 #endif // defined(USE_NSS) |
| 1023 } | 969 } |
| 1024 | 970 |
| 1025 bool CheckNSSVersion(const char* version) { | 971 bool CheckNSSVersion(const char* version) { |
| 1026 return !!NSS_VersionCheck(version); | 972 return !!NSS_VersionCheck(version); |
| 1027 } | 973 } |
| 1028 | 974 |
| 1029 #if defined(USE_NSS) | 975 #if defined(USE_NSS) |
| 1030 ScopedTestNSSDB::ScopedTestNSSDB() | |
| 1031 : is_open_(g_nss_singleton.Get().OpenTestNSSDB()) { | |
| 1032 } | |
| 1033 | |
| 1034 ScopedTestNSSDB::~ScopedTestNSSDB() { | |
| 1035 // Don't close when NSS is < 3.15.1, because it would require an additional | |
| 1036 // sleep for 1 second after closing the database, due to | |
| 1037 // http://bugzil.la/875601. | |
| 1038 if (NSS_VersionCheck("3.15.1")) { | |
| 1039 g_nss_singleton.Get().CloseTestNSSDB(); | |
| 1040 } | |
| 1041 } | |
| 1042 | |
| 1043 base::Lock* GetNSSWriteLock() { | 976 base::Lock* GetNSSWriteLock() { |
| 1044 return g_nss_singleton.Get().write_lock(); | 977 return g_nss_singleton.Get().write_lock(); |
| 1045 } | 978 } |
| 1046 | 979 |
| 1047 AutoNSSWriteLock::AutoNSSWriteLock() : lock_(GetNSSWriteLock()) { | 980 AutoNSSWriteLock::AutoNSSWriteLock() : lock_(GetNSSWriteLock()) { |
| 1048 // May be NULL if the lock is not needed in our version of NSS. | 981 // May be NULL if the lock is not needed in our version of NSS. |
| 1049 if (lock_) | 982 if (lock_) |
| 1050 lock_->Acquire(); | 983 lock_->Acquire(); |
| 1051 } | 984 } |
| 1052 | 985 |
| 1053 AutoNSSWriteLock::~AutoNSSWriteLock() { | 986 AutoNSSWriteLock::~AutoNSSWriteLock() { |
| 1054 if (lock_) { | 987 if (lock_) { |
| 1055 lock_->AssertAcquired(); | 988 lock_->AssertAcquired(); |
| 1056 lock_->Release(); | 989 lock_->Release(); |
| 1057 } | 990 } |
| 1058 } | 991 } |
| 1059 | 992 |
| 1060 AutoSECMODListReadLock::AutoSECMODListReadLock() | 993 AutoSECMODListReadLock::AutoSECMODListReadLock() |
| 1061 : lock_(SECMOD_GetDefaultModuleListLock()) { | 994 : lock_(SECMOD_GetDefaultModuleListLock()) { |
| 1062 SECMOD_GetReadLock(lock_); | 995 SECMOD_GetReadLock(lock_); |
| 1063 } | 996 } |
| 1064 | 997 |
| 1065 AutoSECMODListReadLock::~AutoSECMODListReadLock() { | 998 AutoSECMODListReadLock::~AutoSECMODListReadLock() { |
| 1066 SECMOD_ReleaseReadLock(lock_); | 999 SECMOD_ReleaseReadLock(lock_); |
| 1067 } | 1000 } |
| 1068 | |
| 1069 #endif // defined(USE_NSS) | 1001 #endif // defined(USE_NSS) |
| 1070 | 1002 |
| 1071 #if defined(OS_CHROMEOS) | 1003 #if defined(OS_CHROMEOS) |
| 1072 PK11SlotInfo* GetSystemNSSKeySlot() { | 1004 PK11SlotInfo* GetSystemNSSKeySlot() { |
| 1073 return g_nss_singleton.Get().GetSystemNSSKeySlot(); | 1005 return g_nss_singleton.Get().GetSystemNSSKeySlot(); |
| 1074 } | 1006 } |
| 1075 | 1007 |
| 1008 void SetTestSystemKeySlot(ScopedPK11Slot slot) { | |
|
Ryan Sleevi
2014/07/23 02:15:28
SetSystemKeySlotForTesting - that way presubmit sc
pneubeck (no reviews)
2014/07/23 14:34:17
Done.
| |
| 1009 g_nss_singleton.Get().SetTestSystemKeySlot(ScopedPK11Slot()); | |
| 1010 } | |
| 1011 | |
| 1076 void EnableTPMTokenForNSS() { | 1012 void EnableTPMTokenForNSS() { |
| 1077 g_nss_singleton.Get().EnableTPMTokenForNSS(); | 1013 g_nss_singleton.Get().EnableTPMTokenForNSS(); |
| 1078 } | 1014 } |
| 1079 | 1015 |
| 1080 bool IsTPMTokenEnabledForNSS() { | 1016 bool IsTPMTokenEnabledForNSS() { |
| 1081 return g_nss_singleton.Get().IsTPMTokenEnabledForNSS(); | 1017 return g_nss_singleton.Get().IsTPMTokenEnabledForNSS(); |
| 1082 } | 1018 } |
| 1083 | 1019 |
| 1084 bool IsTPMTokenReady(const base::Closure& callback) { | 1020 bool IsTPMTokenReady(const base::Closure& callback) { |
| 1085 return g_nss_singleton.Get().IsTPMTokenReady(callback); | 1021 return g_nss_singleton.Get().IsTPMTokenReady(callback); |
| 1086 } | 1022 } |
| 1087 | 1023 |
| 1088 void InitializeTPMTokenAndSystemSlot( | 1024 void InitializeTPMTokenAndSystemSlot( |
| 1089 int token_slot_id, | 1025 int token_slot_id, |
| 1090 const base::Callback<void(bool)>& callback) { | 1026 const base::Callback<void(bool)>& callback) { |
| 1091 g_nss_singleton.Get().InitializeTPMTokenAndSystemSlot(token_slot_id, | 1027 g_nss_singleton.Get().InitializeTPMTokenAndSystemSlot(token_slot_id, |
| 1092 callback); | 1028 callback); |
| 1093 } | 1029 } |
| 1094 | 1030 |
| 1095 ScopedTestNSSChromeOSUser::ScopedTestNSSChromeOSUser( | |
| 1096 const std::string& username_hash) | |
| 1097 : username_hash_(username_hash), constructed_successfully_(false) { | |
| 1098 if (!temp_dir_.CreateUniqueTempDir()) | |
| 1099 return; | |
| 1100 constructed_successfully_ = | |
| 1101 InitializeNSSForChromeOSUser(username_hash, | |
| 1102 username_hash, | |
| 1103 temp_dir_.path()); | |
| 1104 } | |
| 1105 | |
| 1106 ScopedTestNSSChromeOSUser::~ScopedTestNSSChromeOSUser() { | |
| 1107 if (constructed_successfully_) | |
| 1108 g_nss_singleton.Get().CloseTestChromeOSUser(username_hash_); | |
| 1109 } | |
| 1110 | |
| 1111 void ScopedTestNSSChromeOSUser::FinishInit() { | |
| 1112 DCHECK(constructed_successfully_); | |
| 1113 if (!ShouldInitializeTPMForChromeOSUser(username_hash_)) | |
| 1114 return; | |
| 1115 WillInitializeTPMForChromeOSUser(username_hash_); | |
| 1116 InitializePrivateSoftwareSlotForChromeOSUser(username_hash_); | |
| 1117 } | |
| 1118 | |
| 1119 bool InitializeNSSForChromeOSUser( | 1031 bool InitializeNSSForChromeOSUser( |
| 1120 const std::string& email, | 1032 const std::string& email, |
| 1121 const std::string& username_hash, | 1033 const std::string& username_hash, |
| 1122 const base::FilePath& path) { | 1034 const base::FilePath& path) { |
| 1123 return g_nss_singleton.Get().InitializeNSSForChromeOSUser( | 1035 return g_nss_singleton.Get().InitializeNSSForChromeOSUser( |
| 1124 email, username_hash, path); | 1036 email, username_hash, path); |
| 1125 } | 1037 } |
| 1126 | 1038 |
| 1127 bool ShouldInitializeTPMForChromeOSUser(const std::string& username_hash) { | 1039 bool ShouldInitializeTPMForChromeOSUser(const std::string& username_hash) { |
| 1128 return g_nss_singleton.Get().ShouldInitializeTPMForChromeOSUser( | 1040 return g_nss_singleton.Get().ShouldInitializeTPMForChromeOSUser( |
| 1129 username_hash); | 1041 username_hash); |
| 1130 } | 1042 } |
| 1131 | 1043 |
| 1132 void WillInitializeTPMForChromeOSUser(const std::string& username_hash) { | 1044 void WillInitializeTPMForChromeOSUser(const std::string& username_hash) { |
| 1133 g_nss_singleton.Get().WillInitializeTPMForChromeOSUser(username_hash); | 1045 g_nss_singleton.Get().WillInitializeTPMForChromeOSUser(username_hash); |
| 1134 } | 1046 } |
| 1135 | 1047 |
| 1136 void InitializeTPMForChromeOSUser( | 1048 void InitializeTPMForChromeOSUser( |
| 1137 const std::string& username_hash, | 1049 const std::string& username_hash, |
| 1138 CK_SLOT_ID slot_id) { | 1050 CK_SLOT_ID slot_id) { |
| 1139 g_nss_singleton.Get().InitializeTPMForChromeOSUser(username_hash, slot_id); | 1051 g_nss_singleton.Get().InitializeTPMForChromeOSUser(username_hash, slot_id); |
| 1140 } | 1052 } |
| 1053 | |
| 1141 void InitializePrivateSoftwareSlotForChromeOSUser( | 1054 void InitializePrivateSoftwareSlotForChromeOSUser( |
| 1142 const std::string& username_hash) { | 1055 const std::string& username_hash) { |
| 1143 g_nss_singleton.Get().InitializePrivateSoftwareSlotForChromeOSUser( | 1056 g_nss_singleton.Get().InitializePrivateSoftwareSlotForChromeOSUser( |
| 1144 username_hash); | 1057 username_hash); |
| 1145 } | 1058 } |
| 1059 | |
| 1146 ScopedPK11Slot GetPublicSlotForChromeOSUser(const std::string& username_hash) { | 1060 ScopedPK11Slot GetPublicSlotForChromeOSUser(const std::string& username_hash) { |
| 1147 return g_nss_singleton.Get().GetPublicSlotForChromeOSUser(username_hash); | 1061 return g_nss_singleton.Get().GetPublicSlotForChromeOSUser(username_hash); |
| 1148 } | 1062 } |
| 1063 | |
| 1149 ScopedPK11Slot GetPrivateSlotForChromeOSUser( | 1064 ScopedPK11Slot GetPrivateSlotForChromeOSUser( |
| 1150 const std::string& username_hash, | 1065 const std::string& username_hash, |
| 1151 const base::Callback<void(ScopedPK11Slot)>& callback) { | 1066 const base::Callback<void(ScopedPK11Slot)>& callback) { |
| 1152 return g_nss_singleton.Get().GetPrivateSlotForChromeOSUser(username_hash, | 1067 return g_nss_singleton.Get().GetPrivateSlotForChromeOSUser(username_hash, |
| 1153 callback); | 1068 callback); |
| 1154 } | 1069 } |
| 1070 | |
| 1071 void CloseChromeOSUserForTesting(const std::string& username_hash) { | |
| 1072 g_nss_singleton.Get().CloseChromeOSUserForTesting(username_hash); | |
| 1073 } | |
| 1155 #endif // defined(OS_CHROMEOS) | 1074 #endif // defined(OS_CHROMEOS) |
| 1156 | 1075 |
| 1157 base::Time PRTimeToBaseTime(PRTime prtime) { | 1076 base::Time PRTimeToBaseTime(PRTime prtime) { |
| 1158 return base::Time::FromInternalValue( | 1077 return base::Time::FromInternalValue( |
| 1159 prtime + base::Time::UnixEpoch().ToInternalValue()); | 1078 prtime + base::Time::UnixEpoch().ToInternalValue()); |
| 1160 } | 1079 } |
| 1161 | 1080 |
| 1162 PRTime BaseTimeToPRTime(base::Time time) { | 1081 PRTime BaseTimeToPRTime(base::Time time) { |
| 1163 return time.ToInternalValue() - base::Time::UnixEpoch().ToInternalValue(); | 1082 return time.ToInternalValue() - base::Time::UnixEpoch().ToInternalValue(); |
| 1164 } | 1083 } |
| 1165 | 1084 |
| 1085 #if !defined(OS_CHROMEOS) | |
| 1166 PK11SlotInfo* GetPersistentNSSKeySlot() { | 1086 PK11SlotInfo* GetPersistentNSSKeySlot() { |
| 1167 return g_nss_singleton.Get().GetPersistentNSSKeySlot(); | 1087 return g_nss_singleton.Get().GetPersistentNSSKeySlot(); |
| 1168 } | 1088 } |
| 1089 #endif | |
| 1169 | 1090 |
| 1170 } // namespace crypto | 1091 } // namespace crypto |
| OLD | NEW |