| Index: chrome/browser/chromeos/login/quick_unlock/pin_backend.cc
|
| diff --git a/chrome/browser/chromeos/login/quick_unlock/pin_backend.cc b/chrome/browser/chromeos/login/quick_unlock/pin_backend.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..d8010404f5b9c00bf342022776811985349046ef
|
| --- /dev/null
|
| +++ b/chrome/browser/chromeos/login/quick_unlock/pin_backend.cc
|
| @@ -0,0 +1,260 @@
|
| +// Copyright 2017 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/chromeos/login/quick_unlock/pin_backend.h"
|
| +
|
| +#include "base/bind.h"
|
| +#include "base/threading/thread_task_runner_handle.h"
|
| +#include "chrome/browser/chromeos/login/quick_unlock/pin_storage_prefs.h"
|
| +#include "chrome/browser/chromeos/login/quick_unlock/quick_unlock_factory.h"
|
| +#include "chrome/browser/chromeos/login/quick_unlock/quick_unlock_storage.h"
|
| +#include "chrome/browser/chromeos/login/quick_unlock/quick_unlock_utils.h"
|
| +#include "chromeos/cryptohome/cryptohome_parameters.h"
|
| +#include "chromeos/cryptohome/homedir_methods.h"
|
| +#include "chromeos/cryptohome/system_salt_getter.h"
|
| +#include "chromeos/login/auth/user_context.h"
|
| +#include "components/signin/core/account_id/account_id.h"
|
| +
|
| +namespace chromeos {
|
| +namespace quick_unlock {
|
| +
|
| +namespace {
|
| +
|
| +constexpr const char* kCryptohomePinLabel = "pin_label";
|
| +
|
| +void DoNothingCryptohome(bool success, cryptohome::MountError return_code) {}
|
| +
|
| +// Returns true if there is a KeyDefinition instance in cryptohome which has the
|
| +// PIN label.
|
| +void HasCryptohomePinKey(
|
| + const PinBackend::BoolCallback& callback,
|
| + bool success,
|
| + cryptohome::MountError return_code,
|
| + const std::vector<cryptohome::KeyDefinition>& key_definitions) {
|
| + for (const cryptohome::KeyDefinition& definition : key_definitions) {
|
| + if (definition.label == kCryptohomePinLabel) {
|
| + callback.Run(true);
|
| + return;
|
| + }
|
| + }
|
| +
|
| + callback.Run(false);
|
| +}
|
| +
|
| +class CryptohomeBackend {
|
| + public:
|
| + CryptohomeBackend();
|
| + ~CryptohomeBackend();
|
| +
|
| + void EnsurePinIsNotInCryptohome(const AccountId& account_id,
|
| + const UserContext& user_context) const;
|
| + void IsPinSetInCryptohome(const AccountId& account_id,
|
| + const PinBackend::BoolCallback& result) const;
|
| + void SetPin(const UserContext& user_context, const std::string& pin);
|
| + void RemovePin(const UserContext& user_context);
|
| + bool NeedsStrongAuth() const;
|
| +
|
| + private:
|
| + void OnSystemSaltObtained(const std::string& system_salt);
|
| + // Called when we add or remove a key from cryptohome.
|
| + void OnCryptohomeKeyChange(bool success, cryptohome::MountError return_code);
|
| +
|
| + void SetIsPinSet(bool is_set);
|
| +
|
| + private:
|
| + bool salt_obtained_ = false;
|
| + std::string system_salt_;
|
| + std::vector<base::Closure> system_salt_callbacks_;
|
| +
|
| + base::WeakPtrFactory<CryptohomeBackend> weak_factory_{this};
|
| +
|
| + DISALLOW_COPY_AND_ASSIGN(CryptohomeBackend);
|
| +};
|
| +
|
| +CryptohomeBackend::CryptohomeBackend() {
|
| + SystemSaltGetter::Get()->GetSystemSalt(base::Bind(
|
| + &CryptohomeBackend::OnSystemSaltObtained, weak_factory_.GetWeakPtr()));
|
| +}
|
| +
|
| +CryptohomeBackend::~CryptohomeBackend() = default;
|
| +
|
| +void CryptohomeBackend::IsPinSetInCryptohome(
|
| + const AccountId& account_id,
|
| + const PinBackend::BoolCallback& callback) const {
|
| + cryptohome::HomedirMethods::GetInstance()->GetKeyDataEx(
|
| + cryptohome::Identification(account_id), kCryptohomePinLabel,
|
| + base::Bind(&HasCryptohomePinKey, callback));
|
| +}
|
| +
|
| +void CryptohomeBackend::SetPin(const UserContext& user_context,
|
| + const std::string& pin) {
|
| + // Rerun this method only after we have system salt.
|
| + if (!salt_obtained_) {
|
| + system_salt_callbacks_.push_back(base::Bind(&CryptohomeBackend::SetPin,
|
| + weak_factory_.GetWeakPtr(),
|
| + user_context, pin));
|
| + return;
|
| + }
|
| +
|
| + const std::string pin_secret = PinBackend::ComputeSecret(pin, system_salt_);
|
| +
|
| + const cryptohome::Identification id(user_context.GetAccountId());
|
| + const cryptohome::Authorization auth(user_context.GetKey()->GetSecret(), "");
|
| + const cryptohome::KeyDefinition key_def(pin_secret, kCryptohomePinLabel,
|
| + cryptohome::PRIV_DEFAULT);
|
| + cryptohome::HomedirMethods::GetInstance()->AddKeyEx(
|
| + id, auth, key_def, true /*replace_existing*/,
|
| + base::Bind(&DoNothingCryptohome));
|
| +}
|
| +
|
| +void CryptohomeBackend::OnSystemSaltObtained(const std::string& system_salt) {
|
| + salt_obtained_ = true;
|
| + system_salt_ = system_salt;
|
| + for (const auto& callback : system_salt_callbacks_)
|
| + callback.Run();
|
| + system_salt_callbacks_.clear();
|
| +}
|
| +
|
| +void CryptohomeBackend::RemovePin(const UserContext& user_context) {
|
| + // Rerun this method only after we have system salt.
|
| + if (!salt_obtained_) {
|
| + system_salt_callbacks_.push_back(base::Bind(&CryptohomeBackend::RemovePin,
|
| + weak_factory_.GetWeakPtr(),
|
| + user_context));
|
| + return;
|
| + }
|
| +
|
| + // Remove any PIN data from cryptohome.
|
| + const cryptohome::Identification id(user_context.GetAccountId());
|
| + const cryptohome::Authorization auth(user_context.GetKey()->GetSecret(), "");
|
| + cryptohome::HomedirMethods::GetInstance()->RemoveKeyEx(
|
| + id, auth, kCryptohomePinLabel, base::Bind(&DoNothingCryptohome));
|
| +}
|
| +
|
| +CryptohomeBackend* g_cryptohome_backend_ = nullptr;
|
| +
|
| +CryptohomeBackend* GetCryptohomeBackend() {
|
| + if (!g_cryptohome_backend_)
|
| + g_cryptohome_backend_ = new CryptohomeBackend();
|
| + return g_cryptohome_backend_;
|
| +}
|
| +
|
| +QuickUnlockStorage* GetPrefsBackend(const AccountId& account_id) {
|
| + return QuickUnlockFactory::GetForAccountId(account_id);
|
| +}
|
| +
|
| +void SendResponse(const PinBackend::BoolCallback& result, bool value) {
|
| + base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE,
|
| + base::Bind(result, value));
|
| +}
|
| +
|
| +} // namespace
|
| +
|
| +// static
|
| +void PinBackend::IsSet(const AccountId& account_id,
|
| + const BoolCallback& result) {
|
| + if (GetPinStorageType() == PinStorageType::kCryptohome) {
|
| + GetCryptohomeBackend()->IsPinSetInCryptohome(account_id, result);
|
| + } else {
|
| + QuickUnlockStorage* storage = GetPrefsBackend(account_id);
|
| + DCHECK(storage);
|
| + SendResponse(result, storage->pin_storage_prefs()->IsPinSet());
|
| + }
|
| +}
|
| +
|
| +// static
|
| +void PinBackend::Set(const UserContext& user_context, const std::string& pin) {
|
| + QuickUnlockStorage* storage = GetPrefsBackend(user_context.GetAccountId());
|
| + DCHECK(storage);
|
| +
|
| + // Make sure to remove the other storage pin.
|
| + if (GetPinStorageType() == PinStorageType::kCryptohome) {
|
| + GetCryptohomeBackend()->SetPin(user_context, pin);
|
| + storage->pin_storage_prefs()->RemovePin();
|
| + } else {
|
| + storage->pin_storage_prefs()->SetPin(pin);
|
| + GetCryptohomeBackend()->RemovePin(user_context);
|
| + }
|
| +}
|
| +
|
| +// static
|
| +void PinBackend::Remove(const UserContext& user_context) {
|
| + GetCryptohomeBackend()->RemovePin(user_context);
|
| +
|
| + QuickUnlockStorage* storage = GetPrefsBackend(user_context.GetAccountId());
|
| + DCHECK(storage);
|
| + storage->pin_storage_prefs()->RemovePin();
|
| +}
|
| +
|
| +// static
|
| +void PinBackend::CanAuthenticate(const AccountId& account_id,
|
| + const BoolCallback& result) {
|
| + if (GetPinStorageType() == PinStorageType::kCryptohome) {
|
| + GetCryptohomeBackend()->IsPinSetInCryptohome(account_id, result);
|
| + } else {
|
| + QuickUnlockStorage* storage = GetPrefsBackend(account_id);
|
| + if (!storage) {
|
| + SendResponse(result, false);
|
| + } else {
|
| + SendResponse(
|
| + result,
|
| + storage->HasStrongAuth() &&
|
| + storage->pin_storage_prefs()->IsPinAuthenticationAvailable());
|
| + }
|
| + }
|
| +}
|
| +
|
| +// static
|
| +void PinBackend::TryAuthenticate(const AccountId& account_id,
|
| + const std::string& pin,
|
| + const BoolCallback& result) {
|
| + if (GetPinStorageType() == PinStorageType::kCryptohome) {
|
| + // TODO(jdufalt): Refactor login auth such that typing a user password does
|
| + // not run crypthome check with wildcard key label. That means we will be
|
| + // forced to run an authentication check here.
|
| + base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE,
|
| + base::Bind(result, false));
|
| + } else {
|
| + QuickUnlockStorage* storage = GetPrefsBackend(account_id);
|
| + DCHECK(storage);
|
| +
|
| + if (!storage->HasStrongAuth()) {
|
| + SendResponse(result, false);
|
| + } else {
|
| + SendResponse(result,
|
| + storage->pin_storage_prefs()->TryAuthenticatePin(pin));
|
| + }
|
| + }
|
| +}
|
| +
|
| +// static
|
| +void PinBackend::NotifyAuthentication(const AccountId& account_id) {
|
| + // Nothing to do for cryptohome backend.
|
| +
|
| + if (GetPinStorageType() == PinStorageType::kPrefs) {
|
| + QuickUnlockStorage* storage = GetPrefsBackend(account_id);
|
| + if (!storage)
|
| + return;
|
| +
|
| + storage->pin_storage_prefs()->ResetUnlockAttemptCount();
|
| + }
|
| +}
|
| +
|
| +// static
|
| +std::string PinBackend::ComputeSecret(const std::string& pin,
|
| + const std::string& salt) {
|
| + Key key(pin);
|
| + key.Transform(Key::KEY_TYPE_SALTED_SHA256_TOP_HALF, salt);
|
| + return key.GetSecret();
|
| +}
|
| +
|
| +// static
|
| +void PinBackend::ResetForTesting() {
|
| + if (g_cryptohome_backend_)
|
| + delete g_cryptohome_backend_;
|
| + g_cryptohome_backend_ = nullptr;
|
| +}
|
| +
|
| +} // namespace quick_unlock
|
| +} // namespace chromeos
|
|
|