Index: crypto/nss_util.cc |
diff --git a/crypto/nss_util.cc b/crypto/nss_util.cc |
index 3ecedf63a48fd51aa73652fdb0725a0e42c46fec..aacbbb8c540fd3878011fedb7ad4c3912bbd1f9c 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/debug/alias.h" |
#include "base/debug/stack_trace.h" |
#include "base/environment.h" |
@@ -34,6 +36,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" |
@@ -88,6 +91,7 @@ base::FilePath GetDefaultConfigDirectory() { |
LOG(ERROR) << "Failed to create " << dir.value() << " directory."; |
dir.clear(); |
} |
+ VLOG(1) << "DefaultConfigDirectory: " << dir.value(); |
return dir; |
} |
@@ -215,6 +219,65 @@ 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() { |
+ // Don't close when NSS is < 3.15.1, because it would require an additional |
+ // sleep for 1 second after closing the database, due to |
+ // http://bugzil.la/875601. |
+ if (NSS_VersionCheck("3.15.1")) { |
+ if (public_slot_ && !is_primary_user_) { |
+ SECStatus status = SECMOD_CloseUserDB(public_slot_.get()); |
+ if (status != SECSuccess) |
+ PLOG(ERROR) << "SECMOD_CloseUserDB failed: " << PORT_GetError(); |
Ryan Sleevi
2013/11/27 00:24:11
ChromeOS is always at 3.15.1 now, soon to be at 3.
mattm
2013/11/27 04:12:23
Done.
|
+ } |
+ } |
+ } |
+ |
+ ScopedPK11Slot GetPublicSlot() { |
+ return ScopedPK11Slot(public_slot_ ? PK11_ReferenceSlot(public_slot_.get()) |
+ : NULL); |
+ } |
+ |
+ ScopedPK11Slot GetPrivateSlot() { |
+ return ScopedPK11Slot( |
+ private_slot_ ? PK11_ReferenceSlot(private_slot_.get()) : NULL); |
Ryan Sleevi
2013/11/27 00:24:11
Why the differing indent style compared with 241?
mattm
2013/11/27 04:12:23
That's what clang-format decided to do, this one w
|
+ } |
+ |
+ void OnPrivateSlotReady( |
+ const base::Callback<void(ScopedPK11Slot)>& callback) { |
+ if (private_slot_) |
+ callback.Run(GetPrivateSlot()); |
+ else |
+ tpm_ready_callback_list_.push_back(callback); |
+ } |
+ |
+ void SetPrivateSlot(ScopedPK11Slot private_slot) { |
+ DCHECK(!private_slot_); |
+ private_slot_ = private_slot.Pass(); |
+ |
+ for (SlotReadyCallbackList::iterator i = tpm_ready_callback_list_.begin(); |
+ i != tpm_ready_callback_list_.end(); |
+ ++i) { |
+ (*i).Run(GetPrivateSlot()); |
+ } |
+ tpm_ready_callback_list_.clear(); |
Ryan Sleevi
2013/11/27 00:24:11
DANGER: This strikes me as a dangerous pattern, in
mattm
2013/11/27 04:12:23
Good call. Done.
|
+ } |
+ |
+ 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) |
@@ -236,6 +299,20 @@ class NSSInitSingleton { |
} |
} |
+ PK11SlotInfo* OpenPersistentNSSDBForPath(const base::FilePath& path) { |
+ DCHECK(thread_checker_.CalledOnValidThread()); |
+ VLOG(1) << __func__ << " " << path.value(); |
+ // We do NSS file io on the IO thread. |
+ base::ThreadRestrictions::ScopedAllowIO allow_io; |
+ |
+ base::FilePath nssdb_path = path.AppendASCII(".pki").AppendASCII("nssdb"); |
+ if (!file_util::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()); |
@@ -245,6 +322,11 @@ class NSSInitSingleton { |
tpm_token_enabled_for_nss_ = true; |
} |
+ bool IsTPMTokenEnabledForNSS() { |
+ DCHECK(thread_checker_.CalledOnValidThread()); |
+ return tpm_token_enabled_for_nss_; |
+ } |
+ |
bool InitializeTPMToken(const std::string& token_name, |
int token_slot_id, |
const std::string& user_pin) { |
@@ -283,6 +365,16 @@ class NSSInitSingleton { |
if (chaps_module_){ |
tpm_slot_ = GetTPMSlotForId(token_slot_id); |
+ if (tpm_slot_) { |
+ for (TPMReadyCallbackList::iterator i = |
+ tpm_ready_callback_list_.begin(); |
+ i != tpm_ready_callback_list_.end(); |
+ ++i) { |
+ (*i).Run(); |
+ } |
+ tpm_ready_callback_list_.clear(); |
Ryan Sleevi
2013/11/27 00:24:11
Ditto RE: danger.
I'm also not thrilled with the
mattm
2013/11/27 04:12:23
Done.
|
+ } |
+ |
return tpm_slot_ != NULL; |
} |
return false; |
@@ -315,6 +407,14 @@ class NSSInitSingleton { |
return tpm_slot_ != NULL; |
} |
+ void OnTPMReady(const base::Closure& callback) { |
+ DCHECK(thread_checker_.CalledOnValidThread()); |
+ if (IsTPMTokenReady()) |
+ callback.Run(); |
+ else |
+ tpm_ready_callback_list_.push_back(callback); |
+ } |
+ |
// 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. |
@@ -334,6 +434,80 @@ 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. |
+ VLOG(1) << username_hash << " already initialized."; |
Ryan Sleevi
2013/11/27 00:24:11
Way too chatty logging
mattm
2013/11/27 04:12:23
Changed things to DVLOG(2). These ones shouldn't a
|
+ return false; |
+ } |
+ ScopedPK11Slot public_slot; |
+ if (is_primary_user) { |
+ VLOG(1) << "Primary user, using GetPublicNSSKeySlot()"; |
+ public_slot.reset(GetPublicNSSKeySlot()); |
+ } else { |
+ VLOG(1) << "Opening NSS DB"; |
+ 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_) { |
+ VLOG(1) << "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(); |
+ } |
+ |
+ void OnPrivateSlotReadyForChromeOSUser( |
+ const std::string& username_hash, |
+ const base::Callback<void(ScopedPK11Slot)>& callback) { |
+ DCHECK(thread_checker_.CalledOnValidThread()); |
+ if (test_slot_) { |
+ VLOG(1) << "returning test_slot_ for " << username_hash; |
+ callback.Run(ScopedPK11Slot(PK11_ReferenceSlot(test_slot_))); |
+ return; |
+ } |
+ |
+ if (chromeos_user_map_.find(username_hash) == chromeos_user_map_.end()) { |
+ LOG(ERROR) << username_hash << " not initialized."; |
+ callback.Run(ScopedPK11Slot()); |
+ return; |
+ } |
+ chromeos_user_map_[username_hash]->OnPrivateSlotReady(callback); |
+ } |
#endif // defined(OS_CHROMEOS) |
@@ -536,6 +710,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; |
@@ -630,12 +807,18 @@ class NSSInitSingleton { |
bool tpm_token_enabled_for_nss_; |
std::string tpm_token_name_; |
std::string tpm_user_pin_; |
+ 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. |
@@ -799,6 +982,10 @@ void EnableTPMTokenForNSS() { |
g_nss_singleton.Get().EnableTPMTokenForNSS(); |
} |
+bool IsTPMTokenEnabledForNSS() { |
+ return g_nss_singleton.Get().IsTPMTokenEnabledForNSS(); |
+} |
+ |
void GetTPMTokenInfo(std::string* token_name, std::string* user_pin) { |
g_nss_singleton.Get().GetTPMTokenInfo(token_name, user_pin); |
} |
@@ -807,12 +994,44 @@ bool IsTPMTokenReady() { |
return g_nss_singleton.Get().IsTPMTokenReady(); |
} |
+void OnTPMReady(const base::Closure& callback) { |
+ g_nss_singleton.Get().OnTPMReady(callback); |
+} |
+ |
bool InitializeTPMToken(const std::string& token_name, |
int token_slot_id, |
const std::string& user_pin) { |
return g_nss_singleton.Get().InitializeTPMToken( |
token_name, token_slot_id, user_pin); |
} |
+ |
+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); |
+} |
+void OnPrivateSlotReadyForChromeOSUser( |
+ const std::string& username_hash, |
+ const base::Callback<void(ScopedPK11Slot)>& callback) { |
+ g_nss_singleton.Get().OnPrivateSlotReadyForChromeOSUser(username_hash, |
+ callback); |
+} |
#endif // defined(OS_CHROMEOS) |
base::Time PRTimeToBaseTime(PRTime prtime) { |