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

Side by Side 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 unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "chrome/browser/chromeos/login/easy_unlock/easy_unlock_tpm_key_manager. h"
6
7 #include "base/base64.h"
8 #include "base/bind.h"
9 #include "base/location.h"
10 #include "base/logging.h"
11 #include "base/memory/ref_counted.h"
12 #include "base/prefs/pref_registry_simple.h"
13 #include "base/prefs/pref_service.h"
14 #include "base/prefs/scoped_user_pref_update.h"
15 #include "base/single_thread_task_runner.h"
16 #include "base/thread_task_runner_handle.h"
17 #include "base/threading/worker_pool.h"
18 #include "base/time/time.h"
19 #include "base/values.h"
20 #include "chrome/browser/browser_process.h"
21 #include "chrome/browser/chromeos/platform_keys/platform_keys.h"
22 #include "chrome/common/pref_names.h"
23 #include "components/pref_registry/pref_registry_syncable.h"
24 #include "crypto/nss_util_internal.h"
25 #include "crypto/rsa_private_key.h"
26 #include "crypto/scoped_nss_types.h"
27
28 namespace {
29
30 // The modulus length for RSA keys used by easy sign-in.
31 const int kKeyModulusLength = 2048;
32
33 // Checks if a private RSA key associated with |public_key| can be found in
34 // |slot|.
35 // Must be called on a worker thread.
36 bool PrivateKeyPresentOnWorkerThread(PK11SlotInfo* slot,
37 const std::string& public_key) {
38 const uint8* public_key_uint8 =
39 reinterpret_cast<const uint8*>(public_key.data());
40 std::vector<uint8> public_key_vector(
41 public_key_uint8, public_key_uint8 + public_key.size());
42
43 scoped_ptr<crypto::RSAPrivateKey> rsa_key(
44 crypto::RSAPrivateKey::FindFromPublicKeyInfo(public_key_vector));
45 return rsa_key && rsa_key->key()->pkcs11Slot == slot;
46 }
47
48 // Creates a RSA key pair in |slot|. When done, it runs |callback| with the
49 // created public key on |response_task_runner|.
50 // If |public_key| is not empty, a key pair will be created only if the private
51 // key associated with |public_key| does not exist in |slot|. Otherwise the
52 // callback will be run with |public_key|.
53 void CreateTpmKeyPairOnWorkerThread(
54 crypto::ScopedPK11Slot slot,
55 const std::string& public_key,
56 const scoped_refptr<base::SingleThreadTaskRunner>& response_task_runner,
57 const base::Callback<void(const std::string&)>& callback) {
58 if (!public_key.empty() &&
59 PrivateKeyPresentOnWorkerThread(slot.get(), public_key)) {
60 response_task_runner->PostTask(FROM_HERE, base::Bind(callback, public_key));
61 return;
62 }
63
64 scoped_ptr<crypto::RSAPrivateKey> rsa_key(
65 crypto::RSAPrivateKey::CreateSensitive(slot.get(), kKeyModulusLength));
66 if (!rsa_key) {
67 LOG(ERROR) << "Failed to create an RSA key.";
68 response_task_runner->PostTask(FROM_HERE,
69 base::Bind(callback, std::string()));
70 return;
71 }
72
73 std::vector<uint8> created_public_key;
74 if (!rsa_key->ExportPublicKey(&created_public_key)) {
75 LOG(ERROR) << "Failed to export public key.";
76 response_task_runner->PostTask(FROM_HERE,
77 base::Bind(callback, std::string()));
78 return;
79 }
80
81 response_task_runner->PostTask(
82 FROM_HERE,
83 base::Bind(callback,
84 std::string(created_public_key.begin(),
85 created_public_key.end())));
86 }
87
88 } // namespace
89
90 // static
91 void EasyUnlockTpmKeyManager::RegisterProfilePrefs(
92 user_prefs::PrefRegistrySyncable* registry) {
93 registry->RegisterStringPref(
94 prefs::kEasyUnlockUserTpmKey,
95 std::string(),
96 user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
97 }
98
99 // static
100 void EasyUnlockTpmKeyManager::RegisterLocalStatePrefs(
101 PrefRegistrySimple* registry) {
102 registry->RegisterDictionaryPref(prefs::kEasyUnlockLocalStateTpmKeys);
103 }
104
105 // static
106 void EasyUnlockTpmKeyManager::ResetLocalStateForUser(
107 const std::string& user_id) {
108 if (!g_browser_process)
109 return;
110 PrefService* local_state = g_browser_process->local_state();
111 if (!local_state)
112 return;
113
114 DictionaryPrefUpdate update(local_state, prefs::kEasyUnlockLocalStateTpmKeys);
115 update->RemoveWithoutPathExpansion(user_id, NULL);
116 }
117
118 EasyUnlockTpmKeyManager::EasyUnlockTpmKeyManager(
119 const std::string& user_id,
120 content::BrowserContext* context,
121 PrefService* user_prefs,
122 PrefService* local_state)
123 : user_id_(user_id),
124 browser_context_(context),
125 user_prefs_(user_prefs),
126 local_state_(local_state),
127 creating_tpm_key_pair_(false),
128 got_tpm_slot_(false),
129 get_tpm_slot_weak_ptr_factory_(this),
130 weak_ptr_factory_(this) {
131 CHECK_EQ(!user_prefs, user_id.empty());
132 }
133
134 EasyUnlockTpmKeyManager::~EasyUnlockTpmKeyManager() {
135 }
136
137 bool EasyUnlockTpmKeyManager::IsTpmKeyPresent(
138 const std::string& user_id,
139 bool check_private_key,
140 const base::Closure& callback) {
141 CHECK(user_prefs_);
142 CHECK_EQ(user_id_, user_id);
143
144 std::string key = GetKeyFromUserPrefs();
145 if (!check_private_key && !creating_tpm_key_pair_ && !key.empty()) {
146 SetKeyInLocalState(user_id, key);
147 return true;
148 }
149
150 tpm_key_present_callbacks_.push_back(callback);
151 if (!creating_tpm_key_pair_) {
152 creating_tpm_key_pair_ = true;
153
154 base::Callback<void(crypto::ScopedPK11Slot)> create_key_with_system_slot =
155 base::Bind(&EasyUnlockTpmKeyManager::CreateKeyInSystemSlot,
156 get_tpm_slot_weak_ptr_factory_.GetWeakPtr(),
157 user_id,
158 key);
159 crypto::ScopedPK11Slot system_slot = crypto::GetSystemNSSKeySlot(
160 create_key_with_system_slot);
161 if (system_slot)
162 create_key_with_system_slot.Run(system_slot.Pass());
163 }
164
165 return false;
166 }
167
168 bool EasyUnlockTpmKeyManager::SetGetSystemSlotTimeoutMs(size_t timeout_ms) {
169 if (got_tpm_slot_)
170 return false;
171
172 base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
173 FROM_HERE,
174 base::Bind(&EasyUnlockTpmKeyManager::OnTpmKeyCreated,
175 get_tpm_slot_weak_ptr_factory_.GetWeakPtr(),
176 user_id_,
177 std::string()),
178 base::TimeDelta::FromMilliseconds(timeout_ms));
179 return true;
180 }
181
182 std::string EasyUnlockTpmKeyManager::GetPublicTpmKey(
183 const std::string& user_id) {
184 if (user_prefs_) {
185 CHECK_EQ(user_id_, user_id);
186 return GetKeyFromUserPrefs();
187 }
188 return GetKeyFromLocalState(user_id);
189 }
190
191 void EasyUnlockTpmKeyManager::SignUsingTpmKey(
192 const std::string& user_id,
193 const std::string& data,
194 const base::Callback<void(const std::string& data)> callback) {
195 std::string key = GetPublicTpmKey(user_id);
196 if (key.empty()) {
197 callback.Run(std::string());
198 return;
199 }
200
201 chromeos::platform_keys::subtle::Sign(
202 chromeos::platform_keys::kTokenIdSystem,
203 key,
204 chromeos::platform_keys::HASH_ALGORITHM_SHA256,
205 data,
206 base::Bind(&EasyUnlockTpmKeyManager::OnDataSigned,
207 weak_ptr_factory_.GetWeakPtr(),
208 callback),
209 browser_context_);
210 }
211
212 std::string EasyUnlockTpmKeyManager::GetKeyFromUserPrefs() {
213 if (!user_prefs_)
214 return std::string();
215 std::string key = user_prefs_->GetString(prefs::kEasyUnlockUserTpmKey);
216 std::string decoded;
217 base::Base64Decode(key, &decoded);
218 return decoded;
219 }
220
221 std::string EasyUnlockTpmKeyManager::GetKeyFromLocalState(
222 const std::string& user_id) {
223 if (!local_state_)
224 return std::string();
225 const base::DictionaryValue* dict =
226 local_state_->GetDictionary(prefs::kEasyUnlockLocalStateTpmKeys);
227 std::string key;
228 if (dict)
229 dict->GetStringWithoutPathExpansion(user_id, &key);
230 std::string decoded;
231 base::Base64Decode(key, &decoded);
232 return decoded;
233 }
234
235 void EasyUnlockTpmKeyManager::SetKeyInLocalState(const std::string& user_id,
236 const std::string& value) {
237 if (!local_state_)
238 return;
239
240 std::string encoded;
241 base::Base64Encode(value, &encoded);
242 DictionaryPrefUpdate update(local_state_,
243 prefs::kEasyUnlockLocalStateTpmKeys);
244 update->SetStringWithoutPathExpansion(user_id, encoded);
245 }
246
247 void EasyUnlockTpmKeyManager::SetKeyInUserPrefs(const std::string& value) {
248 if (!user_prefs_)
249 return;
250
251 std::string encoded;
252 base::Base64Encode(value, &encoded);
253 user_prefs_->SetString(prefs::kEasyUnlockUserTpmKey, encoded);
254 }
255
256 void EasyUnlockTpmKeyManager::CreateKeyInSystemSlot(
257 const std::string& user_id,
258 const std::string& public_key,
259 crypto::ScopedPK11Slot system_slot) {
260 CHECK(system_slot);
261
262 got_tpm_slot_ = true;
263 get_tpm_slot_weak_ptr_factory_.InvalidateWeakPtrs();
264
265 base::WorkerPool::PostTask(
266 FROM_HERE,
267 base::Bind(&CreateTpmKeyPairOnWorkerThread,
268 base::Passed(&system_slot),
269 public_key,
270 base::ThreadTaskRunnerHandle::Get(),
271 base::Bind(&EasyUnlockTpmKeyManager::OnTpmKeyCreated,
272 weak_ptr_factory_.GetWeakPtr(),
273 user_id)),
274 true /* long task */);
275 }
276
277 void EasyUnlockTpmKeyManager::OnTpmKeyCreated(
278 const std::string& user_id,
279 const std::string& public_key) {
280 creating_tpm_key_pair_ = false;
281
282 get_tpm_slot_weak_ptr_factory_.InvalidateWeakPtrs();
283
284 if (!public_key.empty()) {
285 SetKeyInUserPrefs(public_key);
286 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.
287 }
288
289 for (size_t i = 0; i < tpm_key_present_callbacks_.size(); ++i) {
290 if (!tpm_key_present_callbacks_[i].is_null())
291 tpm_key_present_callbacks_[i].Run();
292 }
293
294 tpm_key_present_callbacks_.clear();
295 }
296
297 void EasyUnlockTpmKeyManager::OnDataSigned(
298 const base::Callback<void(const std::string&)>& callback,
299 const std::string& signature,
300 const std::string& error_message) {
301 if (!error_message.empty()) {
302 callback.Run(std::string());
303 return;
304 }
305
306 callback.Run(signature);
307 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698