Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(58)

Unified Diff: crypto/nss_util.cc

Issue 53763003: Initialize per-ChromeOS-user NSS slots and provide the functions to access them. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: fix CertificateManagerBrowserTest Created 7 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « crypto/nss_util.h ('k') | crypto/nss_util_internal.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: crypto/nss_util.cc
diff --git a/crypto/nss_util.cc b/crypto/nss_util.cc
index 82556b44128093b5eeebb68d498f94a6de6309db..5a33b6c3fb9f6bca7fd690561518b01f91303083 100644
--- a/crypto/nss_util.cc
+++ b/crypto/nss_util.cc
@@ -21,8 +21,10 @@
#include <sys/param.h>
#endif
+#include <map>
#include <vector>
+#include "base/callback.h"
#include "base/cpu.h"
#include "base/debug/alias.h"
#include "base/debug/stack_trace.h"
@@ -35,6 +37,7 @@
#include "base/memory/scoped_ptr.h"
#include "base/metrics/histogram.h"
#include "base/native_library.h"
+#include "base/stl_util.h"
#include "base/strings/stringprintf.h"
#include "base/threading/thread_checker.h"
#include "base/threading/thread_restrictions.h"
@@ -89,6 +92,7 @@ base::FilePath GetDefaultConfigDirectory() {
LOG(ERROR) << "Failed to create " << dir.value() << " directory.";
dir.clear();
}
+ DVLOG(2) << "DefaultConfigDirectory: " << dir.value();
return dir;
}
@@ -204,6 +208,58 @@ void CrashOnNSSInitFailure() {
LOG(FATAL) << "nss_error=" << nss_error << ", os_error=" << os_error;
}
+#if defined(OS_CHROMEOS)
+class ChromeOSUserData {
+ public:
+ ChromeOSUserData(ScopedPK11Slot public_slot, bool is_primary_user)
+ : public_slot_(public_slot.Pass()),
+ is_primary_user_(is_primary_user) {}
+ ~ChromeOSUserData() {
+ if (public_slot_ && !is_primary_user_) {
+ SECStatus status = SECMOD_CloseUserDB(public_slot_.get());
+ if (status != SECSuccess)
+ PLOG(ERROR) << "SECMOD_CloseUserDB failed: " << PORT_GetError();
+ }
+ }
+
+ ScopedPK11Slot GetPublicSlot() {
+ return ScopedPK11Slot(
+ public_slot_ ? PK11_ReferenceSlot(public_slot_.get()) : NULL);
+ }
+
+ ScopedPK11Slot GetPrivateSlot(
+ const base::Callback<void(ScopedPK11Slot)>& callback) {
+ if (private_slot_)
+ return ScopedPK11Slot(PK11_ReferenceSlot(private_slot_.get()));
+ if (!callback.is_null())
+ tpm_ready_callback_list_.push_back(callback);
+ return ScopedPK11Slot();
+ }
+
+ void SetPrivateSlot(ScopedPK11Slot private_slot) {
+ DCHECK(!private_slot_);
+ private_slot_ = private_slot.Pass();
+
+ SlotReadyCallbackList callback_list;
+ callback_list.swap(tpm_ready_callback_list_);
+ for (SlotReadyCallbackList::iterator i = callback_list.begin();
+ i != callback_list.end();
+ ++i) {
+ (*i).Run(ScopedPK11Slot(PK11_ReferenceSlot(private_slot_.get())));
+ }
+ }
+
+ private:
+ ScopedPK11Slot public_slot_;
+ ScopedPK11Slot private_slot_;
+ bool is_primary_user_;
+
+ typedef std::vector<base::Callback<void(ScopedPK11Slot)> >
+ SlotReadyCallbackList;
+ SlotReadyCallbackList tpm_ready_callback_list_;
+};
+#endif // defined(OS_CHROMEOS)
+
class NSSInitSingleton {
public:
#if defined(OS_CHROMEOS)
@@ -225,6 +281,21 @@ class NSSInitSingleton {
}
}
+ PK11SlotInfo* OpenPersistentNSSDBForPath(const base::FilePath& path) {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ // NSS is allowed to do IO on the current thread since dispatching
+ // to a dedicated thread would still have the affect of blocking
+ // the current thread, due to NSS's internal locking requirements
+ base::ThreadRestrictions::ScopedAllowIO allow_io;
+
+ base::FilePath nssdb_path = path.AppendASCII(".pki").AppendASCII("nssdb");
+ if (!base::CreateDirectory(nssdb_path)) {
+ LOG(ERROR) << "Failed to create " << nssdb_path.value() << " directory.";
+ return NULL;
+ }
+ return OpenUserDB(nssdb_path, kNSSDatabaseName);
+ }
+
void EnableTPMTokenForNSS() {
DCHECK(thread_checker_.CalledOnValidThread());
@@ -234,6 +305,11 @@ class NSSInitSingleton {
tpm_token_enabled_for_nss_ = true;
}
+ bool IsTPMTokenEnabledForNSS() {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ return tpm_token_enabled_for_nss_;
+ }
+
bool InitializeTPMToken(int token_slot_id) {
DCHECK(thread_checker_.CalledOnValidThread());
@@ -267,19 +343,42 @@ class NSSInitSingleton {
if (chaps_module_){
tpm_slot_ = GetTPMSlotForId(token_slot_id);
- return tpm_slot_ != NULL;
+ if (!tpm_slot_)
+ return false;
+
+ TPMReadyCallbackList callback_list;
+ callback_list.swap(tpm_ready_callback_list_);
+ for (TPMReadyCallbackList::iterator i =
+ callback_list.begin();
+ i != callback_list.end();
+ ++i) {
+ (*i).Run();
+ }
+
+ return true;
}
return false;
}
- bool IsTPMTokenReady() {
- // TODO(mattm): Change to DCHECK when callers have been fixed.
- if (!thread_checker_.CalledOnValidThread()) {
+ bool IsTPMTokenReady(const base::Closure& callback) {
+ if (!callback.is_null()) {
+ // Cannot DCHECK in the general case yet, but since the callback is
+ // a new addition to the API, DCHECK to make sure at least the new uses
+ // don't regress.
+ DCHECK(thread_checker_.CalledOnValidThread());
+ } else if (!thread_checker_.CalledOnValidThread()) {
+ // TODO(mattm): Change to DCHECK when callers have been fixed.
DVLOG(1) << "Called on wrong thread.\n"
<< base::debug::StackTrace().ToString();
}
- return tpm_slot_ != NULL;
+ if (tpm_slot_ != NULL)
+ return true;
+
+ if (!callback.is_null())
+ tpm_ready_callback_list_.push_back(callback);
+
+ return false;
}
// Note that CK_SLOT_ID is an unsigned long, but cryptohome gives us the slot
@@ -291,7 +390,7 @@ class NSSInitSingleton {
if (!chaps_module_)
return NULL;
- VLOG(1) << "Poking chaps module.";
+ DVLOG(3) << "Poking chaps module.";
SECStatus rv = SECMOD_UpdateSlotList(chaps_module_);
if (rv != SECSuccess)
PLOG(ERROR) << "SECMOD_UpdateSlotList failed: " << PORT_GetError();
@@ -301,11 +400,85 @@ class NSSInitSingleton {
LOG(ERROR) << "TPM slot " << slot_id << " not found.";
return slot;
}
+
+ bool InitializeNSSForChromeOSUser(
+ const std::string& email,
+ const std::string& username_hash,
+ bool is_primary_user,
+ const base::FilePath& path) {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ if (chromeos_user_map_.find(username_hash) != chromeos_user_map_.end()) {
+ // This user already exists in our mapping.
+ DVLOG(2) << username_hash << " already initialized.";
+ return false;
+ }
+ ScopedPK11Slot public_slot;
+ if (is_primary_user) {
+ DVLOG(2) << "Primary user, using GetPublicNSSKeySlot()";
+ public_slot.reset(GetPublicNSSKeySlot());
+ } else {
+ DVLOG(2) << "Opening NSS DB " << path.value();
+ public_slot.reset(OpenPersistentNSSDBForPath(path));
+ }
+ chromeos_user_map_[username_hash] =
+ new ChromeOSUserData(public_slot.Pass(), is_primary_user);
+ return true;
+ }
+
+ void InitializeTPMForChromeOSUser(const std::string& username_hash,
+ 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)));
+ }
+
+ void InitializePrivateSoftwareSlotForChromeOSUser(
+ const std::string& username_hash) {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ LOG(WARNING) << "using software private slot for " << username_hash;
+ DCHECK(chromeos_user_map_.find(username_hash) != chromeos_user_map_.end());
+ chromeos_user_map_[username_hash]->SetPrivateSlot(
+ chromeos_user_map_[username_hash]->GetPublicSlot());
+ }
+
+ ScopedPK11Slot GetPublicSlotForChromeOSUser(
+ const std::string& username_hash) {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ if (test_slot_) {
+ DVLOG(2) << "returning test_slot_ for " << username_hash;
+ return ScopedPK11Slot(PK11_ReferenceSlot(test_slot_));
+ }
+
+ if (chromeos_user_map_.find(username_hash) == chromeos_user_map_.end()) {
+ LOG(ERROR) << username_hash << " not initialized.";
+ return ScopedPK11Slot();
+ }
+ return chromeos_user_map_[username_hash]->GetPublicSlot();
+ }
+
+ ScopedPK11Slot GetPrivateSlotForChromeOSUser(
+ const std::string& username_hash,
+ const base::Callback<void(ScopedPK11Slot)>& callback) {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ DCHECK(chromeos_user_map_.find(username_hash) != chromeos_user_map_.end());
+
+ if (test_slot_) {
+ DVLOG(2) << "returning test_slot_ for " << username_hash;
+ return ScopedPK11Slot(PK11_ReferenceSlot(test_slot_));
+ }
+
+ return chromeos_user_map_[username_hash]->GetPrivateSlot(callback);
+ }
#endif // defined(OS_CHROMEOS)
bool OpenTestNSSDB() {
DCHECK(thread_checker_.CalledOnValidThread());
+ // NSS is allowed to do IO on the current thread since dispatching
+ // to a dedicated thread would still have the affect of blocking
+ // the current thread, due to NSS's internal locking requirements
+ base::ThreadRestrictions::ScopedAllowIO allow_io;
if (test_slot_)
return true;
@@ -317,6 +490,10 @@ class NSSInitSingleton {
void CloseTestNSSDB() {
DCHECK(thread_checker_.CalledOnValidThread());
+ // NSS is allowed to do IO on the current thread since dispatching
+ // to a dedicated thread would still have the affect of blocking
+ // the current thread, due to NSS's internal locking requirements
+ base::ThreadRestrictions::ScopedAllowIO allow_io;
if (!test_slot_)
return;
@@ -354,7 +531,7 @@ class NSSInitSingleton {
#if defined(OS_CHROMEOS)
if (tpm_token_enabled_for_nss_) {
- if (IsTPMTokenReady()) {
+ if (IsTPMTokenReady(base::Closure())) {
return PK11_ReferenceSlot(tpm_slot_);
} else {
// If we were supposed to get the hardware token, but were
@@ -505,6 +682,9 @@ class NSSInitSingleton {
// prevent non-joinable threads from using NSS after it's already been shut
// down.
~NSSInitSingleton() {
+#if defined(OS_CHROMEOS)
+ STLDeleteValues(&chromeos_user_map_);
+#endif
if (tpm_slot_) {
PK11_FreeSlot(tpm_slot_);
tpm_slot_ = NULL;
@@ -612,12 +792,18 @@ class NSSInitSingleton {
static bool force_nodb_init_;
bool tpm_token_enabled_for_nss_;
+ typedef std::vector<base::Closure> TPMReadyCallbackList;
+ TPMReadyCallbackList tpm_ready_callback_list_;
SECMODModule* chaps_module_;
PK11SlotInfo* software_slot_;
PK11SlotInfo* test_slot_;
PK11SlotInfo* tpm_slot_;
SECMODModule* root_;
bool chromeos_user_logged_in_;
+#if defined(OS_CHROMEOS)
+ typedef std::map<std::string, ChromeOSUserData*> ChromeOSUserMap;
+ ChromeOSUserMap chromeos_user_map_;
+#endif
#if defined(USE_NSS)
// TODO(davidben): When https://bugzilla.mozilla.org/show_bug.cgi?id=564011
// is fixed, we will no longer need the lock.
@@ -781,13 +967,45 @@ void EnableTPMTokenForNSS() {
g_nss_singleton.Get().EnableTPMTokenForNSS();
}
-bool IsTPMTokenReady() {
- return g_nss_singleton.Get().IsTPMTokenReady();
+bool IsTPMTokenEnabledForNSS() {
+ return g_nss_singleton.Get().IsTPMTokenEnabledForNSS();
+}
+
+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);
}
+
+bool InitializeNSSForChromeOSUser(
+ const std::string& email,
+ const std::string& username_hash,
+ bool is_primary_user,
+ const base::FilePath& path) {
+ return g_nss_singleton.Get().InitializeNSSForChromeOSUser(
+ email, username_hash, is_primary_user, path);
+}
+void InitializeTPMForChromeOSUser(
+ const std::string& username_hash,
+ CK_SLOT_ID slot_id) {
+ g_nss_singleton.Get().InitializeTPMForChromeOSUser(username_hash, slot_id);
+}
+void InitializePrivateSoftwareSlotForChromeOSUser(
+ const std::string& username_hash) {
+ g_nss_singleton.Get().InitializePrivateSoftwareSlotForChromeOSUser(
+ username_hash);
+}
+ScopedPK11Slot GetPublicSlotForChromeOSUser(const std::string& username_hash) {
+ return g_nss_singleton.Get().GetPublicSlotForChromeOSUser(username_hash);
+}
+ScopedPK11Slot GetPrivateSlotForChromeOSUser(
+ const std::string& username_hash,
+ const base::Callback<void(ScopedPK11Slot)>& callback) {
+ return g_nss_singleton.Get().GetPrivateSlotForChromeOSUser(username_hash,
+ callback);
+}
#endif // defined(OS_CHROMEOS)
base::Time PRTimeToBaseTime(PRTime prtime) {
« no previous file with comments | « crypto/nss_util.h ('k') | crypto/nss_util_internal.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698