blob: ae49572b226991083fcce1eee56b92d288034937 [file] [log] [blame] [edit]
// Copyright 2022 The ChromiumOS Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <cstdint>
#include <memory>
#include <optional>
#include <utility>
#include <gtest/gtest.h>
#include <libhwsec-foundation/error/testing_helper.h>
#include <trunks/error_codes.h>
#include <trunks/mock_tpm_utility.h>
#define __packed __attribute((packed))
#define __aligned(x) __attribute((aligned(x)))
#include <pinweaver/pinweaver_types.h>
#include "libhwsec/backend/tpm2/backend_test_base.h"
using hwsec_foundation::error::testing::IsOk;
using hwsec_foundation::error::testing::IsOkAndHolds;
using hwsec_foundation::error::testing::NotOk;
using hwsec_foundation::error::testing::ReturnError;
using hwsec_foundation::error::testing::ReturnValue;
using testing::_;
using testing::DoAll;
using testing::Eq;
using testing::NiceMock;
using testing::Return;
using testing::SaveArg;
using testing::SetArgPointee;
using tpm_manager::TpmManagerStatus;
using ErrorCode = hwsec::Backend::PinWeaver::CredentialTreeResult::ErrorCode;
namespace hwsec {
using BackendPinweaverTpm2Test = BackendTpm2TestBase;
TEST_F(BackendPinweaverTpm2Test, IsEnabled) {
EXPECT_CALL(proxy_->GetMockTpmUtility(), PinWeaverIsSupported(_, _))
.WillOnce(DoAll(SetArgPointee<1>(1), Return(trunks::TPM_RC_SUCCESS)));
EXPECT_THAT(backend_->GetPinWeaverTpm2().IsEnabled(), IsOkAndHolds(true));
}
TEST_F(BackendPinweaverTpm2Test, IsEnabledMismatch) {
EXPECT_CALL(proxy_->GetMockTpmUtility(), PinWeaverIsSupported(_, _))
.WillOnce(Return(trunks::SAPI_RC_ABI_MISMATCH))
.WillOnce(DoAll(SetArgPointee<1>(1), Return(trunks::TPM_RC_SUCCESS)));
EXPECT_THAT(backend_->GetPinWeaverTpm2().IsEnabled(), IsOkAndHolds(true));
}
TEST_F(BackendPinweaverTpm2Test, IsDisabled) {
EXPECT_CALL(proxy_->GetMockTpmUtility(), PinWeaverIsSupported(_, _))
.WillOnce(Return(trunks::TPM_RC_FAILURE));
EXPECT_THAT(backend_->GetPinWeaverTpm2().IsEnabled(), IsOkAndHolds(false));
}
TEST_F(BackendPinweaverTpm2Test, IsDisabledMismatch) {
EXPECT_CALL(proxy_->GetMockTpmUtility(), PinWeaverIsSupported(_, _))
.WillOnce(Return(trunks::SAPI_RC_ABI_MISMATCH))
.WillOnce(Return(trunks::SAPI_RC_ABI_MISMATCH));
EXPECT_THAT(backend_->GetPinWeaverTpm2().IsEnabled(), IsOkAndHolds(false));
}
TEST_F(BackendPinweaverTpm2Test, Reset) {
constexpr uint32_t kLengthLabels = 14;
constexpr uint32_t kBitsPerLevel = 2;
constexpr uint32_t kVersion = 1;
const std::string kFakeRoot = "fake_root";
EXPECT_CALL(proxy_->GetMockTpmUtility(), PinWeaverIsSupported(_, _))
.WillOnce(
DoAll(SetArgPointee<1>(kVersion), Return(trunks::TPM_RC_SUCCESS)));
EXPECT_CALL(proxy_->GetMockTpmUtility(),
PinWeaverResetTree(kVersion, 2, 7, _, _))
.WillOnce(DoAll(SetArgPointee<3>(0), SetArgPointee<4>(kFakeRoot),
Return(trunks::TPM_RC_SUCCESS)));
auto result =
backend_->GetPinWeaverTpm2().Reset(kBitsPerLevel, kLengthLabels);
ASSERT_OK(result);
EXPECT_EQ(result->error, ErrorCode::kSuccess);
EXPECT_EQ(result->new_root, brillo::BlobFromString(kFakeRoot));
}
TEST_F(BackendPinweaverTpm2Test, ResetFailure) {
constexpr uint32_t kLengthLabels = 128;
constexpr uint32_t kBitsPerLevel = 128;
constexpr uint32_t kVersion = 1;
EXPECT_CALL(proxy_->GetMockTpmUtility(), PinWeaverIsSupported(_, _))
.WillOnce(
DoAll(SetArgPointee<1>(kVersion), Return(trunks::TPM_RC_SUCCESS)));
EXPECT_CALL(proxy_->GetMockTpmUtility(),
PinWeaverResetTree(kVersion, 128, 1, _, _))
.WillOnce(DoAll(SetArgPointee<3>(PW_ERR_BITS_PER_LEVEL_INVALID),
Return(trunks::TPM_RC_SUCCESS)));
auto result =
backend_->GetPinWeaverTpm2().Reset(kBitsPerLevel, kLengthLabels);
ASSERT_NOT_OK(result);
}
TEST_F(BackendPinweaverTpm2Test, InsertCredential) {
constexpr uint32_t kVersion = 2;
constexpr uint32_t kLabel = 42;
const std::string kFakeRoot = "fake_root";
const std::string kFakeCred = "fake_cred";
const std::string kFakeMac = "fake_mac";
const brillo::SecureBlob kFakeLeSecret("fake_le_secret");
const brillo::SecureBlob kFakeHeSecret("fake_he_secret");
const brillo::SecureBlob kFakeResetSecret("fake_reset_secret");
const hwsec::Backend::PinWeaver::DelaySchedule kDelaySched = {
{5, UINT32_MAX},
};
const uint32_t kExpirationDelay = 100;
const std::vector<OperationPolicySetting> kPolicies = {
OperationPolicySetting{
.device_config_settings =
DeviceConfigSettings{
.current_user =
DeviceConfigSettings::CurrentUserSetting{
.username = std::nullopt,
},
},
},
OperationPolicySetting{
.device_config_settings =
DeviceConfigSettings{
.current_user =
DeviceConfigSettings::CurrentUserSetting{
.username = "fake_username",
},
},
},
};
const std::vector<brillo::Blob>& kHAux = {
brillo::Blob(32, 'X'),
brillo::Blob(32, 'Y'),
brillo::Blob(32, 'Z'),
};
EXPECT_CALL(proxy_->GetMockTpmUtility(), PinWeaverIsSupported(_, _))
.WillOnce(
DoAll(SetArgPointee<1>(kVersion), Return(trunks::TPM_RC_SUCCESS)));
EXPECT_CALL(proxy_->GetMockTpmUtility(),
PinWeaverInsertLeaf(kVersion, kLabel, _, kFakeLeSecret,
kFakeHeSecret, kFakeResetSecret, kDelaySched,
_, Eq(kExpirationDelay), _, _, _, _))
.WillOnce(DoAll(SetArgPointee<9>(0), SetArgPointee<10>(kFakeRoot),
SetArgPointee<11>(kFakeCred), SetArgPointee<12>(kFakeMac),
Return(trunks::TPM_RC_SUCCESS)));
auto result = backend_->GetPinWeaverTpm2().InsertCredential(
kPolicies, kLabel, kHAux, kFakeLeSecret, kFakeHeSecret, kFakeResetSecret,
kDelaySched, kExpirationDelay);
ASSERT_OK(result);
EXPECT_EQ(result->error, ErrorCode::kSuccess);
EXPECT_EQ(result->new_root, brillo::BlobFromString(kFakeRoot));
ASSERT_TRUE(result->new_cred_metadata.has_value());
EXPECT_EQ(result->new_cred_metadata.value(),
brillo::BlobFromString(kFakeCred));
ASSERT_TRUE(result->new_mac.has_value());
EXPECT_EQ(result->new_mac.value(), brillo::BlobFromString(kFakeMac));
}
TEST_F(BackendPinweaverTpm2Test, InsertCredentialUnsupportedPolicy) {
constexpr uint32_t kVersion = 2;
constexpr uint32_t kLabel = 42;
const std::string kFakeRoot = "fake_root";
const std::string kFakeCred = "fake_cred";
const std::string kFakeMac = "fake_mac";
const brillo::SecureBlob kFakeLeSecret("fake_le_secret");
const brillo::SecureBlob kFakeHeSecret("fake_he_secret");
const brillo::SecureBlob kFakeResetSecret("fake_reset_secret");
const hwsec::Backend::PinWeaver::DelaySchedule kDelaySched = {
{5, UINT32_MAX},
};
const uint32_t kExpirationDelay = 100;
const std::vector<OperationPolicySetting> kPolicies = {
OperationPolicySetting{.permission =
Permission{
.auth_value = brillo::SecureBlob("auth"),
}},
};
const std::vector<brillo::Blob>& kHAux = {
brillo::Blob(32, 'X'),
brillo::Blob(32, 'Y'),
brillo::Blob(32, 'Z'),
};
EXPECT_CALL(proxy_->GetMockTpmUtility(), PinWeaverIsSupported(_, _))
.WillOnce(
DoAll(SetArgPointee<1>(kVersion), Return(trunks::TPM_RC_SUCCESS)));
auto result = backend_->GetPinWeaverTpm2().InsertCredential(
kPolicies, kLabel, kHAux, kFakeLeSecret, kFakeHeSecret, kFakeResetSecret,
kDelaySched, kExpirationDelay);
EXPECT_FALSE(result.ok());
}
TEST_F(BackendPinweaverTpm2Test, InsertCredentialV0PolicyUnsupported) {
constexpr uint32_t kVersion = 0;
constexpr uint32_t kLabel = 42;
const std::string kFakeRoot = "fake_root";
const std::string kFakeCred = "fake_cred";
const std::string kFakeMac = "fake_mac";
const brillo::SecureBlob kFakeLeSecret("fake_le_secret");
const brillo::SecureBlob kFakeHeSecret("fake_he_secret");
const brillo::SecureBlob kFakeResetSecret("fake_reset_secret");
const hwsec::Backend::PinWeaver::DelaySchedule kDelaySched = {
{5, UINT32_MAX},
};
const std::vector<OperationPolicySetting> kPolicies = {
OperationPolicySetting{
.device_config_settings =
DeviceConfigSettings{
.current_user =
DeviceConfigSettings::CurrentUserSetting{
.username = std::nullopt,
},
},
},
OperationPolicySetting{
.device_config_settings =
DeviceConfigSettings{
.current_user =
DeviceConfigSettings::CurrentUserSetting{
.username = "fake_username",
},
},
},
};
const std::vector<brillo::Blob>& kHAux = {
brillo::Blob(32, 'X'),
brillo::Blob(32, 'Y'),
brillo::Blob(32, 'Z'),
};
EXPECT_CALL(proxy_->GetMockTpmUtility(), PinWeaverIsSupported(_, _))
.WillOnce(
DoAll(SetArgPointee<1>(kVersion), Return(trunks::TPM_RC_SUCCESS)));
auto result = backend_->GetPinWeaverTpm2().InsertCredential(
kPolicies, kLabel, kHAux, kFakeLeSecret, kFakeHeSecret, kFakeResetSecret,
kDelaySched, /*expiration_delay=*/std::nullopt);
EXPECT_FALSE(result.ok());
}
TEST_F(BackendPinweaverTpm2Test, InsertCredentialV1ExpirationUnsupported) {
constexpr uint32_t kVersion = 1;
constexpr uint32_t kLabel = 42;
const std::string kFakeRoot = "fake_root";
const std::string kFakeCred = "fake_cred";
const std::string kFakeMac = "fake_mac";
const brillo::SecureBlob kFakeLeSecret("fake_le_secret");
const brillo::SecureBlob kFakeHeSecret("fake_he_secret");
const brillo::SecureBlob kFakeResetSecret("fake_reset_secret");
const hwsec::Backend::PinWeaver::DelaySchedule kDelaySched = {
{5, UINT32_MAX},
};
const uint32_t kExpirationDelay = 100;
const std::vector<OperationPolicySetting> kPolicies = {
OperationPolicySetting{
.device_config_settings =
DeviceConfigSettings{
.current_user =
DeviceConfigSettings::CurrentUserSetting{
.username = std::nullopt,
},
},
},
OperationPolicySetting{
.device_config_settings =
DeviceConfigSettings{
.current_user =
DeviceConfigSettings::CurrentUserSetting{
.username = "fake_username",
},
},
},
};
const std::vector<brillo::Blob>& kHAux = {
brillo::Blob(32, 'X'),
brillo::Blob(32, 'Y'),
brillo::Blob(32, 'Z'),
};
EXPECT_CALL(proxy_->GetMockTpmUtility(), PinWeaverIsSupported(_, _))
.WillOnce(
DoAll(SetArgPointee<1>(kVersion), Return(trunks::TPM_RC_SUCCESS)));
auto result = backend_->GetPinWeaverTpm2().InsertCredential(
kPolicies, kLabel, kHAux, kFakeLeSecret, kFakeHeSecret, kFakeResetSecret,
kDelaySched, kExpirationDelay);
EXPECT_FALSE(result.ok());
}
TEST_F(BackendPinweaverTpm2Test, InsertCredentialNoDelay) {
constexpr uint32_t kVersion = 2;
constexpr uint32_t kLabel = 42;
const std::string kFakeRoot = "fake_root";
const std::string kFakeCred = "fake_cred";
const std::string kFakeMac = "fake_mac";
const brillo::SecureBlob kFakeLeSecret("fake_le_secret");
const brillo::SecureBlob kFakeHeSecret("fake_he_secret");
const brillo::SecureBlob kFakeResetSecret("fake_reset_secret");
const hwsec::Backend::PinWeaver::DelaySchedule kDelaySched = {
{5, UINT32_MAX},
};
const uint32_t kExpirationDelay = 100;
const std::vector<OperationPolicySetting> kPolicies = {
OperationPolicySetting{
.device_config_settings =
DeviceConfigSettings{
.current_user =
DeviceConfigSettings::CurrentUserSetting{
.username = std::nullopt,
},
},
},
OperationPolicySetting{
.device_config_settings =
DeviceConfigSettings{
.current_user =
DeviceConfigSettings::CurrentUserSetting{
.username = "fake_username",
},
},
},
};
const std::vector<brillo::Blob>& kHAux = {
brillo::Blob(32, 'X'),
brillo::Blob(32, 'Y'),
brillo::Blob(32, 'Z'),
};
EXPECT_CALL(proxy_->GetMockTpmUtility(), PinWeaverIsSupported(_, _))
.WillOnce(
DoAll(SetArgPointee<1>(kVersion), Return(trunks::TPM_RC_SUCCESS)));
EXPECT_CALL(proxy_->GetMockTpmUtility(),
PinWeaverInsertLeaf(kVersion, kLabel, _, kFakeLeSecret,
kFakeHeSecret, kFakeResetSecret, kDelaySched,
_, Eq(kExpirationDelay), _, _, _, _))
.WillOnce(DoAll(SetArgPointee<9>(PW_ERR_DELAY_SCHEDULE_INVALID),
Return(trunks::TPM_RC_SUCCESS)));
auto result = backend_->GetPinWeaverTpm2().InsertCredential(
kPolicies, kLabel, kHAux, kFakeLeSecret, kFakeHeSecret, kFakeResetSecret,
kDelaySched, kExpirationDelay);
EXPECT_FALSE(result.ok());
}
TEST_F(BackendPinweaverTpm2Test, CheckCredential) {
constexpr uint32_t kVersion = 1;
constexpr uint32_t kLabel = 42;
const std::string kFakeRoot = "fake_root";
const std::string kFakeCred = "fake_cred";
const std::string kNewCred = "new_cred";
const std::string kFakeMac = "fake_mac";
const brillo::SecureBlob kFakeLeSecret("fake_le_secret");
const brillo::SecureBlob kFakeHeSecret("fake_he_secret");
const brillo::SecureBlob kFakeResetSecret("fake_reset_secret");
const std::vector<brillo::Blob>& kHAux = {
brillo::Blob(32, 'X'),
brillo::Blob(32, 'Y'),
brillo::Blob(32, 'Z'),
};
EXPECT_CALL(proxy_->GetMockTpmUtility(), PinWeaverIsSupported(_, _))
.WillOnce(
DoAll(SetArgPointee<1>(kVersion), Return(trunks::TPM_RC_SUCCESS)));
EXPECT_CALL(proxy_->GetMockTpmUtility(),
PinWeaverTryAuth(kVersion, kFakeLeSecret, _, kFakeCred, _, _, _,
_, _, _, _))
.WillOnce(DoAll(SetArgPointee<4>(0), SetArgPointee<5>(kFakeRoot),
SetArgPointee<7>(kFakeHeSecret),
SetArgPointee<8>(kFakeResetSecret),
SetArgPointee<9>(kNewCred), SetArgPointee<10>(kFakeMac),
Return(trunks::TPM_RC_SUCCESS)));
auto result = backend_->GetPinWeaverTpm2().CheckCredential(
kLabel, kHAux, brillo::BlobFromString(kFakeCred), kFakeLeSecret);
ASSERT_OK(result);
EXPECT_EQ(result->error, ErrorCode::kSuccess);
EXPECT_EQ(result->new_root, brillo::BlobFromString(kFakeRoot));
ASSERT_TRUE(result->new_cred_metadata.has_value());
EXPECT_EQ(result->new_cred_metadata.value(),
brillo::BlobFromString(kNewCred));
ASSERT_TRUE(result->new_mac.has_value());
EXPECT_EQ(result->new_mac.value(), brillo::BlobFromString(kFakeMac));
ASSERT_TRUE(result->he_secret.has_value());
EXPECT_EQ(result->he_secret.value(), kFakeHeSecret);
ASSERT_TRUE(result->reset_secret.has_value());
EXPECT_EQ(result->reset_secret.value(), kFakeResetSecret);
}
TEST_F(BackendPinweaverTpm2Test, CheckCredentialAuthFail) {
constexpr uint32_t kVersion = 1;
constexpr uint32_t kLabel = 42;
const std::string kFakeRoot = "fake_root";
const std::string kFakeCred = "fake_cred";
const std::string kNewCred = "new_cred";
const std::string kFakeMac = "fake_mac";
const brillo::SecureBlob kFakeLeSecret("fake_le_secret");
const brillo::SecureBlob kFakeHeSecret("fake_he_secret");
const brillo::SecureBlob kFakeResetSecret("fake_reset_secret");
const std::vector<brillo::Blob>& kHAux = {
brillo::Blob(32, 'X'),
brillo::Blob(32, 'Y'),
brillo::Blob(32, 'Z'),
};
EXPECT_CALL(proxy_->GetMockTpmUtility(), PinWeaverIsSupported(_, _))
.WillOnce(
DoAll(SetArgPointee<1>(kVersion), Return(trunks::TPM_RC_SUCCESS)));
EXPECT_CALL(proxy_->GetMockTpmUtility(),
PinWeaverTryAuth(kVersion, kFakeLeSecret, _, kFakeCred, _, _, _,
_, _, _, _))
.WillOnce(DoAll(SetArgPointee<4>(PW_ERR_LOWENT_AUTH_FAILED),
SetArgPointee<5>(kFakeRoot), SetArgPointee<9>(kNewCred),
SetArgPointee<10>(kFakeMac),
Return(trunks::TPM_RC_SUCCESS)));
auto result = backend_->GetPinWeaverTpm2().CheckCredential(
kLabel, kHAux, brillo::BlobFromString(kFakeCred), kFakeLeSecret);
ASSERT_OK(result);
EXPECT_EQ(result->error, ErrorCode::kInvalidLeSecret);
EXPECT_EQ(result->new_root, brillo::BlobFromString(kFakeRoot));
ASSERT_TRUE(result->new_cred_metadata.has_value());
EXPECT_EQ(result->new_cred_metadata.value(),
brillo::BlobFromString(kNewCred));
ASSERT_TRUE(result->new_mac.has_value());
EXPECT_EQ(result->new_mac.value(), brillo::BlobFromString(kFakeMac));
ASSERT_TRUE(result->he_secret.has_value());
EXPECT_TRUE(result->he_secret->empty());
ASSERT_TRUE(result->reset_secret.has_value());
EXPECT_TRUE(result->reset_secret->empty());
}
TEST_F(BackendPinweaverTpm2Test, CheckCredentialTpmFail) {
constexpr uint32_t kVersion = 1;
constexpr uint32_t kLabel = 42;
const std::string kFakeCred = "fake_cred";
const brillo::SecureBlob kFakeLeSecret("fake_le_secret");
const std::vector<brillo::Blob>& kHAux = {
brillo::Blob(32, 'X'),
brillo::Blob(32, 'Y'),
brillo::Blob(32, 'Z'),
};
EXPECT_CALL(proxy_->GetMockTpmUtility(), PinWeaverIsSupported(_, _))
.WillOnce(
DoAll(SetArgPointee<1>(kVersion), Return(trunks::TPM_RC_SUCCESS)));
EXPECT_CALL(proxy_->GetMockTpmUtility(),
PinWeaverTryAuth(kVersion, kFakeLeSecret, _, kFakeCred, _, _, _,
_, _, _, _))
.WillOnce(Return(trunks::TPM_RC_FAILURE));
auto result = backend_->GetPinWeaverTpm2().CheckCredential(
kLabel, kHAux, brillo::BlobFromString(kFakeCred), kFakeLeSecret);
EXPECT_FALSE(result.ok());
}
TEST_F(BackendPinweaverTpm2Test, RemoveCredential) {
constexpr uint32_t kVersion = 1;
constexpr uint32_t kLabel = 42;
const std::string kFakeRoot = "fake_root";
const std::string kFakeMac = "fake_mac";
const std::vector<brillo::Blob>& kHAux = {
brillo::Blob(32, 'X'),
brillo::Blob(32, 'Y'),
brillo::Blob(32, 'Z'),
};
EXPECT_CALL(proxy_->GetMockTpmUtility(), PinWeaverIsSupported(_, _))
.WillOnce(
DoAll(SetArgPointee<1>(kVersion), Return(trunks::TPM_RC_SUCCESS)));
EXPECT_CALL(proxy_->GetMockTpmUtility(),
PinWeaverRemoveLeaf(kVersion, kLabel, _, kFakeMac, _, _))
.WillOnce(DoAll(SetArgPointee<4>(0), SetArgPointee<5>(kFakeRoot),
Return(trunks::TPM_RC_SUCCESS)));
auto result = backend_->GetPinWeaverTpm2().RemoveCredential(
kLabel, kHAux, brillo::BlobFromString(kFakeMac));
ASSERT_OK(result);
EXPECT_EQ(result->error, ErrorCode::kSuccess);
EXPECT_EQ(result->new_root, brillo::BlobFromString(kFakeRoot));
}
TEST_F(BackendPinweaverTpm2Test, RemoveCredentialFail) {
constexpr uint32_t kVersion = 1;
constexpr uint32_t kLabel = 42;
const std::string kFakeRoot = "fake_root";
const std::string kFakeMac = "fake_mac";
const std::vector<brillo::Blob>& kHAux = {
brillo::Blob(32, 'X'),
brillo::Blob(32, 'Y'),
brillo::Blob(32, 'Z'),
};
EXPECT_CALL(proxy_->GetMockTpmUtility(), PinWeaverIsSupported(_, _))
.WillOnce(
DoAll(SetArgPointee<1>(kVersion), Return(trunks::TPM_RC_SUCCESS)));
EXPECT_CALL(proxy_->GetMockTpmUtility(),
PinWeaverRemoveLeaf(kVersion, kLabel, _, kFakeMac, _, _))
.WillOnce(DoAll(SetArgPointee<4>(PW_ERR_HMAC_AUTH_FAILED),
SetArgPointee<5>(kFakeRoot),
Return(trunks::TPM_RC_SUCCESS)));
auto result = backend_->GetPinWeaverTpm2().RemoveCredential(
kLabel, kHAux, brillo::BlobFromString(kFakeMac));
EXPECT_FALSE(result.ok());
}
TEST_F(BackendPinweaverTpm2Test, ResetCredential) {
constexpr uint32_t kVersion = 2;
constexpr uint32_t kLabel = 42;
const std::string kFakeRoot = "fake_root";
const std::string kFakeCred = "fake_cred";
const std::string kNewCred = "new_cred";
const std::string kFakeMac = "fake_mac";
const brillo::SecureBlob kFakeResetSecret("fake_reset_secret");
const std::vector<brillo::Blob>& kHAux = {
brillo::Blob(32, 'X'),
brillo::Blob(32, 'Y'),
brillo::Blob(32, 'Z'),
};
EXPECT_CALL(proxy_->GetMockTpmUtility(), PinWeaverIsSupported(_, _))
.WillOnce(
DoAll(SetArgPointee<1>(kVersion), Return(trunks::TPM_RC_SUCCESS)));
EXPECT_CALL(
proxy_->GetMockTpmUtility(),
PinWeaverResetAuth(kVersion, kFakeResetSecret, /*strong_reset=*/true, _,
kFakeCred, _, _, _, _))
.WillOnce(DoAll(SetArgPointee<5>(0), SetArgPointee<6>(kFakeRoot),
SetArgPointee<7>(kNewCred), SetArgPointee<8>(kFakeMac),
Return(trunks::TPM_RC_SUCCESS)));
auto result = backend_->GetPinWeaverTpm2().ResetCredential(
kLabel, kHAux, brillo::BlobFromString(kFakeCred), kFakeResetSecret,
/*strong_reset=*/true);
ASSERT_OK(result);
EXPECT_EQ(result->error, ErrorCode::kSuccess);
EXPECT_EQ(result->new_root, brillo::BlobFromString(kFakeRoot));
ASSERT_TRUE(result->new_cred_metadata.has_value());
EXPECT_EQ(result->new_cred_metadata.value(),
brillo::BlobFromString(kNewCred));
ASSERT_TRUE(result->new_mac.has_value());
EXPECT_EQ(result->new_mac.value(), brillo::BlobFromString(kFakeMac));
}
TEST_F(BackendPinweaverTpm2Test, ResetCredentialV1ExpirationUnsupported) {
constexpr uint32_t kVersion = 1;
constexpr uint32_t kLabel = 42;
const std::string kFakeRoot = "fake_root";
const std::string kFakeCred = "fake_cred";
const std::string kNewCred = "new_cred";
const std::string kFakeMac = "fake_mac";
const brillo::SecureBlob kFakeResetSecret("fake_reset_secret");
const std::vector<brillo::Blob>& kHAux = {
brillo::Blob(32, 'X'),
brillo::Blob(32, 'Y'),
brillo::Blob(32, 'Z'),
};
EXPECT_CALL(proxy_->GetMockTpmUtility(), PinWeaverIsSupported(_, _))
.WillOnce(
DoAll(SetArgPointee<1>(kVersion), Return(trunks::TPM_RC_SUCCESS)));
auto result = backend_->GetPinWeaverTpm2().ResetCredential(
kLabel, kHAux, brillo::BlobFromString(kFakeCred), kFakeResetSecret,
/*strong_reset=*/true);
ASSERT_NOT_OK(result);
}
TEST_F(BackendPinweaverTpm2Test, GetLog) {
constexpr uint32_t kVersion = 1;
const std::string kFakeRoot = "fake_root";
const std::string kNewRoot = "new_root";
trunks::PinWeaverLogEntry entry1;
entry1.set_label(42);
entry1.set_root(kNewRoot);
entry1.mutable_insert_leaf()->set_hmac("fake_mac");
trunks::PinWeaverLogEntry entry2;
entry2.set_label(42);
entry2.set_root(kFakeRoot);
trunks::PinWeaverLogEntry entry3;
entry3.set_label(43);
entry3.set_root(kFakeRoot);
entry3.mutable_remove_leaf();
trunks::PinWeaverLogEntry entry4;
entry4.set_label(44);
entry4.set_root(kNewRoot);
entry4.mutable_reset_tree();
const std::vector<trunks::PinWeaverLogEntry> kFakeLog = {entry1, entry2,
entry3, entry4};
EXPECT_CALL(proxy_->GetMockTpmUtility(), PinWeaverIsSupported(_, _))
.WillOnce(
DoAll(SetArgPointee<1>(kVersion), Return(trunks::TPM_RC_SUCCESS)));
EXPECT_CALL(proxy_->GetMockTpmUtility(),
PinWeaverGetLog(kVersion, kFakeRoot, _, _, _))
.WillOnce(DoAll(SetArgPointee<2>(0), SetArgPointee<3>(kNewRoot),
SetArgPointee<4>(kFakeLog),
Return(trunks::TPM_RC_SUCCESS)));
auto result =
backend_->GetPinWeaverTpm2().GetLog(brillo::BlobFromString(kFakeRoot));
ASSERT_OK(result);
EXPECT_EQ(result->root_hash, brillo::BlobFromString(kNewRoot));
EXPECT_EQ(result->log_entries.size(), kFakeLog.size());
}
TEST_F(BackendPinweaverTpm2Test, GetLogFail) {
constexpr uint32_t kVersion = 1;
const std::string kFakeRoot = "fake_root";
const std::string kNewRoot = "new_root";
EXPECT_CALL(proxy_->GetMockTpmUtility(), PinWeaverIsSupported(_, _))
.WillOnce(
DoAll(SetArgPointee<1>(kVersion), Return(trunks::TPM_RC_SUCCESS)));
EXPECT_CALL(proxy_->GetMockTpmUtility(),
PinWeaverGetLog(kVersion, kFakeRoot, _, _, _))
.WillOnce(DoAll(SetArgPointee<2>(PW_ERR_TREE_INVALID),
Return(trunks::TPM_RC_SUCCESS)));
auto result =
backend_->GetPinWeaverTpm2().GetLog(brillo::BlobFromString(kFakeRoot));
EXPECT_FALSE(result.ok());
}
TEST_F(BackendPinweaverTpm2Test, ReplayLogOperation) {
constexpr uint32_t kVersion = 1;
const std::string kFakeRoot = "fake_root";
const std::string kFakeCred = "fake_cred";
const std::string kNewCred = "new_cred";
const std::string kFakeMac = "fake_mac";
const brillo::SecureBlob kFakeHeSecret("fake_he_secret");
const brillo::SecureBlob kFakeResetSecret("fake_reset_secret");
const std::vector<brillo::Blob>& kHAux = {
brillo::Blob(32, 'X'),
brillo::Blob(32, 'Y'),
brillo::Blob(32, 'Z'),
};
EXPECT_CALL(proxy_->GetMockTpmUtility(), PinWeaverIsSupported(_, _))
.WillOnce(
DoAll(SetArgPointee<1>(kVersion), Return(trunks::TPM_RC_SUCCESS)));
EXPECT_CALL(proxy_->GetMockTpmUtility(),
PinWeaverLogReplay(kVersion, kFakeRoot, _, kFakeCred, _, _, _, _))
.WillOnce(DoAll(SetArgPointee<4>(0), SetArgPointee<5>(kFakeRoot),
SetArgPointee<6>(kNewCred), SetArgPointee<7>(kFakeMac),
Return(trunks::TPM_RC_SUCCESS)));
auto result = backend_->GetPinWeaverTpm2().ReplayLogOperation(
brillo::BlobFromString(kFakeRoot), kHAux,
brillo::BlobFromString(kFakeCred));
ASSERT_OK(result);
EXPECT_EQ(result->new_cred_metadata, brillo::BlobFromString(kNewCred));
EXPECT_EQ(result->new_mac, brillo::BlobFromString(kFakeMac));
}
TEST_F(BackendPinweaverTpm2Test, ReplayLogOperationFail) {
constexpr uint32_t kVersion = 1;
const std::string kFakeRoot = "fake_root";
const std::string kFakeCred = "fake_cred";
const std::string kNewCred = "new_cred";
const std::string kFakeMac = "fake_mac";
const brillo::SecureBlob kFakeHeSecret("fake_he_secret");
const brillo::SecureBlob kFakeResetSecret("fake_reset_secret");
const std::vector<brillo::Blob>& kHAux = {
brillo::Blob(32, 'X'),
brillo::Blob(32, 'Y'),
brillo::Blob(32, 'Z'),
};
EXPECT_CALL(proxy_->GetMockTpmUtility(), PinWeaverIsSupported(_, _))
.WillOnce(
DoAll(SetArgPointee<1>(kVersion), Return(trunks::TPM_RC_SUCCESS)));
EXPECT_CALL(proxy_->GetMockTpmUtility(),
PinWeaverLogReplay(kVersion, kFakeRoot, _, kFakeCred, _, _, _, _))
.WillOnce(DoAll(SetArgPointee<4>(PW_ERR_ROOT_NOT_FOUND),
Return(trunks::TPM_RC_SUCCESS)));
auto result = backend_->GetPinWeaverTpm2().ReplayLogOperation(
brillo::BlobFromString(kFakeRoot), kHAux,
brillo::BlobFromString(kFakeCred));
EXPECT_FALSE(result.ok());
}
TEST_F(BackendPinweaverTpm2Test, GetWrongAuthAttempts) {
brillo::Blob header(sizeof(unimported_leaf_data_t));
brillo::Blob leaf(sizeof(leaf_public_data_t));
struct leaf_public_data_t* leaf_data =
reinterpret_cast<struct leaf_public_data_t*>(leaf.data());
leaf_data->attempt_count.v = 123;
EXPECT_THAT(backend_->GetPinWeaverTpm2().GetWrongAuthAttempts(
brillo::CombineBlobs({header, leaf})),
IsOkAndHolds(123));
}
TEST_F(BackendPinweaverTpm2Test, GetWrongAuthAttemptsEmpty) {
EXPECT_THAT(backend_->GetPinWeaverTpm2().GetWrongAuthAttempts(brillo::Blob()),
NotOk());
}
TEST_F(BackendPinweaverTpm2Test, GetDelaySchedule) {
brillo::Blob header(sizeof(unimported_leaf_data_t));
brillo::Blob leaf(sizeof(leaf_public_data_t));
struct leaf_public_data_t* leaf_data =
reinterpret_cast<struct leaf_public_data_t*>(leaf.data());
leaf_data->delay_schedule[0].attempt_count.v = 5;
leaf_data->delay_schedule[0].time_diff.v = UINT32_MAX;
auto result = backend_->GetPinWeaverTpm2().GetDelaySchedule(
brillo::CombineBlobs({header, leaf}));
ASSERT_OK(result);
ASSERT_EQ(result.value().size(), 1);
EXPECT_EQ(result.value().begin()->first, 5);
EXPECT_EQ(result.value().begin()->second, UINT32_MAX);
}
TEST_F(BackendPinweaverTpm2Test, GetDelayScheduleEmpty) {
auto result = backend_->GetPinWeaverTpm2().GetDelaySchedule(brillo::Blob());
EXPECT_FALSE(result.ok());
}
TEST_F(BackendPinweaverTpm2Test, GetDelayInSecondsV1) {
brillo::Blob header(sizeof(unimported_leaf_data_t));
brillo::Blob leaf(sizeof(leaf_public_data_t));
struct leaf_public_data_t* leaf_data =
reinterpret_cast<struct leaf_public_data_t*>(leaf.data());
leaf_data->delay_schedule[0].attempt_count.v = 5;
leaf_data->delay_schedule[0].time_diff.v = UINT32_MAX;
leaf_data->attempt_count.v = 4;
// In version 1, GetDelayInSeconds only parses the cred metadata, without
// initiating any requests to the PinWeaver server.
EXPECT_CALL(proxy_->GetMockTpmUtility(), PinWeaverIsSupported(_, _))
.WillOnce(DoAll(SetArgPointee<1>(1), Return(trunks::TPM_RC_SUCCESS)));
EXPECT_THAT(backend_->GetPinWeaverTpm2().GetDelayInSeconds(
brillo::CombineBlobs({header, leaf})),
IsOkAndHolds(0));
leaf_data->attempt_count.v = 5;
EXPECT_THAT(backend_->GetPinWeaverTpm2().GetDelayInSeconds(
brillo::CombineBlobs({header, leaf})),
IsOkAndHolds(UINT32_MAX));
}
TEST_F(BackendPinweaverTpm2Test, GetDelayInSecondsV2) {
const std::string kFakeRoot = "fake_root";
brillo::Blob header(sizeof(unimported_leaf_data_t));
brillo::Blob leaf(sizeof(leaf_public_data_t));
struct leaf_public_data_t* leaf_data =
reinterpret_cast<struct leaf_public_data_t*>(leaf.data());
leaf_data->delay_schedule[0].attempt_count.v = 5;
leaf_data->delay_schedule[0].time_diff.v = 60;
leaf_data->delay_schedule[1].attempt_count.v = 6;
leaf_data->delay_schedule[1].time_diff.v = 70;
leaf_data->delay_schedule[2].attempt_count.v = 7;
leaf_data->delay_schedule[2].time_diff.v = UINT32_MAX;
leaf_data->last_access_ts.boot_count = 0;
leaf_data->last_access_ts.timer_value = 100;
leaf_data->attempt_count.v = 4;
// In version 2, GetDelayInSeconds requests the current timestamp from the
// PinWeaver server, so that it can return a more accurate remaining seconds.
EXPECT_CALL(proxy_->GetMockTpmUtility(), PinWeaverIsSupported(_, _))
.WillOnce(DoAll(SetArgPointee<1>(2), Return(trunks::TPM_RC_SUCCESS)));
// This is only called twice because when the delay is infinite, we don't have
// to query the current timestamp.
EXPECT_CALL(proxy_->GetMockTpmUtility(), PinWeaverSysInfo(2, _, _, _, _))
.WillOnce(DoAll(SetArgPointee<1>(0), SetArgPointee<2>(kFakeRoot),
SetArgPointee<3>(0), SetArgPointee<4>(120),
Return(trunks::TPM_RC_SUCCESS)))
.WillOnce(DoAll(SetArgPointee<1>(0), SetArgPointee<2>(kFakeRoot),
SetArgPointee<3>(1), SetArgPointee<4>(10),
Return(trunks::TPM_RC_SUCCESS)));
EXPECT_THAT(backend_->GetPinWeaverTpm2().GetDelayInSeconds(
brillo::CombineBlobs({header, leaf})),
IsOkAndHolds(0));
// Ready timestamp is 100+60=160, and the current timestamp is 120.
leaf_data->attempt_count.v = 5;
EXPECT_THAT(backend_->GetPinWeaverTpm2().GetDelayInSeconds(
brillo::CombineBlobs({header, leaf})),
IsOkAndHolds(40));
// Ready timestamp is 70 because the boot count has changed, and the current
// timestamp is 10.
leaf_data->attempt_count.v = 6;
EXPECT_THAT(backend_->GetPinWeaverTpm2().GetDelayInSeconds(
brillo::CombineBlobs({header, leaf})),
IsOkAndHolds(60));
// Ready timestamp isn't important because the leaf is infinitely locked out.
leaf_data->attempt_count.v = 7;
EXPECT_THAT(backend_->GetPinWeaverTpm2().GetDelayInSeconds(
brillo::CombineBlobs({header, leaf})),
IsOkAndHolds(UINT32_MAX));
}
TEST_F(BackendPinweaverTpm2Test, GetExpirationInSecondsV1) {
constexpr uint32_t kVersion = 1;
const std::string kFakeRoot = "fake_root";
brillo::Blob header(sizeof(unimported_leaf_data_t));
brillo::Blob leaf(sizeof(leaf_public_data_t));
struct leaf_public_data_t* leaf_data =
reinterpret_cast<struct leaf_public_data_t*>(leaf.data());
leaf_data->expiration_delay_s.v = 10;
leaf_data->expiration_ts.boot_count = 1;
leaf_data->expiration_ts.timer_value = 120;
EXPECT_CALL(proxy_->GetMockTpmUtility(), PinWeaverIsSupported(_, _))
.WillOnce(
DoAll(SetArgPointee<1>(kVersion), Return(trunks::TPM_RC_SUCCESS)));
// In version 1, credentials are always treated as having no expiration.
EXPECT_THAT(backend_->GetPinWeaverTpm2().GetExpirationInSeconds(
brillo::CombineBlobs({header, leaf})),
IsOkAndHolds(std::nullopt));
}
TEST_F(BackendPinweaverTpm2Test, GetExpirationInSecondsV2) {
constexpr uint32_t kVersion = 2;
const std::string kFakeRoot = "fake_root";
brillo::Blob header(sizeof(unimported_leaf_data_t));
brillo::Blob leaf(sizeof(leaf_public_data_t));
// Simulate a leaf created at v1.
brillo::Blob leaf_v1(offsetof(leaf_public_data_t, expiration_ts));
struct leaf_public_data_t* leaf_data =
reinterpret_cast<struct leaf_public_data_t*>(leaf.data());
leaf_data->expiration_delay_s.v = 0;
leaf_data->expiration_ts.boot_count = 0;
leaf_data->expiration_ts.timer_value = 0;
EXPECT_CALL(proxy_->GetMockTpmUtility(), PinWeaverIsSupported(_, _))
.WillOnce(
DoAll(SetArgPointee<1>(kVersion), Return(trunks::TPM_RC_SUCCESS)));
// This is only called 3 times because when the delay is 0, we don't have
// to query the current timestamp.
EXPECT_CALL(proxy_->GetMockTpmUtility(),
PinWeaverSysInfo(kVersion, _, _, _, _))
.Times(3)
.WillRepeatedly(DoAll(SetArgPointee<1>(0), SetArgPointee<2>(kFakeRoot),
SetArgPointee<3>(1), SetArgPointee<4>(100),
Return(trunks::TPM_RC_SUCCESS)));
EXPECT_THAT(backend_->GetPinWeaverTpm2().GetExpirationInSeconds(
brillo::CombineBlobs({header, leaf})),
IsOkAndHolds(std::nullopt));
leaf_data->expiration_delay_s.v = 10;
leaf_data->expiration_ts.timer_value = 120;
EXPECT_THAT(backend_->GetPinWeaverTpm2().GetExpirationInSeconds(
brillo::CombineBlobs({header, leaf})),
IsOkAndHolds(0));
leaf_data->expiration_ts.boot_count = 1;
leaf_data->expiration_ts.timer_value = 80;
EXPECT_THAT(backend_->GetPinWeaverTpm2().GetExpirationInSeconds(
brillo::CombineBlobs({header, leaf})),
IsOkAndHolds(0));
leaf_data->expiration_ts.timer_value = 120;
EXPECT_THAT(backend_->GetPinWeaverTpm2().GetExpirationInSeconds(
brillo::CombineBlobs({header, leaf})),
IsOkAndHolds(20));
// Leaf created in version before v2 has no expiration.
EXPECT_THAT(backend_->GetPinWeaverTpm2().GetExpirationInSeconds(
brillo::CombineBlobs({header, leaf_v1})),
IsOkAndHolds(std::nullopt));
}
TEST_F(BackendPinweaverTpm2Test, GeneratePk) {
constexpr uint32_t kVersion = 2;
constexpr uint8_t kAuthChannel = 0;
const std::string kFakeRoot = "fake_root";
const std::string kClientCoordinate(32, 'A');
const std::string kServerCoordinate(32, 'B');
Backend::PinWeaver::PinWeaverEccPoint client_public_key;
memcpy(client_public_key.x, kClientCoordinate.data(),
kClientCoordinate.size());
memcpy(client_public_key.y, kClientCoordinate.data(),
kClientCoordinate.size());
trunks::PinWeaverEccPoint server_public_key;
memcpy(server_public_key.x, kServerCoordinate.data(),
kServerCoordinate.size());
memcpy(server_public_key.y, kServerCoordinate.data(),
kServerCoordinate.size());
EXPECT_CALL(proxy_->GetMockTpmUtility(), PinWeaverIsSupported(_, _))
.WillOnce(
DoAll(SetArgPointee<1>(kVersion), Return(trunks::TPM_RC_SUCCESS)));
EXPECT_CALL(
proxy_->GetMockTpmUtility(),
PinWeaverGenerateBiometricsAuthPk(kVersion, kAuthChannel, _, _, _, _))
.WillOnce(DoAll(SetArgPointee<3>(0), SetArgPointee<4>(kFakeRoot),
SetArgPointee<5>(server_public_key),
Return(trunks::TPM_RC_SUCCESS)));
auto result =
backend_->GetPinWeaverTpm2().GeneratePk(kAuthChannel, client_public_key);
ASSERT_OK(result);
ASSERT_FALSE(memcmp(&*result, &server_public_key, 64));
}
TEST_F(BackendPinweaverTpm2Test, GeneratePkV1Unsupported) {
constexpr uint32_t kVersion = 1;
constexpr uint8_t kAuthChannel = 0;
const std::string kClientCoordinate(32, 'A');
Backend::PinWeaver::PinWeaverEccPoint client_public_key;
memcpy(client_public_key.x, kClientCoordinate.data(),
kClientCoordinate.size());
memcpy(client_public_key.y, kClientCoordinate.data(),
kClientCoordinate.size());
EXPECT_CALL(proxy_->GetMockTpmUtility(), PinWeaverIsSupported(_, _))
.WillOnce(
DoAll(SetArgPointee<1>(kVersion), Return(trunks::TPM_RC_SUCCESS)));
EXPECT_THAT(
backend_->GetPinWeaverTpm2().GeneratePk(kAuthChannel, client_public_key),
NotOk());
}
TEST_F(BackendPinweaverTpm2Test, GeneratePkInvalidAuthChannel) {
constexpr uint32_t kVersion = 2;
constexpr uint8_t kAuthChannel = 2;
const std::string kClientCoordinate(32, 'A');
Backend::PinWeaver::PinWeaverEccPoint client_public_key;
memcpy(client_public_key.x, kClientCoordinate.data(),
kClientCoordinate.size());
memcpy(client_public_key.y, kClientCoordinate.data(),
kClientCoordinate.size());
EXPECT_CALL(proxy_->GetMockTpmUtility(), PinWeaverIsSupported(_, _))
.WillOnce(
DoAll(SetArgPointee<1>(kVersion), Return(trunks::TPM_RC_SUCCESS)));
EXPECT_THAT(
backend_->GetPinWeaverTpm2().GeneratePk(kAuthChannel, client_public_key),
NotOk());
}
TEST_F(BackendPinweaverTpm2Test, InsertRateLimiter) {
constexpr uint32_t kVersion = 2;
constexpr uint8_t kAuthChannel = 0;
constexpr uint32_t kLabel = 42;
const std::string kFakeRoot = "fake_root";
const std::string kFakeCred = "fake_cred";
const std::string kFakeMac = "fake_mac";
const brillo::SecureBlob kFakeResetSecret("fake_reset_secret");
const hwsec::Backend::PinWeaver::DelaySchedule kDelaySched = {
{5, UINT32_MAX},
};
const uint32_t kExpirationDelay = 100;
const std::vector<OperationPolicySetting> kPolicies = {
OperationPolicySetting{
.device_config_settings =
DeviceConfigSettings{
.current_user =
DeviceConfigSettings::CurrentUserSetting{
.username = std::nullopt,
},
},
},
OperationPolicySetting{
.device_config_settings =
DeviceConfigSettings{
.current_user =
DeviceConfigSettings::CurrentUserSetting{
.username = "fake_username",
},
},
},
};
const std::vector<brillo::Blob>& kHAux = {
brillo::Blob(32, 'X'),
brillo::Blob(32, 'Y'),
brillo::Blob(32, 'Z'),
};
EXPECT_CALL(proxy_->GetMockTpmUtility(), PinWeaverIsSupported(_, _))
.WillOnce(
DoAll(SetArgPointee<1>(kVersion), Return(trunks::TPM_RC_SUCCESS)));
EXPECT_CALL(proxy_->GetMockTpmUtility(),
PinWeaverCreateBiometricsAuthRateLimiter(
kVersion, kAuthChannel, kLabel, _, kFakeResetSecret,
kDelaySched, _, Eq(kExpirationDelay), _, _, _, _))
.WillOnce(DoAll(SetArgPointee<8>(0), SetArgPointee<9>(kFakeRoot),
SetArgPointee<10>(kFakeCred), SetArgPointee<11>(kFakeMac),
Return(trunks::TPM_RC_SUCCESS)));
auto result = backend_->GetPinWeaverTpm2().InsertRateLimiter(
kAuthChannel, kPolicies, kLabel, kHAux, kFakeResetSecret, kDelaySched,
kExpirationDelay);
ASSERT_OK(result);
EXPECT_EQ(result->error, ErrorCode::kSuccess);
EXPECT_EQ(result->new_root, brillo::BlobFromString(kFakeRoot));
ASSERT_TRUE(result->new_cred_metadata.has_value());
EXPECT_EQ(result->new_cred_metadata.value(),
brillo::BlobFromString(kFakeCred));
ASSERT_TRUE(result->new_mac.has_value());
EXPECT_EQ(result->new_mac.value(), brillo::BlobFromString(kFakeMac));
}
TEST_F(BackendPinweaverTpm2Test, InsertRateLimiterV1Unsupported) {
constexpr uint32_t kVersion = 1;
constexpr uint8_t kAuthChannel = 0;
constexpr uint32_t kLabel = 42;
const std::string kFakeRoot = "fake_root";
const std::string kFakeCred = "fake_cred";
const std::string kFakeMac = "fake_mac";
const brillo::SecureBlob kFakeResetSecret("fake_reset_secret");
const hwsec::Backend::PinWeaver::DelaySchedule kDelaySched = {
{5, UINT32_MAX},
};
const uint32_t kExpirationDelay = 100;
const std::vector<brillo::Blob>& kHAux = {
brillo::Blob(32, 'X'),
brillo::Blob(32, 'Y'),
brillo::Blob(32, 'Z'),
};
EXPECT_CALL(proxy_->GetMockTpmUtility(), PinWeaverIsSupported(_, _))
.WillOnce(
DoAll(SetArgPointee<1>(kVersion), Return(trunks::TPM_RC_SUCCESS)));
EXPECT_THAT(
backend_->GetPinWeaverTpm2().InsertRateLimiter(
kAuthChannel, /*policies=*/std::vector<OperationPolicySetting>(),
kLabel, kHAux, kFakeResetSecret, kDelaySched, kExpirationDelay),
NotOk());
}
TEST_F(BackendPinweaverTpm2Test, InsertRateLimiterInvalidAuthChannel) {
constexpr uint32_t kVersion = 2;
constexpr uint8_t kAuthChannel = 2;
constexpr uint32_t kLabel = 42;
const std::string kFakeRoot = "fake_root";
const std::string kFakeCred = "fake_cred";
const std::string kFakeMac = "fake_mac";
const brillo::SecureBlob kFakeResetSecret("fake_reset_secret");
const hwsec::Backend::PinWeaver::DelaySchedule kDelaySched = {
{5, UINT32_MAX},
};
const uint32_t kExpirationDelay = 100;
const std::vector<brillo::Blob>& kHAux = {
brillo::Blob(32, 'X'),
brillo::Blob(32, 'Y'),
brillo::Blob(32, 'Z'),
};
EXPECT_CALL(proxy_->GetMockTpmUtility(), PinWeaverIsSupported(_, _))
.WillOnce(
DoAll(SetArgPointee<1>(kVersion), Return(trunks::TPM_RC_SUCCESS)));
EXPECT_THAT(
backend_->GetPinWeaverTpm2().InsertRateLimiter(
kAuthChannel, /*policies=*/std::vector<OperationPolicySetting>(),
kLabel, kHAux, kFakeResetSecret, kDelaySched, kExpirationDelay),
NotOk());
}
TEST_F(BackendPinweaverTpm2Test, StartBiometricsAuth) {
constexpr uint32_t kVersion = 2;
constexpr uint8_t kAuthChannel = 0;
constexpr uint32_t kLabel = 42;
const std::string kFakeRoot = "fake_root";
const std::string kFakeCred = "fake_cred";
const std::string kNewCred = "new_cred";
const std::string kFakeMac = "fake_mac";
const brillo::Blob kFakeClientNonce =
brillo::BlobFromString("fake_client_nonce");
const brillo::Blob kFakeServerNonce =
brillo::BlobFromString("fake_server_nonce");
const brillo::Blob kFakeEncryptedHeSecret =
brillo::BlobFromString("fake_encrypted_he_secret");
const brillo::Blob kFakeIv = brillo::BlobFromString("fake_iv");
const std::vector<brillo::Blob>& kHAux = {
brillo::Blob(32, 'X'),
brillo::Blob(32, 'Y'),
brillo::Blob(32, 'Z'),
};
EXPECT_CALL(proxy_->GetMockTpmUtility(), PinWeaverIsSupported(_, _))
.WillOnce(
DoAll(SetArgPointee<1>(kVersion), Return(trunks::TPM_RC_SUCCESS)));
EXPECT_CALL(
proxy_->GetMockTpmUtility(),
PinWeaverStartBiometricsAuth(kVersion, kAuthChannel, kFakeClientNonce, _,
kFakeCred, _, _, _, _, _, _, _))
.WillOnce(DoAll(SetArgPointee<5>(0), SetArgPointee<6>(kFakeRoot),
SetArgPointee<7>(kFakeServerNonce),
SetArgPointee<8>(kFakeEncryptedHeSecret),
SetArgPointee<9>(kFakeIv), SetArgPointee<10>(kNewCred),
SetArgPointee<11>(kFakeMac),
Return(trunks::TPM_RC_SUCCESS)));
auto result = backend_->GetPinWeaverTpm2().StartBiometricsAuth(
kAuthChannel, kLabel, kHAux, brillo::BlobFromString(kFakeCred),
kFakeClientNonce);
ASSERT_OK(result);
EXPECT_EQ(result->error, ErrorCode::kSuccess);
EXPECT_EQ(result->new_root, brillo::BlobFromString(kFakeRoot));
ASSERT_TRUE(result->new_cred_metadata.has_value());
EXPECT_EQ(result->new_cred_metadata.value(),
brillo::BlobFromString(kNewCred));
ASSERT_TRUE(result->new_mac.has_value());
EXPECT_EQ(result->new_mac.value(), brillo::BlobFromString(kFakeMac));
ASSERT_TRUE(result->server_nonce.has_value());
EXPECT_EQ(result->server_nonce.value(), kFakeServerNonce);
ASSERT_TRUE(result->encrypted_he_secret.has_value());
EXPECT_EQ(result->encrypted_he_secret.value(), kFakeEncryptedHeSecret);
ASSERT_TRUE(result->iv.has_value());
EXPECT_EQ(result->iv.value(), kFakeIv);
}
TEST_F(BackendPinweaverTpm2Test, StartBiometricsAuthAuthFail) {
constexpr uint32_t kVersion = 2;
constexpr uint8_t kWrongAuthChannel = 1;
constexpr uint32_t kLabel = 42;
const std::string kFakeRoot = "fake_root";
const std::string kFakeCred = "fake_cred";
const std::string kNewCred = "new_cred";
const std::string kFakeMac = "fake_mac";
const brillo::Blob kFakeClientNonce =
brillo::BlobFromString("fake_client_nonce");
const std::vector<brillo::Blob>& kHAux = {
brillo::Blob(32, 'X'),
brillo::Blob(32, 'Y'),
brillo::Blob(32, 'Z'),
};
EXPECT_CALL(proxy_->GetMockTpmUtility(), PinWeaverIsSupported(_, _))
.WillOnce(
DoAll(SetArgPointee<1>(kVersion), Return(trunks::TPM_RC_SUCCESS)));
EXPECT_CALL(proxy_->GetMockTpmUtility(),
PinWeaverStartBiometricsAuth(kVersion, kWrongAuthChannel,
kFakeClientNonce, _, kFakeCred, _, _,
_, _, _, _, _))
.WillOnce(DoAll(SetArgPointee<5>(PW_ERR_LOWENT_AUTH_FAILED),
SetArgPointee<6>(kFakeRoot), SetArgPointee<10>(kNewCred),
SetArgPointee<11>(kFakeMac),
Return(trunks::TPM_RC_SUCCESS)));
auto result = backend_->GetPinWeaverTpm2().StartBiometricsAuth(
kWrongAuthChannel, kLabel, kHAux, brillo::BlobFromString(kFakeCred),
kFakeClientNonce);
ASSERT_OK(result);
EXPECT_EQ(result->error, ErrorCode::kInvalidLeSecret);
EXPECT_EQ(result->new_root, brillo::BlobFromString(kFakeRoot));
ASSERT_TRUE(result->new_cred_metadata.has_value());
EXPECT_EQ(result->new_cred_metadata.value(),
brillo::BlobFromString(kNewCred));
ASSERT_TRUE(result->new_mac.has_value());
EXPECT_EQ(result->new_mac.value(), brillo::BlobFromString(kFakeMac));
ASSERT_TRUE(result->server_nonce.has_value());
EXPECT_TRUE(result->server_nonce->empty());
ASSERT_TRUE(result->encrypted_he_secret.has_value());
EXPECT_TRUE(result->encrypted_he_secret->empty());
ASSERT_TRUE(result->iv.has_value());
EXPECT_TRUE(result->iv->empty());
}
TEST_F(BackendPinweaverTpm2Test, StartBiometricsAuthTpmFail) {
constexpr uint32_t kVersion = 2;
constexpr uint8_t kAuthChannel = 0;
constexpr uint32_t kLabel = 42;
const std::string kFakeRoot = "fake_root";
const std::string kFakeCred = "fake_cred";
const std::string kNewCred = "new_cred";
const std::string kFakeMac = "fake_mac";
const brillo::Blob kFakeClientNonce =
brillo::BlobFromString("fake_client_nonce");
const std::vector<brillo::Blob>& kHAux = {
brillo::Blob(32, 'X'),
brillo::Blob(32, 'Y'),
brillo::Blob(32, 'Z'),
};
EXPECT_CALL(proxy_->GetMockTpmUtility(), PinWeaverIsSupported(_, _))
.WillOnce(
DoAll(SetArgPointee<1>(kVersion), Return(trunks::TPM_RC_SUCCESS)));
EXPECT_CALL(
proxy_->GetMockTpmUtility(),
PinWeaverStartBiometricsAuth(kVersion, kAuthChannel, kFakeClientNonce, _,
kFakeCred, _, _, _, _, _, _, _))
.WillOnce(Return(trunks::TPM_RC_FAILURE));
EXPECT_THAT(backend_->GetPinWeaverTpm2().StartBiometricsAuth(
kAuthChannel, kLabel, kHAux,
brillo::BlobFromString(kFakeCred), kFakeClientNonce),
NotOk());
}
TEST_F(BackendPinweaverTpm2Test, StartBiometricsAuthV1NotSupported) {
constexpr uint32_t kVersion = 1;
constexpr uint8_t kAuthChannel = 0;
constexpr uint32_t kLabel = 42;
const std::string kFakeRoot = "fake_root";
const std::string kFakeCred = "fake_cred";
const std::string kNewCred = "new_cred";
const std::string kFakeMac = "fake_mac";
const brillo::Blob kFakeClientNonce =
brillo::BlobFromString("fake_client_nonce");
const std::vector<brillo::Blob>& kHAux = {
brillo::Blob(32, 'X'),
brillo::Blob(32, 'Y'),
brillo::Blob(32, 'Z'),
};
EXPECT_CALL(proxy_->GetMockTpmUtility(), PinWeaverIsSupported(_, _))
.WillOnce(
DoAll(SetArgPointee<1>(kVersion), Return(trunks::TPM_RC_SUCCESS)));
EXPECT_THAT(backend_->GetPinWeaverTpm2().StartBiometricsAuth(
kAuthChannel, kLabel, kHAux,
brillo::BlobFromString(kFakeCred), kFakeClientNonce),
NotOk());
}
TEST_F(BackendPinweaverTpm2Test, StartBiometricsAuthInvalidAuthChannel) {
constexpr uint32_t kVersion = 2;
constexpr uint8_t kAuthChannel = 2;
constexpr uint32_t kLabel = 42;
const std::string kFakeRoot = "fake_root";
const std::string kFakeCred = "fake_cred";
const std::string kNewCred = "new_cred";
const std::string kFakeMac = "fake_mac";
const brillo::Blob kFakeClientNonce =
brillo::BlobFromString("fake_client_nonce");
const std::vector<brillo::Blob>& kHAux = {
brillo::Blob(32, 'X'),
brillo::Blob(32, 'Y'),
brillo::Blob(32, 'Z'),
};
EXPECT_CALL(proxy_->GetMockTpmUtility(), PinWeaverIsSupported(_, _))
.WillOnce(
DoAll(SetArgPointee<1>(kVersion), Return(trunks::TPM_RC_SUCCESS)));
EXPECT_THAT(backend_->GetPinWeaverTpm2().StartBiometricsAuth(
kAuthChannel, kLabel, kHAux,
brillo::BlobFromString(kFakeCred), kFakeClientNonce),
NotOk());
}
TEST_F(BackendPinweaverTpm2Test, BlockGeneratePk) {
constexpr uint32_t kVersion = 2;
const std::string kFakeRoot = "fake_root";
EXPECT_CALL(proxy_->GetMockTpmUtility(), PinWeaverIsSupported(_, _))
.WillOnce(
DoAll(SetArgPointee<1>(kVersion), Return(trunks::TPM_RC_SUCCESS)));
EXPECT_CALL(proxy_->GetMockTpmUtility(),
PinWeaverBlockGenerateBiometricsAuthPk(kVersion, _, _))
.WillOnce(DoAll(SetArgPointee<1>(0), SetArgPointee<2>(kFakeRoot),
Return(trunks::TPM_RC_SUCCESS)));
EXPECT_THAT(backend_->GetPinWeaverTpm2().BlockGeneratePk(), IsOk());
}
TEST_F(BackendPinweaverTpm2Test, BlockGeneratePkV1NotSupported) {
constexpr uint32_t kVersion = 1;
EXPECT_CALL(proxy_->GetMockTpmUtility(), PinWeaverIsSupported(_, _))
.WillOnce(
DoAll(SetArgPointee<1>(kVersion), Return(trunks::TPM_RC_SUCCESS)));
EXPECT_THAT(backend_->GetPinWeaverTpm2().BlockGeneratePk(), NotOk());
}
} // namespace hwsec