| // Copyright 2018 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_DEVICE_H_ | |
| #define BIOD_CROS_FP_DEVICE_H_ | |
| #include <bitset> | |
| #include <memory> | |
| #include <optional> | |
| #include <string> | |
| #include <utility> | |
| #include <vector> | |
| #include <base/files/file_descriptor_watcher_posix.h> | |
| #include <base/files/file_util.h> | |
| #include <libec/fingerprint/cros_fp_device_interface.h> | |
| #include <libec/ec_command_factory.h> | |
| #include <libec/fingerprint/fp_info_command.h> | |
| #include <libec/fingerprint/fp_mode.h> | |
| #include "biod/biod_metrics.h" | |
| #include "biod/uinput_device.h" | |
| namespace biod { | |
| class CrosFpDevice : public ec::CrosFpDeviceInterface { | |
| public: | |
| static std::unique_ptr<CrosFpDevice> Create( | |
| BiodMetricsInterface* biod_metrics, | |
| std::unique_ptr<ec::EcCommandFactoryInterface> ec_command_factory) { | |
| // Using new to access non-public constructor. | |
| // See https://abseil.io/tips/134. | |
| auto dev = base::WrapUnique( | |
| new CrosFpDevice(biod_metrics, std::move(ec_command_factory))); | |
| if (!dev->Init()) { | |
| return nullptr; | |
| } | |
| return dev; | |
| } | |
| void SetMkbpEventCallback(MkbpCallback callback) override; | |
| // Run a simple command to get the version information from FP MCU and check | |
| // whether the image type returned is the same as |expected_image|. | |
| static bool WaitOnEcBoot(const base::ScopedFD& cros_fp_fd, | |
| ec_image expected_image); | |
| // Run a simple command to get the version information from FP MCU. | |
| static std::optional<EcVersion> GetVersion(const base::ScopedFD& cros_fp_fd); | |
| // ec::CrosFpDeviceInterface overrides: | |
| ~CrosFpDevice() override; | |
| bool SetFpMode(const ec::FpMode& mode) override; | |
| ec::FpMode GetFpMode() override; | |
| std::optional<FpStats> GetFpStats() override; | |
| std::optional<std::bitset<32>> GetDirtyMap() override; | |
| bool SupportsPositiveMatchSecret() override; | |
| std::optional<brillo::SecureVector> GetPositiveMatchSecret( | |
| int index) override; | |
| std::optional<GetSecretReply> GetPositiveMatchSecretWithPubkey( | |
| int index, | |
| const brillo::Blob& pk_in_x, | |
| const brillo::Blob& pk_in_y) override; | |
| std::unique_ptr<VendorTemplate> GetTemplate(int index) override; | |
| bool UploadTemplate(const VendorTemplate& tmpl) override; | |
| bool UnlockTemplates(size_t num) override; | |
| bool SetContext(std::string user_id) override; | |
| bool SetNonceContext(const brillo::Blob& nonce, | |
| const brillo::Blob& encrypted_user_id, | |
| const brillo::Blob& iv) override; | |
| std::optional<brillo::Blob> GetNonce() override; | |
| bool ResetContext() override; | |
| // Initialise the entropy in the SBP. If |reset| is true, the old entropy | |
| // will be deleted. If |reset| is false, we will only add entropy, and only | |
| // if no entropy had been added before. | |
| bool InitEntropy(bool reset) override; | |
| bool UpdateFpInfo() override; | |
| std::optional<PairingKeyKeygenReply> PairingKeyKeygen() override; | |
| std::optional<brillo::Blob> PairingKeyWrap( | |
| const brillo::Blob& pub_x, | |
| const brillo::Blob& pub_y, | |
| const brillo::Blob& encrypted_priv) override; | |
| bool LoadPairingKey(const brillo::Blob& encrypted_pairing_key) override; | |
| int MaxTemplateCount() override; | |
| int TemplateVersion() override; | |
| int DeadPixelCount() override; | |
| bool MigrateLegacyTemplate(const std::string& user_id, | |
| const VendorTemplate& tmpl) override; | |
| ec::FpSensorErrors GetHwErrors() override; | |
| ec::EcCmdVersionSupportStatus EcCmdVersionSupported(uint16_t cmd, | |
| uint32_t ver) override; | |
| // Kernel device exposing the MCU command interface. | |
| static constexpr char kCrosFpPath[] = "/dev/cros_fp"; | |
| // Although very rare, we have seen device commands fail due | |
| // to ETIMEDOUT. For this reason, we attempt certain critical | |
| // device IO operation twice. | |
| static constexpr int kMaxIoAttempts = 2; | |
| static constexpr int kLastTemplate = -1; | |
| protected: | |
| CrosFpDevice( | |
| BiodMetricsInterface* biod_metrics, | |
| std::unique_ptr<ec::EcCommandFactoryInterface> ec_command_factory) | |
| : ec_command_factory_(std::move(ec_command_factory)), | |
| biod_metrics_(biod_metrics) {} | |
| bool Init(); | |
| virtual int read(int fd, void* buf, size_t count) { | |
| return ::read(fd, buf, count); | |
| } | |
| std::optional<std::string> ReadVersion(); | |
| private: | |
| struct EcProtocolInfo { | |
| uint16_t max_read = 0; | |
| uint16_t max_write = 0; | |
| }; | |
| bool EcDevInit(); | |
| std::optional<EcProtocolInfo> EcProtoInfo(); | |
| bool EcReboot(ec_image to_image); | |
| // Run the EC command to generate new entropy in the underlying MCU. | |
| // |reset| specifies whether we want to merely add entropy (false), or | |
| // perform a reset, which erases old entropy(true). | |
| bool AddEntropy(bool reset); | |
| // Get block id from rollback info. | |
| std::optional<int32_t> GetRollBackInfoId(); | |
| std::optional<brillo::SecureVector> FpReadMatchSecret(uint16_t index); | |
| std::optional<GetSecretReply> FpReadMatchSecretWithPubkey( | |
| int index, const brillo::Blob& pk_in_x, const brillo::Blob& pk_in_y); | |
| std::optional<int> GetIndexOfLastTemplate(); | |
| // Run a sequence of EC commands to update the entropy in the | |
| // MCU. If |reset| is set to true, it will additionally erase the existing | |
| // entropy too. | |
| bool UpdateEntropy(bool reset); | |
| std::unique_ptr<ec::FlashProtectCommand> GetFlashProtect(); | |
| void OnEventReadable(); | |
| base::ScopedFD cros_fd_; | |
| std::unique_ptr<base::FileDescriptorWatcher::Controller> watcher_; | |
| EcProtocolInfo ec_protocol_info_; | |
| std::unique_ptr<ec::FpInfoCommand> info_; | |
| std::unique_ptr<ec::EcCommandFactoryInterface> ec_command_factory_; | |
| MkbpCallback mkbp_event_; | |
| UinputDevice input_device_; | |
| BiodMetricsInterface* biod_metrics_ = nullptr; // Not owned. | |
| }; | |
| } // namespace biod | |
| #endif // BIOD_CROS_FP_DEVICE_H_ |