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