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.
5 #include "chrome/browser/chromeos/login/extended_authenticator.h"
8 #include "base/strings/string_number_conversions.h"
9 #include "base/strings/string_util.h"
10 #include "chrome/browser/chromeos/boot_times_loader.h"
11 #include "chrome/browser/chromeos/login/login_status_consumer.h"
12 #include "chrome/browser/chromeos/login/parallel_authenticator.h"
13 #include "chromeos/cryptohome/async_method_caller.h"
14 #include "chromeos/cryptohome/cryptohome_parameters.h"
15 #include "chromeos/cryptohome/homedir_methods.h"
16 #include "chromeos/cryptohome/system_salt_getter.h"
17 #include "chromeos/dbus/cryptohome_client.h"
18 #include "chromeos/dbus/dbus_thread_manager.h"
19 #include "content/public/browser/browser_thread.h"
20 #include "crypto/sha2.h"
21 #include "google_apis/gaia/gaia_auth_util.h"
22 #include "third_party/cros_system_api/dbus/service_constants.h"
24 using content::BrowserThread;
30 void RecordStartMarker(const std::string& marker) {
31 std::string full_marker = "Cryptohome-";
32 full_marker.append(marker);
33 full_marker.append("-Start");
34 chromeos::BootTimesLoader::Get()->AddLoginTimeMarker(full_marker, false);
37 void RecordEndMarker(const std::string& marker) {
38 std::string full_marker = "Cryptohome-";
39 full_marker.append(marker);
40 full_marker.append("-End");
41 chromeos::BootTimesLoader::Get()->AddLoginTimeMarker(full_marker, false);
46 ExtendedAuthenticator::ExtendedAuthenticator(AuthStatusConsumer* consumer)
47 : salt_obtained_(false), consumer_(consumer), old_consumer_(NULL) {
48 SystemSaltGetter::Get()->GetSystemSalt(
49 base::Bind(&ExtendedAuthenticator::OnSaltObtained, this));
52 ExtendedAuthenticator::ExtendedAuthenticator(LoginStatusConsumer* consumer)
53 : salt_obtained_(false), consumer_(NULL), old_consumer_(consumer) {
54 SystemSaltGetter::Get()->GetSystemSalt(
55 base::Bind(&ExtendedAuthenticator::OnSaltObtained, this));
58 ExtendedAuthenticator::~ExtendedAuthenticator() {}
60 void ExtendedAuthenticator::SetConsumer(LoginStatusConsumer* consumer) {
61 old_consumer_ = consumer;
64 void ExtendedAuthenticator::OnSaltObtained(const std::string& system_salt) {
65 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
67 salt_obtained_ = true;
68 system_salt_ = system_salt;
69 for (size_t i = 0; i < hashing_queue_.size(); i++) {
70 hashing_queue_[i].Run(system_salt);
72 hashing_queue_.clear();
75 void ExtendedAuthenticator::AuthenticateToMount(
76 const UserContext& context,
77 const HashSuccessCallback& success_callback) {
78 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
79 TransformContext(context,
80 base::Bind(&ExtendedAuthenticator::DoAuthenticateToMount,
85 void ExtendedAuthenticator::AuthenticateToCheck(
86 const UserContext& context,
87 const base::Closure& success_callback) {
88 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
90 TransformContext(context,
91 base::Bind(&ExtendedAuthenticator::DoAuthenticateToCheck,
96 void ExtendedAuthenticator::CreateMount(
97 const std::string& user_id,
98 const std::vector<cryptohome::KeyDefinition>& keys,
99 const HashSuccessCallback& success_callback) {
100 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
102 RecordStartMarker("MountEx");
104 std::string canonicalized = gaia::CanonicalizeEmail(user_id);
105 cryptohome::Identification id(canonicalized);
106 cryptohome::Authorization auth(keys.front());
107 cryptohome::MountParameters mount(false);
108 for (size_t i = 0; i < keys.size(); i++) {
109 mount.create_keys.push_back(keys[i]);
111 UserContext context(user_id, keys.front().key, std::string());
112 context.key_label = keys.front().label;
114 cryptohome::HomedirMethods::GetInstance()->MountEx(
118 base::Bind(&ExtendedAuthenticator::OnMountComplete,
125 void ExtendedAuthenticator::AddKey(const UserContext& context,
126 const cryptohome::KeyDefinition& key,
127 bool replace_existing,
128 const base::Closure& success_callback) {
129 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
130 TransformContext(context,
131 base::Bind(&ExtendedAuthenticator::DoAddKey,
138 void ExtendedAuthenticator::UpdateKeyAuthorized(
139 const UserContext& context,
140 const cryptohome::KeyDefinition& key,
141 const std::string& signature,
142 const base::Closure& success_callback) {
143 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
144 TransformContext(context,
145 base::Bind(&ExtendedAuthenticator::DoUpdateKeyAuthorized,
152 void ExtendedAuthenticator::RemoveKey(const UserContext& context,
153 const std::string& key_to_remove,
154 const base::Closure& success_callback) {
155 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
156 TransformContext(context,
157 base::Bind(&ExtendedAuthenticator::DoRemoveKey,
163 void ExtendedAuthenticator::DoAuthenticateToMount(
164 const HashSuccessCallback& success_callback,
165 const UserContext& user_context) {
166 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
168 RecordStartMarker("MountEx");
170 std::string canonicalized = gaia::CanonicalizeEmail(user_context.username);
171 cryptohome::Identification id(canonicalized);
172 cryptohome::Authorization auth(user_context.password, user_context.key_label);
173 cryptohome::MountParameters mount(false);
175 cryptohome::HomedirMethods::GetInstance()->MountEx(
179 base::Bind(&ExtendedAuthenticator::OnMountComplete,
186 void ExtendedAuthenticator::DoAuthenticateToCheck(
187 const base::Closure& success_callback,
188 const UserContext& user_context) {
189 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
191 RecordStartMarker("CheckKeyEx");
193 std::string canonicalized = gaia::CanonicalizeEmail(user_context.username);
194 cryptohome::Identification id(canonicalized);
195 cryptohome::Authorization auth(user_context.password, user_context.key_label);
197 cryptohome::HomedirMethods::GetInstance()->CheckKeyEx(
200 base::Bind(&ExtendedAuthenticator::OnOperationComplete,
207 void ExtendedAuthenticator::DoAddKey(const cryptohome::KeyDefinition& key,
208 bool replace_existing,
209 const base::Closure& success_callback,
210 const UserContext& user_context) {
211 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
213 RecordStartMarker("AddKeyEx");
215 std::string canonicalized = gaia::CanonicalizeEmail(user_context.username);
216 cryptohome::Identification id(canonicalized);
217 cryptohome::Authorization auth(user_context.password, user_context.key_label);
219 cryptohome::HomedirMethods::GetInstance()->AddKeyEx(
224 base::Bind(&ExtendedAuthenticator::OnOperationComplete,
231 void ExtendedAuthenticator::DoUpdateKeyAuthorized(
232 const cryptohome::KeyDefinition& key,
233 const std::string& signature,
234 const base::Closure& success_callback,
235 const UserContext& user_context) {
236 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
237 RecordStartMarker("UpdateKeyAuthorized");
239 std::string canonicalized = gaia::CanonicalizeEmail(user_context.username);
240 cryptohome::Identification id(canonicalized);
241 cryptohome::Authorization auth(user_context.password, user_context.key_label);
243 cryptohome::HomedirMethods::GetInstance()->UpdateKeyEx(
248 base::Bind(&ExtendedAuthenticator::OnOperationComplete,
250 "UpdateKeyAuthorized",
255 void ExtendedAuthenticator::DoRemoveKey(const std::string& key_to_remove,
256 const base::Closure& success_callback,
257 const UserContext& user_context) {
258 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
260 RecordStartMarker("RemoveKeyEx");
262 std::string canonicalized = gaia::CanonicalizeEmail(user_context.username);
263 cryptohome::Identification id(canonicalized);
264 cryptohome::Authorization auth(user_context.password, user_context.key_label);
266 cryptohome::HomedirMethods::GetInstance()->RemoveKeyEx(
270 base::Bind(&ExtendedAuthenticator::OnOperationComplete,
277 void ExtendedAuthenticator::OnMountComplete(
278 const std::string& time_marker,
279 const UserContext& user_context,
280 const HashSuccessCallback& success_callback,
282 cryptohome::MountError return_code,
283 const std::string& mount_hash) {
284 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
286 RecordEndMarker(time_marker);
288 copy.CopyFrom(user_context);
289 copy.username_hash = mount_hash;
290 if (return_code == cryptohome::MOUNT_ERROR_NONE) {
291 success_callback.Run(mount_hash);
293 old_consumer_->OnLoginSuccess(copy);
296 AuthState state = FAILED_MOUNT;
297 if (return_code == cryptohome::MOUNT_ERROR_TPM_COMM_ERROR ||
298 return_code == cryptohome::MOUNT_ERROR_TPM_DEFEND_LOCK ||
299 return_code == cryptohome::MOUNT_ERROR_TPM_NEEDS_REBOOT) {
302 if (return_code == cryptohome::MOUNT_ERROR_USER_DOES_NOT_EXIST) {
306 consumer_->OnAuthenticationFailure(state);
308 LoginFailure failure(LoginFailure::COULD_NOT_MOUNT_CRYPTOHOME);
309 old_consumer_->OnLoginFailure(failure);
313 void ExtendedAuthenticator::OnOperationComplete(
314 const std::string& time_marker,
315 const UserContext& user_context,
316 const base::Closure& success_callback,
318 cryptohome::MountError return_code) {
319 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
321 RecordEndMarker(time_marker);
322 if (return_code == cryptohome::MOUNT_ERROR_NONE) {
323 success_callback.Run();
325 old_consumer_->OnLoginSuccess(user_context);
329 AuthState state = FAILED_MOUNT;
331 if (return_code == cryptohome::MOUNT_ERROR_TPM_COMM_ERROR ||
332 return_code == cryptohome::MOUNT_ERROR_TPM_DEFEND_LOCK ||
333 return_code == cryptohome::MOUNT_ERROR_TPM_NEEDS_REBOOT) {
337 if (return_code == cryptohome::MOUNT_ERROR_USER_DOES_NOT_EXIST)
341 consumer_->OnAuthenticationFailure(state);
344 LoginFailure failure(LoginFailure::UNLOCK_FAILED);
345 old_consumer_->OnLoginFailure(failure);
349 void ExtendedAuthenticator::HashPasswordWithSalt(
350 const std::string& password,
351 const HashSuccessCallback& success_callback) {
352 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
353 DCHECK(consumer_) << "This is a part of new API";
355 DoHashWithSalt(password, success_callback, system_salt_);
358 void ExtendedAuthenticator::TransformContext(const UserContext& user_context,
359 const ContextCallback& callback) {
360 if (!user_context.need_password_hashing) {
361 callback.Run(user_context);
363 DoHashWithSalt(user_context.password,
364 base::Bind(&ExtendedAuthenticator::DidTransformContext,
372 void ExtendedAuthenticator::DidTransformContext(
373 const UserContext& user_context,
374 const ContextCallback& callback,
375 const std::string& hashed_password) {
376 DCHECK(user_context.need_password_hashing);
378 context.CopyFrom(user_context);
379 context.password = hashed_password;
380 context.need_password_hashing = false;
381 callback.Run(context);
384 void ExtendedAuthenticator::DoHashWithSalt(const std::string& password,
385 const HashSuccessCallback& callback,
386 const std::string& system_salt) {
387 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
389 if (salt_obtained_) {
391 ParallelAuthenticator::HashPassword(password, system_salt);
395 hashing_queue_.push_back(base::Bind(
396 &ExtendedAuthenticator::DoHashWithSalt, this, password, callback));
399 } // namespace chromeos