blob: e95147abf62e0a944e77ee2447cd12d1bbcc3436 [file] [log] [blame]
// Copyright 2019 The ChromiumOS Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <optional>
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include <libec/ec_usb_endpoint.h>
#include <libec/fingerprint/fp_info_command.h>
#include <libec/fingerprint/fp_template_command.h>
#include <libec/fingerprint/fp_unlock_template_command.h>
#include <libec/mock_ec_command_factory.h>
#include "biod/cros_fp_device.h"
#include "biod/mock_biod_metrics.h"
#include "biod/mock_cros_fp_device.h"
#include "libec/fingerprint/fp_sensor_errors.h"
using ec::EcCommandFactoryInterface;
using ec::EcCommandInterface;
using ec::FpGetNonceCommand;
using ec::FpInfoCommand;
using ec::FpMode;
using ec::FpPairingKeyKeygenCommand;
using ec::FpPairingKeyLoadCommand;
using ec::FpPairingKeyWrapCommand;
using ec::FpReadMatchSecretWithPubkeyCommand;
using ec::FpSensorErrors;
using ec::FpSetNonceContextCommand;
using ec::FpTemplateCommand;
using ec::FpUnlockTemplateCommand;
using testing::An;
using testing::NiceMock;
using testing::Return;
namespace biod {
namespace {
class MockEcCommandInterface : public EcCommandInterface {
public:
MOCK_METHOD(bool, Run, (int fd), (override));
MOCK_METHOD(bool, Run, (ec::EcUsbEndpointInterface & uep), (override));
MOCK_METHOD(bool,
RunWithMultipleAttempts,
(int fd, int num_attempts),
(override));
MOCK_METHOD(uint32_t, Version, (), (const, override));
MOCK_METHOD(uint32_t, Command, (), (const, override));
};
class CrosFpDevice_ResetContext : public testing::Test {
public:
class MockCrosFpDevice : public CrosFpDevice {
public:
MockCrosFpDevice(
BiodMetricsInterface* biod_metrics,
std::unique_ptr<EcCommandFactoryInterface> ec_command_factory)
: CrosFpDevice(biod_metrics, std::move(ec_command_factory)) {}
MOCK_METHOD(FpMode, GetFpMode, (), (override));
MOCK_METHOD(bool, SetFpMode, (const FpMode&), (override));
MOCK_METHOD(bool, SetContext, (std::string user_id), (override));
};
class MockFpContextFactory : public ec::MockEcCommandFactory {
public:
std::unique_ptr<EcCommandInterface> FpContextCommand(
ec::CrosFpDeviceInterface* cros_fp,
const std::string& user_id) override {
auto cmd = std::make_unique<MockEcCommandInterface>();
EXPECT_CALL(*cmd, Run(An<int>())).WillOnce(testing::Return(true));
return cmd;
}
};
metrics::MockBiodMetrics mock_biod_metrics;
MockCrosFpDevice mock_cros_fp_device{
&mock_biod_metrics, std::make_unique<MockFpContextFactory>()};
};
TEST_F(CrosFpDevice_ResetContext, Success) {
EXPECT_CALL(mock_cros_fp_device, GetFpMode).Times(1).WillOnce([]() {
return FpMode(FpMode::Mode::kNone);
});
EXPECT_CALL(mock_cros_fp_device, SetContext(std::string())).Times(1);
EXPECT_CALL(mock_biod_metrics,
SendResetContextMode(FpMode(FpMode::Mode::kNone)));
mock_cros_fp_device.ResetContext();
}
TEST_F(CrosFpDevice_ResetContext, WrongMode) {
EXPECT_CALL(mock_cros_fp_device, GetFpMode).Times(1).WillOnce([]() {
return FpMode(FpMode::Mode::kMatch);
});
EXPECT_CALL(mock_cros_fp_device, SetFpMode(FpMode(FpMode::Mode::kNone)))
.WillOnce(Return(true));
EXPECT_CALL(mock_cros_fp_device, SetContext(std::string())).Times(1);
EXPECT_CALL(mock_biod_metrics,
SendResetContextMode(FpMode(FpMode::Mode::kMatch)));
mock_cros_fp_device.ResetContext();
}
TEST_F(CrosFpDevice_ResetContext, Failure) {
EXPECT_CALL(mock_cros_fp_device, GetFpMode).Times(1).WillOnce([]() {
return FpMode(FpMode::Mode::kModeInvalid);
});
EXPECT_CALL(mock_cros_fp_device, SetContext(std::string())).Times(1);
EXPECT_CALL(mock_biod_metrics,
SendResetContextMode(FpMode(FpMode::Mode::kModeInvalid)));
mock_cros_fp_device.ResetContext();
}
class CrosFpDevice_SetContext : public testing::Test {
public:
class MockCrosFpDevice : public CrosFpDevice {
public:
MockCrosFpDevice(
BiodMetricsInterface* biod_metrics,
std::unique_ptr<EcCommandFactoryInterface> ec_command_factory)
: CrosFpDevice(biod_metrics, std::move(ec_command_factory)) {}
MOCK_METHOD(FpMode, GetFpMode, (), (override));
MOCK_METHOD(bool, SetFpMode, (const FpMode& mode), (override));
};
class MockFpContextFactory : public ec::MockEcCommandFactory {
public:
std::unique_ptr<EcCommandInterface> FpContextCommand(
ec::CrosFpDeviceInterface* cros_fp,
const std::string& user_id) override {
auto cmd = std::make_unique<MockEcCommandInterface>();
EXPECT_CALL(*cmd, Run(An<int>())).WillOnce(testing::Return(true));
return cmd;
}
};
metrics::MockBiodMetrics mock_biod_metrics;
MockCrosFpDevice mock_cros_fp_device{
&mock_biod_metrics, std::make_unique<MockFpContextFactory>()};
};
// Test that if FPMCU is in match mode, setting context will trigger a call to
// set FPMCU to none mode then another call to set it back to match mode, and
// will send the original mode to UMA.
TEST_F(CrosFpDevice_SetContext, MatchMode) {
{
testing::InSequence s;
EXPECT_CALL(mock_cros_fp_device, GetFpMode).WillOnce([]() {
return FpMode(FpMode::Mode::kMatch);
});
EXPECT_CALL(mock_cros_fp_device, SetFpMode(FpMode(FpMode::Mode::kNone)))
.WillOnce(Return(true));
EXPECT_CALL(mock_biod_metrics,
SendSetContextMode(FpMode(FpMode::Mode::kMatch)));
EXPECT_CALL(mock_cros_fp_device, SetFpMode(FpMode(FpMode::Mode::kMatch)))
.WillOnce(Return(true));
EXPECT_CALL(mock_biod_metrics, SendSetContextSuccess(true));
}
mock_cros_fp_device.SetContext("beef");
}
// Test that failure to get FPMCU mode in setting context will cause the
// failure to be sent to UMA.
TEST_F(CrosFpDevice_SetContext, SendMetricsOnFailingToGetMode) {
EXPECT_CALL(mock_cros_fp_device, GetFpMode)
.WillOnce(Return(FpMode(FpMode::Mode::kModeInvalid)));
EXPECT_CALL(mock_biod_metrics, SendSetContextSuccess(false));
mock_cros_fp_device.SetContext("beef");
}
// Test that failure to set FPMCU mode in setting context will cause the
// failure to be sent to UMA.
TEST_F(CrosFpDevice_SetContext, SendMetricsOnFailingToSetMode) {
EXPECT_CALL(mock_cros_fp_device, GetFpMode).WillOnce([]() {
return FpMode(FpMode::Mode::kMatch);
});
EXPECT_CALL(mock_cros_fp_device, SetFpMode).WillRepeatedly(Return(false));
EXPECT_CALL(mock_biod_metrics, SendSetContextSuccess(false));
mock_cros_fp_device.SetContext("beef");
}
class CrosFpDevice_DeadPixelCount : public testing::Test {
public:
CrosFpDevice_DeadPixelCount() {
auto mock_command_factory = std::make_unique<ec::MockEcCommandFactory>();
mock_ec_command_factory_ = mock_command_factory.get();
mock_cros_fp_device_ = std::make_unique<MockCrosFpDevice>(
&mock_biod_metrics_, std::move(mock_command_factory));
}
protected:
class MockCrosFpDevice : public CrosFpDevice {
public:
MockCrosFpDevice(
BiodMetricsInterface* biod_metrics,
std::unique_ptr<EcCommandFactoryInterface> ec_command_factory)
: CrosFpDevice(biod_metrics, std::move(ec_command_factory)) {}
};
class MockFpInfoCommand : public FpInfoCommand {
public:
MockFpInfoCommand() { ON_CALL(*this, Run).WillByDefault(Return(true)); }
MOCK_METHOD(bool, Run, (int fd), (override));
MOCK_METHOD(ec_response_fp_info*, Resp, (), (override));
};
metrics::MockBiodMetrics mock_biod_metrics_;
ec::MockEcCommandFactory* mock_ec_command_factory_ = nullptr;
std::unique_ptr<CrosFpDevice> mock_cros_fp_device_;
};
TEST_F(CrosFpDevice_DeadPixelCount, UnknownCount) {
struct ec_response_fp_info resp = {.errors = FP_ERROR_DEAD_PIXELS_UNKNOWN};
EXPECT_CALL(*mock_ec_command_factory_, FpInfoCommand).WillOnce([&resp]() {
auto mock_fp_info_command = std::make_unique<NiceMock<MockFpInfoCommand>>();
EXPECT_CALL(*mock_fp_info_command, Resp).WillRepeatedly(Return(&resp));
return mock_fp_info_command;
});
EXPECT_EQ(mock_cros_fp_device_->DeadPixelCount(),
FpInfoCommand::kDeadPixelsUnknown);
}
TEST_F(CrosFpDevice_DeadPixelCount, OneDeadPixel) {
struct ec_response_fp_info resp = {.errors = FP_ERROR_DEAD_PIXELS(1)};
EXPECT_CALL(*mock_ec_command_factory_, FpInfoCommand).WillOnce([&resp]() {
auto mock_fp_info_command = std::make_unique<NiceMock<MockFpInfoCommand>>();
EXPECT_CALL(*mock_fp_info_command, Resp).WillRepeatedly(Return(&resp));
return mock_fp_info_command;
});
EXPECT_EQ(mock_cros_fp_device_->DeadPixelCount(), 1);
}
class CrosFpDevice_ReadVersion : public testing::Test {
public:
static inline const std::string kValidVersionStr =
"1.0.0\n"
"bloonchipper_v2.0.4277-9f652bb3\n"
"bloonchipper_v2.0.4277-9f652bb3\n"
"read-write\n";
class MockCrosFpDevice : public CrosFpDevice {
public:
MockCrosFpDevice(
BiodMetricsInterface* biod_metrics,
std::unique_ptr<EcCommandFactoryInterface> ec_command_factory)
: CrosFpDevice(biod_metrics, std::move(ec_command_factory)) {}
MOCK_METHOD(int, read, (int, void*, size_t), (override));
using CrosFpDevice::ReadVersion;
};
protected:
metrics::MockBiodMetrics mock_biod_metrics_;
MockCrosFpDevice mock_cros_fp_device_{
&mock_biod_metrics_, std::make_unique<ec::MockEcCommandFactory>()};
};
// Test reading the version string where the string returned by the driver is
// not NUL terminated. The driver won't do this unless the "count" requested
// by userspace in the "read" system call does not have enough space. This test
// doesn't exactly replicate that condition exactly since we don't change
// "count".
TEST_F(CrosFpDevice_ReadVersion, ValidVersionStringNotNulTerminated) {
EXPECT_EQ(kValidVersionStr.size(), 81);
EXPECT_CALL(mock_cros_fp_device_, read)
.WillOnce([](int, void* buf, size_t count) {
// Copy string, excluding terminating NUL.
int num_bytes_to_copy = kValidVersionStr.size();
EXPECT_GE(count, num_bytes_to_copy);
uint8_t* buffer = static_cast<uint8_t*>(buf);
std::memcpy(buffer, kValidVersionStr.data(), num_bytes_to_copy);
return num_bytes_to_copy;
});
std::optional<std::string> version = mock_cros_fp_device_.ReadVersion();
EXPECT_TRUE(version.has_value());
EXPECT_EQ(*version, std::string("1.0.0"));
}
TEST_F(CrosFpDevice_ReadVersion, ValidVersionStringNulTerminated) {
EXPECT_EQ(kValidVersionStr.size(), 81);
EXPECT_CALL(mock_cros_fp_device_, read)
.WillOnce([](int, void* buf, size_t count) {
// Copy entire string, including terminating NUL.
int num_bytes_to_copy = kValidVersionStr.size() + 1;
EXPECT_EQ(num_bytes_to_copy, 82);
EXPECT_GE(count, num_bytes_to_copy);
uint8_t* buffer = static_cast<uint8_t*>(buf);
std::memcpy(buffer, kValidVersionStr.data(), num_bytes_to_copy);
return num_bytes_to_copy;
});
std::optional<std::string> version = mock_cros_fp_device_.ReadVersion();
EXPECT_TRUE(version.has_value());
EXPECT_EQ(*version, std::string("1.0.0"));
}
TEST_F(CrosFpDevice_ReadVersion, InvalidVersionStringNoNewline) {
const std::string kInvalidVersionStr = "1.0.0";
EXPECT_CALL(mock_cros_fp_device_, read)
.WillOnce([kInvalidVersionStr](int, void* buf, size_t count) {
// Copy string, including terminating NUL.
int num_bytes_to_copy = kInvalidVersionStr.size() + 1;
EXPECT_GE(count, num_bytes_to_copy);
uint8_t* buffer = static_cast<uint8_t*>(buf);
std::memcpy(buffer, kInvalidVersionStr.data(), num_bytes_to_copy);
return num_bytes_to_copy;
});
std::optional<std::string> version = mock_cros_fp_device_.ReadVersion();
EXPECT_FALSE(version.has_value());
}
class CrosFpDevice_UploadTemplate : public testing::Test {
public:
CrosFpDevice_UploadTemplate() {
auto mock_command_factory = std::make_unique<ec::MockEcCommandFactory>();
mock_ec_command_factory_ = mock_command_factory.get();
mock_cros_fp_device_ = std::make_unique<MockCrosFpDevice>(
&mock_biod_metrics_, std::move(mock_command_factory));
}
protected:
class MockCrosFpDevice : public CrosFpDevice {
public:
MockCrosFpDevice(
BiodMetricsInterface* biod_metrics,
std::unique_ptr<EcCommandFactoryInterface> ec_command_factory)
: CrosFpDevice(biod_metrics, std::move(ec_command_factory)) {}
};
class MockFpTemplateCommand : public FpTemplateCommand {
public:
MockFpTemplateCommand(std::vector<uint8_t> tmpl, uint16_t max_write_size)
: FpTemplateCommand(tmpl, max_write_size) {
ON_CALL(*this, Run).WillByDefault(Return(true));
ON_CALL(*this, Result).WillByDefault(Return(EC_RES_SUCCESS));
}
MOCK_METHOD(bool, Run, (int fd), (override));
MOCK_METHOD(uint32_t, Result, (), (override, const));
};
class MockFpUnlockTemplateCommand : public FpUnlockTemplateCommand {
public:
MockFpUnlockTemplateCommand() {
ON_CALL(*this, Run).WillByDefault(Return(true));
}
MOCK_METHOD(bool, Run, (int fd), (override));
MOCK_METHOD(uint32_t, Result, (), (override, const));
};
metrics::MockBiodMetrics mock_biod_metrics_;
ec::MockEcCommandFactory* mock_ec_command_factory_ = nullptr;
std::unique_ptr<CrosFpDevice> mock_cros_fp_device_;
};
TEST_F(CrosFpDevice_UploadTemplate, Success) {
std::vector<uint8_t> templ;
EXPECT_CALL(*mock_ec_command_factory_, FpTemplateCommand)
.WillOnce([](std::vector<uint8_t> tmpl, uint16_t max_write_size) {
return std::make_unique<NiceMock<MockFpTemplateCommand>>(
tmpl, max_write_size);
});
EXPECT_CALL(mock_biod_metrics_, SendUploadTemplateResult(EC_RES_SUCCESS));
EXPECT_TRUE(mock_cros_fp_device_->UploadTemplate(templ));
}
TEST_F(CrosFpDevice_UploadTemplate, RunFailure) {
std::vector<uint8_t> templ;
EXPECT_CALL(*mock_ec_command_factory_, FpTemplateCommand)
.WillOnce([](std::vector<uint8_t> tmpl, uint16_t max_write_size) {
auto cmd = std::make_unique<NiceMock<MockFpTemplateCommand>>(
tmpl, max_write_size);
EXPECT_CALL(*cmd, Run).WillRepeatedly(Return(false));
return cmd;
});
EXPECT_CALL(mock_biod_metrics_,
SendUploadTemplateResult(metrics::kCmdRunFailure));
EXPECT_FALSE(mock_cros_fp_device_->UploadTemplate(templ));
}
TEST_F(CrosFpDevice_UploadTemplate, UnlockNoOp) {
EXPECT_TRUE(mock_cros_fp_device_->UnlockTemplates(0));
}
TEST_F(CrosFpDevice_UploadTemplate, UnlockSuccess) {
constexpr uint16_t kFingerNum = 3;
EXPECT_CALL(*mock_ec_command_factory_, FpUnlockTemplateCommand)
.WillOnce([kFingerNum](uint16_t finger_num) {
EXPECT_EQ(finger_num, kFingerNum);
return std::make_unique<NiceMock<MockFpUnlockTemplateCommand>>();
});
EXPECT_TRUE(mock_cros_fp_device_->UnlockTemplates(kFingerNum));
}
TEST_F(CrosFpDevice_UploadTemplate, UnlockRunFailure) {
constexpr uint16_t kFingerNum = 3;
EXPECT_CALL(*mock_ec_command_factory_, FpUnlockTemplateCommand)
.WillOnce([kFingerNum](uint16_t finger_num) {
EXPECT_EQ(finger_num, kFingerNum);
auto cmd = std::make_unique<NiceMock<MockFpUnlockTemplateCommand>>();
EXPECT_CALL(*cmd, Run).WillRepeatedly(Return(false));
return cmd;
});
EXPECT_FALSE(mock_cros_fp_device_->UnlockTemplates(kFingerNum));
}
TEST_F(CrosFpDevice_UploadTemplate, UnlockCommandFailure) {
constexpr uint16_t kFingerNum = 3;
EXPECT_CALL(*mock_ec_command_factory_, FpUnlockTemplateCommand)
.WillOnce([kFingerNum](uint16_t finger_num) {
EXPECT_EQ(finger_num, kFingerNum);
auto cmd = std::make_unique<NiceMock<MockFpUnlockTemplateCommand>>();
EXPECT_CALL(*cmd, Result).WillRepeatedly(Return(EC_RES_ERROR));
return cmd;
});
EXPECT_FALSE(mock_cros_fp_device_->UnlockTemplates(kFingerNum));
}
class CrosFpDevice_HwErrors : public testing::Test {
public:
CrosFpDevice_HwErrors() {
auto mock_command_factory = std::make_unique<ec::MockEcCommandFactory>();
mock_ec_command_factory_ = mock_command_factory.get();
mock_cros_fp_device_ = std::make_unique<MockCrosFpDevice>(
&mock_biod_metrics_, std::move(mock_command_factory));
}
protected:
class MockCrosFpDevice : public CrosFpDevice {
public:
MockCrosFpDevice(
BiodMetricsInterface* biod_metrics,
std::unique_ptr<EcCommandFactoryInterface> ec_command_factory)
: CrosFpDevice(biod_metrics, std::move(ec_command_factory)) {}
};
class MockFpInfoCommand : public FpInfoCommand {
public:
MockFpInfoCommand() { ON_CALL(*this, Run).WillByDefault(Return(true)); }
MOCK_METHOD(bool, Run, (int fd), (override));
MOCK_METHOD(ec_response_fp_info*, Resp, (), (override));
};
metrics::MockBiodMetrics mock_biod_metrics_;
ec::MockEcCommandFactory* mock_ec_command_factory_ = nullptr;
std::unique_ptr<CrosFpDevice> mock_cros_fp_device_;
};
TEST_F(CrosFpDevice_HwErrors, Errors_None) {
struct ec_response_fp_info resp = {.errors = FP_ERROR_DEAD_PIXELS_UNKNOWN};
EXPECT_CALL(*mock_ec_command_factory_, FpInfoCommand).WillOnce([&resp]() {
auto mock_fp_info_command = std::make_unique<NiceMock<MockFpInfoCommand>>();
EXPECT_CALL(*mock_fp_info_command, Resp).WillRepeatedly(Return(&resp));
return mock_fp_info_command;
});
EXPECT_EQ(mock_cros_fp_device_->GetHwErrors(), FpSensorErrors::kNone);
}
TEST_F(CrosFpDevice_HwErrors, Errors_NoIrq) {
struct ec_response_fp_info resp = {.errors = FP_ERROR_NO_IRQ |
FP_ERROR_DEAD_PIXELS_UNKNOWN};
EXPECT_CALL(*mock_ec_command_factory_, FpInfoCommand).WillOnce([&resp]() {
auto mock_fp_info_command = std::make_unique<NiceMock<MockFpInfoCommand>>();
EXPECT_CALL(*mock_fp_info_command, Resp).WillRepeatedly(Return(&resp));
return mock_fp_info_command;
});
EXPECT_EQ(mock_cros_fp_device_->GetHwErrors(), FpSensorErrors::kNoIrq);
}
TEST_F(CrosFpDevice_HwErrors, Errors_SpiCommunication) {
struct ec_response_fp_info resp = {.errors = FP_ERROR_SPI_COMM |
FP_ERROR_DEAD_PIXELS_UNKNOWN};
EXPECT_CALL(*mock_ec_command_factory_, FpInfoCommand).WillOnce([&resp]() {
auto mock_fp_info_command = std::make_unique<NiceMock<MockFpInfoCommand>>();
EXPECT_CALL(*mock_fp_info_command, Resp).WillRepeatedly(Return(&resp));
return mock_fp_info_command;
});
EXPECT_EQ(mock_cros_fp_device_->GetHwErrors(),
FpSensorErrors::kSpiCommunication);
}
TEST_F(CrosFpDevice_HwErrors, Errors_BadHardwareID) {
struct ec_response_fp_info resp = {.errors = FP_ERROR_BAD_HWID |
FP_ERROR_DEAD_PIXELS_UNKNOWN};
EXPECT_CALL(*mock_ec_command_factory_, FpInfoCommand).WillOnce([&resp]() {
auto mock_fp_info_command = std::make_unique<NiceMock<MockFpInfoCommand>>();
EXPECT_CALL(*mock_fp_info_command, Resp).WillRepeatedly(Return(&resp));
return mock_fp_info_command;
});
EXPECT_EQ(mock_cros_fp_device_->GetHwErrors(),
FpSensorErrors::kBadHardwareID);
}
TEST_F(CrosFpDevice_HwErrors, Errors_InitializationFailure) {
struct ec_response_fp_info resp = {.errors = FP_ERROR_INIT_FAIL |
FP_ERROR_DEAD_PIXELS_UNKNOWN};
EXPECT_CALL(*mock_ec_command_factory_, FpInfoCommand).WillOnce([&resp]() {
auto mock_fp_info_command = std::make_unique<NiceMock<MockFpInfoCommand>>();
EXPECT_CALL(*mock_fp_info_command, Resp).WillRepeatedly(Return(&resp));
return mock_fp_info_command;
});
EXPECT_EQ(mock_cros_fp_device_->GetHwErrors(),
FpSensorErrors::kInitializationFailure);
}
TEST_F(CrosFpDevice_HwErrors, Errors_InitializationFailureOrBadHardwareID) {
struct ec_response_fp_info resp = {.errors = FP_ERROR_INIT_FAIL |
FP_ERROR_DEAD_PIXELS_UNKNOWN |
FP_ERROR_BAD_HWID};
EXPECT_CALL(*mock_ec_command_factory_, FpInfoCommand).WillOnce([&resp]() {
auto mock_fp_info_command = std::make_unique<NiceMock<MockFpInfoCommand>>();
EXPECT_CALL(*mock_fp_info_command, Resp).WillRepeatedly(Return(&resp));
return mock_fp_info_command;
});
EXPECT_EQ(
mock_cros_fp_device_->GetHwErrors(),
FpSensorErrors::kInitializationFailure | FpSensorErrors::kBadHardwareID);
}
class CrosFpDevice_GetNonce : public testing::Test {
public:
CrosFpDevice_GetNonce() {
auto mock_command_factory = std::make_unique<ec::MockEcCommandFactory>();
mock_ec_command_factory_ = mock_command_factory.get();
mock_cros_fp_device_ = std::make_unique<MockCrosFpDevice>(
&mock_biod_metrics_, std::move(mock_command_factory));
}
protected:
class MockCrosFpDevice : public CrosFpDevice {
public:
MockCrosFpDevice(
BiodMetricsInterface* biod_metrics,
std::unique_ptr<EcCommandFactoryInterface> ec_command_factory)
: CrosFpDevice(biod_metrics, std::move(ec_command_factory)) {}
};
class MockFpGetNonceCommand : public FpGetNonceCommand {
public:
MockFpGetNonceCommand() { ON_CALL(*this, Run).WillByDefault(Return(true)); }
MOCK_METHOD(bool, Run, (int fd), (override));
MOCK_METHOD(brillo::Blob, Nonce, (), (override, const));
};
metrics::MockBiodMetrics mock_biod_metrics_;
ec::MockEcCommandFactory* mock_ec_command_factory_ = nullptr;
std::unique_ptr<CrosFpDevice> mock_cros_fp_device_;
};
TEST_F(CrosFpDevice_GetNonce, Success) {
const brillo::Blob kNonce(32, 1);
EXPECT_CALL(*mock_ec_command_factory_, FpGetNonceCommand).WillOnce([&]() {
auto cmd = std::make_unique<NiceMock<MockFpGetNonceCommand>>();
EXPECT_CALL(*cmd, Nonce).WillRepeatedly(Return(kNonce));
return cmd;
});
std::optional<brillo::Blob> nonce = mock_cros_fp_device_->GetNonce();
ASSERT_TRUE(nonce.has_value());
EXPECT_EQ(nonce, kNonce);
}
TEST_F(CrosFpDevice_GetNonce, RunFailure) {
EXPECT_CALL(*mock_ec_command_factory_, FpGetNonceCommand).WillOnce([]() {
auto cmd = std::make_unique<NiceMock<MockFpGetNonceCommand>>();
EXPECT_CALL(*cmd, Run).WillRepeatedly(Return(false));
return cmd;
});
std::optional<brillo::Blob> nonce = mock_cros_fp_device_->GetNonce();
EXPECT_FALSE(nonce.has_value());
}
class CrosFpDevice_SetNonceContext : public testing::Test {
public:
CrosFpDevice_SetNonceContext() {
auto mock_command_factory = std::make_unique<ec::MockEcCommandFactory>();
mock_ec_command_factory_ = mock_command_factory.get();
mock_cros_fp_device_ = std::make_unique<MockCrosFpDevice>(
&mock_biod_metrics_, std::move(mock_command_factory));
}
protected:
class MockCrosFpDevice : public CrosFpDevice {
public:
MockCrosFpDevice(
BiodMetricsInterface* biod_metrics,
std::unique_ptr<EcCommandFactoryInterface> ec_command_factory)
: CrosFpDevice(biod_metrics, std::move(ec_command_factory)) {}
};
class MockFpSetNonceContextCommand : public FpSetNonceContextCommand {
public:
using FpSetNonceContextCommand::FpSetNonceContextCommand;
MOCK_METHOD(bool, Run, (int fd), (override));
};
metrics::MockBiodMetrics mock_biod_metrics_;
ec::MockEcCommandFactory* mock_ec_command_factory_ = nullptr;
std::unique_ptr<CrosFpDevice> mock_cros_fp_device_;
};
TEST_F(CrosFpDevice_SetNonceContext, Success) {
const brillo::Blob kNonce(32, 1);
const brillo::Blob kUserId(32, 2);
const brillo::Blob kIv(16, 3);
EXPECT_CALL(*mock_ec_command_factory_, FpSetNonceContextCommand)
.WillOnce([](const brillo::Blob& nonce,
const brillo::Blob& encrypted_user_id,
const brillo::Blob& iv)
-> std::unique_ptr<FpSetNonceContextCommand> {
auto cmd =
FpSetNonceContextCommand::Create<MockFpSetNonceContextCommand>(
nonce, encrypted_user_id, iv);
if (cmd) {
EXPECT_CALL(*cmd, Run).WillRepeatedly(Return(true));
}
return cmd;
});
EXPECT_TRUE(mock_cros_fp_device_->SetNonceContext(kNonce, kUserId, kIv));
}
TEST_F(CrosFpDevice_SetNonceContext, InvalidParams) {
// Incorrect size.
const brillo::Blob kNonce(33, 1);
const brillo::Blob kUserId(32, 2);
const brillo::Blob kIv(16, 3);
EXPECT_CALL(*mock_ec_command_factory_, FpSetNonceContextCommand)
.WillOnce([](const brillo::Blob& nonce,
const brillo::Blob& encrypted_user_id,
const brillo::Blob& iv)
-> std::unique_ptr<FpSetNonceContextCommand> {
auto cmd =
FpSetNonceContextCommand::Create<MockFpSetNonceContextCommand>(
nonce, encrypted_user_id, iv);
EXPECT_EQ(cmd, nullptr);
return cmd;
});
EXPECT_FALSE(mock_cros_fp_device_->SetNonceContext(kNonce, kUserId, kIv));
}
TEST_F(CrosFpDevice_SetNonceContext, RunFailure) {
const brillo::Blob kNonce(32, 1);
const brillo::Blob kUserId(32, 2);
const brillo::Blob kIv(16, 3);
EXPECT_CALL(*mock_ec_command_factory_, FpSetNonceContextCommand)
.WillOnce([](const brillo::Blob& nonce,
const brillo::Blob& encrypted_user_id,
const brillo::Blob& iv)
-> std::unique_ptr<FpSetNonceContextCommand> {
auto cmd =
FpSetNonceContextCommand::Create<MockFpSetNonceContextCommand>(
nonce, encrypted_user_id, iv);
if (cmd) {
EXPECT_CALL(*cmd, Run).WillRepeatedly(Return(false));
}
return cmd;
});
EXPECT_FALSE(mock_cros_fp_device_->SetNonceContext(kNonce, kUserId, kIv));
}
class CrosFpDevice_GetPositiveMatchSecretWithPubkey : public testing::Test {
public:
CrosFpDevice_GetPositiveMatchSecretWithPubkey() {
auto mock_command_factory = std::make_unique<ec::MockEcCommandFactory>();
mock_ec_command_factory_ = mock_command_factory.get();
mock_cros_fp_device_ = std::make_unique<MockCrosFpDevice>(
&mock_biod_metrics_, std::move(mock_command_factory));
}
protected:
class MockCrosFpDevice : public CrosFpDevice {
public:
MockCrosFpDevice(
BiodMetricsInterface* biod_metrics,
std::unique_ptr<EcCommandFactoryInterface> ec_command_factory)
: CrosFpDevice(biod_metrics, std::move(ec_command_factory)) {}
};
class MockFpReadMatchSecretWithPubkeyCommand
: public FpReadMatchSecretWithPubkeyCommand {
public:
using FpReadMatchSecretWithPubkeyCommand::
FpReadMatchSecretWithPubkeyCommand;
MOCK_METHOD(bool, Run, (int fd), (override));
MOCK_METHOD(brillo::Blob, EncryptedSecret, (), (override, const));
MOCK_METHOD(brillo::Blob, Iv, (), (override, const));
MOCK_METHOD(brillo::Blob, PkOutX, (), (override, const));
MOCK_METHOD(brillo::Blob, PkOutY, (), (override, const));
};
metrics::MockBiodMetrics mock_biod_metrics_;
ec::MockEcCommandFactory* mock_ec_command_factory_ = nullptr;
std::unique_ptr<CrosFpDevice> mock_cros_fp_device_;
};
TEST_F(CrosFpDevice_GetPositiveMatchSecretWithPubkey, Success) {
const uint16_t kIndex = 0;
const brillo::Blob kPkInX(32, 1);
const brillo::Blob kPkInY(32, 2);
const brillo::Blob kEncryptedSecret(32, 3);
const brillo::Blob kIv(16, 4);
const brillo::Blob kPkOutX(32, 5);
const brillo::Blob kPkOutY(32, 6);
EXPECT_CALL(*mock_ec_command_factory_, FpReadMatchSecretWithPubkeyCommand)
.WillOnce([&](uint16_t index, const brillo::Blob& pk_in_x,
const brillo::Blob& pk_in_y)
-> std::unique_ptr<FpReadMatchSecretWithPubkeyCommand> {
auto cmd = FpReadMatchSecretWithPubkeyCommand::Create<
MockFpReadMatchSecretWithPubkeyCommand>(index, pk_in_x, pk_in_y);
if (cmd) {
EXPECT_CALL(*cmd, Run).WillRepeatedly(Return(true));
EXPECT_CALL(*cmd, EncryptedSecret)
.WillRepeatedly(Return(kEncryptedSecret));
EXPECT_CALL(*cmd, Iv).WillRepeatedly(Return(kIv));
EXPECT_CALL(*cmd, PkOutX).WillRepeatedly(Return(kPkOutX));
EXPECT_CALL(*cmd, PkOutY).WillRepeatedly(Return(kPkOutY));
}
return cmd;
});
std::optional<ec::CrosFpDeviceInterface::GetSecretReply> reply =
mock_cros_fp_device_->GetPositiveMatchSecretWithPubkey(kIndex, kPkInX,
kPkInY);
ASSERT_TRUE(reply.has_value());
EXPECT_EQ(reply->encrypted_secret, kEncryptedSecret);
EXPECT_EQ(reply->iv, kIv);
EXPECT_EQ(reply->pk_out_x, kPkOutX);
EXPECT_EQ(reply->pk_out_y, kPkOutY);
}
TEST_F(CrosFpDevice_GetPositiveMatchSecretWithPubkey, InvalidParams) {
const uint16_t kIndex = 0;
// Incorrect size.
const brillo::Blob kPkInX(33, 1);
const brillo::Blob kPkInY(32, 2);
EXPECT_CALL(*mock_ec_command_factory_, FpReadMatchSecretWithPubkeyCommand)
.WillOnce([&](uint16_t index, const brillo::Blob& pk_in_x,
const brillo::Blob& pk_in_y)
-> std::unique_ptr<FpReadMatchSecretWithPubkeyCommand> {
auto cmd = FpReadMatchSecretWithPubkeyCommand::Create<
MockFpReadMatchSecretWithPubkeyCommand>(index, pk_in_x, pk_in_y);
EXPECT_EQ(cmd, nullptr);
return cmd;
});
std::optional<ec::CrosFpDeviceInterface::GetSecretReply> reply =
mock_cros_fp_device_->GetPositiveMatchSecretWithPubkey(kIndex, kPkInX,
kPkInY);
EXPECT_FALSE(reply.has_value());
}
TEST_F(CrosFpDevice_GetPositiveMatchSecretWithPubkey, RunFailure) {
const uint16_t kIndex = 0;
const brillo::Blob kPkInX(32, 1);
const brillo::Blob kPkInY(32, 2);
EXPECT_CALL(*mock_ec_command_factory_, FpReadMatchSecretWithPubkeyCommand)
.WillOnce([&](uint16_t index, const brillo::Blob& pk_in_x,
const brillo::Blob& pk_in_y)
-> std::unique_ptr<FpReadMatchSecretWithPubkeyCommand> {
auto cmd = FpReadMatchSecretWithPubkeyCommand::Create<
MockFpReadMatchSecretWithPubkeyCommand>(index, pk_in_x, pk_in_y);
if (cmd) {
EXPECT_CALL(*cmd, Run).WillRepeatedly(Return(false));
}
return cmd;
});
std::optional<ec::CrosFpDeviceInterface::GetSecretReply> reply =
mock_cros_fp_device_->GetPositiveMatchSecretWithPubkey(kIndex, kPkInX,
kPkInY);
EXPECT_FALSE(reply.has_value());
}
class CrosFpDevice_PairingKeyKeygen : public testing::Test {
public:
CrosFpDevice_PairingKeyKeygen() {
auto mock_command_factory = std::make_unique<ec::MockEcCommandFactory>();
mock_ec_command_factory_ = mock_command_factory.get();
mock_cros_fp_device_ = std::make_unique<MockCrosFpDevice>(
&mock_biod_metrics_, std::move(mock_command_factory));
}
protected:
class MockCrosFpDevice : public CrosFpDevice {
public:
MockCrosFpDevice(
BiodMetricsInterface* biod_metrics,
std::unique_ptr<EcCommandFactoryInterface> ec_command_factory)
: CrosFpDevice(biod_metrics, std::move(ec_command_factory)) {}
};
class MockFpPairingKeyKeygenCommand : public FpPairingKeyKeygenCommand {
public:
MockFpPairingKeyKeygenCommand() {
ON_CALL(*this, Run).WillByDefault(Return(true));
}
MOCK_METHOD(bool, Run, (int fd), (override));
MOCK_METHOD(brillo::Blob, PubX, (), (override, const));
MOCK_METHOD(brillo::Blob, PubY, (), (override, const));
MOCK_METHOD(brillo::Blob, EncryptedKey, (), (override, const));
};
metrics::MockBiodMetrics mock_biod_metrics_;
ec::MockEcCommandFactory* mock_ec_command_factory_ = nullptr;
std::unique_ptr<CrosFpDevice> mock_cros_fp_device_;
};
TEST_F(CrosFpDevice_PairingKeyKeygen, Success) {
const brillo::Blob kPubX(32, 1);
const brillo::Blob kPubY(32, 2);
const brillo::Blob kEncryptedKey(sizeof(fp_encrypted_private_key), 3);
EXPECT_CALL(*mock_ec_command_factory_, FpPairingKeyKeygenCommand)
.WillOnce([&]() {
auto cmd = std::make_unique<NiceMock<MockFpPairingKeyKeygenCommand>>();
EXPECT_CALL(*cmd, PubX).WillRepeatedly(Return(kPubX));
EXPECT_CALL(*cmd, PubY).WillRepeatedly(Return(kPubY));
EXPECT_CALL(*cmd, EncryptedKey).WillRepeatedly(Return(kEncryptedKey));
return cmd;
});
std::optional<ec::CrosFpDeviceInterface::PairingKeyKeygenReply> reply =
mock_cros_fp_device_->PairingKeyKeygen();
ASSERT_TRUE(reply.has_value());
EXPECT_EQ(reply->pub_x, kPubX);
EXPECT_EQ(reply->pub_y, kPubY);
EXPECT_EQ(reply->encrypted_private_key, kEncryptedKey);
}
TEST_F(CrosFpDevice_PairingKeyKeygen, RunFailure) {
EXPECT_CALL(*mock_ec_command_factory_, FpPairingKeyKeygenCommand)
.WillOnce([]() {
auto cmd = std::make_unique<NiceMock<MockFpPairingKeyKeygenCommand>>();
EXPECT_CALL(*cmd, Run).WillRepeatedly(Return(false));
return cmd;
});
std::optional<ec::CrosFpDeviceInterface::PairingKeyKeygenReply> reply =
mock_cros_fp_device_->PairingKeyKeygen();
EXPECT_FALSE(reply.has_value());
}
class CrosFpDevice_LoadPairingKey : public testing::Test {
public:
CrosFpDevice_LoadPairingKey() {
auto mock_command_factory = std::make_unique<ec::MockEcCommandFactory>();
mock_ec_command_factory_ = mock_command_factory.get();
mock_cros_fp_device_ = std::make_unique<MockCrosFpDevice>(
&mock_biod_metrics_, std::move(mock_command_factory));
}
protected:
class MockCrosFpDevice : public CrosFpDevice {
public:
MockCrosFpDevice(
BiodMetricsInterface* biod_metrics,
std::unique_ptr<EcCommandFactoryInterface> ec_command_factory)
: CrosFpDevice(biod_metrics, std::move(ec_command_factory)) {}
};
class MockFpPairingKeyLoadCommand : public FpPairingKeyLoadCommand {
public:
using FpPairingKeyLoadCommand::FpPairingKeyLoadCommand;
MOCK_METHOD(bool, Run, (int fd), (override));
};
metrics::MockBiodMetrics mock_biod_metrics_;
ec::MockEcCommandFactory* mock_ec_command_factory_ = nullptr;
std::unique_ptr<CrosFpDevice> mock_cros_fp_device_;
};
TEST_F(CrosFpDevice_LoadPairingKey, Success) {
const brillo::Blob kEncryptedKey(sizeof(ec_fp_encrypted_pairing_key), 1);
EXPECT_CALL(*mock_ec_command_factory_, FpPairingKeyLoadCommand)
.WillOnce([](const brillo::Blob& encrypted_key)
-> std::unique_ptr<FpPairingKeyLoadCommand> {
auto cmd = FpPairingKeyLoadCommand::Create<MockFpPairingKeyLoadCommand>(
encrypted_key);
if (cmd) {
EXPECT_CALL(*cmd, Run).WillRepeatedly(Return(true));
}
return cmd;
});
EXPECT_TRUE(mock_cros_fp_device_->LoadPairingKey(kEncryptedKey));
}
TEST_F(CrosFpDevice_LoadPairingKey, InvalidParams) {
// Incorrect size.
const brillo::Blob kEncryptedKey(sizeof(ec_fp_encrypted_pairing_key) + 1, 1);
EXPECT_CALL(*mock_ec_command_factory_, FpPairingKeyLoadCommand)
.WillOnce([](const brillo::Blob& encrypted_key)
-> std::unique_ptr<FpPairingKeyLoadCommand> {
auto cmd = FpPairingKeyLoadCommand::Create<MockFpPairingKeyLoadCommand>(
encrypted_key);
EXPECT_EQ(cmd, nullptr);
return cmd;
});
EXPECT_FALSE(mock_cros_fp_device_->LoadPairingKey(kEncryptedKey));
}
TEST_F(CrosFpDevice_LoadPairingKey, RunFailure) {
const brillo::Blob kEncryptedKey(sizeof(ec_fp_encrypted_pairing_key), 1);
EXPECT_CALL(*mock_ec_command_factory_, FpPairingKeyLoadCommand)
.WillOnce([](const brillo::Blob& encrypted_key)
-> std::unique_ptr<FpPairingKeyLoadCommand> {
auto cmd = FpPairingKeyLoadCommand::Create<MockFpPairingKeyLoadCommand>(
encrypted_key);
if (cmd) {
EXPECT_CALL(*cmd, Run).WillRepeatedly(Return(false));
}
return cmd;
});
EXPECT_FALSE(mock_cros_fp_device_->LoadPairingKey(kEncryptedKey));
}
class CrosFpDevice_PairingKeyWrap : public testing::Test {
public:
CrosFpDevice_PairingKeyWrap() {
auto mock_command_factory = std::make_unique<ec::MockEcCommandFactory>();
mock_ec_command_factory_ = mock_command_factory.get();
mock_cros_fp_device_ = std::make_unique<MockCrosFpDevice>(
&mock_biod_metrics_, std::move(mock_command_factory));
}
protected:
class MockCrosFpDevice : public CrosFpDevice {
public:
MockCrosFpDevice(
BiodMetricsInterface* biod_metrics,
std::unique_ptr<EcCommandFactoryInterface> ec_command_factory)
: CrosFpDevice(biod_metrics, std::move(ec_command_factory)) {}
};
class MockFpPairingKeyWrapCommand : public FpPairingKeyWrapCommand {
public:
using FpPairingKeyWrapCommand::FpPairingKeyWrapCommand;
MOCK_METHOD(bool, Run, (int fd), (override));
MOCK_METHOD(brillo::Blob, EncryptedPairingKey, (), (override, const));
};
metrics::MockBiodMetrics mock_biod_metrics_;
ec::MockEcCommandFactory* mock_ec_command_factory_ = nullptr;
std::unique_ptr<CrosFpDevice> mock_cros_fp_device_;
};
TEST_F(CrosFpDevice_PairingKeyWrap, Success) {
const brillo::Blob kPubX(32, 1);
const brillo::Blob kPubY(32, 2);
const brillo::Blob kEncryptedKey(sizeof(fp_encrypted_private_key), 3);
const brillo::Blob kEncryptedPk(sizeof(ec_fp_encrypted_pairing_key), 4);
EXPECT_CALL(*mock_ec_command_factory_, FpPairingKeyWrapCommand)
.WillOnce([&](const brillo::Blob& pub_x, const brillo::Blob& pub_y,
const brillo::Blob& encrypted_key)
-> std::unique_ptr<FpPairingKeyWrapCommand> {
auto cmd = FpPairingKeyWrapCommand::Create<MockFpPairingKeyWrapCommand>(
pub_x, pub_y, encrypted_key);
if (cmd) {
EXPECT_CALL(*cmd, Run).WillRepeatedly(Return(true));
EXPECT_CALL(*cmd, EncryptedPairingKey)
.WillRepeatedly(Return(kEncryptedPk));
}
return cmd;
});
std::optional<brillo::Blob> reply =
mock_cros_fp_device_->PairingKeyWrap(kPubX, kPubY, kEncryptedKey);
ASSERT_TRUE(reply.has_value());
EXPECT_EQ(*reply, kEncryptedPk);
}
TEST_F(CrosFpDevice_PairingKeyWrap, InvalidParams) {
// Incorrect size.
const brillo::Blob kPubX(33, 1);
const brillo::Blob kPubY(32, 2);
const brillo::Blob kEncryptedKey(sizeof(fp_encrypted_private_key), 3);
EXPECT_CALL(*mock_ec_command_factory_, FpPairingKeyWrapCommand)
.WillOnce([&](const brillo::Blob& pub_x, const brillo::Blob& pub_y,
const brillo::Blob& encrypted_key)
-> std::unique_ptr<FpPairingKeyWrapCommand> {
auto cmd = FpPairingKeyWrapCommand::Create<MockFpPairingKeyWrapCommand>(
pub_x, pub_y, encrypted_key);
EXPECT_EQ(cmd, nullptr);
return cmd;
});
std::optional<brillo::Blob> reply =
mock_cros_fp_device_->PairingKeyWrap(kPubX, kPubY, kEncryptedKey);
EXPECT_FALSE(reply.has_value());
}
TEST_F(CrosFpDevice_PairingKeyWrap, RunFailure) {
const brillo::Blob kPubX(32, 1);
const brillo::Blob kPubY(32, 2);
const brillo::Blob kEncryptedKey(sizeof(fp_encrypted_private_key), 3);
EXPECT_CALL(*mock_ec_command_factory_, FpPairingKeyWrapCommand)
.WillOnce([&](const brillo::Blob& pub_x, const brillo::Blob& pub_y,
const brillo::Blob& encrypted_key)
-> std::unique_ptr<FpPairingKeyWrapCommand> {
auto cmd = FpPairingKeyWrapCommand::Create<MockFpPairingKeyWrapCommand>(
pub_x, pub_y, encrypted_key);
if (cmd) {
EXPECT_CALL(*cmd, Run).WillRepeatedly(Return(false));
}
return cmd;
});
std::optional<brillo::Blob> reply =
mock_cros_fp_device_->PairingKeyWrap(kPubX, kPubY, kEncryptedKey);
EXPECT_FALSE(reply.has_value());
}
} // namespace
} // namespace biod