| 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 258 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 269 SlotReadyCallbackList tpm_ready_callback_list_; | 269 SlotReadyCallbackList tpm_ready_callback_list_; |
| 270 }; | 270 }; |
| 271 #endif // defined(OS_CHROMEOS) | 271 #endif // defined(OS_CHROMEOS) |
| 272 | 272 |
| 273 class NSSInitSingleton { | 273 class NSSInitSingleton { |
| 274 public: | 274 public: |
| 275 #if defined(OS_CHROMEOS) | 275 #if defined(OS_CHROMEOS) |
| 276 // Used with PostTaskAndReply to pass handles to worker thread and back. | 276 // Used with PostTaskAndReply to pass handles to worker thread and back. |
| 277 struct TPMModuleAndSlot { | 277 struct TPMModuleAndSlot { |
| 278 explicit TPMModuleAndSlot(SECMODModule* init_chaps_module) | 278 explicit TPMModuleAndSlot(SECMODModule* init_chaps_module) |
| 279 : chaps_module(init_chaps_module), tpm_slot(NULL) {} | 279 : chaps_module(init_chaps_module) {} |
| 280 SECMODModule* chaps_module; | 280 SECMODModule* chaps_module; |
| 281 PK11SlotInfo* tpm_slot; | 281 crypto::ScopedPK11Slot tpm_slot; |
| 282 }; | 282 }; |
| 283 | 283 |
| 284 ScopedPK11Slot OpenPersistentNSSDBForPath(const std::string& db_name, | 284 ScopedPK11Slot OpenPersistentNSSDBForPath(const std::string& db_name, |
| 285 const base::FilePath& path) { | 285 const base::FilePath& path) { |
| 286 DCHECK(thread_checker_.CalledOnValidThread()); | 286 DCHECK(thread_checker_.CalledOnValidThread()); |
| 287 // NSS is allowed to do IO on the current thread since dispatching | 287 // NSS is allowed to do IO on the current thread since dispatching |
| 288 // to a dedicated thread would still have the affect of blocking | 288 // to a dedicated thread would still have the affect of blocking |
| 289 // the current thread, due to NSS's internal locking requirements | 289 // the current thread, due to NSS's internal locking requirements |
| 290 base::ThreadRestrictions::ScopedAllowIO allow_io; | 290 base::ThreadRestrictions::ScopedAllowIO allow_io; |
| 291 | 291 |
| (...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 379 } | 379 } |
| 380 | 380 |
| 381 void OnInitializedTPMTokenAndSystemSlot( | 381 void OnInitializedTPMTokenAndSystemSlot( |
| 382 const base::Callback<void(bool)>& callback, | 382 const base::Callback<void(bool)>& callback, |
| 383 scoped_ptr<TPMModuleAndSlot> tpm_args) { | 383 scoped_ptr<TPMModuleAndSlot> tpm_args) { |
| 384 DCHECK(thread_checker_.CalledOnValidThread()); | 384 DCHECK(thread_checker_.CalledOnValidThread()); |
| 385 DVLOG(2) << "Loaded chaps: " << !!tpm_args->chaps_module | 385 DVLOG(2) << "Loaded chaps: " << !!tpm_args->chaps_module |
| 386 << ", got tpm slot: " << !!tpm_args->tpm_slot; | 386 << ", got tpm slot: " << !!tpm_args->tpm_slot; |
| 387 | 387 |
| 388 chaps_module_ = tpm_args->chaps_module; | 388 chaps_module_ = tpm_args->chaps_module; |
| 389 tpm_slot_ = tpm_args->tpm_slot; | 389 tpm_slot_ = tpm_args->tpm_slot.Pass(); |
| 390 if (!chaps_module_ && test_system_slot_) { | 390 if (!chaps_module_ && test_system_slot_) { |
| 391 // chromeos_unittests try to test the TPM initialization process. If we | 391 // chromeos_unittests try to test the TPM initialization process. If we |
| 392 // have a test DB open, pretend that it is the TPM slot. | 392 // have a test DB open, pretend that it is the TPM slot. |
| 393 tpm_slot_ = PK11_ReferenceSlot(test_system_slot_.get()); | 393 tpm_slot_.reset(PK11_ReferenceSlot(test_system_slot_.get())); |
| 394 } | 394 } |
| 395 initializing_tpm_token_ = false; | 395 initializing_tpm_token_ = false; |
| 396 | 396 |
| 397 if (tpm_slot_) { | 397 if (tpm_slot_) { |
| 398 TPMReadyCallbackList callback_list; | 398 TPMReadyCallbackList callback_list; |
| 399 callback_list.swap(tpm_ready_callback_list_); | 399 callback_list.swap(tpm_ready_callback_list_); |
| 400 for (TPMReadyCallbackList::iterator i = callback_list.begin(); | 400 for (TPMReadyCallbackList::iterator i = callback_list.begin(); |
| 401 i != callback_list.end(); | 401 i != callback_list.end(); |
| 402 ++i) { | 402 ++i) { |
| 403 (*i).Run(); | 403 (*i).Run(); |
| 404 } | 404 } |
| 405 } | 405 } |
| 406 | 406 |
| 407 callback.Run(!!tpm_slot_); | 407 callback.Run(!!tpm_slot_); |
| 408 } | 408 } |
| 409 | 409 |
| 410 bool IsTPMTokenReady(const base::Closure& callback) { | 410 bool IsTPMTokenReady(const base::Closure& callback) { |
| 411 if (!callback.is_null()) { | 411 if (!callback.is_null()) { |
| 412 // Cannot DCHECK in the general case yet, but since the callback is | 412 // Cannot DCHECK in the general case yet, but since the callback is |
| 413 // a new addition to the API, DCHECK to make sure at least the new uses | 413 // a new addition to the API, DCHECK to make sure at least the new uses |
| 414 // don't regress. | 414 // don't regress. |
| 415 DCHECK(thread_checker_.CalledOnValidThread()); | 415 DCHECK(thread_checker_.CalledOnValidThread()); |
| 416 } else if (!thread_checker_.CalledOnValidThread()) { | 416 } else if (!thread_checker_.CalledOnValidThread()) { |
| 417 // TODO(mattm): Change to DCHECK when callers have been fixed. | 417 // TODO(mattm): Change to DCHECK when callers have been fixed. |
| 418 DVLOG(1) << "Called on wrong thread.\n" | 418 DVLOG(1) << "Called on wrong thread.\n" |
| 419 << base::debug::StackTrace().ToString(); | 419 << base::debug::StackTrace().ToString(); |
| 420 } | 420 } |
| 421 | 421 |
| 422 if (tpm_slot_ != NULL) | 422 if (tpm_slot_) |
| 423 return true; | 423 return true; |
| 424 | 424 |
| 425 if (!callback.is_null()) | 425 if (!callback.is_null()) |
| 426 tpm_ready_callback_list_.push_back(callback); | 426 tpm_ready_callback_list_.push_back(callback); |
| 427 | 427 |
| 428 return false; | 428 return false; |
| 429 } | 429 } |
| 430 | 430 |
| 431 // Note that CK_SLOT_ID is an unsigned long, but cryptohome gives us the slot | 431 // Note that CK_SLOT_ID is an unsigned long, but cryptohome gives us the slot |
| 432 // id as an int. This should be safe since this is only used with chaps, which | 432 // id as an int. This should be safe since this is only used with chaps, which |
| 433 // we also control. | 433 // we also control. |
| 434 static PK11SlotInfo* GetTPMSlotForIdOnWorkerThread(SECMODModule* chaps_module, | 434 static crypto::ScopedPK11Slot GetTPMSlotForIdOnWorkerThread( |
| 435 CK_SLOT_ID slot_id) { | 435 SECMODModule* chaps_module, |
| 436 CK_SLOT_ID slot_id) { |
| 436 DCHECK(chaps_module); | 437 DCHECK(chaps_module); |
| 437 | 438 |
| 438 DVLOG(3) << "Poking chaps module."; | 439 DVLOG(3) << "Poking chaps module."; |
| 439 SECStatus rv = SECMOD_UpdateSlotList(chaps_module); | 440 SECStatus rv = SECMOD_UpdateSlotList(chaps_module); |
| 440 if (rv != SECSuccess) | 441 if (rv != SECSuccess) |
| 441 PLOG(ERROR) << "SECMOD_UpdateSlotList failed: " << PORT_GetError(); | 442 PLOG(ERROR) << "SECMOD_UpdateSlotList failed: " << PORT_GetError(); |
| 442 | 443 |
| 443 PK11SlotInfo* slot = SECMOD_LookupSlot(chaps_module->moduleID, slot_id); | 444 PK11SlotInfo* slot = SECMOD_LookupSlot(chaps_module->moduleID, slot_id); |
| 444 if (!slot) | 445 if (!slot) |
| 445 LOG(ERROR) << "TPM slot " << slot_id << " not found."; | 446 LOG(ERROR) << "TPM slot " << slot_id << " not found."; |
| 446 return slot; | 447 return crypto::ScopedPK11Slot(slot); |
| 447 } | 448 } |
| 448 | 449 |
| 449 bool InitializeNSSForChromeOSUser( | 450 bool InitializeNSSForChromeOSUser( |
| 450 const std::string& email, | 451 const std::string& email, |
| 451 const std::string& username_hash, | 452 const std::string& username_hash, |
| 452 const base::FilePath& path) { | 453 const base::FilePath& path) { |
| 453 DCHECK(thread_checker_.CalledOnValidThread()); | 454 DCHECK(thread_checker_.CalledOnValidThread()); |
| 454 if (chromeos_user_map_.find(username_hash) != chromeos_user_map_.end()) { | 455 if (chromeos_user_map_.find(username_hash) != chromeos_user_map_.end()) { |
| 455 // This user already exists in our mapping. | 456 // This user already exists in our mapping. |
| 456 DVLOG(2) << username_hash << " already initialized."; | 457 DVLOG(2) << username_hash << " already initialized."; |
| (...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 508 true /* task_is_slow */ | 509 true /* task_is_slow */ |
| 509 ); | 510 ); |
| 510 } | 511 } |
| 511 | 512 |
| 512 void OnInitializedTPMForChromeOSUser(const std::string& username_hash, | 513 void OnInitializedTPMForChromeOSUser(const std::string& username_hash, |
| 513 scoped_ptr<TPMModuleAndSlot> tpm_args) { | 514 scoped_ptr<TPMModuleAndSlot> tpm_args) { |
| 514 DCHECK(thread_checker_.CalledOnValidThread()); | 515 DCHECK(thread_checker_.CalledOnValidThread()); |
| 515 DVLOG(2) << "Got tpm slot for " << username_hash << " " | 516 DVLOG(2) << "Got tpm slot for " << username_hash << " " |
| 516 << !!tpm_args->tpm_slot; | 517 << !!tpm_args->tpm_slot; |
| 517 chromeos_user_map_[username_hash]->SetPrivateSlot( | 518 chromeos_user_map_[username_hash]->SetPrivateSlot( |
| 518 ScopedPK11Slot(tpm_args->tpm_slot)); | 519 tpm_args->tpm_slot.Pass()); |
| 519 } | 520 } |
| 520 | 521 |
| 521 void InitializePrivateSoftwareSlotForChromeOSUser( | 522 void InitializePrivateSoftwareSlotForChromeOSUser( |
| 522 const std::string& username_hash) { | 523 const std::string& username_hash) { |
| 523 DCHECK(thread_checker_.CalledOnValidThread()); | 524 DCHECK(thread_checker_.CalledOnValidThread()); |
| 524 VLOG(1) << "using software private slot for " << username_hash; | 525 VLOG(1) << "using software private slot for " << username_hash; |
| 525 DCHECK(chromeos_user_map_.find(username_hash) != chromeos_user_map_.end()); | 526 DCHECK(chromeos_user_map_.find(username_hash) != chromeos_user_map_.end()); |
| 526 DCHECK(chromeos_user_map_[username_hash]-> | 527 DCHECK(chromeos_user_map_[username_hash]-> |
| 527 private_slot_initialization_started()); | 528 private_slot_initialization_started()); |
| 528 | 529 |
| (...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 589 << base::debug::StackTrace().ToString(); | 590 << base::debug::StackTrace().ToString(); |
| 590 } | 591 } |
| 591 | 592 |
| 592 return PK11_GetInternalKeySlot(); | 593 return PK11_GetInternalKeySlot(); |
| 593 } | 594 } |
| 594 #endif | 595 #endif |
| 595 | 596 |
| 596 #if defined(OS_CHROMEOS) | 597 #if defined(OS_CHROMEOS) |
| 597 void GetSystemNSSKeySlotCallback( | 598 void GetSystemNSSKeySlotCallback( |
| 598 const base::Callback<void(ScopedPK11Slot)>& callback) { | 599 const base::Callback<void(ScopedPK11Slot)>& callback) { |
| 599 callback.Run(ScopedPK11Slot(PK11_ReferenceSlot(tpm_slot_))); | 600 callback.Run(ScopedPK11Slot(PK11_ReferenceSlot(tpm_slot_.get()))); |
| 600 } | 601 } |
| 601 | 602 |
| 602 ScopedPK11Slot GetSystemNSSKeySlot( | 603 ScopedPK11Slot GetSystemNSSKeySlot( |
| 603 const base::Callback<void(ScopedPK11Slot)>& callback) { | 604 const base::Callback<void(ScopedPK11Slot)>& callback) { |
| 604 DCHECK(thread_checker_.CalledOnValidThread()); | 605 DCHECK(thread_checker_.CalledOnValidThread()); |
| 605 // TODO(mattm): chromeos::TPMTokenloader always calls | 606 // TODO(mattm): chromeos::TPMTokenloader always calls |
| 606 // InitializeTPMTokenAndSystemSlot with slot 0. If the system slot is | 607 // InitializeTPMTokenAndSystemSlot with slot 0. If the system slot is |
| 607 // disabled, tpm_slot_ will be the first user's slot instead. Can that be | 608 // disabled, tpm_slot_ will be the first user's slot instead. Can that be |
| 608 // detected and return NULL instead? | 609 // detected and return NULL instead? |
| 609 | 610 |
| 610 base::Closure wrapped_callback; | 611 base::Closure wrapped_callback; |
| 611 if (!callback.is_null()) { | 612 if (!callback.is_null()) { |
| 612 wrapped_callback = | 613 wrapped_callback = |
| 613 base::Bind(&NSSInitSingleton::GetSystemNSSKeySlotCallback, | 614 base::Bind(&NSSInitSingleton::GetSystemNSSKeySlotCallback, |
| 614 base::Unretained(this) /* singleton is leaky */, | 615 base::Unretained(this) /* singleton is leaky */, |
| 615 callback); | 616 callback); |
| 616 } | 617 } |
| 617 if (IsTPMTokenReady(wrapped_callback)) | 618 if (IsTPMTokenReady(wrapped_callback)) |
| 618 return ScopedPK11Slot(PK11_ReferenceSlot(tpm_slot_)); | 619 return ScopedPK11Slot(PK11_ReferenceSlot(tpm_slot_.get())); |
| 619 return ScopedPK11Slot(); | 620 return ScopedPK11Slot(); |
| 620 } | 621 } |
| 621 #endif | 622 #endif |
| 622 | 623 |
| 623 #if defined(USE_NSS) | 624 #if defined(USE_NSS) |
| 624 base::Lock* write_lock() { | 625 base::Lock* write_lock() { |
| 625 return &write_lock_; | 626 return &write_lock_; |
| 626 } | 627 } |
| 627 #endif // defined(USE_NSS) | 628 #endif // defined(USE_NSS) |
| 628 | 629 |
| 629 // This method is used to force NSS to be initialized without a DB. | 630 // This method is used to force NSS to be initialized without a DB. |
| 630 // Call this method before NSSInitSingleton() is constructed. | 631 // Call this method before NSSInitSingleton() is constructed. |
| 631 static void ForceNoDBInit() { | 632 static void ForceNoDBInit() { |
| 632 force_nodb_init_ = true; | 633 force_nodb_init_ = true; |
| 633 } | 634 } |
| 634 | 635 |
| 635 private: | 636 private: |
| 636 friend struct base::DefaultLazyInstanceTraits<NSSInitSingleton>; | 637 friend struct base::DefaultLazyInstanceTraits<NSSInitSingleton>; |
| 637 | 638 |
| 638 NSSInitSingleton() | 639 NSSInitSingleton() |
| 639 : tpm_token_enabled_for_nss_(false), | 640 : tpm_token_enabled_for_nss_(false), |
| 640 initializing_tpm_token_(false), | 641 initializing_tpm_token_(false), |
| 641 chaps_module_(NULL), | 642 chaps_module_(NULL), |
| 642 tpm_slot_(NULL), | |
| 643 root_(NULL) { | 643 root_(NULL) { |
| 644 base::TimeTicks start_time = base::TimeTicks::Now(); | 644 base::TimeTicks start_time = base::TimeTicks::Now(); |
| 645 | 645 |
| 646 // It's safe to construct on any thread, since LazyInstance will prevent any | 646 // It's safe to construct on any thread, since LazyInstance will prevent any |
| 647 // other threads from accessing until the constructor is done. | 647 // other threads from accessing until the constructor is done. |
| 648 thread_checker_.DetachFromThread(); | 648 thread_checker_.DetachFromThread(); |
| 649 | 649 |
| 650 DisableAESNIIfNeeded(); | 650 DisableAESNIIfNeeded(); |
| 651 | 651 |
| 652 EnsureNSPRInit(); | 652 EnsureNSPRInit(); |
| (...skipping 96 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 749 50); | 749 50); |
| 750 } | 750 } |
| 751 | 751 |
| 752 // NOTE(willchan): We don't actually execute this code since we leak NSS to | 752 // NOTE(willchan): We don't actually execute this code since we leak NSS to |
| 753 // prevent non-joinable threads from using NSS after it's already been shut | 753 // prevent non-joinable threads from using NSS after it's already been shut |
| 754 // down. | 754 // down. |
| 755 ~NSSInitSingleton() { | 755 ~NSSInitSingleton() { |
| 756 #if defined(OS_CHROMEOS) | 756 #if defined(OS_CHROMEOS) |
| 757 STLDeleteValues(&chromeos_user_map_); | 757 STLDeleteValues(&chromeos_user_map_); |
| 758 #endif | 758 #endif |
| 759 if (tpm_slot_) { | 759 tpm_slot_.reset(); |
| 760 PK11_FreeSlot(tpm_slot_); | |
| 761 tpm_slot_ = NULL; | |
| 762 } | |
| 763 if (root_) { | 760 if (root_) { |
| 764 SECMOD_UnloadUserModule(root_); | 761 SECMOD_UnloadUserModule(root_); |
| 765 SECMOD_DestroyModule(root_); | 762 SECMOD_DestroyModule(root_); |
| 766 root_ = NULL; | 763 root_ = NULL; |
| 767 } | 764 } |
| 768 if (chaps_module_) { | 765 if (chaps_module_) { |
| 769 SECMOD_UnloadUserModule(chaps_module_); | 766 SECMOD_UnloadUserModule(chaps_module_); |
| 770 SECMOD_DestroyModule(chaps_module_); | 767 SECMOD_DestroyModule(chaps_module_); |
| 771 chaps_module_ = NULL; | 768 chaps_module_ = NULL; |
| 772 } | 769 } |
| (...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 837 } | 834 } |
| 838 | 835 |
| 839 // If this is set to true NSS is forced to be initialized without a DB. | 836 // If this is set to true NSS is forced to be initialized without a DB. |
| 840 static bool force_nodb_init_; | 837 static bool force_nodb_init_; |
| 841 | 838 |
| 842 bool tpm_token_enabled_for_nss_; | 839 bool tpm_token_enabled_for_nss_; |
| 843 bool initializing_tpm_token_; | 840 bool initializing_tpm_token_; |
| 844 typedef std::vector<base::Closure> TPMReadyCallbackList; | 841 typedef std::vector<base::Closure> TPMReadyCallbackList; |
| 845 TPMReadyCallbackList tpm_ready_callback_list_; | 842 TPMReadyCallbackList tpm_ready_callback_list_; |
| 846 SECMODModule* chaps_module_; | 843 SECMODModule* chaps_module_; |
| 847 PK11SlotInfo* tpm_slot_; | 844 crypto::ScopedPK11Slot tpm_slot_; |
| 848 SECMODModule* root_; | 845 SECMODModule* root_; |
| 849 #if defined(OS_CHROMEOS) | 846 #if defined(OS_CHROMEOS) |
| 850 typedef std::map<std::string, ChromeOSUserData*> ChromeOSUserMap; | 847 typedef std::map<std::string, ChromeOSUserData*> ChromeOSUserMap; |
| 851 ChromeOSUserMap chromeos_user_map_; | 848 ChromeOSUserMap chromeos_user_map_; |
| 852 ScopedPK11Slot test_system_slot_; | 849 ScopedPK11Slot test_system_slot_; |
| 853 #endif | 850 #endif |
| 854 #if defined(USE_NSS) | 851 #if defined(USE_NSS) |
| 855 // TODO(davidben): When https://bugzilla.mozilla.org/show_bug.cgi?id=564011 | 852 // TODO(davidben): When https://bugzilla.mozilla.org/show_bug.cgi?id=564011 |
| 856 // is fixed, we will no longer need the lock. | 853 // is fixed, we will no longer need the lock. |
| 857 base::Lock write_lock_; | 854 base::Lock write_lock_; |
| (...skipping 235 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1093 return time.ToInternalValue() - base::Time::UnixEpoch().ToInternalValue(); | 1090 return time.ToInternalValue() - base::Time::UnixEpoch().ToInternalValue(); |
| 1094 } | 1091 } |
| 1095 | 1092 |
| 1096 #if !defined(OS_CHROMEOS) | 1093 #if !defined(OS_CHROMEOS) |
| 1097 PK11SlotInfo* GetPersistentNSSKeySlot() { | 1094 PK11SlotInfo* GetPersistentNSSKeySlot() { |
| 1098 return g_nss_singleton.Get().GetPersistentNSSKeySlot(); | 1095 return g_nss_singleton.Get().GetPersistentNSSKeySlot(); |
| 1099 } | 1096 } |
| 1100 #endif | 1097 #endif |
| 1101 | 1098 |
| 1102 } // namespace crypto | 1099 } // namespace crypto |
| OLD | NEW |