blob: 2112f0375209c5fb1c5537d252d66d2e02ed3da1 [file] [log] [blame]
// Copyright 2023 The ChromiumOS Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef BIOD_CROS_FP_AUTH_STACK_MANAGER_H_
#define BIOD_CROS_FP_AUTH_STACK_MANAGER_H_
#include "biod/auth_stack_manager.h"
#include <memory>
#include <string>
#include <vector>
#include <base/memory/weak_ptr.h>
#include <base/timer/timer.h>
#include <libhwsec/frontend/pinweaver_manager/frontend.h>
#include "biod/cros_fp_device.h"
#include "biod/cros_fp_session_manager.h"
#include "biod/maintenance_scheduler.h"
#include "biod/pairing_key_storage.h"
#include "biod/power_button_filter_interface.h"
#include "biod/proto_bindings/constants.pb.h"
#include "biod/proto_bindings/messages.pb.h"
namespace biod {
class BiodMetrics;
class CrosFpAuthStackManager : public AuthStackManager {
public:
// Current state of CrosFpAuthStackManager. We maintain a state machine
// because some operations can only be processed in some states.
enum class State {
// Initial state, neither any session is pending nor we're expecting
// Create/AuthenticateCredential commands to come.
kNone,
// An EnrollSession is ongoing.
kEnroll,
// An EnrollSession is completed successfully and we're expecting a
// CreateCredential command.
kEnrollDone,
// An AuthSession is ongoing.
kAuth,
// An AuthSession is completed successfully and we're expecting a
// AuthenticateCredential command.
kAuthDone,
// An AuthenticateCredential is completed, and we're waiting for user to
// lift their finger before the next auth attempt.
kWaitForFingerUp,
// If during WaitForFingerUp state, we received an AuthenticateCredential
// command, we transition to this state so that after finger is up we
// immediately start the next match.
kAuthWaitForFingerUp,
// Something went wrong in keeping sync between biod and FPMCU, and it's
// better to not process any Enroll/Auth commands in this state.
kLocked,
};
CrosFpAuthStackManager(
std::unique_ptr<PowerButtonFilterInterface> power_button_filter,
std::unique_ptr<ec::CrosFpDeviceInterface> cros_fp_device,
BiodMetricsInterface* biod_metrics,
std::unique_ptr<CrosFpSessionManager> session_manager,
std::unique_ptr<PairingKeyStorage> pk_storage,
std::unique_ptr<const hwsec::PinWeaverManagerFrontend> pinweaver_manager,
std::unique_ptr<CrosFpSessionManager> legacy_session_manager,
State state = State::kNone,
// This param allows tests to set an initial |pending_match_event_| when
// initial state is State::kAuthDone.
std::optional<uint32_t> pending_match_event = std::nullopt);
CrosFpAuthStackManager(const CrosFpAuthStackManager&) = delete;
CrosFpAuthStackManager& operator=(const CrosFpAuthStackManager&) = delete;
// Initializes the AuthStack. Without calling Initialize, many functions might
// not work.
bool Initialize();
// Establishes Pk with GSC.
virtual bool EstablishPairingKey();
// AuthStackManager overrides:
~CrosFpAuthStackManager() override = default;
BiometricType GetType() override;
GetNonceReply GetNonce() override;
AuthStackManager::Session StartEnrollSession(
const StartEnrollSessionRequest& request) override;
CreateCredentialReply CreateCredential(
const CreateCredentialRequest& request) override;
AuthStackManager::Session StartAuthSession(
const StartAuthSessionRequest& request) override;
void AuthenticateCredential(
const AuthenticateCredentialRequest& request,
AuthStackManager::AuthenticateCredentialCallback callback) override;
DeleteCredentialReply DeleteCredential(
const DeleteCredentialRequest& request) override;
void OnUserLoggedOut() override;
void OnUserLoggedIn(const std::string& user_id) override;
bool SendStatsOnLogin() override;
ListLegacyRecordsReply ListLegacyRecords() override;
void EnrollLegacyTemplate(
const EnrollLegacyTemplateRequest& request,
AuthStackManager::EnrollLegacyTemplateCallback callback) override;
void SetEnrollScanDoneHandler(const AuthStackManager::EnrollScanDoneCallback&
on_enroll_scan_done) override;
void SetAuthScanDoneHandler(
const AuthStackManager::AuthScanDoneCallback& on_auth_scan_done) override;
void SetSessionFailedHandler(const AuthStackManager::SessionFailedCallback&
on_session_failed) override;
State GetState() const { return state_; }
protected:
void EndEnrollSession() override;
void EndAuthSession() override;
private:
using SessionAction = base::RepeatingCallback<void(const uint32_t event)>;
// In charge of handling the migration APIs.
class CrosFpMigrator {
public:
CrosFpMigrator(CrosFpAuthStackManager* manager,
std::unique_ptr<CrosFpSessionManager> session_manager);
void OnUserLoggedIn(const std::string& user_id);
void OnUserLoggedOut();
// See AuthStackManager::ListLegacyRecords.
ListLegacyRecordsReply ListLegacyRecords();
// See AuthStackManager::EnrollLegacyTemplate.
void EnrollLegacyTemplate(
const EnrollLegacyTemplateRequest& request,
AuthStackManager::EnrollLegacyTemplateCallback callback);
private:
CrosFpAuthStackManager* manager_;
std::unique_ptr<CrosFpSessionManager> session_manager_;
};
// For testing.
friend class CrosFpAuthStackManagerPeer;
void OnMkbpEvent(uint32_t event);
void KillMcuSession();
void OnTaskComplete();
// Load the pairing key into FPMCU. This is called on every boot when
// AuthStackManager is initialized.
bool LoadPairingKey();
void OnEnrollScanDone(ScanResult result,
const AuthStackManager::EnrollStatus& enroll_status);
void OnAuthScanDone();
void OnSessionFailed();
bool LoadUser(std::string user_id, bool lock_to_user);
// Load encrypted user templates into FPMCU. We only need to do this when
// the current user has changed, or when we delete a template, or after we
// enrolled a new finger.
bool UploadCurrentUserTemplates();
bool RequestEnrollImage();
bool RequestEnrollFingerUp();
void DoEnrollImageEvent(uint32_t event);
void DoEnrollFingerUpEvent(uint32_t event);
BiodMetricsInterface::StartAuthSessionStatus PrepareStartAuthSession(
const StartAuthSessionRequest& request);
bool RequestMatchFingerDown();
void OnMatchFingerDown(uint32_t event);
bool RequestFingerUp();
void OnFingerUpEvent(uint32_t event);
// Report the matching latency. |matched| is whether the match was successful.
void ReportMatchLatency(bool matched);
void UpdateDirtyTemplates();
std::string CurrentStateToString();
// Whether current state is waiting for a next session action.
bool IsActiveState();
bool CanStartEnroll();
bool CanCreateCredential();
bool CanStartAuth();
bool CanAuthenticateCredential();
BiodMetricsInterface* biod_metrics_ = nullptr;
std::unique_ptr<ec::CrosFpDeviceInterface> cros_dev_;
SessionAction next_session_action_;
AuthStackManager::EnrollScanDoneCallback on_enroll_scan_done_;
AuthStackManager::AuthScanDoneCallback on_auth_scan_done_;
AuthStackManager::SessionFailedCallback on_session_failed_;
std::unique_ptr<PowerButtonFilterInterface> power_button_filter_;
std::unique_ptr<CrosFpSessionManager> session_manager_;
std::unique_ptr<PairingKeyStorage> pk_storage_;
std::unique_ptr<const hwsec::PinWeaverManagerFrontend> pinweaver_manager_;
State state_;
// This is used to disallow authenticating/enrolling fingerprint for a second
// user after a user has logged-in. Note that CrOS currently supports
// multi-login, but as biod and FPMCU can only hold state for a single user,
// we stick to the first logged-in user.
bool locked_to_current_user_ = false;
// Used to track the number of enrollment captures, in order to report
// metrics.
uint8_t num_enrollment_captures_ = 0;
// We need to cache the StartAuthSession request if we receive it during
// WaitForFingerUp state.
std::optional<StartAuthSessionRequest> pending_request_;
// We need to cache the match event received in match mode, as the actual
// match request will come in another command (AuthenticateCredential). This
// should be non-null iff we're in AuthDone state.
std::optional<uint32_t> pending_match_event_;
std::unique_ptr<MaintenanceScheduler> maintenance_scheduler_;
// In charge of handling legacy fingerprint migration APIs.
std::unique_ptr<CrosFpMigrator> migrator_;
base::WeakPtrFactory<CrosFpAuthStackManager> session_weak_factory_;
};
} // namespace biod
#endif // BIOD_CROS_FP_AUTH_STACK_MANAGER_H_