-
Notifications
You must be signed in to change notification settings - Fork 6.7k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add PinEngine and use it for webauthn pin authentication
This CL adds the class `PinEngine` which decouples WebAuthN PIN Auth from the QuickUnlock infrastructure in the case of auth factors enabled. This brings us a step closer to the goal of getting rid of QuickUnlock, while also allowing WebAuthN to use AuthSession based authentication for PIN. Bug: b:241256423 Change-Id: I0fcfa61dfb198c6b022e7634d3b2ce7893cc89d6 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3968738 Reviewed-by: Denis Kuznetsov <antrim@chromium.org> Commit-Queue: Elie Maamari <emaamari@google.com> Reviewed-by: Xiyuan Xia <xiyuan@chromium.org> Cr-Commit-Position: refs/heads/main@{#1067456}
- Loading branch information
Elie Maamari
authored and
Chromium LUCI CQ
committed
Nov 4, 2022
1 parent
3d141c7
commit af46b49
Showing
5 changed files
with
274 additions
and
11 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,149 @@ | ||
// Copyright 2022 The Chromium Authors | ||
// Use of this source code is governed by a BSD-style license that can be | ||
// found in the LICENSE file. | ||
|
||
#include "chrome/browser/ui/ash/cryptohome_pin_engine.h" | ||
|
||
#include "ash/constants/ash_pref_names.h" | ||
#include "base/check_op.h" | ||
#include "base/containers/contains.h" | ||
#include "chrome/browser/ash/profiles/profile_helper.h" | ||
#include "chrome/browser/browser_process.h" | ||
#include "chrome/browser/profiles/profile.h" | ||
#include "chromeos/ash/components/login/auth/auth_performer.h" | ||
#include "components/account_id/account_id.h" | ||
#include "components/prefs/pref_service.h" | ||
#include "components/user_manager/known_user.h" | ||
|
||
namespace ash { | ||
namespace { | ||
|
||
// Possible values for the `kQuickUnlockModeAllowlist` policy. | ||
constexpr char kFactorsOptionAll[] = "all"; | ||
constexpr char kFactorsOptionPin[] = "PIN"; | ||
|
||
bool HasPolicyValue(const PrefService& pref_service, | ||
CryptohomePinEngine::Purpose purpose, | ||
const char* value) { | ||
const base::Value::List* factors = nullptr; | ||
switch (purpose) { | ||
case CryptohomePinEngine::Purpose::kUnlock: | ||
factors = &pref_service.GetList(prefs::kQuickUnlockModeAllowlist); | ||
break; | ||
case CryptohomePinEngine::Purpose::kWebAuthn: | ||
factors = &pref_service.GetList(prefs::kWebAuthnFactors); | ||
break; | ||
default: | ||
return false; | ||
} | ||
return base::Contains(*factors, base::Value(value)); | ||
} | ||
|
||
// Check if pin is disabled for a specific purpose (so not including | ||
// kAny) by reading the policy value. | ||
bool IsPinDisabledByPolicySinglePurpose(const PrefService& pref_service, | ||
CryptohomePinEngine::Purpose purpose) { | ||
DCHECK_NE(purpose, CryptohomePinEngine::Purpose::kAny); | ||
const bool enabled = | ||
HasPolicyValue(pref_service, purpose, kFactorsOptionAll) || | ||
HasPolicyValue(pref_service, purpose, kFactorsOptionPin); | ||
return !enabled; | ||
} | ||
|
||
absl::optional<bool> IsCryptohomePinDisabledByPolicy( | ||
const AccountId& account_id, | ||
CryptohomePinEngine::Purpose purpose) { | ||
Profile* profile = | ||
ash::ProfileHelper::Get()->GetProfileByAccountId(account_id); | ||
|
||
if (!profile) | ||
return absl::nullopt; | ||
|
||
auto* pref_service = profile->GetPrefs(); | ||
|
||
if (!pref_service) { | ||
return absl::nullopt; | ||
} | ||
|
||
if (purpose == CryptohomePinEngine::Purpose::kAny) { | ||
return IsPinDisabledByPolicySinglePurpose( | ||
*pref_service, CryptohomePinEngine::Purpose::kUnlock) && | ||
IsPinDisabledByPolicySinglePurpose( | ||
*pref_service, CryptohomePinEngine::Purpose::kWebAuthn); | ||
} | ||
return IsPinDisabledByPolicySinglePurpose(*pref_service, purpose); | ||
} | ||
|
||
// Read the salt from local state. | ||
std::string GetUserSalt(const AccountId& account_id) { | ||
user_manager::KnownUser known_user(g_browser_process->local_state()); | ||
if (const std::string* salt = | ||
known_user.FindStringPath(account_id, prefs::kQuickUnlockPinSalt)) { | ||
return *salt; | ||
} | ||
return {}; | ||
} | ||
|
||
} // namespace | ||
|
||
CryptohomePinEngine::CryptohomePinEngine(ash::AuthPerformer* auth_performer) | ||
: auth_performer_(auth_performer) {} | ||
|
||
CryptohomePinEngine::~CryptohomePinEngine() = default; | ||
|
||
void CryptohomePinEngine::IsPinAuthAvailable( | ||
Purpose purpose, | ||
std::unique_ptr<UserContext> user_context, | ||
IsPinAuthAvailableCallback callback) { | ||
auto is_pin_disabled_by_policy = | ||
IsCryptohomePinDisabledByPolicy(user_context->GetAccountId(), purpose); | ||
|
||
if (!is_pin_disabled_by_policy.has_value() || | ||
is_pin_disabled_by_policy.value()) { | ||
std::move(callback).Run(false, std::move(user_context)); | ||
return; | ||
} | ||
|
||
CheckCryptohomePinFactor(std::move(user_context), std::move(callback)); | ||
} | ||
|
||
void CryptohomePinEngine::Authenticate( | ||
const cryptohome::RawPin& pin, | ||
std::unique_ptr<UserContext> user_context, | ||
AuthOperationCallback callback) { | ||
auto salt = GetUserSalt(user_context->GetAccountId()); | ||
auth_performer_->AuthenticateWithPin(*pin, salt, std::move(user_context), | ||
std::move(callback)); | ||
} | ||
|
||
void CryptohomePinEngine::CheckCryptohomePinFactor( | ||
std::unique_ptr<UserContext> user_context, | ||
IsPinAuthAvailableCallback callback) { | ||
auth_factor_editor_.GetAuthFactorsConfiguration( | ||
std::move(user_context), | ||
base::BindOnce(&CryptohomePinEngine::OnGetAuthFactorsConfiguration, | ||
weak_factory_.GetWeakPtr(), std::move(callback))); | ||
} | ||
|
||
void CryptohomePinEngine::OnGetAuthFactorsConfiguration( | ||
IsPinAuthAvailableCallback callback, | ||
std::unique_ptr<UserContext> user_context, | ||
absl::optional<AuthenticationError> error) { | ||
if (error.has_value()) { | ||
std::move(callback).Run(false, std::move(user_context)); | ||
return; | ||
} | ||
|
||
const auto& config = user_context->GetAuthFactorsConfiguration(); | ||
const cryptohome::AuthFactor* pin_factor = | ||
config.FindFactorByType(cryptohome::AuthFactorType::kPin); | ||
|
||
if (!pin_factor || pin_factor->GetPinStatus().auth_locked) { | ||
std::move(callback).Run(false, std::move(user_context)); | ||
return; | ||
} | ||
|
||
std::move(callback).Run(true, std::move(user_context)); | ||
} | ||
|
||
} // namespace ash |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,67 @@ | ||
// Copyright 2022 The Chromium Authors | ||
// Use of this source code is governed by a BSD-style license that can be | ||
// found in the LICENSE file. | ||
|
||
#ifndef CHROME_BROWSER_UI_ASH_CRYPTOHOME_PIN_ENGINE_H_ | ||
#define CHROME_BROWSER_UI_ASH_CRYPTOHOME_PIN_ENGINE_H_ | ||
|
||
#include <memory> | ||
#include <string> | ||
|
||
#include "base/functional/callback_forward.h" | ||
#include "base/memory/weak_ptr.h" | ||
#include "chromeos/ash/components/cryptohome/common_types.h" | ||
#include "chromeos/ash/components/login/auth/auth_factor_editor.h" | ||
#include "chromeos/ash/components/login/auth/auth_performer.h" | ||
#include "third_party/abseil-cpp/absl/types/optional.h" | ||
|
||
namespace ash { | ||
|
||
class UserContext; | ||
|
||
// Handles Pin related authentication operations and is the source of truth | ||
// for the availability of Pin authentication. | ||
class CryptohomePinEngine { | ||
public: | ||
enum class Purpose { kAny, kUnlock, kWebAuthn }; | ||
|
||
explicit CryptohomePinEngine(ash::AuthPerformer* auth_performer); | ||
CryptohomePinEngine(const CryptohomePinEngine&) = delete; | ||
CryptohomePinEngine& operator=(const CryptohomePinEngine&) = delete; | ||
virtual ~CryptohomePinEngine(); | ||
|
||
using IsPinAuthAvailableCallback = | ||
base::OnceCallback<void(bool, std::unique_ptr<UserContext>)>; | ||
|
||
// Checks the availability of Pin authentication, based on things like | ||
// policy configuration and whether or not the auth factor is set up. | ||
void IsPinAuthAvailable(Purpose purpose, | ||
std::unique_ptr<UserContext> user_context, | ||
IsPinAuthAvailableCallback callback); | ||
|
||
// The `user_context` parameter must have an associated `authsession_id`, | ||
// acquired from a call to `AuthPerformer::StartAuthSession`. | ||
void Authenticate(const cryptohome::RawPin& pin, | ||
std::unique_ptr<UserContext> user_context, | ||
AuthOperationCallback callback); | ||
|
||
private: | ||
// Checks for Pin factor availability and lockout status | ||
void CheckCryptohomePinFactor(std::unique_ptr<UserContext> user_context, | ||
IsPinAuthAvailableCallback callback); | ||
|
||
void OnGetAuthFactorsConfiguration(IsPinAuthAvailableCallback callback, | ||
std::unique_ptr<UserContext> user_context, | ||
absl::optional<AuthenticationError> error); | ||
|
||
// Non owning pointer | ||
const base::raw_ptr<ash::AuthPerformer> auth_performer_; | ||
|
||
ash::AuthFactorEditor auth_factor_editor_; | ||
|
||
base::WeakPtrFactory<CryptohomePinEngine> weak_factory_{this}; | ||
}; | ||
|
||
} // namespace ash | ||
|
||
#endif // CHROME_BROWSER_UI_ASH_CRYPTOHOME_PIN_ENGINE_H_ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters