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 |