diff options
author | mattm@chromium.org <mattm@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-02-27 22:27:21 +0000 |
---|---|---|
committer | mattm@chromium.org <mattm@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-02-27 22:27:21 +0000 |
commit | e2ea5ca6a89c308af53c5ee6d5d1f61ccb11faf8 (patch) | |
tree | 84d778268dd77316c7db3bc451ae0726053d768f /crypto | |
parent | 33c2fdaffa5d8a026eff689790bf33e2dacb5025 (diff) | |
download | chromium_src-e2ea5ca6a89c308af53c5ee6d5d1f61ccb11faf8.zip chromium_src-e2ea5ca6a89c308af53c5ee6d5d1f61ccb11faf8.tar.gz chromium_src-e2ea5ca6a89c308af53c5ee6d5d1f61ccb11faf8.tar.bz2 |
chromeos: Load chaps module and lookup TPM slots on the worker pool.
BUG=345713
Review URL: https://codereview.chromium.org/181053002
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@253942 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'crypto')
-rw-r--r-- | crypto/nss_util.cc | 155 | ||||
-rw-r--r-- | crypto/nss_util.h | 12 |
2 files changed, 126 insertions, 41 deletions
diff --git a/crypto/nss_util.cc b/crypto/nss_util.cc index 4d4a8f7..8e7e9ac 100644 --- a/crypto/nss_util.cc +++ b/crypto/nss_util.cc @@ -22,7 +22,6 @@ #include <vector> #include "base/bind.h" -#include "base/callback.h" #include "base/cpu.h" #include "base/debug/alias.h" #include "base/debug/stack_trace.h" @@ -39,6 +38,7 @@ #include "base/strings/stringprintf.h" #include "base/threading/thread_checker.h" #include "base/threading/thread_restrictions.h" +#include "base/threading/worker_pool.h" #include "build/build_config.h" // USE_NSS means we use NSS for everything crypto-related. If USE_NSS is not @@ -265,6 +265,14 @@ class ChromeOSUserData { class NSSInitSingleton { public: #if defined(OS_CHROMEOS) + // Used with PostTaskAndReply to pass handles to worker thread and back. + struct TPMModuleAndSlot { + explicit TPMModuleAndSlot(SECMODModule* init_chaps_module) + : chaps_module(init_chaps_module), tpm_slot(NULL) {} + SECMODModule* chaps_module; + PK11SlotInfo* tpm_slot; + }; + void OpenPersistentNSSDB() { DCHECK(thread_checker_.CalledOnValidThread()); @@ -312,21 +320,57 @@ class NSSInitSingleton { return tpm_token_enabled_for_nss_; } - bool InitializeTPMToken(int token_slot_id) { + void InitializeTPMToken(int token_slot_id, + const base::Callback<void(bool)>& callback) { DCHECK(thread_checker_.CalledOnValidThread()); - + // Should not be called while there is already an initialization in + // progress. + DCHECK(!initializing_tpm_token_); // If EnableTPMTokenForNSS hasn't been called, return false. - if (!tpm_token_enabled_for_nss_) - return false; + if (!tpm_token_enabled_for_nss_) { + base::MessageLoop::current()->PostTask(FROM_HERE, + base::Bind(callback, false)); + return; + } // If everything is already initialized, then return true. - if (chaps_module_ && tpm_slot_) - return true; + // Note that only |tpm_slot_| is checked, since |chaps_module_| could be + // NULL in tests while |tpm_slot_| has been set to the test DB. + if (tpm_slot_) { + base::MessageLoop::current()->PostTask(FROM_HERE, + base::Bind(callback, true)); + return; + } + // Note that a reference is not taken to chaps_module_. This is safe since + // NSSInitSingleton is Leaky, so the reference it holds is never released. + scoped_ptr<TPMModuleAndSlot> tpm_args(new TPMModuleAndSlot(chaps_module_)); + TPMModuleAndSlot* tpm_args_ptr = tpm_args.get(); + if (base::WorkerPool::PostTaskAndReply( + FROM_HERE, + base::Bind(&NSSInitSingleton::InitializeTPMTokenOnWorkerThread, + token_slot_id, + tpm_args_ptr), + base::Bind(&NSSInitSingleton::OnInitializedTPMToken, + base::Unretained(this), // NSSInitSingleton is leaky + callback, + base::Passed(&tpm_args)), + true /* task_is_slow */ + )) { + initializing_tpm_token_ = true; + } else { + base::MessageLoop::current()->PostTask(FROM_HERE, + base::Bind(callback, false)); + } + } + + static void InitializeTPMTokenOnWorkerThread(CK_SLOT_ID token_slot_id, + TPMModuleAndSlot* tpm_args) { // This tries to load the Chaps module so NSS can talk to the hardware // TPM. - if (!chaps_module_) { - chaps_module_ = LoadModule( + if (!tpm_args->chaps_module) { + DVLOG(3) << "Loading chaps..."; + tpm_args->chaps_module = LoadModule( kChapsModuleName, kChapsPath, // For more details on these parameters, see: @@ -335,31 +379,39 @@ class NSSInitSingleton { // read from this slot without requiring a call to C_Login. // askpw=only -- Only authenticate to the token when necessary. "NSS=\"slotParams=(0={slotFlags=[PublicCerts] askpw=only})\""); - if (!chaps_module_ && test_slot_) { - // chromeos_unittests try to test the TPM initialization process. If we - // have a test DB open, pretend that it is the TPM slot. - tpm_slot_ = PK11_ReferenceSlot(test_slot_); - return true; - } } - if (chaps_module_){ - tpm_slot_ = GetTPMSlotForId(token_slot_id); + if (tpm_args->chaps_module) { + tpm_args->tpm_slot = + GetTPMSlotForIdOnWorkerThread(tpm_args->chaps_module, token_slot_id); + } + } - if (!tpm_slot_) - return false; + void OnInitializedTPMToken(const base::Callback<void(bool)>& callback, + scoped_ptr<TPMModuleAndSlot> tpm_args) { + DCHECK(thread_checker_.CalledOnValidThread()); + DVLOG(2) << "Loaded chaps: " << !!tpm_args->chaps_module + << ", got tpm slot: " << !!tpm_args->tpm_slot; + + chaps_module_ = tpm_args->chaps_module; + tpm_slot_ = tpm_args->tpm_slot; + if (!chaps_module_ && test_slot_) { + // chromeos_unittests try to test the TPM initialization process. If we + // have a test DB open, pretend that it is the TPM slot. + tpm_slot_ = PK11_ReferenceSlot(test_slot_); + } + initializing_tpm_token_ = false; + if (tpm_slot_) { TPMReadyCallbackList callback_list; callback_list.swap(tpm_ready_callback_list_); - for (TPMReadyCallbackList::iterator i = - callback_list.begin(); + for (TPMReadyCallbackList::iterator i = callback_list.begin(); i != callback_list.end(); ++i) { (*i).Run(); } - - return true; } - return false; + + callback.Run(!!tpm_slot_); } bool IsTPMTokenReady(const base::Closure& callback) { @@ -386,18 +438,16 @@ class NSSInitSingleton { // Note that CK_SLOT_ID is an unsigned long, but cryptohome gives us the slot // id as an int. This should be safe since this is only used with chaps, which // we also control. - PK11SlotInfo* GetTPMSlotForId(CK_SLOT_ID slot_id) { - DCHECK(thread_checker_.CalledOnValidThread()); - - if (!chaps_module_) - return NULL; + static PK11SlotInfo* GetTPMSlotForIdOnWorkerThread(SECMODModule* chaps_module, + CK_SLOT_ID slot_id) { + DCHECK(chaps_module); DVLOG(3) << "Poking chaps module."; - SECStatus rv = SECMOD_UpdateSlotList(chaps_module_); + SECStatus rv = SECMOD_UpdateSlotList(chaps_module); if (rv != SECSuccess) PLOG(ERROR) << "SECMOD_UpdateSlotList failed: " << PORT_GetError(); - PK11SlotInfo* slot = SECMOD_LookupSlot(chaps_module_->moduleID, slot_id); + PK11SlotInfo* slot = SECMOD_LookupSlot(chaps_module->moduleID, slot_id); if (!slot) LOG(ERROR) << "TPM slot " << slot_id << " not found."; return slot; @@ -431,8 +481,34 @@ class NSSInitSingleton { CK_SLOT_ID slot_id) { DCHECK(thread_checker_.CalledOnValidThread()); DCHECK(chromeos_user_map_.find(username_hash) != chromeos_user_map_.end()); - chromeos_user_map_[username_hash] - ->SetPrivateSlot(ScopedPK11Slot(GetTPMSlotForId(slot_id))); + + if (!chaps_module_) + return; + + // Note that a reference is not taken to chaps_module_. This is safe since + // NSSInitSingleton is Leaky, so the reference it holds is never released. + scoped_ptr<TPMModuleAndSlot> tpm_args(new TPMModuleAndSlot(chaps_module_)); + TPMModuleAndSlot* tpm_args_ptr = tpm_args.get(); + base::WorkerPool::PostTaskAndReply( + FROM_HERE, + base::Bind(&NSSInitSingleton::InitializeTPMTokenOnWorkerThread, + slot_id, + tpm_args_ptr), + base::Bind(&NSSInitSingleton::OnInitializedTPMForChromeOSUser, + base::Unretained(this), // NSSInitSingleton is leaky + username_hash, + base::Passed(&tpm_args)), + true /* task_is_slow */ + ); + } + + void OnInitializedTPMForChromeOSUser(const std::string& username_hash, + scoped_ptr<TPMModuleAndSlot> tpm_args) { + DCHECK(thread_checker_.CalledOnValidThread()); + DVLOG(2) << "Got tpm slot for " << username_hash << " " + << !!tpm_args->tpm_slot; + chromeos_user_map_[username_hash]->SetPrivateSlot( + ScopedPK11Slot(tpm_args->tpm_slot)); } void InitializePrivateSoftwareSlotForChromeOSUser( @@ -590,6 +666,7 @@ class NSSInitSingleton { NSSInitSingleton() : tpm_token_enabled_for_nss_(false), + initializing_tpm_token_(false), chaps_module_(NULL), software_slot_(NULL), test_slot_(NULL), @@ -754,9 +831,9 @@ class NSSInitSingleton { } // Load the given module for this NSS session. - SECMODModule* LoadModule(const char* name, - const char* library_path, - const char* params) { + static SECMODModule* LoadModule(const char* name, + const char* library_path, + const char* params) { std::string modparams = base::StringPrintf( "name=\"%s\" library=\"%s\" %s", name, library_path, params ? params : ""); @@ -818,6 +895,7 @@ class NSSInitSingleton { static bool force_nodb_init_; bool tpm_token_enabled_for_nss_; + bool initializing_tpm_token_; typedef std::vector<base::Closure> TPMReadyCallbackList; TPMReadyCallbackList tpm_ready_callback_list_; SECMODModule* chaps_module_; @@ -1005,8 +1083,9 @@ bool IsTPMTokenReady(const base::Closure& callback) { return g_nss_singleton.Get().IsTPMTokenReady(callback); } -bool InitializeTPMToken(int token_slot_id) { - return g_nss_singleton.Get().InitializeTPMToken(token_slot_id); +void InitializeTPMToken(int token_slot_id, + const base::Callback<void(bool)>& callback) { + g_nss_singleton.Get().InitializeTPMToken(token_slot_id, callback); } ScopedTestNSSChromeOSUser::ScopedTestNSSChromeOSUser( diff --git a/crypto/nss_util.h b/crypto/nss_util.h index cf93cb5..e94c4f6 100644 --- a/crypto/nss_util.h +++ b/crypto/nss_util.h @@ -7,7 +7,7 @@ #include <string> #include "base/basictypes.h" -#include "base/callback_forward.h" +#include "base/callback.h" #include "base/compiler_specific.h" #include "base/files/scoped_temp_dir.h" #include "crypto/crypto_export.h" @@ -118,8 +118,14 @@ CRYPTO_EXPORT bool IsTPMTokenEnabledForNSS(); CRYPTO_EXPORT bool IsTPMTokenReady(const base::Closure& callback) WARN_UNUSED_RESULT; -// Initialize the TPM token. Does nothing if it is already initialized. -CRYPTO_EXPORT bool InitializeTPMToken(int token_slot_id); +// Initialize the TPM token. The |callback| will run on the same thread with +// true if the token and slot were successfully loaded or were already +// initialized. |callback| will be passed false if loading failed. +// Once called, InitializeTPMToken must not be called again until the |callback| +// has been run. +CRYPTO_EXPORT void InitializeTPMToken( + int token_slot_id, + const base::Callback<void(bool)>& callback); // Exposed for unittests only. class CRYPTO_EXPORT_PRIVATE ScopedTestNSSChromeOSUser { |