• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/auth/extended_authenticator.h"
6 
7 #include "base/bind.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/auth/key.h"
12 #include "chrome/browser/chromeos/login/auth/login_status_consumer.h"
13 #include "chrome/browser/chromeos/login/auth/user_context.h"
14 #include "chromeos/cryptohome/async_method_caller.h"
15 #include "chromeos/cryptohome/cryptohome_parameters.h"
16 #include "chromeos/cryptohome/homedir_methods.h"
17 #include "chromeos/cryptohome/system_salt_getter.h"
18 #include "chromeos/dbus/cryptohome_client.h"
19 #include "chromeos/dbus/dbus_thread_manager.h"
20 #include "content/public/browser/browser_thread.h"
21 #include "crypto/sha2.h"
22 #include "google_apis/gaia/gaia_auth_util.h"
23 #include "third_party/cros_system_api/dbus/service_constants.h"
24 
25 using content::BrowserThread;
26 
27 namespace chromeos {
28 
29 namespace {
30 
RecordStartMarker(const std::string & marker)31 void RecordStartMarker(const std::string& marker) {
32   std::string full_marker = "Cryptohome-";
33   full_marker.append(marker);
34   full_marker.append("-Start");
35   chromeos::BootTimesLoader::Get()->AddLoginTimeMarker(full_marker, false);
36 }
37 
RecordEndMarker(const std::string & marker)38 void RecordEndMarker(const std::string& marker) {
39   std::string full_marker = "Cryptohome-";
40   full_marker.append(marker);
41   full_marker.append("-End");
42   chromeos::BootTimesLoader::Get()->AddLoginTimeMarker(full_marker, false);
43 }
44 
45 }  // namespace
46 
ExtendedAuthenticator(AuthStatusConsumer * consumer)47 ExtendedAuthenticator::ExtendedAuthenticator(AuthStatusConsumer* consumer)
48     : salt_obtained_(false), consumer_(consumer), old_consumer_(NULL) {
49   SystemSaltGetter::Get()->GetSystemSalt(
50       base::Bind(&ExtendedAuthenticator::OnSaltObtained, this));
51 }
52 
ExtendedAuthenticator(LoginStatusConsumer * consumer)53 ExtendedAuthenticator::ExtendedAuthenticator(LoginStatusConsumer* consumer)
54     : salt_obtained_(false), consumer_(NULL), old_consumer_(consumer) {
55   SystemSaltGetter::Get()->GetSystemSalt(
56       base::Bind(&ExtendedAuthenticator::OnSaltObtained, this));
57 }
58 
SetConsumer(LoginStatusConsumer * consumer)59 void ExtendedAuthenticator::SetConsumer(LoginStatusConsumer* consumer) {
60   old_consumer_ = consumer;
61 }
62 
AuthenticateToMount(const UserContext & context,const ResultCallback & success_callback)63 void ExtendedAuthenticator::AuthenticateToMount(
64     const UserContext& context,
65     const ResultCallback& success_callback) {
66   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
67   TransformKeyIfNeeded(context,
68                        base::Bind(&ExtendedAuthenticator::DoAuthenticateToMount,
69                                   this,
70                                   success_callback));
71 }
72 
AuthenticateToCheck(const UserContext & context,const base::Closure & success_callback)73 void ExtendedAuthenticator::AuthenticateToCheck(
74     const UserContext& context,
75     const base::Closure& success_callback) {
76   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
77   TransformKeyIfNeeded(context,
78                        base::Bind(&ExtendedAuthenticator::DoAuthenticateToCheck,
79                                   this,
80                                   success_callback));
81 }
82 
CreateMount(const std::string & user_id,const std::vector<cryptohome::KeyDefinition> & keys,const ResultCallback & success_callback)83 void ExtendedAuthenticator::CreateMount(
84     const std::string& user_id,
85     const std::vector<cryptohome::KeyDefinition>& keys,
86     const ResultCallback& success_callback) {
87   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
88 
89   RecordStartMarker("MountEx");
90 
91   std::string canonicalized = gaia::CanonicalizeEmail(user_id);
92   cryptohome::Identification id(canonicalized);
93   cryptohome::Authorization auth(keys.front());
94   cryptohome::MountParameters mount(false);
95   for (size_t i = 0; i < keys.size(); i++) {
96     mount.create_keys.push_back(keys[i]);
97   }
98   UserContext context(user_id);
99   Key key(keys.front().key);
100   key.SetLabel(keys.front().label);
101   context.SetKey(key);
102 
103   cryptohome::HomedirMethods::GetInstance()->MountEx(
104       id,
105       auth,
106       mount,
107       base::Bind(&ExtendedAuthenticator::OnMountComplete,
108                  this,
109                  "MountEx",
110                  context,
111                  success_callback));
112 }
113 
AddKey(const UserContext & context,const cryptohome::KeyDefinition & key,bool replace_existing,const base::Closure & success_callback)114 void ExtendedAuthenticator::AddKey(const UserContext& context,
115                                    const cryptohome::KeyDefinition& key,
116                                    bool replace_existing,
117                                    const base::Closure& success_callback) {
118   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
119   TransformKeyIfNeeded(context,
120                        base::Bind(&ExtendedAuthenticator::DoAddKey,
121                                   this,
122                                   key,
123                                   replace_existing,
124                                   success_callback));
125 }
126 
UpdateKeyAuthorized(const UserContext & context,const cryptohome::KeyDefinition & key,const std::string & signature,const base::Closure & success_callback)127 void ExtendedAuthenticator::UpdateKeyAuthorized(
128     const UserContext& context,
129     const cryptohome::KeyDefinition& key,
130     const std::string& signature,
131     const base::Closure& success_callback) {
132   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
133   TransformKeyIfNeeded(context,
134                        base::Bind(&ExtendedAuthenticator::DoUpdateKeyAuthorized,
135                                   this,
136                                   key,
137                                   signature,
138                                   success_callback));
139 }
140 
RemoveKey(const UserContext & context,const std::string & key_to_remove,const base::Closure & success_callback)141 void ExtendedAuthenticator::RemoveKey(const UserContext& context,
142                                       const std::string& key_to_remove,
143                                       const base::Closure& success_callback) {
144   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
145   TransformKeyIfNeeded(context,
146                        base::Bind(&ExtendedAuthenticator::DoRemoveKey,
147                                   this,
148                                   key_to_remove,
149                                   success_callback));
150 }
151 
TransformKeyIfNeeded(const UserContext & user_context,const ContextCallback & callback)152 void ExtendedAuthenticator::TransformKeyIfNeeded(
153     const UserContext& user_context,
154     const ContextCallback& callback) {
155   if (user_context.GetKey()->GetKeyType() != Key::KEY_TYPE_PASSWORD_PLAIN) {
156     callback.Run(user_context);
157     return;
158   }
159 
160   if (!salt_obtained_) {
161     system_salt_callbacks_.push_back(base::Bind(
162         &ExtendedAuthenticator::TransformKeyIfNeeded,
163         this,
164         user_context,
165         callback));
166     return;
167   }
168 
169   UserContext transformed_context = user_context;
170   transformed_context.GetKey()->Transform(Key::KEY_TYPE_SALTED_SHA256_TOP_HALF,
171                                           system_salt_);
172   callback.Run(transformed_context);
173 }
174 
~ExtendedAuthenticator()175 ExtendedAuthenticator::~ExtendedAuthenticator() {
176 }
177 
OnSaltObtained(const std::string & system_salt)178 void ExtendedAuthenticator::OnSaltObtained(const std::string& system_salt) {
179   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
180 
181   salt_obtained_ = true;
182   system_salt_ = system_salt;
183   for (std::vector<base::Closure>::const_iterator it =
184            system_salt_callbacks_.begin();
185        it != system_salt_callbacks_.end(); ++it) {
186     it->Run();
187   }
188   system_salt_callbacks_.clear();
189 }
190 
DoAuthenticateToMount(const ResultCallback & success_callback,const UserContext & user_context)191 void ExtendedAuthenticator::DoAuthenticateToMount(
192     const ResultCallback& success_callback,
193     const UserContext& user_context) {
194   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
195 
196   RecordStartMarker("MountEx");
197 
198   std::string canonicalized = gaia::CanonicalizeEmail(user_context.GetUserID());
199   cryptohome::Identification id(canonicalized);
200   const Key* const key = user_context.GetKey();
201   cryptohome::Authorization auth(key->GetSecret(), key->GetLabel());
202   cryptohome::MountParameters mount(false);
203 
204   cryptohome::HomedirMethods::GetInstance()->MountEx(
205       id,
206       auth,
207       mount,
208       base::Bind(&ExtendedAuthenticator::OnMountComplete,
209                  this,
210                  "MountEx",
211                  user_context,
212                  success_callback));
213 }
214 
DoAuthenticateToCheck(const base::Closure & success_callback,const UserContext & user_context)215 void ExtendedAuthenticator::DoAuthenticateToCheck(
216     const base::Closure& success_callback,
217     const UserContext& user_context) {
218   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
219 
220   RecordStartMarker("CheckKeyEx");
221 
222   std::string canonicalized = gaia::CanonicalizeEmail(user_context.GetUserID());
223   cryptohome::Identification id(canonicalized);
224   const Key* const key = user_context.GetKey();
225   cryptohome::Authorization auth(key->GetSecret(), key->GetLabel());
226 
227   cryptohome::HomedirMethods::GetInstance()->CheckKeyEx(
228       id,
229       auth,
230       base::Bind(&ExtendedAuthenticator::OnOperationComplete,
231                  this,
232                  "CheckKeyEx",
233                  user_context,
234                  success_callback));
235 }
236 
DoAddKey(const cryptohome::KeyDefinition & key,bool replace_existing,const base::Closure & success_callback,const UserContext & user_context)237 void ExtendedAuthenticator::DoAddKey(const cryptohome::KeyDefinition& key,
238                                      bool replace_existing,
239                                      const base::Closure& success_callback,
240                                      const UserContext& user_context) {
241   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
242 
243   RecordStartMarker("AddKeyEx");
244 
245   std::string canonicalized = gaia::CanonicalizeEmail(user_context.GetUserID());
246   cryptohome::Identification id(canonicalized);
247   const Key* const auth_key = user_context.GetKey();
248   cryptohome::Authorization auth(auth_key->GetSecret(), auth_key->GetLabel());
249 
250   cryptohome::HomedirMethods::GetInstance()->AddKeyEx(
251       id,
252       auth,
253       key,
254       replace_existing,
255       base::Bind(&ExtendedAuthenticator::OnOperationComplete,
256                  this,
257                  "AddKeyEx",
258                  user_context,
259                  success_callback));
260 }
261 
DoUpdateKeyAuthorized(const cryptohome::KeyDefinition & key,const std::string & signature,const base::Closure & success_callback,const UserContext & user_context)262 void ExtendedAuthenticator::DoUpdateKeyAuthorized(
263     const cryptohome::KeyDefinition& key,
264     const std::string& signature,
265     const base::Closure& success_callback,
266     const UserContext& user_context) {
267   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
268   RecordStartMarker("UpdateKeyAuthorized");
269 
270   std::string canonicalized = gaia::CanonicalizeEmail(user_context.GetUserID());
271   cryptohome::Identification id(canonicalized);
272   const Key* const auth_key = user_context.GetKey();
273   cryptohome::Authorization auth(auth_key->GetSecret(), auth_key->GetLabel());
274 
275   cryptohome::HomedirMethods::GetInstance()->UpdateKeyEx(
276       id,
277       auth,
278       key,
279       signature,
280       base::Bind(&ExtendedAuthenticator::OnOperationComplete,
281                  this,
282                  "UpdateKeyAuthorized",
283                  user_context,
284                  success_callback));
285 }
286 
DoRemoveKey(const std::string & key_to_remove,const base::Closure & success_callback,const UserContext & user_context)287 void ExtendedAuthenticator::DoRemoveKey(const std::string& key_to_remove,
288                                         const base::Closure& success_callback,
289                                         const UserContext& user_context) {
290   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
291 
292   RecordStartMarker("RemoveKeyEx");
293 
294   std::string canonicalized = gaia::CanonicalizeEmail(user_context.GetUserID());
295   cryptohome::Identification id(canonicalized);
296   const Key* const auth_key = user_context.GetKey();
297   cryptohome::Authorization auth(auth_key->GetSecret(), auth_key->GetLabel());
298 
299   cryptohome::HomedirMethods::GetInstance()->RemoveKeyEx(
300       id,
301       auth,
302       key_to_remove,
303       base::Bind(&ExtendedAuthenticator::OnOperationComplete,
304                  this,
305                  "RemoveKeyEx",
306                  user_context,
307                  success_callback));
308 }
309 
OnMountComplete(const std::string & time_marker,const UserContext & user_context,const ResultCallback & success_callback,bool success,cryptohome::MountError return_code,const std::string & mount_hash)310 void ExtendedAuthenticator::OnMountComplete(
311     const std::string& time_marker,
312     const UserContext& user_context,
313     const ResultCallback& success_callback,
314     bool success,
315     cryptohome::MountError return_code,
316     const std::string& mount_hash) {
317   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
318 
319   RecordEndMarker(time_marker);
320   UserContext copy = user_context;
321   copy.SetUserIDHash(mount_hash);
322   if (return_code == cryptohome::MOUNT_ERROR_NONE) {
323     if (!success_callback.is_null())
324       success_callback.Run(mount_hash);
325     if (old_consumer_)
326       old_consumer_->OnLoginSuccess(copy);
327     return;
328   }
329   AuthState state = FAILED_MOUNT;
330   if (return_code == cryptohome::MOUNT_ERROR_TPM_COMM_ERROR ||
331       return_code == cryptohome::MOUNT_ERROR_TPM_DEFEND_LOCK ||
332       return_code == cryptohome::MOUNT_ERROR_TPM_NEEDS_REBOOT) {
333     state = FAILED_TPM;
334   }
335   if (return_code == cryptohome::MOUNT_ERROR_USER_DOES_NOT_EXIST) {
336     state = NO_MOUNT;
337   }
338   if (consumer_)
339     consumer_->OnAuthenticationFailure(state);
340   if (old_consumer_) {
341     LoginFailure failure(LoginFailure::COULD_NOT_MOUNT_CRYPTOHOME);
342     old_consumer_->OnLoginFailure(failure);
343   }
344 }
345 
OnOperationComplete(const std::string & time_marker,const UserContext & user_context,const base::Closure & success_callback,bool success,cryptohome::MountError return_code)346 void ExtendedAuthenticator::OnOperationComplete(
347     const std::string& time_marker,
348     const UserContext& user_context,
349     const base::Closure& success_callback,
350     bool success,
351     cryptohome::MountError return_code) {
352   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
353 
354   RecordEndMarker(time_marker);
355   if (return_code == cryptohome::MOUNT_ERROR_NONE) {
356     if (!success_callback.is_null())
357       success_callback.Run();
358     if (old_consumer_)
359       old_consumer_->OnLoginSuccess(user_context);
360     return;
361   }
362 
363   AuthState state = FAILED_MOUNT;
364 
365   if (return_code == cryptohome::MOUNT_ERROR_TPM_COMM_ERROR ||
366       return_code == cryptohome::MOUNT_ERROR_TPM_DEFEND_LOCK ||
367       return_code == cryptohome::MOUNT_ERROR_TPM_NEEDS_REBOOT) {
368     state = FAILED_TPM;
369   }
370 
371   if (return_code == cryptohome::MOUNT_ERROR_USER_DOES_NOT_EXIST)
372     state = NO_MOUNT;
373 
374   if (consumer_)
375     consumer_->OnAuthenticationFailure(state);
376 
377   if (old_consumer_) {
378     LoginFailure failure(LoginFailure::UNLOCK_FAILED);
379     old_consumer_->OnLoginFailure(failure);
380   }
381 }
382 
383 }  // namespace chromeos
384