summaryrefslogtreecommitdiffstats
path: root/crypto/nss_util.cc
diff options
context:
space:
mode:
authormattm@chromium.org <mattm@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-02-27 22:27:21 +0000
committermattm@chromium.org <mattm@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-02-27 22:27:21 +0000
commite2ea5ca6a89c308af53c5ee6d5d1f61ccb11faf8 (patch)
tree84d778268dd77316c7db3bc451ae0726053d768f /crypto/nss_util.cc
parent33c2fdaffa5d8a026eff689790bf33e2dacb5025 (diff)
downloadchromium_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/nss_util.cc')
-rw-r--r--crypto/nss_util.cc155
1 files changed, 117 insertions, 38 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(