blob: 308f0778710e61d02e69ce69e8906b4bb4e98238 [file] [log] [blame]
// Copyright 2025 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <libcr51sign/cr51_image_descriptor.h>
#include <libcr51sign/libcr51sign.h>
#include <libhoth/protocol/key_rotation.h>
#include <libhoth/transports/libhoth_dbus.h>
#include <flashupdate/validator/key_rotate_helper.hpp>
#include <memory>
#include <gmock/gmock.h>
#include <gtest/gtest.h>
using ::testing::_;
using ::testing::DoAll;
using ::testing::Return;
using ::testing::SetArgPointee;
using ::testing::SetArrayArgument;
// Mocking C functions from libhoth and libcr51sign
class MockApi
{
public:
virtual ~MockApi() = default;
MOCK_METHOD(int, libhoth_dbus_open,
(const struct libhoth_dbus_device_init_options* opts,
struct libhoth_device** hoth_device));
MOCK_METHOD(enum key_rotation_err, libhoth_key_rotation_chunk_type_count,
(struct libhoth_device * hoth_device, uint32_t chunk_typecode,
uint16_t* chunk_count));
MOCK_METHOD(enum key_rotation_err, libhoth_key_rotation_read_chunk_type,
(struct libhoth_device * dev, uint32_t chunk_typecode,
uint32_t chunk_index, uint16_t offset, uint16_t size,
struct hoth_response_key_rotation_record_read* read_response,
uint16_t* response_size));
MOCK_METHOD(int, hash_init, (void* ctx, enum hash_type type));
MOCK_METHOD(int, hash_update, (void* ctx, const uint8_t* data, size_t len));
MOCK_METHOD(int, hash_final, (void* ctx, uint8_t* digest));
};
// Global mock object
static std::unique_ptr<MockApi> mock_api;
// C function trampolines to the mock object
extern "C"
{
int libhoth_dbus_open(const struct libhoth_dbus_device_init_options* opts,
struct libhoth_device** hoth_device)
{
if (mock_api)
{
return mock_api->libhoth_dbus_open(opts, hoth_device);
}
return -1; // Should not happen in tests
}
enum key_rotation_err libhoth_key_rotation_chunk_type_count(
struct libhoth_device* hoth_device, uint32_t chunk_typecode,
uint16_t* chunk_count)
{
if (mock_api)
{
return mock_api->libhoth_key_rotation_chunk_type_count(
hoth_device, chunk_typecode, chunk_count);
}
return KEY_ROTATION_ERR;
}
enum key_rotation_err libhoth_key_rotation_read_chunk_type(
struct libhoth_device* dev, uint32_t chunk_typecode, uint32_t chunk_index,
uint16_t offset, uint16_t size,
struct hoth_response_key_rotation_record_read* read_response,
uint16_t* response_size)
{
if (mock_api)
{
return mock_api->libhoth_key_rotation_read_chunk_type(
dev, chunk_typecode, chunk_index, offset, size, read_response,
response_size);
}
return KEY_ROTATION_ERR;
}
int hash_init(void* ctx, enum hash_type type)
{
if (mock_api)
{
return mock_api->hash_init(ctx, type);
}
return -1;
}
int hash_update(void* ctx, const uint8_t* data, size_t len)
{
if (mock_api)
{
return mock_api->hash_update(ctx, data, len);
}
return -1;
}
int hash_final(void* ctx, uint8_t* digest)
{
if (mock_api)
{
return mock_api->hash_final(ctx, digest);
}
return -1;
}
} // extern "C"
namespace google::cr51
{
class KeyRotateHelperTest : public ::testing::Test
{
protected:
void SetUp() override
{
mock_api = std::make_unique<::testing::StrictMock<MockApi>>();
}
void TearDown() override
{
mock_api.reset();
}
// A dummy device pointer. The value doesn't matter as it's just passed
// around.
struct libhoth_device* dummy_hoth_device =
reinterpret_cast<struct libhoth_device*>(0xDEADBEEF);
};
TEST_F(KeyRotateHelperTest, SetHothId)
{
std::string id = "my-hoth-device";
setHothId(id);
// We can't read back HothId, but we can check if it's used correctly.
// This test has to run before any other test that successfully opens a hoth
// device, due to the static variable in hothDevice().
EXPECT_CALL(
*mock_api,
libhoth_dbus_open(
::testing::Truly(
[&](const struct libhoth_dbus_device_init_options* opts) {
return strcmp(opts->hoth_id, id.c_str()) == 0;
}),
_))
.WillOnce(Return(-1)); // Return error to not cache the device.
sha256 hash{};
trustDescriptorHash(nullptr, reinterpret_cast<uint8_t*>(&hash),
sizeof(hash));
}
TEST_F(KeyRotateHelperTest, TrustDescriptorHashWrongHashSize)
{
sha256 hash{};
EXPECT_FALSE(trustDescriptorHash(nullptr, reinterpret_cast<uint8_t*>(&hash),
sizeof(hash) - 1));
}
TEST_F(KeyRotateHelperTest, TrustDescriptorHashHothOpenFails)
{
sha256 hash{};
EXPECT_CALL(*mock_api, libhoth_dbus_open(_, _)).WillOnce(Return(-1));
EXPECT_FALSE(trustDescriptorHash(nullptr, reinterpret_cast<uint8_t*>(&hash),
sizeof(hash)));
}
// Grouping tests that need a valid hoth device to avoid issues with static
// hoth_device in hothDevice().
class KeyRotateHelperWithDeviceTest : public KeyRotateHelperTest
{
protected:
// This static pointer is needed because SetUpTestSuite is static.
static struct libhoth_device* dummy_hoth_device_for_suite;
// SetUpTestSuite is called once before any tests in this suite are run.
static void SetUpTestSuite()
{
// Create the mock API once for the whole suite.
mock_api = std::make_unique<::testing::StrictMock<MockApi>>();
// Expect the dbus_open call once for the entire suite. This will be
// triggered by the first test that calls hothDevice().
EXPECT_CALL(*mock_api, libhoth_dbus_open(_, _))
.WillOnce(DoAll(SetArgPointee<1>(dummy_hoth_device_for_suite),
Return(0)));
}
// TearDownTestSuite is called once after all tests in this suite are run.
static void TearDownTestSuite()
{
mock_api.reset();
}
// Override per-test SetUp and TearDown to do nothing, preventing
// interference with the suite-level setup.
void SetUp() override {}
void TearDown() override {}
};
struct libhoth_device*
KeyRotateHelperWithDeviceTest::dummy_hoth_device_for_suite =
reinterpret_cast<struct libhoth_device*>(0xDEADBEEF);
TEST_F(KeyRotateHelperWithDeviceTest, TrustDescriptorHashGetChunkCountFails)
{
sha256 hash{};
EXPECT_CALL(*mock_api, libhoth_key_rotation_chunk_type_count(
dummy_hoth_device_for_suite,
KEY_ROTATION_CHUNK_TYPE_CODE_BASH, _))
.WillOnce(Return(KEY_ROTATION_ERR));
EXPECT_FALSE(trustDescriptorHash(nullptr, reinterpret_cast<uint8_t*>(&hash),
sizeof(hash)));
}
TEST_F(KeyRotateHelperWithDeviceTest, TrustDescriptorHashNoChunks)
{
sha256 hash{};
EXPECT_CALL(*mock_api, libhoth_key_rotation_chunk_type_count(
dummy_hoth_device_for_suite,
KEY_ROTATION_CHUNK_TYPE_CODE_BASH, _))
.WillOnce(DoAll(SetArgPointee<2>(0), Return(KEY_ROTATION_CMD_SUCCESS)));
EXPECT_FALSE(trustDescriptorHash(nullptr, reinterpret_cast<uint8_t*>(&hash),
sizeof(hash)));
}
TEST_F(KeyRotateHelperWithDeviceTest, TrustDescriptorHashMatch)
{
sha256 hash{0x01, 0x02, 0x03, 0x04};
struct hoth_response_key_rotation_record_read response = {};
struct bios_allowed_hash_list* hash_list =
reinterpret_cast<struct bios_allowed_hash_list*>(&response.data);
hash_list->hash_count = 1;
memcpy(hash_list->hash_list[0], &hash, sizeof(hash));
uint16_t response_size =
sizeof(struct bios_allowed_hash_list) + sizeof(sha256);
EXPECT_CALL(*mock_api, libhoth_key_rotation_chunk_type_count(
dummy_hoth_device_for_suite,
KEY_ROTATION_CHUNK_TYPE_CODE_BASH, _))
.WillOnce(DoAll(SetArgPointee<2>(1), Return(KEY_ROTATION_CMD_SUCCESS)));
EXPECT_CALL(*mock_api,
libhoth_key_rotation_read_chunk_type(
dummy_hoth_device_for_suite,
KEY_ROTATION_CHUNK_TYPE_CODE_BASH, 0, _, _, _, _))
.WillOnce(
DoAll(SetArgPointee<5>(response), SetArgPointee<6>(response_size),
Return(KEY_ROTATION_CMD_SUCCESS)));
EXPECT_TRUE(trustDescriptorHash(nullptr, reinterpret_cast<uint8_t*>(&hash),
sizeof(hash)));
}
TEST_F(KeyRotateHelperWithDeviceTest, TrustDescriptorHashMatchOnSecondChunk)
{
sha256 hash{0x01, 0x02, 0x03, 0x04};
// Setup for chunk_count = 3
EXPECT_CALL(*mock_api, libhoth_key_rotation_chunk_type_count(
dummy_hoth_device_for_suite,
KEY_ROTATION_CHUNK_TYPE_CODE_BASH, _))
.WillOnce(DoAll(SetArgPointee<2>(3), Return(KEY_ROTATION_CMD_SUCCESS)));
// Setup for first chunk (non-matching)
struct hoth_response_key_rotation_record_read non_matching_response = {};
struct bios_allowed_hash_list* non_matching_hash_list =
reinterpret_cast<struct bios_allowed_hash_list*>(
&non_matching_response.data);
non_matching_hash_list->hash_count = 1;
sha256 non_matching_hash{0xff, 0xff, 0xff, 0xff};
memcpy(non_matching_hash_list->hash_list[0], &non_matching_hash,
sizeof(non_matching_hash));
uint16_t non_matching_response_size =
sizeof(struct bios_allowed_hash_list) + sizeof(sha256);
EXPECT_CALL(*mock_api, libhoth_key_rotation_read_chunk_type(
dummy_hoth_device_for_suite,
KEY_ROTATION_CHUNK_TYPE_CODE_BASH, 0,
sizeof(key_rotation_chunk_header), 0, _, _))
.WillOnce(DoAll(SetArgPointee<5>(non_matching_response),
SetArgPointee<6>(non_matching_response_size),
Return(KEY_ROTATION_CMD_SUCCESS)));
// Setup for second chunk (matching)
struct hoth_response_key_rotation_record_read matching_response = {};
struct bios_allowed_hash_list* matching_hash_list =
reinterpret_cast<struct bios_allowed_hash_list*>(
&matching_response.data);
matching_hash_list->hash_count = 1;
memcpy(matching_hash_list->hash_list[0], &hash, sizeof(hash));
uint16_t matching_response_size =
sizeof(struct bios_allowed_hash_list) + sizeof(sha256);
EXPECT_CALL(*mock_api, libhoth_key_rotation_read_chunk_type(
dummy_hoth_device_for_suite,
KEY_ROTATION_CHUNK_TYPE_CODE_BASH, 1,
sizeof(key_rotation_chunk_header), 0, _, _))
.WillOnce(DoAll(SetArgPointee<5>(matching_response),
SetArgPointee<6>(matching_response_size),
Return(KEY_ROTATION_CMD_SUCCESS)));
EXPECT_TRUE(trustDescriptorHash(nullptr, reinterpret_cast<uint8_t*>(&hash),
sizeof(hash)));
}
TEST_F(KeyRotateHelperWithDeviceTest, TrustDescriptorHashMatchOnThirdChunk)
{
sha256 hash{0x01, 0x02, 0x03, 0x04};
// Setup for chunk_count = 3
EXPECT_CALL(*mock_api, libhoth_key_rotation_chunk_type_count(
dummy_hoth_device_for_suite,
KEY_ROTATION_CHUNK_TYPE_CODE_BASH, _))
.WillOnce(DoAll(SetArgPointee<2>(3), Return(KEY_ROTATION_CMD_SUCCESS)));
// Setup for first and second chunks (non-matching)
for (int i = 0; i < 2; ++i)
{
struct hoth_response_key_rotation_record_read non_matching_response =
{};
struct bios_allowed_hash_list* non_matching_hash_list =
reinterpret_cast<struct bios_allowed_hash_list*>(
&non_matching_response.data);
non_matching_hash_list->hash_count = 1;
sha256 non_matching_hash{0xff, 0xff, 0xff, (uint8_t)i};
memcpy(non_matching_hash_list->hash_list[0], &non_matching_hash,
sizeof(non_matching_hash));
uint16_t non_matching_response_size =
sizeof(struct bios_allowed_hash_list) + sizeof(sha256);
EXPECT_CALL(*mock_api,
libhoth_key_rotation_read_chunk_type(
dummy_hoth_device_for_suite,
KEY_ROTATION_CHUNK_TYPE_CODE_BASH, i, _, _, _, _))
.WillOnce(DoAll(SetArgPointee<5>(non_matching_response),
SetArgPointee<6>(non_matching_response_size),
Return(KEY_ROTATION_CMD_SUCCESS)));
}
// Setup for third chunk (matching)
struct hoth_response_key_rotation_record_read matching_response = {};
struct bios_allowed_hash_list* matching_hash_list =
reinterpret_cast<struct bios_allowed_hash_list*>(
&matching_response.data);
matching_hash_list->hash_count = 1;
memcpy(matching_hash_list->hash_list[0], &hash, sizeof(hash));
uint16_t matching_response_size =
sizeof(struct bios_allowed_hash_list) + sizeof(sha256);
EXPECT_CALL(*mock_api, libhoth_key_rotation_read_chunk_type(
dummy_hoth_device_for_suite,
KEY_ROTATION_CHUNK_TYPE_CODE_BASH, 2,
sizeof(key_rotation_chunk_header), 0, _, _))
.WillOnce(DoAll(SetArgPointee<5>(matching_response),
SetArgPointee<6>(matching_response_size),
Return(KEY_ROTATION_CMD_SUCCESS)));
EXPECT_TRUE(trustDescriptorHash(nullptr, reinterpret_cast<uint8_t*>(&hash),
sizeof(hash)));
}
TEST_F(KeyRotateHelperTest, TrustKeyInCr51SignatureNullArgs)
{
EXPECT_FALSE(
trustKeyInCr51Signature(nullptr, SIGNATURE_RSA2048_PKCS15, nullptr, 0));
char dummy_ctx;
EXPECT_FALSE(trustKeyInCr51Signature(&dummy_ctx, SIGNATURE_RSA2048_PKCS15,
nullptr, 0)); // NOLINT
struct signature_rsa2048_pkcs15 sig;
EXPECT_FALSE(trustKeyInCr51Signature(nullptr, SIGNATURE_RSA2048_PKCS15,
&sig, sizeof(sig)));
}
TEST_F(KeyRotateHelperTest, TrustKeyInCr51SignatureUnsupportedScheme)
{
char dummy_ctx;
struct signature_rsa2048_pkcs15 sig{};
EXPECT_FALSE(trustKeyInCr51Signature(
&dummy_ctx, static_cast<enum signature_scheme>(99), &sig, sizeof(sig)));
}
TEST_F(KeyRotateHelperTest, TrustKeyInCr51SignatureHashFails)
{
char dummy_ctx;
struct signature_rsa2048_pkcs15 sig{};
EXPECT_CALL(*mock_api, hash_init(_, HASH_SHA2_256)).WillOnce(Return(1));
EXPECT_FALSE(trustKeyInCr51Signature(&dummy_ctx, SIGNATURE_RSA2048_PKCS15,
&sig, sizeof(sig)));
}
TEST_F(KeyRotateHelperWithDeviceTest, TrustKeyInCr51SignatureMatch)
{
char dummy_ctx;
struct signature_rsa4096_pkcs15 sig = {};
sha256 key_fingerprint{0x01, 0x02, 0x03, 0x04};
EXPECT_CALL(*mock_api, hash_init(_, HASH_SHA2_256)).WillOnce(Return(0));
EXPECT_CALL(*mock_api, hash_update(_, _, _)).WillRepeatedly(Return(0));
EXPECT_CALL(*mock_api, hash_final(_, _))
.WillOnce(DoAll(
SetArrayArgument<1>(reinterpret_cast<uint8_t*>(&key_fingerprint),
reinterpret_cast<uint8_t*>(&key_fingerprint) +
sizeof(key_fingerprint)),
Return(0)));
EXPECT_CALL(*mock_api, libhoth_key_rotation_chunk_type_count(
dummy_hoth_device_for_suite,
KEY_ROTATION_CHUNK_TYPE_CODE_BKEY, _))
.WillOnce(DoAll(SetArgPointee<2>(1), Return(KEY_ROTATION_CMD_SUCCESS)));
struct hoth_response_key_rotation_record_read response = {};
struct bios_verifiction_key_fingerprint* trusted_key =
reinterpret_cast<struct bios_verifiction_key_fingerprint*>(
&response.data);
memcpy(trusted_key->key_fingerprint, &key_fingerprint,
sizeof(key_fingerprint));
uint16_t response_size = sizeof(struct bios_verifiction_key_fingerprint);
EXPECT_CALL(*mock_api,
libhoth_key_rotation_read_chunk_type(
dummy_hoth_device_for_suite,
KEY_ROTATION_CHUNK_TYPE_CODE_BKEY, 0, _, _, _, _))
.WillOnce(
DoAll(SetArgPointee<5>(response), SetArgPointee<6>(response_size),
Return(KEY_ROTATION_CMD_SUCCESS)));
EXPECT_TRUE(trustKeyInCr51Signature(&dummy_ctx, SIGNATURE_RSA4096_PKCS15,
&sig, sizeof(sig)));
}
TEST_F(KeyRotateHelperWithDeviceTest, TrustKeyInCr51SignatureMatchOnSecondChunk)
{
char dummy_ctx;
struct signature_rsa4096_pkcs15 sig = {};
sha256 key_fingerprint{0x01, 0x02, 0x03, 0x04};
EXPECT_CALL(*mock_api, hash_init(_, HASH_SHA2_256)).WillOnce(Return(0));
EXPECT_CALL(*mock_api, hash_update(_, _, _)).WillRepeatedly(Return(0));
EXPECT_CALL(*mock_api, hash_final(_, _))
.WillOnce(DoAll(
SetArrayArgument<1>(reinterpret_cast<uint8_t*>(&key_fingerprint),
reinterpret_cast<uint8_t*>(&key_fingerprint) +
sizeof(key_fingerprint)),
Return(0)));
EXPECT_CALL(*mock_api, libhoth_key_rotation_chunk_type_count(
dummy_hoth_device_for_suite,
KEY_ROTATION_CHUNK_TYPE_CODE_BKEY, _))
.WillOnce(DoAll(SetArgPointee<2>(3), Return(KEY_ROTATION_CMD_SUCCESS)));
// Setup for first chunk (non-matching)
struct hoth_response_key_rotation_record_read non_matching_response = {};
struct bios_verifiction_key_fingerprint* non_matching_key =
reinterpret_cast<struct bios_verifiction_key_fingerprint*>(
&non_matching_response.data);
sha256 non_matching_fingerprint{0xff, 0xff, 0xff, 0xff};
memcpy(non_matching_key->key_fingerprint, &non_matching_fingerprint,
sizeof(non_matching_fingerprint));
uint16_t non_matching_response_size =
sizeof(struct bios_verifiction_key_fingerprint);
EXPECT_CALL(*mock_api, libhoth_key_rotation_read_chunk_type(
dummy_hoth_device_for_suite,
KEY_ROTATION_CHUNK_TYPE_CODE_BKEY, 0,
sizeof(key_rotation_chunk_header), 0, _, _))
.WillOnce(DoAll(SetArgPointee<5>(non_matching_response),
SetArgPointee<6>(non_matching_response_size),
Return(KEY_ROTATION_CMD_SUCCESS)));
// Setup for second chunk (matching)
struct hoth_response_key_rotation_record_read matching_response = {};
struct bios_verifiction_key_fingerprint* matching_key =
reinterpret_cast<struct bios_verifiction_key_fingerprint*>(
&matching_response.data);
memcpy(matching_key->key_fingerprint, &key_fingerprint,
sizeof(key_fingerprint));
uint16_t matching_response_size =
sizeof(struct bios_verifiction_key_fingerprint);
EXPECT_CALL(*mock_api, libhoth_key_rotation_read_chunk_type(
dummy_hoth_device_for_suite,
KEY_ROTATION_CHUNK_TYPE_CODE_BKEY, 1,
sizeof(key_rotation_chunk_header), 0, _, _))
.WillOnce(DoAll(SetArgPointee<5>(matching_response),
SetArgPointee<6>(matching_response_size),
Return(KEY_ROTATION_CMD_SUCCESS)));
EXPECT_TRUE(trustKeyInCr51Signature(&dummy_ctx, SIGNATURE_RSA4096_PKCS15,
&sig, sizeof(sig)));
}
TEST_F(KeyRotateHelperWithDeviceTest, TrustKeyInCr51SignatureMatchOnThirdChunk)
{
char dummy_ctx;
struct signature_rsa4096_pkcs15 sig = {};
sha256 key_fingerprint{0x01, 0x02, 0x03, 0x04};
EXPECT_CALL(*mock_api, hash_init(_, HASH_SHA2_256)).WillOnce(Return(0));
EXPECT_CALL(*mock_api, hash_update(_, _, _)).WillRepeatedly(Return(0));
EXPECT_CALL(*mock_api, hash_final(_, _))
.WillOnce(DoAll(
SetArrayArgument<1>(reinterpret_cast<uint8_t*>(&key_fingerprint),
reinterpret_cast<uint8_t*>(&key_fingerprint) +
sizeof(key_fingerprint)),
Return(0)));
EXPECT_CALL(*mock_api, libhoth_key_rotation_chunk_type_count(
dummy_hoth_device_for_suite,
KEY_ROTATION_CHUNK_TYPE_CODE_BKEY, _))
.WillOnce(DoAll(SetArgPointee<2>(3), Return(KEY_ROTATION_CMD_SUCCESS)));
// Setup for first and second chunks (non-matching)
for (int i = 0; i < 2; ++i)
{
struct hoth_response_key_rotation_record_read non_matching_response =
{};
struct bios_verifiction_key_fingerprint* non_matching_key =
reinterpret_cast<struct bios_verifiction_key_fingerprint*>(
&non_matching_response.data);
sha256 non_matching_fingerprint{0xff, 0xff, 0xff, (uint8_t)i};
memcpy(non_matching_key->key_fingerprint, &non_matching_fingerprint,
sizeof(non_matching_fingerprint));
uint16_t non_matching_response_size =
sizeof(struct bios_verifiction_key_fingerprint);
EXPECT_CALL(*mock_api,
libhoth_key_rotation_read_chunk_type(
dummy_hoth_device_for_suite,
KEY_ROTATION_CHUNK_TYPE_CODE_BKEY, i, _, _, _, _))
.WillOnce(DoAll(SetArgPointee<5>(non_matching_response),
SetArgPointee<6>(non_matching_response_size),
Return(KEY_ROTATION_CMD_SUCCESS)));
}
// Setup for third chunk (matching)
struct hoth_response_key_rotation_record_read matching_response = {};
struct bios_verifiction_key_fingerprint* matching_key =
reinterpret_cast<struct bios_verifiction_key_fingerprint*>(
&matching_response.data);
memcpy(matching_key->key_fingerprint, &key_fingerprint,
sizeof(key_fingerprint));
uint16_t matching_response_size =
sizeof(struct bios_verifiction_key_fingerprint);
EXPECT_CALL(*mock_api, libhoth_key_rotation_read_chunk_type(
dummy_hoth_device_for_suite,
KEY_ROTATION_CHUNK_TYPE_CODE_BKEY, 2,
sizeof(key_rotation_chunk_header), 0, _, _))
.WillOnce(DoAll(SetArgPointee<5>(matching_response),
SetArgPointee<6>(matching_response_size),
Return(KEY_ROTATION_CMD_SUCCESS)));
EXPECT_TRUE(trustKeyInCr51Signature(&dummy_ctx, SIGNATURE_RSA4096_PKCS15,
&sig, sizeof(sig)));
}
TEST_F(KeyRotateHelperTest, AlwaysTrustDescriptorHash)
{
sha256 hash{};
// It should return true even if the underlying function returns false.
EXPECT_CALL(*mock_api, libhoth_dbus_open(_, _)).WillOnce(Return(-1));
EXPECT_TRUE(alwaysTrustDescriptorHash(
nullptr, reinterpret_cast<uint8_t*>(&hash), sizeof(hash)));
}
TEST_F(KeyRotateHelperTest, AlwaysTrustKeyInCr51Signature)
{
char dummy_ctx;
struct signature_rsa2048_pkcs15 sig{};
// It should return true even if the underlying function returns false.
EXPECT_CALL(*mock_api, hash_init(_, _)).WillOnce(Return(1)); // make it fail
EXPECT_TRUE(alwaysTrustKeyInCr51Signature(
&dummy_ctx, SIGNATURE_RSA2048_PKCS15, &sig, sizeof(sig)));
}
TEST_F(KeyRotateHelperWithDeviceTest, NeverTrustDescriptorHash)
{
sha256 hash{0x01, 0x02, 0x03, 0x04};
// It should return false even if the underlying function returns true.
struct hoth_response_key_rotation_record_read response = {};
struct bios_allowed_hash_list* hash_list =
reinterpret_cast<struct bios_allowed_hash_list*>(&response.data);
hash_list->hash_count = 1;
memcpy(hash_list->hash_list[0], &hash, sizeof(hash));
uint16_t response_size =
sizeof(struct bios_allowed_hash_list) + sizeof(sha256);
EXPECT_CALL(*mock_api, libhoth_key_rotation_chunk_type_count(
dummy_hoth_device_for_suite,
KEY_ROTATION_CHUNK_TYPE_CODE_BASH, _))
.WillOnce(DoAll(SetArgPointee<2>(1), Return(KEY_ROTATION_CMD_SUCCESS)));
EXPECT_CALL(*mock_api,
libhoth_key_rotation_read_chunk_type(
dummy_hoth_device_for_suite,
KEY_ROTATION_CHUNK_TYPE_CODE_BASH, 0, _, _, _, _))
.WillOnce(
DoAll(SetArgPointee<5>(response), SetArgPointee<6>(response_size),
Return(KEY_ROTATION_CMD_SUCCESS)));
EXPECT_FALSE(neverTrustDescriptorHash(
nullptr, reinterpret_cast<uint8_t*>(&hash), sizeof(hash)));
}
TEST_F(KeyRotateHelperTest, IsBiosKeyRotationSupportHothOpenFails)
{
// This test must run before any test that successfully opens a hoth device
// due to the static hoth_device cache in the production code.
EXPECT_CALL(*mock_api, libhoth_dbus_open(_, _)).WillOnce(Return(-1));
EXPECT_FALSE(isBiosKeyRotationSupport());
}
TEST_F(KeyRotateHelperWithDeviceTest, IsBiosKeyRotationSupportChunkCountFails)
{
EXPECT_CALL(*mock_api, libhoth_key_rotation_chunk_type_count(
dummy_hoth_device_for_suite,
KEY_ROTATION_CHUNK_TYPE_CODE_BKEY, _))
.WillOnce(Return(KEY_ROTATION_ERR));
EXPECT_FALSE(isBiosKeyRotationSupport());
}
TEST_F(KeyRotateHelperWithDeviceTest, IsBiosKeyRotationSupportNoChunks)
{
EXPECT_CALL(*mock_api, libhoth_key_rotation_chunk_type_count(
dummy_hoth_device_for_suite,
KEY_ROTATION_CHUNK_TYPE_CODE_BKEY, _))
.WillOnce(DoAll(SetArgPointee<2>(0), Return(KEY_ROTATION_CMD_SUCCESS)));
EXPECT_FALSE(isBiosKeyRotationSupport());
}
TEST_F(KeyRotateHelperWithDeviceTest, IsBiosKeyRotationSupportSuccess)
{
EXPECT_CALL(*mock_api, libhoth_key_rotation_chunk_type_count(
dummy_hoth_device_for_suite,
KEY_ROTATION_CHUNK_TYPE_CODE_BKEY, _))
.WillOnce(DoAll(SetArgPointee<2>(1), Return(KEY_ROTATION_CMD_SUCCESS)));
EXPECT_TRUE(isBiosKeyRotationSupport());
}
} // namespace google::cr51