flashupdate: Implement BIOS key metrics writer for key rotation

Introduce the BIOS key metrics writer logic in flashupdate. This writes
telemetry data to `/run/bios_key/` containing four metrics:
- bios_key_validation_method: EMBEDDED_KEY or PAYLOAD_KEY
- bios_key_image_family: Decimal image family of the validating key
- bios_key_version: The config package version from Hoth key rotation record
- bios_key_validation_key_data: First 64 bits of the validating key's modulus (hex)

The metrics writer is hooked into:
1. isBiosKeyRotationSupport(): Writes EMBEDDED_KEY when key rotation is
   not supported or there are zero keys defined.
2. trustKeyInCr51Signature(): Writes PAYLOAD_KEY, image family, version
   (queried via libhoth_key_rotation_get_version), and validation key data
   (extracted from the validating key's modulus) when a key match happens.

Updated unit tests to align with this design and added mock coverage for
libhoth_key_rotation_get_version.

Google-Bug-Id: 459542518
Change-Id: Ibdf47909f85cf2ebd30fc9ed1bf02db3a543bc0d
Signed-off-by: Manan J. Mehta <mjmehta@google.com>
diff --git a/subprojects/flashupdate/meson_options.txt b/subprojects/flashupdate/meson_options.txt
index f3f8235..2bec758 100644
--- a/subprojects/flashupdate/meson_options.txt
+++ b/subprojects/flashupdate/meson_options.txt
@@ -2,3 +2,5 @@
 option('dev', type: 'boolean', value: false,  description: 'Enable Development Workflow')
 option('cr51-mauv-path', type: 'string', description: 'CR51 MAUV Stored File')
 option('cr51-mauv-offset', type: 'integer',  description: 'Offset to reset the MAUV data')
+option('bios-key-metrics-dir', type: 'string', value: '/run/bios_key', description: 'Directory to write BIOS key metrics')
+
diff --git a/subprojects/flashupdate/src/meson.build b/subprojects/flashupdate/src/meson.build
index 9319b8f..2cd79b7 100644
--- a/subprojects/flashupdate/src/meson.build
+++ b/subprojects/flashupdate/src/meson.build
@@ -49,6 +49,11 @@
 conf_data = configuration_data()
 conf_data.set_quoted('CR51_MAUV_PATH', get_option('cr51-mauv-path'))
 conf_data.set('CR51_MAUV_OFFSET', get_option('cr51-mauv-offset'))
+metrics_dir = get_option('bios-key-metrics-dir')
+if not get_option('tests').disabled()
+  metrics_dir = '/tmp/flashupdate_test_bios_key'
+endif
+conf_data.set_quoted('BIOS_KEY_METRICS_DIR', metrics_dir)
 config_h = configure_file(
   output: 'config.h',
   configuration: conf_data
diff --git a/subprojects/flashupdate/src/validator/key_rotate_helper.cpp b/subprojects/flashupdate/src/validator/key_rotate_helper.cpp
index d272628..a20ad26 100644
--- a/subprojects/flashupdate/src/validator/key_rotate_helper.cpp
+++ b/subprojects/flashupdate/src/validator/key_rotate_helper.cpp
@@ -11,6 +11,8 @@
 // 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 "config.h"
+
 #include "flashupdate/validator/key_rotate_helper.hpp"
 
 #include "flashupdate/info.hpp"
@@ -22,7 +24,9 @@
 #include <libhoth/transports/libhoth_dbus.h>
 
 #include <cstdint>
+#include <filesystem>
 #include <format>
+#include <fstream>
 #include <string_view>
 
 namespace
@@ -238,6 +242,111 @@
     }
     return true;
 }
+
+void writeBiosKeyMetricFiles(std::string_view validation_method,
+                             uint32_t image_family, uint32_t version,
+                             uint64_t validation_key_data)
+{
+    std::string dir = BIOS_KEY_METRICS_DIR;
+    std::string tmp_dir = dir + ".tmp";
+    std::error_code ec;
+
+    // 1. Create and write to a .tmp directory first. We use the
+    // write-to-tmp-and-rename pattern to ensure that the metrics update is
+    // atomic. This prevents a telemetry reader from experiencing race
+    // conditions, such as reading partially-written files (partial writes) or a
+    // mix of old and new files (group inconsistency).
+    std::filesystem::create_directories(tmp_dir, ec);
+    if (ec)
+    {
+        LOG(flashupdate::LogLevel::Error, "Failed to create directory {}: {}",
+            tmp_dir, ec.message());
+        return;
+    }
+
+    auto write_file = [](const std::filesystem::path& path,
+                         const std::string_view content) {
+        std::ofstream file(path, std::ios::out | std::ios::trunc);
+        if (!file.is_open())
+        {
+            LOG(flashupdate::LogLevel::Error,
+                "Failed to open file for writing: {}", path.string());
+            return;
+        }
+        file << content << "\n";
+    };
+
+    std::filesystem::path tmp_dir_path(tmp_dir);
+    write_file(tmp_dir_path / "bios_key_validation_method", validation_method);
+    write_file(tmp_dir_path / "bios_key_image_family",
+               std::to_string(image_family));
+    write_file(tmp_dir_path / "bios_key_version", std::to_string(version));
+    write_file(tmp_dir_path / "bios_key_validation_key_data",
+               std::format("0x{:016x}", validation_key_data));
+
+    // 2. Delete the old target directory
+    std::filesystem::remove_all(dir, ec);
+    if (ec && ec != std::errc::no_such_file_or_directory)
+    {
+        LOG(flashupdate::LogLevel::Error,
+            "Failed to remove old directory {}: {}", dir, ec.message());
+        return;
+    }
+
+    // 3. Rename tmp directory to target directory
+    std::filesystem::rename(tmp_dir, dir, ec);
+    if (ec)
+    {
+        LOG(flashupdate::LogLevel::Error,
+            "Failed to rename directory {} to {}: {}", tmp_dir, dir,
+            ec.message());
+        return;
+    }
+
+    LOG(flashupdate::LogLevel::Notice,
+        "Write bios key metric files: {} {} {} {}", validation_method,
+        image_family, version, std::format("0x{:016x}", validation_key_data));
+}
+
+void clearBiosKeyMetricFiles()
+{
+    std::string dir = BIOS_KEY_METRICS_DIR;
+    std::error_code ec;
+    std::filesystem::remove_all(dir, ec);
+    if (ec && ec != std::errc::no_such_file_or_directory)
+    {
+        LOG(flashupdate::LogLevel::Error,
+            "Failed to clear metrics directory {}: {}", dir, ec.message());
+    }
+}
+
+const uint8_t* getModulusFromCr51Signature(enum signature_scheme scheme,
+                                           const void* cr51_signature)
+{
+    if (!cr51_signature)
+    {
+        return nullptr;
+    }
+    switch (scheme)
+    {
+        case SIGNATURE_RSA2048_PKCS15:
+            return reinterpret_cast<const struct signature_rsa2048_pkcs15*>(
+                       cr51_signature)
+                ->modulus;
+        case SIGNATURE_RSA3072_PKCS15:
+            return reinterpret_cast<const struct signature_rsa3072_pkcs15*>(
+                       cr51_signature)
+                ->modulus;
+        case SIGNATURE_RSA4096_PKCS15:
+        case SIGNATURE_RSA4096_PKCS15_SHA512:
+            return reinterpret_cast<const struct signature_rsa4096_pkcs15*>(
+                       cr51_signature)
+                ->modulus;
+        default:
+            return nullptr;
+    }
+}
+
 } // namespace
 
 namespace google
@@ -359,6 +468,7 @@
         hoth_device, KEY_ROTATION_CHUNK_TYPE_CODE_BKEY);
     if (trusted_bios_key_count < 0)
     {
+        writeBiosKeyMetricFiles("EMBEDDED_KEY", 0, 0, 0);
         return false;
     }
 
@@ -403,13 +513,47 @@
                 "Match trusted bios key finger print in {}_{}",
                 rotConfigChunkName(KEY_ROTATION_CHUNK_TYPE_CODE_BKEY),
                 chunk_index);
+
+            uint32_t version = 0;
+            struct hoth_response_key_rotation_record_version record_version;
+            enum key_rotation_err version_err =
+                libhoth_key_rotation_get_version(hoth_device, &record_version);
+            if (version_err == KEY_ROTATION_CMD_SUCCESS)
+            {
+                version = record_version.version;
+            }
+            else
+            {
+                LOG(flashupdate::LogLevel::Error,
+                    "Get key rotation version failed: {}",
+                    static_cast<int>(version_err));
+            }
+
+            uint64_t val_key_data = 0;
+            const uint8_t* modulus =
+                getModulusFromCr51Signature(scheme, cr51_signature);
+            if (modulus)
+            {
+                for (size_t i = 0; i < 8; ++i)
+                {
+                    val_key_data = (val_key_data << 8) | modulus[i];
+                }
+            }
+
+            writeBiosKeyMetricFiles("PAYLOAD_KEY",
+                                    trusted_bios_key->image_family, version,
+                                    val_key_data);
+
             return true;
         }
     }
 
     LOG(flashupdate::LogLevel::Notice, "Not match any trusted bios key");
+    writeBiosKeyMetricFiles("EMBEDDED_KEY", 0, 0, 0);
+
     return false;
 }
+
 // For Testing or debug
 bool alwaysTrustDescriptorHash(const void* ctx, const uint8_t* descriptor_hash,
                                size_t hash_size)
@@ -453,13 +597,19 @@
 bool isBiosKeyRotationSupport()
 {
     struct libhoth_device* hoth_device = hothDevice();
-    if (!hoth_device)
-    {
-        return false;
-    }
 
-    return chunkCountInHothRoTConfig(hoth_device,
-                                     KEY_ROTATION_CHUNK_TYPE_CODE_BKEY) > 0;
+    // Clear any stale metric files written by previous runs.
+    clearBiosKeyMetricFiles();
+
+    if (hoth_device && chunkCountInHothRoTConfig(
+                           hoth_device, KEY_ROTATION_CHUNK_TYPE_CODE_BKEY) > 0)
+    {
+        return true;
+    }
+    // If rotation is not supported, we immediately record that we are
+    // using the EMBEDDED_KEY
+    writeBiosKeyMetricFiles("EMBEDDED_KEY", 0, 0, 0);
+    return false;
 }
 } // namespace cr51
 } // namespace google
diff --git a/subprojects/flashupdate/test/validator/key_rotate_helper.cpp b/subprojects/flashupdate/test/validator/key_rotate_helper.cpp
index da88f19..0f21131 100644
--- a/subprojects/flashupdate/test/validator/key_rotate_helper.cpp
+++ b/subprojects/flashupdate/test/validator/key_rotate_helper.cpp
@@ -19,6 +19,8 @@
 
 #include <flashupdate/validator/key_rotate_helper.hpp>
 
+#include <filesystem>
+#include <fstream>
 #include <memory>
 
 #include <gmock/gmock.h>
@@ -46,6 +48,10 @@
                  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(
+        enum key_rotation_err, libhoth_key_rotation_get_version,
+        (struct libhoth_device * dev,
+         struct hoth_response_key_rotation_record_version* record_version));
     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));
@@ -94,6 +100,17 @@
     return KEY_ROTATION_ERR;
 }
 
+enum key_rotation_err libhoth_key_rotation_get_version(
+    struct libhoth_device* dev,
+    struct hoth_response_key_rotation_record_version* record_version)
+{
+    if (mock_api)
+    {
+        return mock_api->libhoth_key_rotation_get_version(dev, record_version);
+    }
+    return KEY_ROTATION_ERR;
+}
+
 int hash_init(void* ctx, enum hash_type type)
 {
     if (mock_api)
@@ -130,11 +147,15 @@
   protected:
     void SetUp() override
     {
+        std::error_code ec;
+        std::filesystem::remove_all("/tmp/flashupdate_test_bios_key", ec);
         mock_api = std::make_unique<::testing::StrictMock<MockApi>>();
     }
 
     void TearDown() override
     {
+        std::error_code ec;
+        std::filesystem::remove_all("/tmp/flashupdate_test_bios_key", ec);
         mock_api.reset();
     }
 
@@ -205,6 +226,8 @@
     // TearDownTestSuite is called once after all tests in this suite are run.
     static void TearDownTestSuite()
     {
+        std::error_code ec;
+        std::filesystem::remove_all("/tmp/flashupdate_test_bios_key", ec);
         mock_api.reset();
     }
 
@@ -411,7 +434,10 @@
     struct libcr51sign_ctx dummy_ctx;
     dummy_ctx.descriptor.image_family = 2;
     struct signature_rsa4096_pkcs15 sig = {};
-    sha256 key_fingerprint{0x01, 0x02, 0x03, 0x04};
+    uint8_t test_modulus[8] = {0x12, 0x34, 0x56, 0x78, 0xab, 0xcd, 0xef, 0x01};
+    memcpy(sig.modulus, test_modulus, sizeof(test_modulus));
+
+    sha256 key_fingerprint = {0x12, 0x34, 0x56, 0x78, 0xab, 0xcd, 0xef, 0x01};
 
     EXPECT_CALL(*mock_api, hash_init(_, HASH_SHA2_256)).WillOnce(Return(0));
     EXPECT_CALL(*mock_api, hash_update(_, _, _)).WillRepeatedly(Return(0));
@@ -442,8 +468,54 @@
         .WillOnce(
             DoAll(SetArgPointee<5>(response), SetArgPointee<6>(response_size),
                   Return(KEY_ROTATION_CMD_SUCCESS)));
+
+    struct hoth_response_key_rotation_record_version record_version = {
+        .version = 16};
+    EXPECT_CALL(*mock_api, libhoth_key_rotation_get_version(
+                               dummy_hoth_device_for_suite, _))
+        .WillOnce(DoAll(SetArgPointee<1>(record_version),
+                        Return(KEY_ROTATION_CMD_SUCCESS)));
+
+    // Clean up any existing files before the test
+    std::error_code ec;
+    std::filesystem::remove_all("/tmp/flashupdate_test_bios_key", ec);
+
     EXPECT_TRUE(trustKeyInCr51Signature(&dummy_ctx, SIGNATURE_RSA4096_PKCS15,
                                         &sig, sizeof(sig)));
+
+    // Verify that the files were created and contain the correct values
+    EXPECT_TRUE(std::filesystem::exists(
+        "/tmp/flashupdate_test_bios_key/bios_key_validation_method"));
+    EXPECT_TRUE(std::filesystem::exists(
+        "/tmp/flashupdate_test_bios_key/bios_key_image_family"));
+    EXPECT_TRUE(std::filesystem::exists(
+        "/tmp/flashupdate_test_bios_key/bios_key_version"));
+    EXPECT_TRUE(std::filesystem::exists(
+        "/tmp/flashupdate_test_bios_key/bios_key_validation_key_data"));
+
+    std::ifstream method_file(
+        "/tmp/flashupdate_test_bios_key/bios_key_validation_method");
+    std::string method;
+    std::getline(method_file, method);
+    EXPECT_EQ(method, "PAYLOAD_KEY");
+
+    std::ifstream family_file(
+        "/tmp/flashupdate_test_bios_key/bios_key_image_family");
+    std::string family;
+    std::getline(family_file, family);
+    EXPECT_EQ(family, "2");
+
+    std::ifstream version_file(
+        "/tmp/flashupdate_test_bios_key/bios_key_version");
+    std::string version;
+    std::getline(version_file, version);
+    EXPECT_EQ(version, "16");
+
+    std::ifstream key_data_file(
+        "/tmp/flashupdate_test_bios_key/bios_key_validation_key_data");
+    std::string key_data;
+    std::getline(key_data_file, key_data);
+    EXPECT_EQ(key_data, "0x12345678abcdef01");
 }
 
 TEST_F(KeyRotateHelperWithDeviceTest,
@@ -545,8 +617,54 @@
                         SetArgPointee<6>(matching_response_size),
                         Return(KEY_ROTATION_CMD_SUCCESS)));
 
+    // Mock get_version failure to cover the version fallback path
+    EXPECT_CALL(*mock_api, libhoth_key_rotation_get_version(
+                               dummy_hoth_device_for_suite, _))
+        .WillOnce(Return(KEY_ROTATION_ERR));
+
+    // Clean up any existing files before the test
+    std::error_code ec;
+    std::filesystem::remove_all("/tmp/flashupdate_test_bios_key", ec);
+
+    uint8_t test_modulus[8] = {0x12, 0x34, 0x56, 0x78, 0xab, 0xcd, 0xef, 0x01};
+    memcpy(sig.modulus, test_modulus, sizeof(test_modulus));
+
     EXPECT_TRUE(trustKeyInCr51Signature(&dummy_ctx, SIGNATURE_RSA4096_PKCS15,
                                         &sig, sizeof(sig)));
+
+    // Verify fallback files were created
+    EXPECT_TRUE(std::filesystem::exists(
+        "/tmp/flashupdate_test_bios_key/bios_key_validation_method"));
+    EXPECT_TRUE(std::filesystem::exists(
+        "/tmp/flashupdate_test_bios_key/bios_key_image_family"));
+    EXPECT_TRUE(std::filesystem::exists(
+        "/tmp/flashupdate_test_bios_key/bios_key_version"));
+    EXPECT_TRUE(std::filesystem::exists(
+        "/tmp/flashupdate_test_bios_key/bios_key_validation_key_data"));
+
+    std::ifstream method_file(
+        "/tmp/flashupdate_test_bios_key/bios_key_validation_method");
+    std::string method;
+    std::getline(method_file, method);
+    EXPECT_EQ(method, "PAYLOAD_KEY");
+
+    std::ifstream family_file(
+        "/tmp/flashupdate_test_bios_key/bios_key_image_family");
+    std::string family;
+    std::getline(family_file, family);
+    EXPECT_EQ(family, "0");
+
+    std::ifstream version_file(
+        "/tmp/flashupdate_test_bios_key/bios_key_version");
+    std::string version;
+    std::getline(version_file, version);
+    EXPECT_EQ(version, "0");
+
+    std::ifstream key_data_file(
+        "/tmp/flashupdate_test_bios_key/bios_key_validation_key_data");
+    std::string key_data;
+    std::getline(key_data_file, key_data);
+    EXPECT_EQ(key_data, "0x12345678abcdef01");
 }
 
 TEST_F(KeyRotateHelperWithDeviceTest, TrustKeyInCr51SignatureMatchOnThirdChunk)
@@ -610,6 +728,11 @@
                         SetArgPointee<6>(matching_response_size),
                         Return(KEY_ROTATION_CMD_SUCCESS)));
 
+    // Mock get_version failure to cover the version fallback path
+    EXPECT_CALL(*mock_api, libhoth_key_rotation_get_version(
+                               dummy_hoth_device_for_suite, _))
+        .WillOnce(Return(KEY_ROTATION_ERR));
+
     EXPECT_TRUE(trustKeyInCr51Signature(&dummy_ctx, SIGNATURE_RSA4096_PKCS15,
                                         &sig, sizeof(sig)));
 }
@@ -666,7 +789,17 @@
     // 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());
+
+    // Verify that the files were created and contain the correct values
+    EXPECT_TRUE(std::filesystem::exists(
+        "/tmp/flashupdate_test_bios_key/bios_key_validation_method"));
+    std::ifstream method_file(
+        "/tmp/flashupdate_test_bios_key/bios_key_validation_method");
+    std::string method;
+    std::getline(method_file, method);
+    EXPECT_EQ(method, "EMBEDDED_KEY");
 }
 
 TEST_F(KeyRotateHelperWithDeviceTest, IsBiosKeyRotationSupportChunkCountFails)
@@ -678,15 +811,6 @@
     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(
@@ -696,4 +820,187 @@
     EXPECT_TRUE(isBiosKeyRotationSupport());
 }
 
+TEST_F(KeyRotateHelperWithDeviceTest, IsBiosKeyRotationSupportClearsMetrics)
+{
+    // First, write some files
+    std::error_code ec;
+    std::string dir = "/tmp/flashupdate_test_bios_key";
+    std::filesystem::create_directories(dir, ec);
+    ASSERT_FALSE(ec);
+
+    auto write_dummy = [&](const std::string& name) {
+        std::ofstream file(std::filesystem::path(dir) / name);
+        file << "dummy\n";
+    };
+    write_dummy("bios_key_validation_method");
+    write_dummy("bios_key_image_family");
+    write_dummy("bios_key_version");
+    write_dummy("bios_key_validation_key_data");
+
+    // Verify they exist
+    EXPECT_TRUE(std::filesystem::exists(dir + "/bios_key_validation_method"));
+    EXPECT_TRUE(std::filesystem::exists(dir + "/bios_key_image_family"));
+    EXPECT_TRUE(std::filesystem::exists(dir + "/bios_key_version"));
+    EXPECT_TRUE(std::filesystem::exists(dir + "/bios_key_validation_key_data"));
+
+    // Mock Hoth call to succeed so isBiosKeyRotationSupport returns true
+    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)));
+
+    // Call isBiosKeyRotationSupport, which should clear the files
+    EXPECT_TRUE(isBiosKeyRotationSupport());
+
+    // Verify they are gone
+    EXPECT_FALSE(std::filesystem::exists(dir + "/bios_key_validation_method"));
+    EXPECT_FALSE(std::filesystem::exists(dir + "/bios_key_image_family"));
+    EXPECT_FALSE(std::filesystem::exists(dir + "/bios_key_version"));
+    EXPECT_FALSE(
+        std::filesystem::exists(dir + "/bios_key_validation_key_data"));
+}
+
+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)));
+
+    // Clean up any existing files before the test
+    std::error_code ec;
+    std::filesystem::remove_all("/tmp/flashupdate_test_bios_key", ec);
+
+    EXPECT_FALSE(isBiosKeyRotationSupport());
+
+    // Verify that the files were created and contain the correct values
+    EXPECT_TRUE(std::filesystem::exists(
+        "/tmp/flashupdate_test_bios_key/bios_key_validation_method"));
+    EXPECT_TRUE(std::filesystem::exists(
+        "/tmp/flashupdate_test_bios_key/bios_key_image_family"));
+    EXPECT_TRUE(std::filesystem::exists(
+        "/tmp/flashupdate_test_bios_key/bios_key_version"));
+    EXPECT_TRUE(std::filesystem::exists(
+        "/tmp/flashupdate_test_bios_key/bios_key_validation_key_data"));
+
+    std::ifstream method_file(
+        "/tmp/flashupdate_test_bios_key/bios_key_validation_method");
+    std::string method;
+    std::getline(method_file, method);
+    EXPECT_EQ(method, "EMBEDDED_KEY");
+
+    std::ifstream family_file(
+        "/tmp/flashupdate_test_bios_key/bios_key_image_family");
+    std::string family;
+    std::getline(family_file, family);
+    EXPECT_EQ(family, "0");
+
+    std::ifstream version_file(
+        "/tmp/flashupdate_test_bios_key/bios_key_version");
+    std::string version;
+    std::getline(version_file, version);
+    EXPECT_EQ(version, "0");
+
+    std::ifstream key_data_file(
+        "/tmp/flashupdate_test_bios_key/bios_key_validation_key_data");
+    std::string key_data;
+    std::getline(key_data_file, key_data);
+    EXPECT_EQ(key_data, "0x0000000000000000");
+}
+
+TEST_F(KeyRotateHelperWithDeviceTest, TrustKeyInCr51SignatureChunkCountError)
+{
+    struct libcr51sign_ctx dummy_ctx;
+    struct signature_rsa4096_pkcs15 sig = {};
+
+    sha256 key_fingerprint = {0x12, 0x34, 0x56, 0x78, 0xab, 0xcd, 0xef, 0x01};
+
+    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(Return(KEY_ROTATION_ERR));
+
+    // Clean up any existing files before the test
+    std::error_code ec;
+    std::filesystem::remove_all("/tmp/flashupdate_test_bios_key", ec);
+
+    EXPECT_FALSE(trustKeyInCr51Signature(&dummy_ctx, SIGNATURE_RSA4096_PKCS15,
+                                         &sig, sizeof(sig)));
+
+    // Verify that the files were created and contain the correct values
+    EXPECT_TRUE(std::filesystem::exists(
+        "/tmp/flashupdate_test_bios_key/bios_key_validation_method"));
+    std::ifstream method_file(
+        "/tmp/flashupdate_test_bios_key/bios_key_validation_method");
+    std::string method;
+    std::getline(method_file, method);
+    EXPECT_EQ(method, "EMBEDDED_KEY");
+}
+
+TEST_F(KeyRotateHelperWithDeviceTest, TrustKeyInCr51SignatureNoMatch)
+{
+    struct libcr51sign_ctx dummy_ctx;
+    struct signature_rsa4096_pkcs15 sig = {};
+    sha256 key_fingerprint = {0x12, 0x34, 0x56, 0x78, 0xab, 0xcd, 0xef, 0x01};
+
+    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)));
+
+    // Define 1 trusted key in Hoth, but it won't match
+    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);
+    trusted_key->image_family = 2;
+    // Different fingerprint
+    sha256 different_fingerprint = {0xff, 0xff, 0xff, 0xff};
+    memcpy(trusted_key->key_fingerprint, &different_fingerprint,
+           sizeof(different_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)));
+
+    // Clean up any existing files before the test
+    std::error_code ec;
+    std::filesystem::remove_all("/tmp/flashupdate_test_bios_key", ec);
+
+    EXPECT_FALSE(trustKeyInCr51Signature(&dummy_ctx, SIGNATURE_RSA4096_PKCS15,
+                                         &sig, sizeof(sig)));
+
+    // Verify that the files were created and contain EMBEDDED_KEY
+    EXPECT_TRUE(std::filesystem::exists(
+        "/tmp/flashupdate_test_bios_key/bios_key_validation_method"));
+    std::ifstream method_file(
+        "/tmp/flashupdate_test_bios_key/bios_key_validation_method");
+    std::string method;
+    std::getline(method_file, method);
+    EXPECT_EQ(method, "EMBEDDED_KEY");
+}
+
 } // namespace google::cr51