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

Unified Diff: chrome/browser/chromeos/login/easy_unlock/easy_unlock_tpm_key_manager.cc

Issue 729803002: Easy Sign-in: Use TPM RSA key to sign nonce in sign-in protocol (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: . Created 6 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
Index: chrome/browser/chromeos/login/easy_unlock/easy_unlock_tpm_key_manager.cc
diff --git a/chrome/browser/chromeos/login/easy_unlock/easy_unlock_tpm_key_manager.cc b/chrome/browser/chromeos/login/easy_unlock/easy_unlock_tpm_key_manager.cc
new file mode 100644
index 0000000000000000000000000000000000000000..cd3ed9be54161163d99223a43580f45ab7a59426
--- /dev/null
+++ b/chrome/browser/chromeos/login/easy_unlock/easy_unlock_tpm_key_manager.cc
@@ -0,0 +1,307 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/chromeos/login/easy_unlock/easy_unlock_tpm_key_manager.h"
+
+#include "base/base64.h"
+#include "base/bind.h"
+#include "base/location.h"
+#include "base/logging.h"
+#include "base/memory/ref_counted.h"
+#include "base/prefs/pref_registry_simple.h"
+#include "base/prefs/pref_service.h"
+#include "base/prefs/scoped_user_pref_update.h"
+#include "base/single_thread_task_runner.h"
+#include "base/thread_task_runner_handle.h"
+#include "base/threading/worker_pool.h"
+#include "base/time/time.h"
+#include "base/values.h"
+#include "chrome/browser/browser_process.h"
+#include "chrome/browser/chromeos/platform_keys/platform_keys.h"
+#include "chrome/common/pref_names.h"
+#include "components/pref_registry/pref_registry_syncable.h"
+#include "crypto/nss_util_internal.h"
+#include "crypto/rsa_private_key.h"
+#include "crypto/scoped_nss_types.h"
+
+namespace {
+
+// The modulus length for RSA keys used by easy sign-in.
+const int kKeyModulusLength = 2048;
+
+// Checks if a private RSA key associated with |public_key| can be found in
+// |slot|.
+// Must be called on a worker thread.
+bool PrivateKeyPresentOnWorkerThread(PK11SlotInfo* slot,
+ const std::string& public_key) {
+ const uint8* public_key_uint8 =
+ reinterpret_cast<const uint8*>(public_key.data());
+ std::vector<uint8> public_key_vector(
+ public_key_uint8, public_key_uint8 + public_key.size());
+
+ scoped_ptr<crypto::RSAPrivateKey> rsa_key(
+ crypto::RSAPrivateKey::FindFromPublicKeyInfo(public_key_vector));
+ return rsa_key && rsa_key->key()->pkcs11Slot == slot;
+}
+
+// Creates a RSA key pair in |slot|. When done, it runs |callback| with the
+// created public key on |response_task_runner|.
+// If |public_key| is not empty, a key pair will be created only if the private
+// key associated with |public_key| does not exist in |slot|. Otherwise the
+// callback will be run with |public_key|.
+void CreateTpmKeyPairOnWorkerThread(
+ crypto::ScopedPK11Slot slot,
+ const std::string& public_key,
+ const scoped_refptr<base::SingleThreadTaskRunner>& response_task_runner,
+ const base::Callback<void(const std::string&)>& callback) {
+ if (!public_key.empty() &&
+ PrivateKeyPresentOnWorkerThread(slot.get(), public_key)) {
+ response_task_runner->PostTask(FROM_HERE, base::Bind(callback, public_key));
+ return;
+ }
+
+ scoped_ptr<crypto::RSAPrivateKey> rsa_key(
+ crypto::RSAPrivateKey::CreateSensitive(slot.get(), kKeyModulusLength));
+ if (!rsa_key) {
+ LOG(ERROR) << "Failed to create an RSA key.";
+ response_task_runner->PostTask(FROM_HERE,
+ base::Bind(callback, std::string()));
+ return;
+ }
+
+ std::vector<uint8> created_public_key;
+ if (!rsa_key->ExportPublicKey(&created_public_key)) {
+ LOG(ERROR) << "Failed to export public key.";
+ response_task_runner->PostTask(FROM_HERE,
+ base::Bind(callback, std::string()));
+ return;
+ }
+
+ response_task_runner->PostTask(
+ FROM_HERE,
+ base::Bind(callback,
+ std::string(created_public_key.begin(),
+ created_public_key.end())));
+}
+
+} // namespace
+
+// static
+void EasyUnlockTpmKeyManager::RegisterProfilePrefs(
+ user_prefs::PrefRegistrySyncable* registry) {
+ registry->RegisterStringPref(
+ prefs::kEasyUnlockUserTpmKey,
+ std::string(),
+ user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
+}
+
+// static
+void EasyUnlockTpmKeyManager::RegisterLocalStatePrefs(
+ PrefRegistrySimple* registry) {
+ registry->RegisterDictionaryPref(prefs::kEasyUnlockLocalStateTpmKeys);
+}
+
+// static
+void EasyUnlockTpmKeyManager::ResetLocalStateForUser(
+ const std::string& user_id) {
+ if (!g_browser_process)
+ return;
+ PrefService* local_state = g_browser_process->local_state();
+ if (!local_state)
+ return;
+
+ DictionaryPrefUpdate update(local_state, prefs::kEasyUnlockLocalStateTpmKeys);
+ update->RemoveWithoutPathExpansion(user_id, NULL);
+}
+
+EasyUnlockTpmKeyManager::EasyUnlockTpmKeyManager(
+ const std::string& user_id,
+ content::BrowserContext* context,
+ PrefService* user_prefs,
+ PrefService* local_state)
+ : user_id_(user_id),
+ browser_context_(context),
+ user_prefs_(user_prefs),
+ local_state_(local_state),
+ creating_tpm_key_pair_(false),
+ got_tpm_slot_(false),
+ get_tpm_slot_weak_ptr_factory_(this),
+ weak_ptr_factory_(this) {
+ CHECK_EQ(!user_prefs, user_id.empty());
+}
+
+EasyUnlockTpmKeyManager::~EasyUnlockTpmKeyManager() {
+}
+
+bool EasyUnlockTpmKeyManager::IsTpmKeyPresent(
+ const std::string& user_id,
+ bool check_private_key,
+ const base::Closure& callback) {
+ CHECK(user_prefs_);
+ CHECK_EQ(user_id_, user_id);
+
+ std::string key = GetKeyFromUserPrefs();
+ if (!check_private_key && !creating_tpm_key_pair_ && !key.empty()) {
+ SetKeyInLocalState(user_id, key);
+ return true;
+ }
+
+ tpm_key_present_callbacks_.push_back(callback);
+ if (!creating_tpm_key_pair_) {
+ creating_tpm_key_pair_ = true;
+
+ base::Callback<void(crypto::ScopedPK11Slot)> create_key_with_system_slot =
+ base::Bind(&EasyUnlockTpmKeyManager::CreateKeyInSystemSlot,
+ get_tpm_slot_weak_ptr_factory_.GetWeakPtr(),
+ user_id,
+ key);
+ crypto::ScopedPK11Slot system_slot = crypto::GetSystemNSSKeySlot(
+ create_key_with_system_slot);
+ if (system_slot)
+ create_key_with_system_slot.Run(system_slot.Pass());
+ }
+
+ return false;
+}
+
+bool EasyUnlockTpmKeyManager::SetGetSystemSlotTimeoutMs(size_t timeout_ms) {
+ if (got_tpm_slot_)
+ return false;
+
+ base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
+ FROM_HERE,
+ base::Bind(&EasyUnlockTpmKeyManager::OnTpmKeyCreated,
+ get_tpm_slot_weak_ptr_factory_.GetWeakPtr(),
+ user_id_,
+ std::string()),
+ base::TimeDelta::FromMilliseconds(timeout_ms));
+ return true;
+}
+
+std::string EasyUnlockTpmKeyManager::GetPublicTpmKey(
+ const std::string& user_id) {
+ if (user_prefs_) {
+ CHECK_EQ(user_id_, user_id);
+ return GetKeyFromUserPrefs();
+ }
+ return GetKeyFromLocalState(user_id);
+}
+
+void EasyUnlockTpmKeyManager::SignUsingTpmKey(
+ const std::string& user_id,
+ const std::string& data,
+ const base::Callback<void(const std::string& data)> callback) {
+ std::string key = GetPublicTpmKey(user_id);
+ if (key.empty()) {
+ callback.Run(std::string());
+ return;
+ }
+
+ chromeos::platform_keys::subtle::Sign(
+ chromeos::platform_keys::kTokenIdSystem,
+ key,
+ chromeos::platform_keys::HASH_ALGORITHM_SHA256,
+ data,
+ base::Bind(&EasyUnlockTpmKeyManager::OnDataSigned,
+ weak_ptr_factory_.GetWeakPtr(),
+ callback),
+ browser_context_);
+}
+
+std::string EasyUnlockTpmKeyManager::GetKeyFromUserPrefs() {
+ if (!user_prefs_)
+ return std::string();
+ std::string key = user_prefs_->GetString(prefs::kEasyUnlockUserTpmKey);
+ std::string decoded;
+ base::Base64Decode(key, &decoded);
+ return decoded;
+}
+
+std::string EasyUnlockTpmKeyManager::GetKeyFromLocalState(
+ const std::string& user_id) {
+ if (!local_state_)
+ return std::string();
+ const base::DictionaryValue* dict =
+ local_state_->GetDictionary(prefs::kEasyUnlockLocalStateTpmKeys);
+ std::string key;
+ if (dict)
+ dict->GetStringWithoutPathExpansion(user_id, &key);
+ std::string decoded;
+ base::Base64Decode(key, &decoded);
+ return decoded;
+}
+
+void EasyUnlockTpmKeyManager::SetKeyInLocalState(const std::string& user_id,
+ const std::string& value) {
+ if (!local_state_)
+ return;
+
+ std::string encoded;
+ base::Base64Encode(value, &encoded);
+ DictionaryPrefUpdate update(local_state_,
+ prefs::kEasyUnlockLocalStateTpmKeys);
+ update->SetStringWithoutPathExpansion(user_id, encoded);
+}
+
+void EasyUnlockTpmKeyManager::SetKeyInUserPrefs(const std::string& value) {
+ if (!user_prefs_)
+ return;
+
+ std::string encoded;
+ base::Base64Encode(value, &encoded);
+ user_prefs_->SetString(prefs::kEasyUnlockUserTpmKey, encoded);
+}
+
+void EasyUnlockTpmKeyManager::CreateKeyInSystemSlot(
+ const std::string& user_id,
+ const std::string& public_key,
+ crypto::ScopedPK11Slot system_slot) {
+ CHECK(system_slot);
+
+ got_tpm_slot_ = true;
+ get_tpm_slot_weak_ptr_factory_.InvalidateWeakPtrs();
+
+ base::WorkerPool::PostTask(
+ FROM_HERE,
+ base::Bind(&CreateTpmKeyPairOnWorkerThread,
+ base::Passed(&system_slot),
+ public_key,
+ base::ThreadTaskRunnerHandle::Get(),
+ base::Bind(&EasyUnlockTpmKeyManager::OnTpmKeyCreated,
+ weak_ptr_factory_.GetWeakPtr(),
+ user_id)),
+ true /* long task */);
+}
+
+void EasyUnlockTpmKeyManager::OnTpmKeyCreated(
+ const std::string& user_id,
+ const std::string& public_key) {
+ creating_tpm_key_pair_ = false;
+
+ get_tpm_slot_weak_ptr_factory_.InvalidateWeakPtrs();
+
+ if (!public_key.empty()) {
+ SetKeyInUserPrefs(public_key);
+ SetKeyInLocalState(user_id, public_key);
xiyuan 2014/12/02 23:15:58 Since the private key is protected in TPM, can we
tbarzic 2014/12/03 19:10:28 yeah, sounds reasonable.. Done.
+ }
+
+ for (size_t i = 0; i < tpm_key_present_callbacks_.size(); ++i) {
+ if (!tpm_key_present_callbacks_[i].is_null())
+ tpm_key_present_callbacks_[i].Run();
+ }
+
+ tpm_key_present_callbacks_.clear();
+}
+
+void EasyUnlockTpmKeyManager::OnDataSigned(
+ const base::Callback<void(const std::string&)>& callback,
+ const std::string& signature,
+ const std::string& error_message) {
+ if (!error_message.empty()) {
+ callback.Run(std::string());
+ return;
+ }
+
+ callback.Run(signature);
+}

Powered by Google App Engine
This is Rietveld 408576698