Home | History | Annotate | Download | only in signin
      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/signin/easy_unlock_auth_attempt.h"
      6 
      7 #include "base/logging.h"
      8 #include "chrome/browser/extensions/api/screenlock_private/screenlock_private_api.h"
      9 #include "chrome/browser/profiles/profile.h"
     10 #include "chrome/browser/signin/screenlock_bridge.h"
     11 #include "crypto/encryptor.h"
     12 #include "crypto/symmetric_key.h"
     13 
     14 
     15 #if defined(OS_CHROMEOS)
     16 #include "chrome/browser/chromeos/login/easy_unlock/easy_unlock_key_manager.h"
     17 #endif
     18 
     19 namespace {
     20 
     21 // Fake secret used to force invalid login.
     22 const char kStubSecret[] = "\xFF\x00";
     23 
     24 // Decrypts the secret that should be used to login from |wrapped_secret| using
     25 // raw AES key |raw_key|.
     26 // In a case of error, an empty string is returned.
     27 std::string UnwrapSecret(const std::string& wrapped_secret,
     28                          const std::string& raw_key) {
     29   if (raw_key.empty())
     30     return std::string();
     31 
     32   // Import the key structure.
     33   scoped_ptr<crypto::SymmetricKey> key(
     34      crypto::SymmetricKey::Import(crypto::SymmetricKey::AES, raw_key));
     35 
     36   if (!key)
     37     return std::string();
     38 
     39   std::string iv(raw_key.size(), ' ');
     40   crypto::Encryptor encryptor;
     41   if (!encryptor.Init(key.get(), crypto::Encryptor::CBC, iv))
     42     return std::string();
     43 
     44   std::string secret;
     45   if (!encryptor.Decrypt(wrapped_secret, &secret))
     46     return std::string();
     47 
     48   return secret;
     49 }
     50 
     51 }  // namespace
     52 
     53 EasyUnlockAuthAttempt::EasyUnlockAuthAttempt(Profile* profile,
     54                                              const std::string& user_id,
     55                                              Type type)
     56     : profile_(profile),
     57       state_(STATE_IDLE),
     58       user_id_(user_id),
     59       type_(type) {
     60 }
     61 
     62 EasyUnlockAuthAttempt::~EasyUnlockAuthAttempt() {
     63   if (state_ == STATE_RUNNING)
     64     Cancel(user_id_);
     65 }
     66 
     67 bool EasyUnlockAuthAttempt::Start(const std::string& user_id) {
     68   DCHECK(state_ == STATE_IDLE);
     69 
     70   if (!ScreenlockBridge::Get()->IsLocked())
     71     return false;
     72 
     73   if (user_id != user_id_) {
     74     Cancel(user_id);
     75     return false;
     76   }
     77 
     78   ScreenlockBridge::LockHandler::AuthType auth_type =
     79       ScreenlockBridge::Get()->lock_handler()->GetAuthType(user_id);
     80 
     81   if (auth_type != ScreenlockBridge::LockHandler::USER_CLICK) {
     82     Cancel(user_id);
     83     return false;
     84   }
     85 
     86   state_ = STATE_RUNNING;
     87 
     88   // TODO(tbarzic): Replace this with an easyUnlockPrivate event that will
     89   // report more context to the app (e.g. user id, whether the attempt is for
     90   // signin or unlock).
     91   extensions::ScreenlockPrivateEventRouter* router =
     92       extensions::ScreenlockPrivateEventRouter::GetFactoryInstance()->Get(
     93           profile_);
     94   return router->OnAuthAttempted(auth_type, "");
     95 }
     96 
     97 void EasyUnlockAuthAttempt::FinalizeUnlock(const std::string& user_id,
     98                                            bool success) {
     99   if (state_ != STATE_RUNNING || user_id != user_id_)
    100     return;
    101 
    102   if (type_ != TYPE_UNLOCK) {
    103     Cancel(user_id_);
    104     return;
    105   }
    106 
    107   if (!ScreenlockBridge::Get()->IsLocked())
    108     return;
    109 
    110   if (success) {
    111     ScreenlockBridge::Get()->lock_handler()->Unlock(user_id_);
    112   } else {
    113     ScreenlockBridge::Get()->lock_handler()->EnableInput();
    114   }
    115 
    116   state_ = STATE_DONE;
    117 }
    118 
    119 void EasyUnlockAuthAttempt::FinalizeSignin(const std::string& user_id,
    120                                            const std::string& wrapped_secret,
    121                                            const std::string& raw_session_key) {
    122   if (state_ != STATE_RUNNING || user_id != user_id_)
    123     return;
    124 
    125   if (type_ != TYPE_SIGNIN) {
    126     Cancel(user_id_);
    127     return;
    128   }
    129 
    130   if (!ScreenlockBridge::Get()->IsLocked())
    131     return;
    132 
    133 
    134   std::string unwrapped_secret = UnwrapSecret(wrapped_secret, raw_session_key);
    135 
    136   // If secret is not set, set it to an arbitrary value, otherwise there will
    137   // be no authenitcation attempt and the ui will get stuck.
    138   // TODO(tbarzic): Find a better way to handle this case.
    139   if (unwrapped_secret.empty())
    140     unwrapped_secret = kStubSecret;
    141 
    142   std::string key_label;
    143 #if defined(OS_CHROMEOS)
    144   key_label = chromeos::EasyUnlockKeyManager::GetKeyLabel(0u);
    145 #endif  // defined(OS_CHROMEOS)
    146 
    147   ScreenlockBridge::Get()->lock_handler()->AttemptEasySignin(
    148       user_id,
    149       unwrapped_secret,
    150       key_label);
    151   state_ = STATE_DONE;
    152 }
    153 
    154 void EasyUnlockAuthAttempt::Cancel(const std::string& user_id) {
    155   if (type_ == TYPE_UNLOCK)
    156     FinalizeUnlock(user_id, false);
    157   else
    158     FinalizeSignin(user_id, "", "");
    159   state_ = STATE_DONE;
    160 }
    161