// Copyright 2014 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "chrome/browser/signin/easy_unlock_auth_attempt.h" #include "base/bind.h" #include "base/command_line.h" #include "base/logging.h" #include "build/build_config.h" #include "chrome/browser/signin/easy_unlock_app_manager.h" #include "components/proximity_auth/screenlock_bridge.h" #include "components/proximity_auth/switches.h" #include "crypto/encryptor.h" #include "crypto/symmetric_key.h" #if defined(OS_CHROMEOS) #include "chrome/browser/chromeos/login/easy_unlock/easy_unlock_key_manager.h" #endif namespace { // Decrypts the secret that should be used to login from |wrapped_secret| using // raw AES key |raw_key|. // In a case of error, an empty string is returned. std::string UnwrapSecret(const std::string& wrapped_secret, const std::string& raw_key) { if (raw_key.empty()) return std::string(); // Import the key structure. scoped_ptr key( crypto::SymmetricKey::Import(crypto::SymmetricKey::AES, raw_key)); if (!key) return std::string(); std::string iv(raw_key.size(), ' '); crypto::Encryptor encryptor; if (!encryptor.Init(key.get(), crypto::Encryptor::CBC, iv)) return std::string(); std::string secret; if (!encryptor.Decrypt(wrapped_secret, &secret)) return std::string(); return secret; } void DefaultAuthAttemptFinalizedHandler( EasyUnlockAuthAttempt::Type auth_attempt_type, bool success, const AccountId& account_id, const std::string& key_secret, const std::string& key_label) { if (!proximity_auth::ScreenlockBridge::Get()->IsLocked()) return; switch (auth_attempt_type) { case EasyUnlockAuthAttempt::TYPE_UNLOCK: if (success) { proximity_auth::ScreenlockBridge::Get()->lock_handler()->Unlock( account_id); } else { proximity_auth::ScreenlockBridge::Get()->lock_handler()->EnableInput(); } return; case EasyUnlockAuthAttempt::TYPE_SIGNIN: if (success) { proximity_auth::ScreenlockBridge::Get() ->lock_handler() ->AttemptEasySignin(account_id, key_secret, key_label); } else { // Attempting signin with an empty secret is equivalent to canceling the // attempt. proximity_auth::ScreenlockBridge::Get() ->lock_handler() ->AttemptEasySignin(account_id, std::string(), std::string()); } return; } } } // namespace EasyUnlockAuthAttempt::EasyUnlockAuthAttempt( EasyUnlockAppManager* app_manager, const AccountId& account_id, Type type, const FinalizedCallback& finalized_callback) : app_manager_(app_manager), state_(STATE_IDLE), account_id_(account_id), type_(type), finalized_callback_(finalized_callback) { if (finalized_callback_.is_null()) finalized_callback_ = base::Bind(&DefaultAuthAttemptFinalizedHandler); } EasyUnlockAuthAttempt::~EasyUnlockAuthAttempt() { if (state_ == STATE_RUNNING) Cancel(account_id_); } bool EasyUnlockAuthAttempt::Start() { DCHECK_EQ(STATE_IDLE, state_); if (!proximity_auth::ScreenlockBridge::Get()->IsLocked()) return false; proximity_auth::ScreenlockBridge::LockHandler::AuthType auth_type = proximity_auth::ScreenlockBridge::Get()->lock_handler()->GetAuthType( account_id_); if (auth_type != proximity_auth::ScreenlockBridge::LockHandler::USER_CLICK) { Cancel(account_id_); return false; } state_ = STATE_RUNNING; // We need this workaround for ProximityAuthSystem, since we don't load the // full background app anymore. The call to // |app_manager_->SendAuthAttemptEvent()| returns false, as there is no // observer registered for the |screenlock::OnAuthAttempted| event. As a // result, the auth attempt will always fail. // TODO(sacomoto): Clean this up when the background app is not needed // anymore. if (!app_manager_->SendAuthAttemptEvent() && !base::CommandLine::ForCurrentProcess()->HasSwitch( proximity_auth::switches::kEnableBluetoothLowEnergyDiscovery)) { Cancel(account_id_); return false; } return true; } void EasyUnlockAuthAttempt::FinalizeUnlock(const AccountId& account_id, bool success) { if (state_ != STATE_RUNNING || account_id != account_id_) return; if (!proximity_auth::ScreenlockBridge::Get()->IsLocked()) return; if (type_ != TYPE_UNLOCK) { Cancel(account_id_); return; } finalized_callback_.Run(type_, success, account_id, std::string(), std::string()); state_ = STATE_DONE; } void EasyUnlockAuthAttempt::FinalizeSignin(const AccountId& account_id, const std::string& wrapped_secret, const std::string& raw_session_key) { if (state_ != STATE_RUNNING || account_id != account_id_) return; if (!proximity_auth::ScreenlockBridge::Get()->IsLocked()) return; if (type_ != TYPE_SIGNIN) { Cancel(account_id_); return; } if (wrapped_secret.empty()) { Cancel(account_id_); return; } std::string unwrapped_secret = UnwrapSecret(wrapped_secret, raw_session_key); std::string key_label; #if defined(OS_CHROMEOS) key_label = chromeos::EasyUnlockKeyManager::GetKeyLabel(0u); #endif // defined(OS_CHROMEOS) const bool kSuccess = true; finalized_callback_.Run(type_, kSuccess, account_id, unwrapped_secret, key_label); state_ = STATE_DONE; } void EasyUnlockAuthAttempt::Cancel(const AccountId& account_id) { state_ = STATE_DONE; const bool kFailure = false; finalized_callback_.Run(type_, kFailure, account_id, std::string(), std::string()); }