blob: 9300977e2640042a31c748c1a1ec992be8aef826 [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.
#include "cryptohome/auth_factor/types/fingerprint.h"
#include <limits>
#include <memory>
#include <string>
#include <utility>
#include <base/files/file_path.h>
#include <base/functional/callback.h>
#include <base/test/test_future.h>
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include <libhwsec-foundation/crypto/aes.h>
#include <libhwsec-foundation/error/testing_helper.h>
#include <libstorage/platform/mock_platform.h>
#include "cryptohome/auth_blocks/biometrics_auth_block_service.h"
#include "cryptohome/auth_blocks/mock_biometrics_command_processor.h"
#include "cryptohome/auth_factor/metadata.h"
#include "cryptohome/auth_factor/storage_type.h"
#include "cryptohome/auth_factor/type.h"
#include "cryptohome/auth_factor/types/interface.h"
#include "cryptohome/auth_factor/types/test_utils.h"
#include "cryptohome/flatbuffer_schemas/auth_block_state.h"
#include "cryptohome/flatbuffer_schemas/auth_factor.h"
#include "cryptohome/user_secret_stash/manager.h"
#include "cryptohome/user_secret_stash/storage.h"
#include "cryptohome/util/async_init.h"
namespace cryptohome {
namespace {
using ::base::test::TestFuture;
using ::cryptohome::error::CryptohomeError;
using ::cryptohome::error::ErrorActionSet;
using ::hwsec::PinWeaverManagerFrontend::AuthChannel::kFingerprintAuthChannel;
using ::hwsec_foundation::kAesGcmIVSize;
using ::hwsec_foundation::kAesGcmTagSize;
using ::hwsec_foundation::error::testing::IsOk;
using ::hwsec_foundation::error::testing::IsOkAnd;
using ::hwsec_foundation::error::testing::NotOk;
using ::hwsec_foundation::error::testing::ReturnError;
using ::hwsec_foundation::error::testing::ReturnValue;
using ::testing::_;
using ::testing::Eq;
using ::testing::IsFalse;
using ::testing::IsNull;
using ::testing::IsTrue;
using ::testing::NiceMock;
using ::testing::Optional;
using ::testing::Return;
class FingerprintDriverTest : public AuthFactorDriverGenericTest {
protected:
const error::CryptohomeError::ErrorLocationPair kErrorLocationPlaceholder =
error::CryptohomeError::ErrorLocationPair(
static_cast<::cryptohome::error::CryptohomeError::ErrorLocation>(1),
"Testing1");
static constexpr uint64_t kLeLabel = 0xdeadbeefbaadf00d;
static constexpr char kUserSpecifiedName[] = "Finger 1";
FingerprintDriverTest() {
auto processor = std::make_unique<MockBiometricsCommandProcessor>();
bio_command_processor_ = processor.get();
EXPECT_CALL(*bio_command_processor_, SetEnrollScanDoneCallback(_));
EXPECT_CALL(*bio_command_processor_, SetAuthScanDoneCallback(_));
EXPECT_CALL(*bio_command_processor_, SetSessionFailedCallback(_));
bio_service_ = std::make_unique<BiometricsAuthBlockService>(
std::move(processor), /*enroll_signal_sender=*/base::DoNothing(),
/*auth_signal_sender=*/base::DoNothing());
}
// Create a USS that contains kleLabel as the rate limiter ID.
void CreateUssWithRateLimiterId() {
EncryptedUss::Container uss_container = {
.ciphertext = brillo::BlobFromString("encrypted bytes!"),
.iv = brillo::BlobFromString(std::string(kAesGcmIVSize, '\x0a')),
.gcm_tag = brillo::BlobFromString(std::string(kAesGcmTagSize, '\x0b')),
.created_on_os_version = "1.2.3.4",
.user_metadata =
{
.fingerprint_rate_limiter_id = kLeLabel,
},
};
EncryptedUss uss(uss_container);
UserUssStorage user_uss_storage(uss_storage_, kObfuscatedUser);
ASSERT_THAT(uss.ToStorage(user_uss_storage), IsOk());
}
NiceMock<libstorage::MockPlatform> platform_;
UssStorage uss_storage_{&platform_};
UssManager uss_manager_{uss_storage_};
MockBiometricsCommandProcessor* bio_command_processor_;
std::unique_ptr<BiometricsAuthBlockService> bio_service_;
};
TEST_F(FingerprintDriverTest, ConvertToProto) {
// Setup
FingerprintAuthFactorDriver fp_driver(
&platform_, &crypto_, &uss_manager_,
AsyncInitPtr<BiometricsAuthBlockService>(bio_service_.get()));
AuthFactorDriver& driver = fp_driver;
FingerprintMetadata fingerprint_metadata{.was_migrated = true};
AuthFactorMetadata metadata =
CreateMetadataWithType<FingerprintMetadata>(fingerprint_metadata);
metadata.common.user_specified_name = std::string(kUserSpecifiedName);
// Test
std::optional<user_data_auth::AuthFactor> proto =
driver.ConvertToProto(kLabel, metadata);
// Verify
ASSERT_THAT(proto, Optional(_));
EXPECT_THAT(proto.value().type(),
Eq(user_data_auth::AUTH_FACTOR_TYPE_FINGERPRINT));
EXPECT_THAT(proto.value().label(), Eq(kLabel));
EXPECT_THAT(proto->common_metadata().chromeos_version_last_updated(),
Eq(kChromeosVersion));
EXPECT_THAT(proto->common_metadata().chrome_version_last_updated(),
Eq(kChromeVersion));
EXPECT_THAT(proto->common_metadata().lockout_policy(),
Eq(user_data_auth::LOCKOUT_POLICY_NONE));
EXPECT_THAT(proto->common_metadata().user_specified_name(),
Eq(kUserSpecifiedName));
EXPECT_THAT(proto.value().has_fingerprint_metadata(), IsTrue());
EXPECT_THAT(proto.value().fingerprint_metadata().was_migrated(), IsTrue());
}
TEST_F(FingerprintDriverTest, ConvertToProtoNullOpt) {
// Setup
FingerprintAuthFactorDriver fp_driver(
&platform_, &crypto_, &uss_manager_,
AsyncInitPtr<BiometricsAuthBlockService>(bio_service_.get()));
AuthFactorDriver& driver = fp_driver;
AuthFactorMetadata metadata;
// Test
std::optional<user_data_auth::AuthFactor> proto =
driver.ConvertToProto(kLabel, metadata);
// Verify
EXPECT_THAT(proto, Eq(std::nullopt));
}
TEST_F(FingerprintDriverTest, UnsupportedWithVk) {
// Setup
FingerprintAuthFactorDriver fp_driver(
&platform_, &crypto_, &uss_manager_,
AsyncInitPtr<BiometricsAuthBlockService>(bio_service_.get()));
AuthFactorDriver& driver = fp_driver;
// Test, Verify.
EXPECT_THAT(
driver.IsSupportedByStorage({AuthFactorStorageType::kVaultKeyset}, {}),
IsFalse());
}
TEST_F(FingerprintDriverTest, SupportedWithVkUssMix) {
// Setup
FingerprintAuthFactorDriver fp_driver(
&platform_, &crypto_, &uss_manager_,
AsyncInitPtr<BiometricsAuthBlockService>(bio_service_.get()));
AuthFactorDriver& driver = fp_driver;
// Test, Verify.
EXPECT_THAT(
driver.IsSupportedByStorage({AuthFactorStorageType::kVaultKeyset,
AuthFactorStorageType::kUserSecretStash},
{}),
IsTrue());
}
TEST_F(FingerprintDriverTest, UnsupportedWithKiosk) {
// Setup
FingerprintAuthFactorDriver fp_driver(
&platform_, &crypto_, &uss_manager_,
AsyncInitPtr<BiometricsAuthBlockService>(bio_service_.get()));
AuthFactorDriver& driver = fp_driver;
// Test, Verify.
EXPECT_THAT(
driver.IsSupportedByStorage({AuthFactorStorageType::kUserSecretStash},
{AuthFactorType::kKiosk}),
IsFalse());
}
TEST_F(FingerprintDriverTest, UnsupportedByBlock) {
// Setup
FingerprintAuthFactorDriver fp_driver(
&platform_, &crypto_, &uss_manager_,
AsyncInitPtr<BiometricsAuthBlockService>(bio_service_.get()));
AuthFactorDriver& driver = fp_driver;
// Test, Verify
EXPECT_THAT(driver.IsSupportedByHardware(), IsFalse());
}
TEST_F(FingerprintDriverTest, SupportedByBlock) {
// Setup
EXPECT_CALL(*bio_command_processor_, IsReady()).WillOnce(Return(true));
EXPECT_CALL(hwsec_, IsReady()).WillOnce(ReturnValue(true));
EXPECT_CALL(hwsec_, IsBiometricsPinWeaverEnabled())
.WillOnce(ReturnValue(true));
FingerprintAuthFactorDriver fp_driver(
&platform_, &crypto_, &uss_manager_,
AsyncInitPtr<BiometricsAuthBlockService>(bio_service_.get()));
AuthFactorDriver& driver = fp_driver;
// Test, Verify
EXPECT_THAT(driver.IsSupportedByHardware(), IsTrue());
}
TEST_F(FingerprintDriverTest, PrepareForAddFailure) {
const brillo::SecureBlob kResetSecret(32, 1);
const brillo::Blob kNonce(32, 2);
// Setup.
FingerprintAuthFactorDriver fp_driver(
&platform_, &crypto_, &uss_manager_,
AsyncInitPtr<BiometricsAuthBlockService>(bio_service_.get()));
AuthFactorDriver& driver = fp_driver;
EXPECT_CALL(*bio_command_processor_, GetNonce(_))
.WillOnce(
[&kNonce](auto&& callback) { std::move(callback).Run(kNonce); });
EXPECT_CALL(hwsec_pw_manager_,
StartBiometricsAuth(kFingerprintAuthChannel, kLeLabel, kNonce))
.WillOnce(
Return(hwsec::PinWeaverManagerFrontend::StartBiometricsAuthReply{}));
EXPECT_CALL(*bio_command_processor_, StartEnrollSession(_, _))
.WillOnce(
[](auto&&, auto&& callback) { std::move(callback).Run(false); });
// Test.
TestFuture<CryptohomeStatusOr<std::unique_ptr<PreparedAuthFactorToken>>>
prepare_result;
PrepareInput prepare_input{
.username = kObfuscatedUser,
.reset_secret = kResetSecret,
.rate_limiter_label = kLeLabel,
};
driver.PrepareForAdd(prepare_input, prepare_result.GetCallback());
// Verify.
EXPECT_THAT(prepare_result.Get(), NotOk());
EXPECT_THAT(prepare_result.Get().status()->local_legacy_error(),
Eq(user_data_auth::CRYPTOHOME_ERROR_FINGERPRINT_ERROR_INTERNAL));
}
TEST_F(FingerprintDriverTest, PrepareForAddSuccess) {
const brillo::SecureBlob kResetSecret(32, 1);
const brillo::Blob kNonce(32, 2);
// Setup.
FingerprintAuthFactorDriver fp_driver(
&platform_, &crypto_, &uss_manager_,
AsyncInitPtr<BiometricsAuthBlockService>(bio_service_.get()));
AuthFactorDriver& driver = fp_driver;
EXPECT_CALL(*bio_command_processor_, GetNonce(_))
.WillOnce(
[&kNonce](auto&& callback) { std::move(callback).Run(kNonce); });
EXPECT_CALL(hwsec_pw_manager_,
StartBiometricsAuth(kFingerprintAuthChannel, kLeLabel, kNonce))
.WillOnce(
Return(hwsec::PinWeaverManagerFrontend::StartBiometricsAuthReply{}));
EXPECT_CALL(*bio_command_processor_, StartEnrollSession(_, _))
.WillOnce([](auto&&, auto&& callback) { std::move(callback).Run(true); });
// Test.
TestFuture<CryptohomeStatusOr<std::unique_ptr<PreparedAuthFactorToken>>>
prepare_result;
PrepareInput prepare_input{
.username = kObfuscatedUser,
.reset_secret = kResetSecret,
.rate_limiter_label = kLeLabel,
};
driver.PrepareForAdd(prepare_input, prepare_result.GetCallback());
// Verify.
EXPECT_THAT(prepare_result.Get(), IsOk());
}
TEST_F(FingerprintDriverTest, PrepareForAuthenticateFailure) {
const brillo::Blob kNonce(32, 2);
// Setup.
FingerprintAuthFactorDriver fp_driver(
&platform_, &crypto_, &uss_manager_,
AsyncInitPtr<BiometricsAuthBlockService>(bio_service_.get()));
AuthFactorDriver& driver = fp_driver;
EXPECT_CALL(*bio_command_processor_, GetNonce(_))
.WillOnce(
[&kNonce](auto&& callback) { std::move(callback).Run(kNonce); });
EXPECT_CALL(hwsec_pw_manager_,
StartBiometricsAuth(kFingerprintAuthChannel, kLeLabel, kNonce))
.WillOnce(
Return(hwsec::PinWeaverManagerFrontend::StartBiometricsAuthReply{}));
EXPECT_CALL(*bio_command_processor_, StartAuthenticateSession(_, _, _))
.WillOnce([](auto&&, auto&&, auto&& callback) {
std::move(callback).Run(false);
});
// Test.
TestFuture<CryptohomeStatusOr<std::unique_ptr<PreparedAuthFactorToken>>>
prepare_result;
PrepareInput prepare_input{
.username = kObfuscatedUser,
.rate_limiter_label = kLeLabel,
};
driver.PrepareForAuthenticate(prepare_input, prepare_result.GetCallback());
// Verify.
EXPECT_THAT(prepare_result.Get(), NotOk());
EXPECT_THAT(prepare_result.Get().status()->local_legacy_error(),
Eq(user_data_auth::CRYPTOHOME_ERROR_FINGERPRINT_ERROR_INTERNAL));
}
TEST_F(FingerprintDriverTest, PrepareForAuthenticateSuccess) {
const brillo::Blob kNonce(32, 2);
// Setup.
FingerprintAuthFactorDriver fp_driver(
&platform_, &crypto_, &uss_manager_,
AsyncInitPtr<BiometricsAuthBlockService>(bio_service_.get()));
AuthFactorDriver& driver = fp_driver;
EXPECT_CALL(*bio_command_processor_, GetNonce(_))
.WillOnce(
[&kNonce](auto&& callback) { std::move(callback).Run(kNonce); });
EXPECT_CALL(hwsec_pw_manager_,
StartBiometricsAuth(kFingerprintAuthChannel, kLeLabel, kNonce))
.WillOnce(
Return(hwsec::PinWeaverManagerFrontend::StartBiometricsAuthReply{}));
EXPECT_CALL(*bio_command_processor_, StartAuthenticateSession(_, _, _))
.WillOnce([](auto&&, auto&&, auto&& callback) {
std::move(callback).Run(true);
});
// Test.
TestFuture<CryptohomeStatusOr<std::unique_ptr<PreparedAuthFactorToken>>>
prepare_result;
PrepareInput prepare_input{
.username = kObfuscatedUser,
.rate_limiter_label = kLeLabel,
};
driver.PrepareForAuthenticate(prepare_input, prepare_result.GetCallback());
// Verify.
EXPECT_THAT(prepare_result.Get(), IsOk());
}
TEST_F(FingerprintDriverTest, GetDelayFailsWithoutLeLabel) {
FingerprintAuthFactorDriver fp_driver(
&platform_, &crypto_, &uss_manager_,
AsyncInitPtr<BiometricsAuthBlockService>(bio_service_.get()));
AuthFactorDriver& driver = fp_driver;
AuthFactor factor(AuthFactorType::kFingerprint, kLabel,
CreateMetadataWithType<FingerprintMetadata>(),
{.state = FingerprintAuthBlockState()});
auto delay_in_ms = driver.GetFactorDelay(kObfuscatedUser, factor);
ASSERT_THAT(delay_in_ms, NotOk());
EXPECT_THAT(delay_in_ms.status()->local_legacy_error(),
Eq(user_data_auth::CRYPTOHOME_ERROR_BACKING_STORE_FAILURE));
}
TEST_F(FingerprintDriverTest, GetDelayInfinite) {
FingerprintAuthFactorDriver fp_driver(
&platform_, &crypto_, &uss_manager_,
AsyncInitPtr<BiometricsAuthBlockService>(bio_service_.get()));
AuthFactorDriver& driver = fp_driver;
AuthFactor factor(AuthFactorType::kFingerprint, kLabel,
CreateMetadataWithType<FingerprintMetadata>(),
{.state = FingerprintAuthBlockState()});
CreateUssWithRateLimiterId();
EXPECT_CALL(hwsec_pw_manager_, GetDelayInSeconds(kLeLabel))
.WillOnce(ReturnValue(std::numeric_limits<uint32_t>::max()));
auto delay_in_ms = driver.GetFactorDelay(kObfuscatedUser, factor);
ASSERT_THAT(delay_in_ms, IsOk());
EXPECT_THAT(delay_in_ms->is_max(), IsTrue());
}
TEST_F(FingerprintDriverTest, GetDelayFinite) {
FingerprintAuthFactorDriver fp_driver(
&platform_, &crypto_, &uss_manager_,
AsyncInitPtr<BiometricsAuthBlockService>(bio_service_.get()));
AuthFactorDriver& driver = fp_driver;
AuthFactor factor(AuthFactorType::kFingerprint, kLabel,
CreateMetadataWithType<FingerprintMetadata>(),
{.state = FingerprintAuthBlockState()});
CreateUssWithRateLimiterId();
EXPECT_CALL(hwsec_pw_manager_, GetDelayInSeconds(kLeLabel))
.WillOnce(ReturnValue(10));
auto delay_in_ms = driver.GetFactorDelay(kObfuscatedUser, factor);
ASSERT_THAT(delay_in_ms, IsOk());
EXPECT_THAT(*delay_in_ms, Eq(base::Seconds(10)));
}
TEST_F(FingerprintDriverTest, GetDelayZero) {
FingerprintAuthFactorDriver fp_driver(
&platform_, &crypto_, &uss_manager_,
AsyncInitPtr<BiometricsAuthBlockService>(bio_service_.get()));
AuthFactorDriver& driver = fp_driver;
AuthFactor factor(AuthFactorType::kFingerprint, kLabel,
CreateMetadataWithType<FingerprintMetadata>(),
{.state = FingerprintAuthBlockState()});
CreateUssWithRateLimiterId();
EXPECT_CALL(hwsec_pw_manager_, GetDelayInSeconds(kLeLabel))
.WillOnce(ReturnValue(0));
auto delay_in_ms = driver.GetFactorDelay(kObfuscatedUser, factor);
ASSERT_THAT(delay_in_ms, IsOk());
EXPECT_THAT(delay_in_ms->is_zero(), IsTrue());
}
TEST_F(FingerprintDriverTest, GetTimeUntilExpirationFailsWithoutLeLabel) {
FingerprintAuthFactorDriver fp_driver(
&platform_, &crypto_, &uss_manager_,
AsyncInitPtr<BiometricsAuthBlockService>(bio_service_.get()));
AuthFactorDriver& driver = fp_driver;
AuthFactor factor(AuthFactorType::kFingerprint, kLabel,
CreateMetadataWithType<FingerprintMetadata>(),
{.state = FingerprintAuthBlockState()});
auto delay = driver.GetTimeUntilExpiration(kObfuscatedUser, factor);
ASSERT_THAT(delay, NotOk());
EXPECT_THAT(delay.status()->local_legacy_error(),
Eq(user_data_auth::CRYPTOHOME_ERROR_BACKING_STORE_FAILURE));
}
TEST_F(FingerprintDriverTest, IsNotExpired) {
FingerprintAuthFactorDriver fp_driver(
&platform_, &crypto_, &uss_manager_,
AsyncInitPtr<BiometricsAuthBlockService>(bio_service_.get()));
AuthFactorDriver& driver = fp_driver;
AuthFactor factor(AuthFactorType::kFingerprint, kLabel,
CreateMetadataWithType<FingerprintMetadata>(),
{.state = FingerprintAuthBlockState()});
CreateUssWithRateLimiterId();
EXPECT_CALL(hwsec_pw_manager_, GetExpirationInSeconds(kLeLabel))
.WillOnce(ReturnValue(10));
auto delay = driver.GetTimeUntilExpiration(kObfuscatedUser, factor);
ASSERT_THAT(delay, IsOkAnd(Eq(base::Seconds(10))));
}
TEST_F(FingerprintDriverTest, IsExpired) {
FingerprintAuthFactorDriver fp_driver(
&platform_, &crypto_, &uss_manager_,
AsyncInitPtr<BiometricsAuthBlockService>(bio_service_.get()));
AuthFactorDriver& driver = fp_driver;
AuthFactor factor(AuthFactorType::kFingerprint, kLabel,
CreateMetadataWithType<FingerprintMetadata>(),
{.state = FingerprintAuthBlockState()});
CreateUssWithRateLimiterId();
EXPECT_CALL(hwsec_pw_manager_, GetExpirationInSeconds(kLeLabel))
.WillOnce(ReturnValue(0));
auto delay = driver.GetTimeUntilExpiration(kObfuscatedUser, factor);
ASSERT_THAT(delay, IsOkAnd(Eq(base::TimeDelta())));
}
TEST_F(FingerprintDriverTest, CreateCredentialVerifierFails) {
FingerprintAuthFactorDriver fp_driver(
&platform_, &crypto_, &uss_manager_,
AsyncInitPtr<BiometricsAuthBlockService>(bio_service_.get()));
AuthFactorDriver& driver = fp_driver;
auto verifier = driver.CreateCredentialVerifier(kLabel, {}, {});
EXPECT_THAT(verifier, IsNull());
}
} // namespace
} // namespace cryptohome