summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--chromeos/tpm_token_loader.cc19
-rw-r--r--crypto/nss_util.cc155
-rw-r--r--crypto/nss_util.h12
3 files changed, 140 insertions, 46 deletions
diff --git a/chromeos/tpm_token_loader.cc b/chromeos/tpm_token_loader.cc
index f48fb16..7f88581 100644
--- a/chromeos/tpm_token_loader.cc
+++ b/chromeos/tpm_token_loader.cc
@@ -48,6 +48,12 @@ void CallOpenPersistentNSSDB() {
crypto::EnableTPMTokenForNSS();
}
+void PostResultToTaskRunner(scoped_refptr<base::SequencedTaskRunner> runner,
+ const base::Callback<void(bool)>& callback,
+ bool success) {
+ runner->PostTask(FROM_HERE, base::Bind(callback, success));
+}
+
} // namespace
static TPMTokenLoader* g_tpm_token_loader = NULL;
@@ -197,12 +203,15 @@ void TPMTokenLoader::ContinueTokenInitialization() {
return;
}
case TPM_TOKEN_INFO_RECEIVED: {
- base::PostTaskAndReplyWithResult(
- crypto_task_runner_.get(),
+ crypto_task_runner_->PostTask(
FROM_HERE,
- base::Bind(&crypto::InitializeTPMToken, tpm_token_slot_id_),
- base::Bind(&TPMTokenLoader::OnTPMTokenInitialized,
- weak_factory_.GetWeakPtr()));
+ base::Bind(
+ &crypto::InitializeTPMToken,
+ tpm_token_slot_id_,
+ base::Bind(&PostResultToTaskRunner,
+ base::MessageLoopProxy::current(),
+ base::Bind(&TPMTokenLoader::OnTPMTokenInitialized,
+ weak_factory_.GetWeakPtr()))));
return;
}
case TPM_TOKEN_INITIALIZED: {
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 {