blob: 0d342d3e250babd57f44a5f6b8ed8abad05bbf25 [file] [log] [blame]
/*
* Copyright (C) 2019 The Android Open Source Project
*
* 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 <endian.h>
#include <android-base/unique_fd.h>
#include <base/files/file_util.h>
#include <base/rand_util.h>
#include <base/strings/string_util.h>
#include <libavb/libavb.h>
#include "avb_util.h"
#include "fs_avb_test_util.h"
// Target classes or functions to test:
using android::fs_mgr::AvbPartitionToDevicePatition;
using android::fs_mgr::DeriveAvbPartitionName;
using android::fs_mgr::FstabEntry;
using android::fs_mgr::GetAvbFooter;
using android::fs_mgr::GetAvbPropertyDescriptor;
using android::fs_mgr::GetChainPartitionInfo;
using android::fs_mgr::GetTotalSize;
using android::fs_mgr::LoadAndVerifyVbmetaByPartition;
using android::fs_mgr::LoadAndVerifyVbmetaByPath;
using android::fs_mgr::ValidatePublicKeyBlob;
using android::fs_mgr::VBMetaData;
using android::fs_mgr::VBMetaVerifyResult;
using android::fs_mgr::VerifyVBMetaData;
using android::fs_mgr::VerifyVBMetaSignature;
namespace fs_avb_host_test {
class AvbUtilTest : public BaseFsAvbTest {
public:
AvbUtilTest(){};
protected:
~AvbUtilTest(){};
// Helper function for VerifyVBMetaSignature test. Modifies vbmeta.data()
// in a number of places at |offset| of size |length| and checks that
// VerifyVBMetaSignature() returns |expected_result|.
bool TestVBMetaModification(VBMetaVerifyResult expected_result, const VBMetaData& vbmeta,
size_t offset, size_t length);
// Modifies a random bit for a file, in the range of [offset, offset + length - 1].
void ModifyFile(const base::FilePath& file_path, size_t offset, ssize_t length);
// Loads the content of avb_image_path and comparies it with the content of vbmeta.
bool CompareVBMeta(const base::FilePath& avb_image_path, const VBMetaData& expected_vbmeta);
// Sets the flas in vbmeta header, the image_path could be a vbmeta.img or a system.img.
void SetVBMetaFlags(const base::FilePath& image_path, uint32_t flags);
};
void AvbUtilTest::SetVBMetaFlags(const base::FilePath& image_path, uint32_t flags) {
if (!base::PathExists(image_path)) return;
std::string image_file_name = image_path.RemoveExtension().BaseName().value();
bool is_vbmeta_partition =
base::StartsWith(image_file_name, "vbmeta", base::CompareCase::INSENSITIVE_ASCII);
android::base::unique_fd fd(open(image_path.value().c_str(), O_RDWR | O_CLOEXEC));
EXPECT_TRUE(fd > 0);
uint64_t vbmeta_offset = 0; // for vbmeta.img
if (!is_vbmeta_partition) {
std::unique_ptr<AvbFooter> footer = GetAvbFooter(fd);
EXPECT_NE(nullptr, footer);
vbmeta_offset = footer->vbmeta_offset;
}
auto flags_offset = vbmeta_offset + offsetof(AvbVBMetaImageHeader, flags);
uint32_t flags_data = htobe32(flags);
EXPECT_EQ(flags_offset, lseek64(fd, flags_offset, SEEK_SET));
EXPECT_EQ(sizeof flags_data, write(fd, &flags_data, sizeof flags_data));
}
TEST_F(AvbUtilTest, AvbPartitionToDevicePatition) {
EXPECT_EQ("system", AvbPartitionToDevicePatition("system", "", ""));
EXPECT_EQ("system", AvbPartitionToDevicePatition("system", "", "_b"));
EXPECT_EQ("system_a", AvbPartitionToDevicePatition("system", "_a", ""));
EXPECT_EQ("system_a", AvbPartitionToDevicePatition("system", "_a", "_b"));
EXPECT_EQ("system_b", AvbPartitionToDevicePatition("system_other", "", "_b"));
EXPECT_EQ("system_b", AvbPartitionToDevicePatition("system_other", "_a", "_b"));
}
TEST_F(AvbUtilTest, DeriveAvbPartitionName) {
// The fstab_entry to test.
FstabEntry fstab_entry = {
.blk_device = "/dev/block/dm-1", // a dm-linear device (logical)
.mount_point = "/system",
.fs_type = "ext4",
.logical_partition_name = "system",
};
// Logical partitions.
// non-A/B
fstab_entry.fs_mgr_flags.logical = true;
EXPECT_EQ("system", DeriveAvbPartitionName(fstab_entry, "_dont_care", "_dont_care"));
EXPECT_EQ("system", DeriveAvbPartitionName(fstab_entry, "_a", "_b"));
EXPECT_EQ("system", DeriveAvbPartitionName(fstab_entry, "", ""));
// Active slot.
fstab_entry.fs_mgr_flags.slot_select = true;
fstab_entry.logical_partition_name = "system_a";
EXPECT_EQ("system", DeriveAvbPartitionName(fstab_entry, "_a", "_dont_care"));
EXPECT_EQ("system", DeriveAvbPartitionName(fstab_entry, "_a", "_b"));
EXPECT_EQ("system", DeriveAvbPartitionName(fstab_entry, "_a", ""));
EXPECT_EQ("system_a", DeriveAvbPartitionName(fstab_entry, "_wont_erase_a", "_dont_care"));
// The other slot.
fstab_entry.fs_mgr_flags.slot_select = false;
fstab_entry.fs_mgr_flags.slot_select_other = true;
fstab_entry.logical_partition_name = "system_b";
EXPECT_EQ("system_other", DeriveAvbPartitionName(fstab_entry, "_dont_care", "_b"));
EXPECT_EQ("system_other", DeriveAvbPartitionName(fstab_entry, "_a", "_b"));
EXPECT_EQ("system_other", DeriveAvbPartitionName(fstab_entry, "", "_b"));
EXPECT_EQ("system_b_other", DeriveAvbPartitionName(fstab_entry, "_dont_care", "_wont_erase_b"));
// Non-logical partitions.
// non-A/B.
fstab_entry.fs_mgr_flags.logical = false;
fstab_entry.fs_mgr_flags.slot_select = false;
fstab_entry.fs_mgr_flags.slot_select_other = false;
fstab_entry.blk_device = "/dev/block/by-name/system";
EXPECT_EQ("system", DeriveAvbPartitionName(fstab_entry, "_dont_care", "_dont_care"));
EXPECT_EQ("system", DeriveAvbPartitionName(fstab_entry, "_a", "_b"));
EXPECT_EQ("system", DeriveAvbPartitionName(fstab_entry, "", ""));
// Active slot _a.
fstab_entry.fs_mgr_flags.slot_select = true;
fstab_entry.blk_device = "/dev/block/by-name/system_a";
EXPECT_EQ("system", DeriveAvbPartitionName(fstab_entry, "_a", "_dont_care"));
EXPECT_EQ("system", DeriveAvbPartitionName(fstab_entry, "_a", "_b"));
EXPECT_EQ("system", DeriveAvbPartitionName(fstab_entry, "_a", ""));
EXPECT_EQ("system_a", DeriveAvbPartitionName(fstab_entry, "_wont_erase_a", "_dont_care"));
// Inactive slot _b.
fstab_entry.fs_mgr_flags.slot_select = false;
fstab_entry.fs_mgr_flags.slot_select_other = true;
fstab_entry.blk_device = "/dev/block/by-name/system_b";
EXPECT_EQ("system_other", DeriveAvbPartitionName(fstab_entry, "dont_care", "_b"));
EXPECT_EQ("system_other", DeriveAvbPartitionName(fstab_entry, "_a", "_b"));
EXPECT_EQ("system_other", DeriveAvbPartitionName(fstab_entry, "", "_b"));
EXPECT_EQ("system_b_other", DeriveAvbPartitionName(fstab_entry, "dont_care", "_wont_erase_b"));
}
TEST_F(AvbUtilTest, GetFdTotalSize) {
// Generates a raw test.img via BaseFsAvbTest.
const size_t image_size = 5 * 1024 * 1024;
base::FilePath image_path = GenerateImage("test.img", image_size);
// Checks file size is as expected via base::GetFileSize().
int64_t file_size;
ASSERT_TRUE(base::GetFileSize(image_path, &file_size));
EXPECT_EQ(image_size, file_size);
// Checks file size is expected via libfs_avb internal utils.
auto fd = OpenUniqueReadFd(image_path);
EXPECT_EQ(image_size, GetTotalSize(fd));
}
TEST_F(AvbUtilTest, GetFdTotalSizeWithOffset) {
// Generates a raw test.img via BaseFsAvbTest.
const size_t image_size = 10 * 1024 * 1024;
base::FilePath image_path = GenerateImage("test.img", image_size);
// Checks file size is expected even with a non-zero offset at the beginning.
auto fd = OpenUniqueReadFd(image_path);
off_t initial_offset = 2019;
EXPECT_EQ(initial_offset, lseek(fd, initial_offset, SEEK_SET));
EXPECT_EQ(image_size, GetTotalSize(fd)); // checks that total size is still returned.
EXPECT_EQ(initial_offset, lseek(fd, 0, SEEK_CUR)); // checks original offset is restored.
}
TEST_F(AvbUtilTest, GetAvbFooter) {
// Generates a raw system.img
const size_t image_size = 10 * 1024 * 1024;
const size_t partition_size = 15 * 1024 * 1024;
base::FilePath system_path = GenerateImage("system.img", image_size);
EXPECT_NE(0U, system_path.value().size());
// Checks image size is as expected.
int64_t file_size;
ASSERT_TRUE(base::GetFileSize(system_path, &file_size));
EXPECT_EQ(image_size, file_size);
// Appends AVB Hashtree Footer.
AddAvbFooter(system_path, "hashtree", "system", partition_size, "SHA512_RSA8192", 20,
data_dir_.Append("testkey_rsa8192.pem"), "d00df00d",
"--internal_release_string \"unit test\"");
// Checks partition size is as expected, after adding footer.
ASSERT_TRUE(base::GetFileSize(system_path, &file_size));
EXPECT_EQ(partition_size, file_size);
// Checks avb footer and avb vbmeta.
EXPECT_EQ(
"Footer version: 1.0\n"
"Image size: 15728640 bytes\n"
"Original image size: 10485760 bytes\n"
"VBMeta offset: 10661888\n"
"VBMeta size: 3648 bytes\n"
"--\n"
"Minimum libavb version: 1.0\n"
"Header Block: 256 bytes\n"
"Authentication Block: 1088 bytes\n"
"Auxiliary Block: 2304 bytes\n"
"Algorithm: SHA512_RSA8192\n"
"Rollback Index: 20\n"
"Flags: 0\n"
"Release String: 'unit test'\n"
"Descriptors:\n"
" Hashtree descriptor:\n"
" Version of dm-verity: 1\n"
" Image Size: 10485760 bytes\n"
" Tree Offset: 10485760\n"
" Tree Size: 86016 bytes\n"
" Data Block Size: 4096 bytes\n"
" Hash Block Size: 4096 bytes\n"
" FEC num roots: 2\n"
" FEC offset: 10571776\n"
" FEC size: 90112 bytes\n"
" Hash Algorithm: sha1\n"
" Partition Name: system\n"
" Salt: d00df00d\n"
" Root Digest: a3d5dd307341393d85de356c384ff543ec1ed81b\n"
" Flags: 0\n",
InfoImage(system_path));
// Checks each field from GetAvbFooter(fd).
auto fd = OpenUniqueReadFd(system_path);
auto footer = GetAvbFooter(fd);
EXPECT_NE(nullptr, footer);
EXPECT_EQ(10485760, footer->original_image_size);
EXPECT_EQ(10661888, footer->vbmeta_offset);
EXPECT_EQ(3648, footer->vbmeta_size);
}
TEST_F(AvbUtilTest, GetAvbFooterErrorVerification) {
// Generates a raw system.img
const size_t image_size = 5 * 1024 * 1024;
base::FilePath system_path = GenerateImage("system.img", image_size);
// Checks each field from GetAvbFooter(fd).
auto fd = OpenUniqueReadFd(system_path);
auto footer = GetAvbFooter(fd);
EXPECT_EQ(nullptr, footer);
}
TEST_F(AvbUtilTest, GetAvbFooterInsufficientSize) {
// Generates a raw system.img
const size_t image_size = AVB_FOOTER_SIZE - 10;
base::FilePath system_path = GenerateImage("system.img", image_size);
// Checks each field from GetAvbFooter(fd).
auto fd = OpenUniqueReadFd(system_path);
auto footer = GetAvbFooter(fd);
EXPECT_EQ(nullptr, footer);
}
TEST_F(AvbUtilTest, GetAvbPropertyDescriptor_Basic) {
// Makes a vbmeta.img with some properties.
GenerateVBMetaImage("vbmeta.img", "SHA256_RSA4096", 0, data_dir_.Append("testkey_rsa4096.pem"),
{}, /* include_descriptor_image_paths */
{}, /* chain_partitions */
"--prop foo:android "
"--prop bar:treble "
"--internal_release_string \"unit test\" ");
auto vbmeta = LoadVBMetaData("vbmeta.img");
// Puts the vbmeta into a vector, for GetAvbPropertyDescriptor to use.
std::vector<VBMetaData> vbmeta_images;
vbmeta_images.emplace_back(std::move(vbmeta));
EXPECT_EQ("android", GetAvbPropertyDescriptor("foo", vbmeta_images));
EXPECT_EQ("treble", GetAvbPropertyDescriptor("bar", vbmeta_images));
EXPECT_EQ("", GetAvbPropertyDescriptor("non-existent", vbmeta_images));
}
TEST_F(AvbUtilTest, GetAvbPropertyDescriptor_SecurityPatchLevel) {
// Generates a raw boot.img
const size_t boot_image_size = 5 * 1024 * 1024;
const size_t boot_partition_size = 10 * 1024 * 1024;
base::FilePath boot_path = GenerateImage("boot.img", boot_image_size);
// Adds AVB Hash Footer.
AddAvbFooter(boot_path, "hash", "boot", boot_partition_size, "SHA256_RSA2048", 10,
data_dir_.Append("testkey_rsa2048.pem"), "d00df00d",
"--internal_release_string \"unit test\"");
// Generates a raw system.img, use a smaller size to speed-up unit test.
const size_t system_image_size = 10 * 1024 * 1024;
const size_t system_partition_size = 15 * 1024 * 1024;
base::FilePath system_path = GenerateImage("system.img", system_image_size);
// Adds AVB Hashtree Footer.
AddAvbFooter(system_path, "hashtree", "system", system_partition_size, "SHA512_RSA4096", 20,
data_dir_.Append("testkey_rsa4096.pem"), "d00df00d",
"--prop com.android.build.system.security_patch:2019-04-05 "
"--internal_release_string \"unit test\"");
// Generates chain partition descriptors.
base::FilePath rsa4096_public_key =
ExtractPublicKeyAvb(data_dir_.Append("testkey_rsa4096.pem"));
// Makes a vbmeta.img including the 'system' chained descriptor.
GenerateVBMetaImage("vbmeta.img", "SHA256_RSA4096", 0, data_dir_.Append("testkey_rsa4096.pem"),
{boot_path}, /* include_descriptor_image_paths */
{{"system", 3, rsa4096_public_key}}, /* chain_partitions */
"--internal_release_string \"unit test\"");
auto vbmeta = LoadVBMetaData("vbmeta.img");
auto system_vbmeta = ExtractAndLoadVBMetaData(system_path, "system-vbmeta.img");
// Puts the vbmeta into a vector, for GetAvbPropertyDescriptor to use.
std::vector<VBMetaData> vbmeta_images;
vbmeta_images.emplace_back(std::move(vbmeta));
vbmeta_images.emplace_back(std::move(system_vbmeta));
EXPECT_EQ("2019-04-05",
GetAvbPropertyDescriptor("com.android.build.system.security_patch", vbmeta_images));
}
TEST_F(AvbUtilTest, GetVBMetaHeader) {
// Generates a raw boot.img
const size_t image_size = 5 * 1024 * 1024;
const size_t partition_size = 10 * 1024 * 1024;
base::FilePath boot_path = GenerateImage("boot.img", image_size);
// Appends AVB Hash Footer.
AddAvbFooter(boot_path, "hash", "boot", partition_size, "SHA256_RSA4096", 10,
data_dir_.Append("testkey_rsa4096.pem"), "d00df00d",
"--internal_release_string \"unit test\"");
// Extracts boot vbmeta from boot.img into boot-vbmeta.img.
base::FilePath boot_vbmeta = ExtractVBMetaImage(boot_path, "boot-vbmeta.img");
EXPECT_EQ(
"Minimum libavb version: 1.0\n"
"Header Block: 256 bytes\n"
"Authentication Block: 576 bytes\n"
"Auxiliary Block: 1216 bytes\n"
"Algorithm: SHA256_RSA4096\n"
"Rollback Index: 10\n"
"Flags: 0\n"
"Release String: 'unit test'\n"
"Descriptors:\n"
" Hash descriptor:\n"
" Image Size: 5242880 bytes\n"
" Hash Algorithm: sha256\n"
" Partition Name: boot\n"
" Salt: d00df00d\n"
" Digest: "
"222dd01e98284a1fcd7781f85d1392e43a530511a64eff96db197db90ebc4df1\n"
" Flags: 0\n",
InfoImage("boot-vbmeta.img"));
// Creates a VBMetaData with the content from boot-vbmeta.img.
std::string content;
EXPECT_TRUE(base::ReadFileToString(boot_vbmeta, &content));
VBMetaData vbmeta((uint8_t*)content.data(), content.size(), "boot-vbmeta");
EXPECT_EQ(content.size(), vbmeta.size());
// Checks each field returned from GetVBMetaHeader().
auto vbmeta_header = vbmeta.GetVBMetaHeader(false /* update_vbmeta_size */);
EXPECT_NE(nullptr, vbmeta_header);
EXPECT_EQ(576, vbmeta_header->authentication_data_block_size);
EXPECT_EQ(1216, vbmeta_header->auxiliary_data_block_size);
EXPECT_EQ(AVB_ALGORITHM_TYPE_SHA256_RSA4096, vbmeta_header->algorithm_type);
EXPECT_EQ(0, vbmeta_header->hash_offset);
EXPECT_EQ(32, vbmeta_header->hash_size);
EXPECT_EQ(32, vbmeta_header->signature_offset);
EXPECT_EQ(512, vbmeta_header->signature_size);
EXPECT_EQ(176, vbmeta_header->public_key_offset);
EXPECT_EQ(1032, vbmeta_header->public_key_size);
EXPECT_EQ(0, vbmeta_header->descriptors_offset);
EXPECT_EQ(176, vbmeta_header->descriptors_size);
EXPECT_EQ(10, vbmeta_header->rollback_index);
EXPECT_EQ(0, vbmeta_header->flags);
EXPECT_EQ("unit test", std::string((const char*)vbmeta_header->release_string));
// Appends some garbage to the end of the vbmeta buffer, checks it still can work.
std::string padding(2020, 'A'); // Generate a padding with length 2020.
std::string content_padding = content + padding;
VBMetaData vbmeta_padding((const uint8_t*)content_padding.data(), content_padding.size(),
"boot");
EXPECT_EQ(content_padding.size(), vbmeta_padding.size());
// Checks each field still can be parsed properly, even with garbage padding.
vbmeta_header = vbmeta_padding.GetVBMetaHeader(false /* update_vbmeta_size */);
EXPECT_NE(nullptr, vbmeta_header);
EXPECT_EQ(576, vbmeta_header->authentication_data_block_size);
EXPECT_EQ(1216, vbmeta_header->auxiliary_data_block_size);
EXPECT_EQ(AVB_ALGORITHM_TYPE_SHA256_RSA4096, vbmeta_header->algorithm_type);
EXPECT_EQ(0, vbmeta_header->hash_offset);
EXPECT_EQ(32, vbmeta_header->hash_size);
EXPECT_EQ(32, vbmeta_header->signature_offset);
EXPECT_EQ(512, vbmeta_header->signature_size);
EXPECT_EQ(176, vbmeta_header->public_key_offset);
EXPECT_EQ(1032, vbmeta_header->public_key_size);
EXPECT_EQ(0, vbmeta_header->descriptors_offset);
EXPECT_EQ(176, vbmeta_header->descriptors_size);
EXPECT_EQ(10, vbmeta_header->rollback_index);
EXPECT_EQ(0, vbmeta_header->flags);
EXPECT_EQ("unit test", std::string((const char*)vbmeta_header->release_string));
// Checks vbmeta size is updated to the actual size without padding.
vbmeta_header = vbmeta_padding.GetVBMetaHeader(true /* update_vbmeta_size */);
EXPECT_EQ(content_padding.size() - padding.size(), vbmeta_padding.size());
}
TEST_F(AvbUtilTest, ValidatePublicKeyBlob) {
// Generates a raw key.bin
const size_t key_size = 2048;
base::FilePath key_path = GenerateImage("key.bin", key_size);
uint8_t key_data[key_size];
EXPECT_EQ(key_size, base::ReadFile(key_path, (char*)key_data, key_size));
std::string expected_key_blob;
EXPECT_TRUE(base::ReadFileToString(key_path, &expected_key_blob));
EXPECT_TRUE(ValidatePublicKeyBlob(key_data, key_size, expected_key_blob));
key_data[10] ^= 0x80; // toggles a bit and expects a failure
EXPECT_FALSE(ValidatePublicKeyBlob(key_data, key_size, expected_key_blob));
key_data[10] ^= 0x80; // toggles the bit again, should pass
EXPECT_TRUE(ValidatePublicKeyBlob(key_data, key_size, expected_key_blob));
}
TEST_F(AvbUtilTest, VerifyEmptyPublicKeyBlob) {
// Generates a raw key.bin
const size_t key_size = 2048;
base::FilePath key_path = GenerateImage("key.bin", key_size);
uint8_t key_data[key_size];
EXPECT_EQ(key_size, base::ReadFile(key_path, (char*)key_data, key_size));
std::string expected_key_blob = ""; // empty means no expectation, thus return true.
EXPECT_TRUE(ValidatePublicKeyBlob(key_data, key_size, expected_key_blob));
}
TEST_F(AvbUtilTest, ValidatePublicKeyBlob_MultipleAllowedKeys) {
base::FilePath rsa2048_public_key =
ExtractPublicKeyAvb(data_dir_.Append("testkey_rsa2048.pem"));
base::FilePath rsa4096_public_key =
ExtractPublicKeyAvb(data_dir_.Append("testkey_rsa4096.pem"));
base::FilePath rsa8192_public_key =
ExtractPublicKeyAvb(data_dir_.Append("testkey_rsa8192.pem"));
std::vector<std::string> allowed_key_paths;
allowed_key_paths.push_back(rsa2048_public_key.value());
allowed_key_paths.push_back(rsa4096_public_key.value());
std::string expected_key_blob_2048;
EXPECT_TRUE(base::ReadFileToString(rsa2048_public_key, &expected_key_blob_2048));
std::string expected_key_blob_4096;
EXPECT_TRUE(base::ReadFileToString(rsa4096_public_key, &expected_key_blob_4096));
std::string expected_key_blob_8192;
EXPECT_TRUE(base::ReadFileToString(rsa8192_public_key, &expected_key_blob_8192));
EXPECT_TRUE(ValidatePublicKeyBlob(expected_key_blob_2048, allowed_key_paths));
EXPECT_TRUE(ValidatePublicKeyBlob(expected_key_blob_4096, allowed_key_paths));
EXPECT_FALSE(ValidatePublicKeyBlob(expected_key_blob_8192, allowed_key_paths));
EXPECT_FALSE(ValidatePublicKeyBlob("invalid_content", allowed_key_paths));
EXPECT_FALSE(ValidatePublicKeyBlob("", allowed_key_paths));
allowed_key_paths.push_back(rsa8192_public_key.value());
EXPECT_TRUE(ValidatePublicKeyBlob(expected_key_blob_8192, allowed_key_paths));
}
TEST_F(AvbUtilTest, VerifyVBMetaSignature) {
const size_t image_size = 10 * 1024 * 1024;
const size_t partition_size = 15 * 1024 * 1024;
auto signing_key = data_dir_.Append("testkey_rsa4096.pem");
auto vbmeta = GenerateImageAndExtractVBMetaData("system", image_size, partition_size,
"hashtree", signing_key, "SHA256_RSA4096",
10 /* rollback_index */);
auto expected_public_key_blob = ExtractPublicKeyAvbBlob(signing_key);
EXPECT_EQ(VBMetaVerifyResult::kSuccess,
VerifyVBMetaSignature(vbmeta, expected_public_key_blob,
nullptr /* out_public_key_data */));
// Converts the expected key into an 'unexpected' key.
expected_public_key_blob[10] ^= 0x80;
EXPECT_EQ(VBMetaVerifyResult::kErrorVerification,
VerifyVBMetaSignature(vbmeta, expected_public_key_blob,
nullptr /* out_public_key_data */));
}
TEST_F(AvbUtilTest, VerifyVBMetaSignatureOutputPublicKeyData) {
const size_t image_size = 10 * 1024 * 1024;
const size_t partition_size = 15 * 1024 * 1024;
auto signing_key = data_dir_.Append("testkey_rsa4096.pem");
auto vbmeta = GenerateImageAndExtractVBMetaData("system", image_size, partition_size,
"hashtree", signing_key, "SHA256_RSA4096",
10 /* rollback_index */);
std::string out_public_key_data;
auto expected_public_key_blob = ExtractPublicKeyAvbBlob(signing_key);
EXPECT_EQ(VBMetaVerifyResult::kSuccess,
VerifyVBMetaSignature(vbmeta, expected_public_key_blob, &out_public_key_data));
EXPECT_EQ(out_public_key_data, expected_public_key_blob);
// Converts the expected key into an 'unexpected' key.
expected_public_key_blob[10] ^= 0x80;
EXPECT_EQ(VBMetaVerifyResult::kErrorVerification,
VerifyVBMetaSignature(vbmeta, expected_public_key_blob, &out_public_key_data));
EXPECT_NE(out_public_key_data, expected_public_key_blob);
}
bool AvbUtilTest::TestVBMetaModification(VBMetaVerifyResult expected_result,
const VBMetaData& vbmeta, size_t offset, size_t length) {
uint8_t* d = reinterpret_cast<uint8_t*>(vbmeta.data());
const int kNumCheckIntervals = 8;
// Tests |kNumCheckIntervals| modifications in the start, middle, and
// end of the given sub-array at offset with size.
for (int n = 0; n <= kNumCheckIntervals; n++) {
size_t o = std::min(length * n / kNumCheckIntervals, length - 1) + offset;
d[o] ^= 0x80;
VBMetaVerifyResult result = VerifyVBMetaSignature(vbmeta, "" /* expected_public_key_blob */,
nullptr /* out_public_key_data */);
d[o] ^= 0x80;
if (result != expected_result) {
return false;
}
}
return true;
}
TEST_F(AvbUtilTest, VerifyVBMetaSignatureWithModification) {
const size_t image_size = 10 * 1024 * 1024;
const size_t partition_size = 15 * 1024 * 1024;
auto signing_key = data_dir_.Append("testkey_rsa4096.pem");
auto vbmeta = GenerateImageAndExtractVBMetaData("system", image_size, partition_size,
"hashtree", signing_key, "SHA256_RSA4096",
10 /* rollback_index */);
auto header = vbmeta.GetVBMetaHeader(true /* update_vbmeta_size */);
size_t header_block_offset = 0;
size_t authentication_block_offset = header_block_offset + sizeof(AvbVBMetaImageHeader);
size_t auxiliary_block_offset =
authentication_block_offset + header->authentication_data_block_size;
// Should detect modifications in the auxiliary data block.
EXPECT_TRUE(TestVBMetaModification(VBMetaVerifyResult::kErrorVerification, vbmeta,
auxiliary_block_offset, header->auxiliary_data_block_size));
// Sholud detect modifications in the hash part of authentication data block.
EXPECT_TRUE(TestVBMetaModification(VBMetaVerifyResult::kErrorVerification, vbmeta,
authentication_block_offset + header->hash_offset,
header->hash_size));
// Sholud detect modifications in the signature part of authentication data block.
EXPECT_TRUE(TestVBMetaModification(VBMetaVerifyResult::kErrorVerification, vbmeta,
authentication_block_offset + header->signature_offset,
header->signature_size));
}
TEST_F(AvbUtilTest, VerifyVBMetaSignatureNotSigned) {
const size_t image_size = 10 * 1024 * 1024;
const size_t partition_size = 15 * 1024 * 1024;
auto vbmeta = GenerateImageAndExtractVBMetaData(
"system", image_size, partition_size, "hashtree", {} /* avb_signing_key */,
"" /* avb_algorithm */, 10 /* rollback_index */);
EXPECT_EQ(VBMetaVerifyResult::kErrorVerification,
VerifyVBMetaSignature(vbmeta, "" /* expected_public_key_blob */,
nullptr /* out_public_key_data */));
}
TEST_F(AvbUtilTest, VerifyVBMetaSignatureInvalidVBMeta) {
const size_t buffer_size = 5 * 1024 * 1024;
std::vector<uint8_t> vbmeta_buffer(buffer_size);
for (size_t n = 0; n < buffer_size; n++) {
vbmeta_buffer[n] = uint8_t(n);
}
VBMetaData invalid_vbmeta((const uint8_t*)vbmeta_buffer.data(), vbmeta_buffer.size(),
"invalid_vbmeta");
EXPECT_EQ(VBMetaVerifyResult::kError,
VerifyVBMetaSignature(invalid_vbmeta, "" /* expected_public_key_blob */,
nullptr /* out_public_Key_data */));
}
bool AvbUtilTest::CompareVBMeta(const base::FilePath& avb_image_path,
const VBMetaData& expected_vbmeta) {
if (!base::PathExists(avb_image_path)) return false;
std::string image_file_name = avb_image_path.RemoveExtension().BaseName().value();
base::FilePath extracted_vbmeta_path;
if (base::StartsWith(image_file_name, "vbmeta", base::CompareCase::INSENSITIVE_ASCII)) {
extracted_vbmeta_path = avb_image_path; // no need to extract if it's a vbmeta image.
} else {
extracted_vbmeta_path = ExtractVBMetaImage(avb_image_path, image_file_name + "-vbmeta.img");
}
// Gets file size of the vbmeta image.
int64_t extracted_vbmeta_size;
EXPECT_TRUE(base::GetFileSize(extracted_vbmeta_path, &extracted_vbmeta_size));
// Reads the vbmeta into a vector.
std::vector<uint8_t> extracted_vbmeta_content(extracted_vbmeta_size);
EXPECT_TRUE(base::ReadFile(extracted_vbmeta_path,
reinterpret_cast<char*>(extracted_vbmeta_content.data()),
extracted_vbmeta_size));
// Compares extracted_vbmeta_content with the expected_vbmeta.
EXPECT_EQ(expected_vbmeta.size(), extracted_vbmeta_size);
return memcmp(reinterpret_cast<void*>(extracted_vbmeta_content.data()),
reinterpret_cast<void*>(expected_vbmeta.data()), extracted_vbmeta_size) == 0;
}
TEST_F(AvbUtilTest, VerifyVBMetaDataWithoutFooter) {
// Generates chain partition descriptors.
base::FilePath rsa2048_public_key =
ExtractPublicKeyAvb(data_dir_.Append("testkey_rsa2048.pem"));
base::FilePath rsa4096_public_key =
ExtractPublicKeyAvb(data_dir_.Append("testkey_rsa4096.pem"));
// Makes a vbmeta image includeing 'boot' and 'system' chained descriptors.
auto vbmeta_path = GenerateVBMetaImage("vbmeta.img", "SHA256_RSA8192", 0,
data_dir_.Append("testkey_rsa8192.pem"),
{}, /* include_descriptor_image_paths */
{{"boot", 1, rsa2048_public_key}, /* chain_partitions */
{"system", 2, rsa4096_public_key}},
"--internal_release_string \"unit test\"");
EXPECT_EQ(
"Minimum libavb version: 1.0\n"
"Header Block: 256 bytes\n"
"Authentication Block: 1088 bytes\n"
"Auxiliary Block: 3840 bytes\n"
"Algorithm: SHA256_RSA8192\n"
"Rollback Index: 0\n"
"Flags: 0\n"
"Release String: 'unit test'\n"
"Descriptors:\n"
" Chain Partition descriptor:\n"
" Partition Name: boot\n"
" Rollback Index Location: 1\n"
" Public key (sha1): cdbb77177f731920bbe0a0f94f84d9038ae0617d\n"
" Chain Partition descriptor:\n"
" Partition Name: system\n"
" Rollback Index Location: 2\n"
" Public key (sha1): 2597c218aae470a130f61162feaae70afd97f011\n",
InfoImage("vbmeta.img"));
android::base::unique_fd fd(open(vbmeta_path.value().c_str(), O_RDONLY | O_CLOEXEC));
ASSERT_TRUE(fd > 0);
VBMetaVerifyResult verify_result;
std::string out_public_key_data;
std::unique_ptr<VBMetaData> vbmeta = VerifyVBMetaData(
fd, "vbmeta", "" /*expected_public_key_blob */, &out_public_key_data, &verify_result);
EXPECT_TRUE(vbmeta != nullptr);
EXPECT_EQ(VBMetaVerifyResult::kSuccess, verify_result);
auto rsa8192_public_key_blob = ExtractPublicKeyAvbBlob(data_dir_.Append("testkey_rsa8192.pem"));
EXPECT_EQ(rsa8192_public_key_blob, out_public_key_data);
// Checkes the returned vbmeta content is the same as that extracted via avbtool.
vbmeta->GetVBMetaHeader(true /* update_vbmeta_size */);
EXPECT_TRUE(CompareVBMeta(vbmeta_path, *vbmeta));
}
TEST_F(AvbUtilTest, VerifyVBMetaDataWithFooter) {
const size_t image_size = 10 * 1024 * 1024;
const size_t partition_size = 15 * 1024 * 1024;
base::FilePath system_path = GenerateImage("system.img", image_size);
// Appends AVB Hashtree Footer.
AddAvbFooter(system_path, "hashtree", "system", partition_size, "SHA512_RSA8192", 20,
data_dir_.Append("testkey_rsa8192.pem"), "d00df00d",
"--internal_release_string \"unit test\"");
android::base::unique_fd fd(open(system_path.value().c_str(), O_RDONLY | O_CLOEXEC));
ASSERT_TRUE(fd > 0);
VBMetaVerifyResult verify_result;
std::string out_public_key_data;
std::unique_ptr<VBMetaData> vbmeta = VerifyVBMetaData(
fd, "system", "" /*expected_public_key_blob */, &out_public_key_data, &verify_result);
EXPECT_TRUE(vbmeta != nullptr);
EXPECT_EQ(VBMetaVerifyResult::kSuccess, verify_result);
auto rsa8192_public_key_blob = ExtractPublicKeyAvbBlob(data_dir_.Append("testkey_rsa8192.pem"));
EXPECT_EQ(rsa8192_public_key_blob, out_public_key_data);
// Checkes the returned vbmeta content is the same as that extracted via avbtool.
EXPECT_TRUE(CompareVBMeta(system_path, *vbmeta));
}
// Modifies a random bit for a file, in the range of [offset, offset + length - 1].
// Length < 0 means only resets previous modification without introducing new modification.
void AvbUtilTest::ModifyFile(const base::FilePath& file_path, size_t offset, ssize_t length) {
static int last_modified_location = -1;
static std::string last_file_path;
int64_t file_size;
ASSERT_TRUE(base::GetFileSize(file_path, &file_size));
std::vector<uint8_t> file_content(file_size);
ASSERT_TRUE(base::ReadFile(file_path, reinterpret_cast<char*>(file_content.data()), file_size));
// Resets previous modification for consecutive calls on the same file.
if (last_file_path == file_path.value()) {
file_content[last_modified_location] ^= 0x80;
}
// Introduces a new modification.
if (length > 0) {
int modify_location = base::RandInt(offset, offset + length - 1);
file_content[modify_location] ^= 0x80;
last_file_path = file_path.value();
last_modified_location = modify_location;
}
ASSERT_EQ(file_size, static_cast<const size_t>(base::WriteFile(
file_path, reinterpret_cast<const char*>(file_content.data()),
file_content.size())));
}
TEST_F(AvbUtilTest, VerifyVBMetaDataError) {
const size_t image_size = 10 * 1024 * 1024;
const size_t partition_size = 15 * 1024 * 1024;
base::FilePath system_path = GenerateImage("system.img", image_size);
// Appends AVB Hashtree Footer.
AddAvbFooter(system_path, "hashtree", "system", partition_size, "SHA512_RSA8192", 20,
data_dir_.Append("testkey_rsa8192.pem"), "d00df00d",
"--internal_release_string \"unit test\"");
android::base::unique_fd fd(open(system_path.value().c_str(), O_RDONLY | O_CLOEXEC));
ASSERT_TRUE(fd > 0);
std::unique_ptr<AvbFooter> footer = GetAvbFooter(fd);
EXPECT_TRUE(footer != nullptr);
VBMetaVerifyResult verify_result;
std::string out_public_key_data;
std::unique_ptr<VBMetaData> vbmeta = VerifyVBMetaData(
fd, "system", "" /*expected_public_key_blob */, &out_public_key_data, &verify_result);
EXPECT_NE(nullptr, vbmeta);
EXPECT_EQ(VBMetaVerifyResult::kSuccess, verify_result);
auto rsa8192_public_key_blob = ExtractPublicKeyAvbBlob(data_dir_.Append("testkey_rsa8192.pem"));
EXPECT_EQ(rsa8192_public_key_blob, out_public_key_data);
// Modifies hash and signature, checks there is verification error.
auto header = vbmeta->GetVBMetaHeader(true /* update_vbmeta_size */);
size_t header_block_offset = 0;
size_t authentication_block_offset = header_block_offset + sizeof(AvbVBMetaImageHeader);
// Modifies the hash.
ModifyFile(system_path,
footer->vbmeta_offset + authentication_block_offset + header->hash_offset,
header->hash_size);
android::base::unique_fd hash_modified_fd(
open(system_path.value().c_str(), O_RDONLY | O_CLOEXEC));
ASSERT_TRUE(hash_modified_fd > 0);
// Should return ErrorVerification.
vbmeta = VerifyVBMetaData(hash_modified_fd, "system", "" /*expected_public_key_blob */,
nullptr /* out_public_key_data */, &verify_result);
EXPECT_NE(nullptr, vbmeta);
EXPECT_TRUE(CompareVBMeta(system_path, *vbmeta));
EXPECT_EQ(VBMetaVerifyResult::kErrorVerification, verify_result);
// Modifies the auxiliary data block.
size_t auxiliary_block_offset =
authentication_block_offset + header->authentication_data_block_size;
ModifyFile(system_path, footer->vbmeta_offset + auxiliary_block_offset,
header->auxiliary_data_block_size);
android::base::unique_fd aux_modified_fd(
open(system_path.value().c_str(), O_RDONLY | O_CLOEXEC));
ASSERT_TRUE(aux_modified_fd > 0);
// Should return ErrorVerification.
vbmeta = VerifyVBMetaData(aux_modified_fd, "system", "" /*expected_public_key_blob */,
nullptr /* out_public_key_data */, &verify_result);
EXPECT_NE(nullptr, vbmeta);
EXPECT_TRUE(CompareVBMeta(system_path, *vbmeta));
EXPECT_EQ(VBMetaVerifyResult::kErrorVerification, verify_result);
// Resets previous modification by setting offset to -1, and checks the verification can pass.
ModifyFile(system_path, 0 /* offset */, -1 /* length */);
android::base::unique_fd ok_fd(open(system_path.value().c_str(), O_RDONLY | O_CLOEXEC));
ASSERT_TRUE(ok_fd > 0);
// Should return ResultOK..
vbmeta = VerifyVBMetaData(ok_fd, "system", "" /*expected_public_key_blob */,
nullptr /* out_public_key_data */, &verify_result);
EXPECT_NE(nullptr, vbmeta);
EXPECT_TRUE(CompareVBMeta(system_path, *vbmeta));
EXPECT_EQ(VBMetaVerifyResult::kSuccess, verify_result);
}
TEST_F(AvbUtilTest, GetChainPartitionInfo) {
// Generates a raw boot.img
const size_t boot_image_size = 5 * 1024 * 1024;
const size_t boot_partition_size = 10 * 1024 * 1024;
base::FilePath boot_path = GenerateImage("boot.img", boot_image_size);
// Adds AVB Hash Footer.
AddAvbFooter(boot_path, "hash", "boot", boot_partition_size, "SHA256_RSA2048", 10,
data_dir_.Append("testkey_rsa2048.pem"), "d00df00d",
"--internal_release_string \"unit test\"");
// Generates a raw system.img, use a smaller size to speed-up unit test.
const size_t system_image_size = 10 * 1024 * 1024;
const size_t system_partition_size = 15 * 1024 * 1024;
base::FilePath system_path = GenerateImage("system.img", system_image_size);
// Adds AVB Hashtree Footer.
AddAvbFooter(system_path, "hashtree", "system", system_partition_size, "SHA512_RSA4096", 20,
data_dir_.Append("testkey_rsa4096.pem"), "d00df00d",
"--internal_release_string \"unit test\"");
// Generates chain partition descriptors.
base::FilePath rsa2048_public_key =
ExtractPublicKeyAvb(data_dir_.Append("testkey_rsa2048.pem"));
base::FilePath rsa4096_public_key =
ExtractPublicKeyAvb(data_dir_.Append("testkey_rsa4096.pem"));
// Makes a vbmeta_system.img including the 'system' chained descriptor.
GenerateVBMetaImage("vbmeta_system.img", "SHA256_RSA4096", 0,
data_dir_.Append("testkey_rsa4096.pem"),
{}, /* include_descriptor_image_paths */
{{"system", 3, rsa4096_public_key}}, /* chain_partitions */
"--internal_release_string \"unit test\"");
// Makes a vbmeta image includeing 'boot' and 'vbmeta_system' chained descriptors.
GenerateVBMetaImage("vbmeta.img", "SHA256_RSA8192", 0, data_dir_.Append("testkey_rsa8192.pem"),
{}, /* include_descriptor_image_paths */
{{"boot", 1, rsa2048_public_key}, /* chain_partitions */
{"vbmeta_system", 2, rsa4096_public_key}},
"--internal_release_string \"unit test\"");
// Calculates the digest of all chained partitions, to ensure the chained is formed properly.
EXPECT_EQ("6f4bf815a651aa35ec7102a88b7906b91aef284bc5e20d0bf527c7d460da3266",
CalcVBMetaDigest("vbmeta.img", "sha256"));
// Loads the key blobs for comparison.
std::string expected_key_blob_2048;
EXPECT_TRUE(base::ReadFileToString(rsa2048_public_key, &expected_key_blob_2048));
std::string expected_key_blob_4096;
EXPECT_TRUE(base::ReadFileToString(rsa4096_public_key, &expected_key_blob_4096));
// Checks chain descriptors in vbmeta.img
EXPECT_EQ(
"Minimum libavb version: 1.0\n"
"Header Block: 256 bytes\n"
"Authentication Block: 1088 bytes\n"
"Auxiliary Block: 3840 bytes\n"
"Algorithm: SHA256_RSA8192\n"
"Rollback Index: 0\n"
"Flags: 0\n"
"Release String: 'unit test'\n"
"Descriptors:\n"
" Chain Partition descriptor:\n"
" Partition Name: boot\n"
" Rollback Index Location: 1\n"
" Public key (sha1): cdbb77177f731920bbe0a0f94f84d9038ae0617d\n"
" Chain Partition descriptor:\n"
" Partition Name: vbmeta_system\n"
" Rollback Index Location: 2\n"
" Public key (sha1): 2597c218aae470a130f61162feaae70afd97f011\n",
InfoImage("vbmeta.img"));
bool fatal_error = false;
auto chained_descriptors = GetChainPartitionInfo(LoadVBMetaData("vbmeta.img"), &fatal_error);
EXPECT_EQ(2, chained_descriptors.size()); // contains 'boot' and 'vbmeta_system'.
EXPECT_EQ(false, fatal_error);
EXPECT_EQ("boot", chained_descriptors[0].partition_name);
EXPECT_EQ(expected_key_blob_2048, chained_descriptors[0].public_key_blob);
EXPECT_EQ("vbmeta_system", chained_descriptors[1].partition_name);
EXPECT_EQ(expected_key_blob_4096, chained_descriptors[1].public_key_blob);
// Checks chain descriptors in vbmeta_system.img
EXPECT_EQ(
"Minimum libavb version: 1.0\n"
"Header Block: 256 bytes\n"
"Authentication Block: 576 bytes\n"
"Auxiliary Block: 2176 bytes\n"
"Algorithm: SHA256_RSA4096\n"
"Rollback Index: 0\n"
"Flags: 0\n"
"Release String: 'unit test'\n"
"Descriptors:\n"
" Chain Partition descriptor:\n"
" Partition Name: system\n"
" Rollback Index Location: 3\n"
" Public key (sha1): 2597c218aae470a130f61162feaae70afd97f011\n",
InfoImage("vbmeta_system.img"));
chained_descriptors = GetChainPartitionInfo(LoadVBMetaData("vbmeta_system.img"), &fatal_error);
EXPECT_EQ(1, chained_descriptors.size()); // contains 'system' only.
EXPECT_EQ(false, fatal_error);
EXPECT_EQ("system", chained_descriptors[0].partition_name);
EXPECT_EQ(expected_key_blob_4096, chained_descriptors[0].public_key_blob);
}
TEST_F(AvbUtilTest, GetChainPartitionInfoNone) {
// Generates a raw boot.img
const size_t boot_image_size = 5 * 1024 * 1024;
const size_t boot_partition_size = 10 * 1024 * 1024;
base::FilePath boot_path = GenerateImage("boot.img", boot_image_size);
// Adds AVB Hash Footer.
AddAvbFooter(boot_path, "hash", "boot", boot_partition_size, "SHA256_RSA4096", 10,
data_dir_.Append("testkey_rsa4096.pem"), "d00df00d",
"--internal_release_string \"unit test\"");
// Generates a raw system.img, use a smaller size to speed-up unit test.
const size_t system_image_size = 10 * 1024 * 1024;
const size_t system_partition_size = 15 * 1024 * 1024;
base::FilePath system_path = GenerateImage("system.img", system_image_size);
// Adds AVB Hashtree Footer.
AddAvbFooter(system_path, "hashtree", "system", system_partition_size, "SHA512_RSA8192", 20,
data_dir_.Append("testkey_rsa8192.pem"), "d00df00d",
"--internal_release_string \"unit test\"");
// Makes a vbmeta.img including both 'boot' and 'system' descriptors.
GenerateVBMetaImage("vbmeta.img", "SHA256_RSA2048", 0, data_dir_.Append("testkey_rsa2048.pem"),
{boot_path, system_path}, /* include_descriptor_image_paths */
{}, /* chain_partitions */
"--internal_release_string \"unit test\"");
EXPECT_EQ("a069cbfc30c816cddf3b53f1ad53b7ca5d61a3d93845eb596bbb1b40caa1c62f",
CalcVBMetaDigest("vbmeta.img", "sha256"));
EXPECT_EQ(
"Minimum libavb version: 1.0\n"
"Header Block: 256 bytes\n"
"Authentication Block: 320 bytes\n"
"Auxiliary Block: 960 bytes\n"
"Algorithm: SHA256_RSA2048\n"
"Rollback Index: 0\n"
"Flags: 0\n"
"Release String: 'unit test'\n"
"Descriptors:\n"
" Hash descriptor:\n"
" Image Size: 5242880 bytes\n"
" Hash Algorithm: sha256\n"
" Partition Name: boot\n"
" Salt: d00df00d\n"
" Digest: "
"222dd01e98284a1fcd7781f85d1392e43a530511a64eff96db197db90ebc4df1\n"
" Flags: 0\n"
" Hashtree descriptor:\n"
" Version of dm-verity: 1\n"
" Image Size: 10485760 bytes\n"
" Tree Offset: 10485760\n"
" Tree Size: 86016 bytes\n"
" Data Block Size: 4096 bytes\n"
" Hash Block Size: 4096 bytes\n"
" FEC num roots: 2\n"
" FEC offset: 10571776\n"
" FEC size: 90112 bytes\n"
" Hash Algorithm: sha1\n"
" Partition Name: system\n"
" Salt: d00df00d\n"
" Root Digest: a3d5dd307341393d85de356c384ff543ec1ed81b\n"
" Flags: 0\n",
InfoImage("vbmeta.img"));
// Checks none of chain descriptors is found.
bool fatal_error = false;
auto chained_descriptors = GetChainPartitionInfo(LoadVBMetaData("vbmeta.img"), &fatal_error);
EXPECT_EQ(0, chained_descriptors.size()); // There is no chain descriptors.
EXPECT_EQ(false, fatal_error);
}
TEST_F(AvbUtilTest, LoadAndVerifyVbmetaByPath) {
// Generates a raw system_other.img, use a smaller size to speed-up unit test.
const size_t system_image_size = 10 * 1024 * 1024;
const size_t system_partition_size = 15 * 1024 * 1024;
base::FilePath system_path = GenerateImage("system_other.img", system_image_size);
// Adds AVB Hashtree Footer.
AddAvbFooter(system_path, "hashtree", "system_other", system_partition_size, "SHA512_RSA4096",
20, data_dir_.Append("testkey_rsa4096.pem"), "d00df00d",
"--internal_release_string \"unit test\"");
std::string expected_key_blob_4096 =
ExtractPublicKeyAvbBlob(data_dir_.Append("testkey_rsa4096.pem"));
bool verification_disabled;
VBMetaVerifyResult verify_result;
std::string out_public_key_data;
std::unique_ptr<VBMetaData> vbmeta = LoadAndVerifyVbmetaByPath(
system_path.value(), "system_other", expected_key_blob_4096,
false /* allow_verification_error */, false /* rollback_protection */,
false /* is_chained_vbmeta */, &out_public_key_data, &verification_disabled,
&verify_result);
EXPECT_NE(nullptr, vbmeta);
EXPECT_EQ(VBMetaVerifyResult::kSuccess, verify_result);
EXPECT_EQ(false, verification_disabled);
EXPECT_EQ(expected_key_blob_4096, out_public_key_data);
EXPECT_EQ(2112UL, vbmeta->size());
EXPECT_EQ(system_path.value(), vbmeta->vbmeta_path());
EXPECT_EQ("system_other", vbmeta->partition());
EXPECT_TRUE(CompareVBMeta(system_path, *vbmeta));
}
TEST_F(AvbUtilTest, LoadAndVerifyVbmetaByPathErrorVerification) {
// Generates a raw system_other.img, use a smaller size to speed-up unit test.
const size_t system_image_size = 10 * 1024 * 1024;
const size_t system_partition_size = 15 * 1024 * 1024;
base::FilePath system_path = GenerateImage("system_other.img", system_image_size);
// Adds AVB Hashtree Footer.
AddAvbFooter(system_path, "hashtree", "system_other", system_partition_size, "SHA512_RSA4096",
20, data_dir_.Append("testkey_rsa4096.pem"), "d00df00d",
"--internal_release_string \"unit test\"");
std::string expected_key_blob_4096 =
ExtractPublicKeyAvbBlob(data_dir_.Append("testkey_rsa4096.pem"));
// Modifies the auxiliary data of system_other.img
auto fd = OpenUniqueReadFd(system_path);
auto system_footer = GetAvbFooter(fd);
auto system_vbmeta = ExtractAndLoadVBMetaData(system_path, "system_other-vbmeta.img");
auto system_header = system_vbmeta.GetVBMetaHeader(true /* update_vbmeta_size */);
size_t header_block_offset = 0;
size_t authentication_block_offset = header_block_offset + sizeof(AvbVBMetaImageHeader);
size_t auxiliary_block_offset =
authentication_block_offset + system_header->authentication_data_block_size;
// Modifies the hash.
ModifyFile(
system_path,
(system_footer->vbmeta_offset + authentication_block_offset + system_header->hash_offset),
system_header->hash_size);
VBMetaVerifyResult verify_result;
// Not allow verification error.
std::unique_ptr<VBMetaData> vbmeta = LoadAndVerifyVbmetaByPath(
system_path.value(), "system_other", expected_key_blob_4096,
false /* allow_verification_error */, false /* rollback_protection */,
false /* is_chained_vbmeta */, nullptr /* out_public_key_data */,
nullptr /* verification_disabled */, &verify_result);
EXPECT_EQ(nullptr, vbmeta);
// Allow verification error.
vbmeta = LoadAndVerifyVbmetaByPath(
system_path.value(), "system_other", expected_key_blob_4096,
true /* allow_verification_error */, false /* rollback_protection */,
false /* is_chained_vbmeta */, nullptr /* out_public_key_data */,
nullptr /* verification_disabled */, &verify_result);
EXPECT_NE(nullptr, vbmeta);
EXPECT_EQ(VBMetaVerifyResult::kErrorVerification, verify_result);
EXPECT_EQ(2112UL, vbmeta->size());
EXPECT_EQ(system_path.value(), vbmeta->vbmeta_path());
EXPECT_EQ("system_other", vbmeta->partition());
EXPECT_TRUE(CompareVBMeta(system_path, *vbmeta));
// Modifies the auxiliary data block.
ModifyFile(system_path, system_footer->vbmeta_offset + auxiliary_block_offset,
system_header->auxiliary_data_block_size);
// Not allow verification error.
vbmeta = LoadAndVerifyVbmetaByPath(
system_path.value(), "system_other", expected_key_blob_4096,
false /* allow_verification_error */, false /* rollback_protection */,
false /* is_chained_vbmeta */, nullptr /* out_public_key_data */,
nullptr /* verification_disabled */, &verify_result);
EXPECT_EQ(nullptr, vbmeta);
// Allow verification error.
vbmeta = LoadAndVerifyVbmetaByPath(
system_path.value(), "system_other", expected_key_blob_4096,
true /* allow_verification_error */, false /* rollback_protection */,
false /* is_chained_vbmeta */, nullptr /* out_public_key_data */,
nullptr /* verification_disabled */, &verify_result);
EXPECT_NE(nullptr, vbmeta);
EXPECT_EQ(VBMetaVerifyResult::kErrorVerification, verify_result);
}
TEST_F(AvbUtilTest, LoadAndVerifyVbmetaByPathUnexpectedPublicKey) {
// Generates a raw system_other.img, use a smaller size to speed-up unit test.
const size_t system_image_size = 10 * 1024 * 1024;
const size_t system_partition_size = 15 * 1024 * 1024;
base::FilePath system_path = GenerateImage("system_other.img", system_image_size);
// Adds AVB Hashtree Footer.
AddAvbFooter(system_path, "hashtree", "system_other", system_partition_size, "SHA512_RSA4096",
20, data_dir_.Append("testkey_rsa4096.pem"), "d00df00d",
"--internal_release_string \"unit test\"");
std::string unexpected_key_blob_2048 =
ExtractPublicKeyAvbBlob(data_dir_.Append("testkey_rsa2048.pem"));
std::string expected_key_blob_4096 =
ExtractPublicKeyAvbBlob(data_dir_.Append("testkey_rsa4096.pem"));
// Uses the correct expected public key.
VBMetaVerifyResult verify_result;
std::string out_public_key_data;
std::unique_ptr<VBMetaData> vbmeta = LoadAndVerifyVbmetaByPath(
system_path.value(), "system_other", expected_key_blob_4096,
false /* allow_verification_error */, false /* rollback_protection */,
false /* is_chained_vbmeta */, &out_public_key_data,
nullptr /* verification_disabled */, &verify_result);
EXPECT_NE(nullptr, vbmeta);
EXPECT_EQ(verify_result, VBMetaVerifyResult::kSuccess);
EXPECT_EQ(expected_key_blob_4096, out_public_key_data);
EXPECT_EQ(2112UL, vbmeta->size());
EXPECT_EQ(system_path.value(), vbmeta->vbmeta_path());
EXPECT_EQ("system_other", vbmeta->partition());
EXPECT_TRUE(CompareVBMeta(system_path, *vbmeta));
// Uses the wrong expected public key with allow_verification_error set to false.
vbmeta = LoadAndVerifyVbmetaByPath(
system_path.value(), "system_other", unexpected_key_blob_2048,
false /* allow_verification_error */, false /* rollback_protection */,
false /* is_chained_vbmeta */, &out_public_key_data,
nullptr /* verification_disabled */, &verify_result);
EXPECT_EQ(nullptr, vbmeta);
// Checks out_public_key_data is still loaded properly, if the error is due
// to an unexpected public key instead of vbmeta image verification error.
EXPECT_EQ(expected_key_blob_4096, out_public_key_data);
// Uses the wrong expected public key with allow_verification_error set to true.
vbmeta = LoadAndVerifyVbmetaByPath(
system_path.value(), "system_other", unexpected_key_blob_2048,
true /* allow_verification_error */, false /* rollback_protection */,
false /* is_chained_vbmeta */, &out_public_key_data,
nullptr /* verification_disabled */, &verify_result);
EXPECT_NE(nullptr, vbmeta);
EXPECT_EQ(expected_key_blob_4096, out_public_key_data);
EXPECT_EQ(verify_result, VBMetaVerifyResult::kErrorVerification);
EXPECT_EQ(2112UL, vbmeta->size());
EXPECT_EQ(system_path.value(), vbmeta->vbmeta_path());
EXPECT_EQ("system_other", vbmeta->partition());
EXPECT_TRUE(CompareVBMeta(system_path, *vbmeta));
}
TEST_F(AvbUtilTest, LoadAndVerifyVbmetaByPathVerificationDisabled) {
// Generates a raw system_other.img, use a smaller size to speed-up unit test.
const size_t system_image_size = 10 * 1024 * 1024;
const size_t system_partition_size = 15 * 1024 * 1024;
base::FilePath system_path = GenerateImage("system_other.img", system_image_size);
// Adds AVB Hashtree Footer.
AddAvbFooter(system_path, "hashtree", "system_other", system_partition_size, "SHA512_RSA4096",
20, data_dir_.Append("testkey_rsa4096.pem"), "d00df00d",
"--internal_release_string \"unit test\"");
base::FilePath rsa4096_public_key =
ExtractPublicKeyAvb(data_dir_.Append("testkey_rsa4096.pem"));
std::string expected_key_blob_4096;
EXPECT_TRUE(base::ReadFileToString(rsa4096_public_key, &expected_key_blob_4096));
// Sets disabled flag and expect the returned verification_disabled is true.
SetVBMetaFlags(system_path, AVB_VBMETA_IMAGE_FLAGS_VERIFICATION_DISABLED);
bool verification_disabled;
VBMetaVerifyResult verify_result;
std::string out_public_key_data;
std::unique_ptr<VBMetaData> vbmeta = LoadAndVerifyVbmetaByPath(
system_path.value(), "system_other", expected_key_blob_4096,
true /* allow_verification_error */, false /* rollback_protection */,
false /* is_chained_vbmeta */, nullptr /* out_public_key_data */,
&verification_disabled, &verify_result);
EXPECT_NE(nullptr, vbmeta);
EXPECT_EQ(VBMetaVerifyResult::kErrorVerification, verify_result);
EXPECT_EQ(true, verification_disabled); // should be true.
EXPECT_EQ(2112UL, vbmeta->size());
EXPECT_EQ(system_path.value(), vbmeta->vbmeta_path());
EXPECT_EQ("system_other", vbmeta->partition());
EXPECT_TRUE(CompareVBMeta(system_path, *vbmeta));
// Since the vbmeta flags is modified, vbmeta will be nullptr
// if verification error isn't allowed.
vbmeta = LoadAndVerifyVbmetaByPath(
system_path.value(), "system_other", expected_key_blob_4096,
false /* allow_verification_error */, false /* rollback_protection */,
false /* is_chained_vbmeta */, nullptr /* out_public_key_data */,
&verification_disabled, &verify_result);
EXPECT_EQ(nullptr, vbmeta);
}
TEST_F(AvbUtilTest, LoadAndVerifyVbmetaByPartition) {
// Generates a raw boot.img
const size_t boot_image_size = 5 * 1024 * 1024;
const size_t boot_partition_size = 10 * 1024 * 1024;
base::FilePath boot_path = GenerateImage("boot.img", boot_image_size);
// Adds AVB Hash Footer.
AddAvbFooter(boot_path, "hash", "boot", boot_partition_size, "SHA256_RSA2048", 10,
data_dir_.Append("testkey_rsa2048.pem"), "d00df00d",
"--internal_release_string \"unit test\"");
// Generates a raw system.img, use a smaller size to speed-up unit test.
const size_t system_image_size = 10 * 1024 * 1024;
const size_t system_partition_size = 15 * 1024 * 1024;
base::FilePath system_path = GenerateImage("system.img", system_image_size);
// Adds AVB Hashtree Footer.
AddAvbFooter(system_path, "hashtree", "system", system_partition_size, "SHA512_RSA4096", 20,
data_dir_.Append("testkey_rsa4096.pem"), "d00df00d",
"--internal_release_string \"unit test\"");
// Generates chain partition descriptors.
base::FilePath rsa2048_public_key =
ExtractPublicKeyAvb(data_dir_.Append("testkey_rsa2048.pem"));
base::FilePath rsa4096_public_key =
ExtractPublicKeyAvb(data_dir_.Append("testkey_rsa4096.pem"));
// Makes a vbmeta_system.img including the 'system' chained descriptor.
auto vbmeta_system_path = GenerateVBMetaImage(
"vbmeta_system.img", "SHA256_RSA4096", 0, data_dir_.Append("testkey_rsa4096.pem"),
{}, /* include_descriptor_image_paths */
{{"system", 3, rsa4096_public_key}}, /* chain_partitions */
"--internal_release_string \"unit test\"");
// Makes a vbmeta image includeing 'boot' and 'vbmeta_system' chained descriptors.
auto vbmeta_path = GenerateVBMetaImage("vbmeta.img", "SHA256_RSA8192", 0,
data_dir_.Append("testkey_rsa8192.pem"),
{}, /* include_descriptor_image_paths */
{{"boot", 1, rsa2048_public_key}, /* chain_partitions */
{"vbmeta_system", 2, rsa4096_public_key}},
"--internal_release_string \"unit test\"");
// Calculates the digest of all chained partitions, to ensure the chained is formed properly.
EXPECT_EQ("6f4bf815a651aa35ec7102a88b7906b91aef284bc5e20d0bf527c7d460da3266",
CalcVBMetaDigest("vbmeta.img", "sha256"));
// Starts to test LoadAndVerifyVbmetaByPartition.
std::vector<VBMetaData> vbmeta_images;
auto vbmeta_image_path = [this](const std::string& partition_name) {
return test_dir_.Append(partition_name + ".img").value();
};
EXPECT_EQ(VBMetaVerifyResult::kSuccess,
LoadAndVerifyVbmetaByPartition(
"vbmeta" /* partition_name */, "" /* ab_suffix */, "" /* other_suffix */,
"" /* expected_public_key_blob*/, false /* allow_verification_error */,
true /* load_chained_vbmeta */, true /* rollback_protection */, vbmeta_image_path,
false /* is_chained_vbmeta*/, &vbmeta_images));
EXPECT_EQ(4UL, vbmeta_images.size()); // vbmeta, boot, vbmeta_system and system
// Binary comparison for each vbmeta image.
EXPECT_TRUE(CompareVBMeta(vbmeta_path, vbmeta_images[0]));
EXPECT_TRUE(CompareVBMeta(boot_path, vbmeta_images[1]));
EXPECT_TRUE(CompareVBMeta(vbmeta_system_path, vbmeta_images[2]));
EXPECT_TRUE(CompareVBMeta(system_path, vbmeta_images[3]));
// Skip loading chained vbmeta images.
vbmeta_images.clear();
EXPECT_EQ(VBMetaVerifyResult::kSuccess,
LoadAndVerifyVbmetaByPartition(
"vbmeta" /* partition_name */, "" /* ab_suffix */, "" /* other_suffix */,
"" /* expected_public_key_blob*/, false /* allow_verification_error */,
false /* load_chained_vbmeta */, true /* rollback_protection */,
vbmeta_image_path, false /* is_chained_vbmeta*/, &vbmeta_images));
// Only vbmeta is loaded.
EXPECT_EQ(1UL, vbmeta_images.size());
EXPECT_TRUE(CompareVBMeta(vbmeta_path, vbmeta_images[0]));
}
TEST_F(AvbUtilTest, LoadAndVerifyVbmetaByPartitionWithSuffixes) {
// Tests the following chained partitions.
// vbmeta_a.img
// |--> boot_b.img (boot_other)
// |--> vbmeta_system_b.img (vbmeta_system_other)
// |--> system_a.img
// Generates a raw boot_b.img
const size_t boot_image_size = 5 * 1024 * 1024;
const size_t boot_partition_size = 10 * 1024 * 1024;
base::FilePath boot_path = GenerateImage("boot_b.img", boot_image_size);
// Adds AVB Hash Footer.
AddAvbFooter(boot_path, "hash", "boot", boot_partition_size, "SHA256_RSA2048", 10,
data_dir_.Append("testkey_rsa2048.pem"), "d00df00d",
"--internal_release_string \"unit test\"");
// Generates a raw system_a.img, use a smaller size to speed-up unit test.
const size_t system_image_size = 10 * 1024 * 1024;
const size_t system_partition_size = 15 * 1024 * 1024;
base::FilePath system_path = GenerateImage("system_a.img", system_image_size);
// Adds AVB Hashtree Footer.
AddAvbFooter(system_path, "hashtree", "system", system_partition_size, "SHA512_RSA4096", 20,
data_dir_.Append("testkey_rsa4096.pem"), "d00df00d",
"--internal_release_string \"unit test\"");
// Generates chain partition descriptors.
base::FilePath rsa2048_public_key =
ExtractPublicKeyAvb(data_dir_.Append("testkey_rsa2048.pem"));
base::FilePath rsa4096_public_key =
ExtractPublicKeyAvb(data_dir_.Append("testkey_rsa4096.pem"));
// Makes a vbmeta_system_b.img including the 'system' chained descriptor.
auto vbmeta_system_path = GenerateVBMetaImage(
"vbmeta_system_b.img", "SHA256_RSA4096", 0, data_dir_.Append("testkey_rsa4096.pem"),
{}, /* include_descriptor_image_paths */
{{"system", 3, rsa4096_public_key}}, /* chain_partitions */
"--internal_release_string \"unit test\"");
// Makes a vbmeta_a.img includeing 'boot_other' and 'vbmeta_system_other' chained descriptors.
auto vbmeta_path = GenerateVBMetaImage(
"vbmeta_a.img", "SHA256_RSA8192", 0, data_dir_.Append("testkey_rsa8192.pem"),
{}, /* include_descriptor_image_paths */
{{"boot_other", 1, rsa2048_public_key}, /* chain_partitions */
{"vbmeta_system_other", 2, rsa4096_public_key}},
"--internal_release_string \"unit test\"");
// Starts to test LoadAndVerifyVbmetaByPartition with ab_suffix and ab_other_suffix.
auto vbmeta_image_path = [this](const std::string& partition_name) {
return test_dir_.Append(partition_name + ".img").value();
};
std::vector<VBMetaData> vbmeta_images;
EXPECT_EQ(VBMetaVerifyResult::kSuccess,
LoadAndVerifyVbmetaByPartition(
"vbmeta" /* partition_name */, "_a" /* ab_suffix */, "_b" /* other_suffix */,
"" /* expected_public_key_blob*/, false /* allow_verification_error */,
true /* load_chained_vbmeta */, true /* rollback_protection */, vbmeta_image_path,
false /* is_chained_vbmeta*/, &vbmeta_images));
EXPECT_EQ(4UL, vbmeta_images.size()); // vbmeta, boot_other, vbmeta_system_other and system
// Binary comparison for each vbmeta image.
EXPECT_TRUE(CompareVBMeta(vbmeta_path, vbmeta_images[0]));
EXPECT_TRUE(CompareVBMeta(boot_path, vbmeta_images[1]));
EXPECT_TRUE(CompareVBMeta(vbmeta_system_path, vbmeta_images[2]));
EXPECT_TRUE(CompareVBMeta(system_path, vbmeta_images[3]));
// Skips loading chained vbmeta images.
vbmeta_images.clear();
EXPECT_EQ(VBMetaVerifyResult::kSuccess,
LoadAndVerifyVbmetaByPartition(
"vbmeta" /* partition_name */, "_a" /* ab_suffix */, "_b" /* other_suffix */,
"" /* expected_public_key_blob*/, false /* allow_verification_error */,
false /* load_chained_vbmeta */, true /* rollback_protection */,
vbmeta_image_path, false /* is_chained_vbmeta*/, &vbmeta_images));
// Only vbmeta is loaded.
EXPECT_EQ(1UL, vbmeta_images.size());
EXPECT_TRUE(CompareVBMeta(vbmeta_path, vbmeta_images[0]));
// Using an invalid suffix for 'other' slot, checks it returns error.
EXPECT_EQ(VBMetaVerifyResult::kError,
LoadAndVerifyVbmetaByPartition(
"vbmeta" /* partition_name */, "_a" /* ab_suffix */,
"_invalid_suffix" /* other_suffix */, "" /* expected_public_key_blob*/,
false /* allow_verification_error */, true /* load_chained_vbmeta */,
true /* rollback_protection */, vbmeta_image_path, false /* is_chained_vbmeta*/,
&vbmeta_images));
}
TEST_F(AvbUtilTest, LoadAndVerifyVbmetaByPartitionErrorVerification) {
// Generates a raw boot.img
const size_t boot_image_size = 5 * 1024 * 1024;
const size_t boot_partition_size = 10 * 1024 * 1024;
base::FilePath boot_path = GenerateImage("boot.img", boot_image_size);
// Adds AVB Hash Footer.
AddAvbFooter(boot_path, "hash", "boot", boot_partition_size, "SHA256_RSA2048", 10,
data_dir_.Append("testkey_rsa2048.pem"), "d00df00d",
"--internal_release_string \"unit test\"");
// Generates a raw system.img, use a smaller size to speed-up unit test.
const size_t system_image_size = 10 * 1024 * 1024;
const size_t system_partition_size = 15 * 1024 * 1024;
base::FilePath system_path = GenerateImage("system.img", system_image_size);
// Adds AVB Hashtree Footer.
AddAvbFooter(system_path, "hashtree", "system", system_partition_size, "SHA512_RSA4096", 20,
data_dir_.Append("testkey_rsa4096.pem"), "d00df00d",
"--internal_release_string \"unit test\"");
// Generates chain partition descriptors.
base::FilePath rsa2048_public_key =
ExtractPublicKeyAvb(data_dir_.Append("testkey_rsa2048.pem"));
base::FilePath rsa4096_public_key =
ExtractPublicKeyAvb(data_dir_.Append("testkey_rsa4096.pem"));
// Makes a vbmeta image includeing 'boot' and 'vbmeta_system' chained descriptors.
auto vbmeta_path = GenerateVBMetaImage("vbmeta.img", "SHA256_RSA8192", 0,
data_dir_.Append("testkey_rsa8192.pem"),
{}, /* include_descriptor_image_paths */
{{"boot", 1, rsa2048_public_key}, /* chain_partitions */
{"system", 2, rsa4096_public_key}},
"--internal_release_string \"unit test\"");
// Calculates the digest of all chained partitions, to ensure the chained is formed properly.
EXPECT_EQ("abbe11b316901f3336e26630f64c4732dadbe14532186ac8640e4141a403721f",
CalcVBMetaDigest("vbmeta.img", "sha256"));
auto vbmeta = LoadVBMetaData("vbmeta.img");
// Modifies hash, checks there is error if allow_verification_error is false.
auto header = vbmeta.GetVBMetaHeader(true /* update_vbmeta_size */);
size_t header_block_offset = 0;
size_t authentication_block_offset = header_block_offset + sizeof(AvbVBMetaImageHeader);
// Modifies the hash.
ModifyFile(vbmeta_path, authentication_block_offset + header->hash_offset, header->hash_size);
// Starts to test LoadAndVerifyVbmetaByPartition.
std::vector<VBMetaData> vbmeta_images;
auto vbmeta_image_path = [this](const std::string& partition_name) {
return test_dir_.Append(partition_name + ".img").value();
};
EXPECT_EQ(VBMetaVerifyResult::kError,
LoadAndVerifyVbmetaByPartition(
"vbmeta" /* partition_name */, "" /* ab_suffix */, "" /* other_suffix */,
"" /* expected_public_key_blob*/, false /* allow_verification_error */,
true /* load_chained_vbmeta */, true /* rollback_protection */, vbmeta_image_path,
false /* is_chained_vbmeta*/, &vbmeta_images));
// Stops to load vbmeta because the top-level vbmeta has verification error.
EXPECT_EQ(0UL, vbmeta_images.size());
// Tries again with verification error allowed.
EXPECT_EQ(VBMetaVerifyResult::kErrorVerification,
LoadAndVerifyVbmetaByPartition(
"vbmeta" /* partition_name */, "" /* ab_suffix */, "", /* other_suffix */
"" /* expected_public_key_blob*/, true /* allow_verification_error */,
true /* load_chained_vbmeta */, true /* rollback_protection */, vbmeta_image_path,
false /* is_chained_vbmeta*/, &vbmeta_images));
EXPECT_EQ(3UL, vbmeta_images.size()); // vbmeta, boot, and system
// Binary comparison for each vbmeta image.
EXPECT_TRUE(CompareVBMeta(vbmeta_path, vbmeta_images[0]));
EXPECT_TRUE(CompareVBMeta(boot_path, vbmeta_images[1]));
EXPECT_TRUE(CompareVBMeta(system_path, vbmeta_images[2]));
// Resets the modification of the hash.
ModifyFile(vbmeta_path, 0 /* offset */, -1 /* length */);
// Modifies the auxiliary data of system.img
auto fd = OpenUniqueReadFd(system_path);
auto system_footer = GetAvbFooter(fd);
auto system_vbmeta = ExtractAndLoadVBMetaData(system_path, "system-vbmeta.img");
auto system_header = system_vbmeta.GetVBMetaHeader(true /* update_vbmeta_size */);
size_t auxiliary_block_offset =
authentication_block_offset + system_header->authentication_data_block_size;
// Modifies the auxiliary data block.
ModifyFile(system_path, system_footer->vbmeta_offset + auxiliary_block_offset,
system_header->auxiliary_data_block_size);
vbmeta_images.clear();
EXPECT_EQ(VBMetaVerifyResult::kError,
LoadAndVerifyVbmetaByPartition(
"vbmeta" /* partition_name */, "" /* ab_suffix */, "" /* other_suffix */,
"" /* expected_public_key_blob*/, false /* allow_verification_error */,
true /* load_chained_vbmeta */, true /* rollback_protection */, vbmeta_image_path,
false /* is_chained_vbmeta*/, &vbmeta_images));
// 'vbmeta', 'boot' but no 'system', because of verification error.
EXPECT_EQ(2UL, vbmeta_images.size());
// Binary comparison for the loaded 'vbmeta' and 'boot'.
EXPECT_TRUE(CompareVBMeta(vbmeta_path, vbmeta_images[0]));
EXPECT_TRUE(CompareVBMeta(boot_path, vbmeta_images[1]));
// Resets the modification of the auxiliary data.
ModifyFile(system_path, 0 /* offset */, -1 /* length */);
// Sets the vbmeta header flags on a chained partition, which introduces an error.
ModifyFile(system_path, system_footer->vbmeta_offset + offsetof(AvbVBMetaImageHeader, flags),
sizeof(uint32_t));
EXPECT_EQ(VBMetaVerifyResult::kError,
LoadAndVerifyVbmetaByPartition(
"vbmeta" /* partition_name */, "" /* ab_suffix */, "" /* other_suffix */,
"" /* expected_public_key_blob*/, true /* allow_verification_error */,
true /* load_chained_vbmeta */, true /* rollback_protection */, vbmeta_image_path,
false /* is_chained_vbmeta*/, &vbmeta_images));
}
TEST_F(AvbUtilTest, LoadAndVerifyVbmetaByPartitionVerificationDisabled) {
// Generates a raw boot.img
const size_t boot_image_size = 5 * 1024 * 1024;
const size_t boot_partition_size = 10 * 1024 * 1024;
base::FilePath boot_path = GenerateImage("boot.img", boot_image_size);
// Adds AVB Hash Footer.
AddAvbFooter(boot_path, "hash", "boot", boot_partition_size, "SHA256_RSA2048", 10,
data_dir_.Append("testkey_rsa2048.pem"), "d00df00d",
"--internal_release_string \"unit test\"");
// Generates a raw system.img, use a smaller size to speed-up unit test.
const size_t system_image_size = 10 * 1024 * 1024;
const size_t system_partition_size = 15 * 1024 * 1024;
base::FilePath system_path = GenerateImage("system.img", system_image_size);
// Adds AVB Hashtree Footer.
AddAvbFooter(system_path, "hashtree", "system", system_partition_size, "SHA512_RSA4096", 20,
data_dir_.Append("testkey_rsa4096.pem"), "d00df00d",
"--internal_release_string \"unit test\"");
// Generates chain partition descriptors.
base::FilePath rsa2048_public_key =
ExtractPublicKeyAvb(data_dir_.Append("testkey_rsa2048.pem"));
base::FilePath rsa4096_public_key =
ExtractPublicKeyAvb(data_dir_.Append("testkey_rsa4096.pem"));
// Makes a vbmeta_system.img including the 'system' chained descriptor.
auto vbmeta_system_path = GenerateVBMetaImage(
"vbmeta_system.img", "SHA256_RSA4096", 0, data_dir_.Append("testkey_rsa4096.pem"),
{}, /* include_descriptor_image_paths */
{{"system", 3, rsa4096_public_key}}, /* chain_partitions */
"--internal_release_string \"unit test\"");
// Makes a vbmeta image includeing 'boot' and 'vbmeta_system' chained descriptors.
auto vbmeta_path = GenerateVBMetaImage("vbmeta.img", "SHA256_RSA8192", 0,
data_dir_.Append("testkey_rsa8192.pem"),
{}, /* include_descriptor_image_paths */
{{"boot", 1, rsa2048_public_key}, /* chain_partitions */
{"vbmeta_system", 2, rsa4096_public_key}},
"--internal_release_string \"unit test\"");
// Calculates the digest of all chained partitions, to ensure the chained is formed properly.
EXPECT_EQ("6f4bf815a651aa35ec7102a88b7906b91aef284bc5e20d0bf527c7d460da3266",
CalcVBMetaDigest("vbmeta.img", "sha256"));
// Starts to test LoadAndVerifyVbmetaByPartition.
std::vector<VBMetaData> vbmeta_images;
auto vbmeta_image_path = [this](const std::string& partition_name) {
return test_dir_.Append(partition_name + ".img").value();
};
EXPECT_EQ(VBMetaVerifyResult::kSuccess,
LoadAndVerifyVbmetaByPartition(
"vbmeta" /* partition_name */, "" /* ab_suffix */, "" /* other_suffix */,
"" /* expected_public_key_blob*/, false /* allow_verification_error */,
true /* load_chained_vbmeta */, true /* rollback_protection */, vbmeta_image_path,
false /* is_chained_vbmeta*/, &vbmeta_images));
EXPECT_EQ(4UL, vbmeta_images.size()); // vbmeta, boot, vbmeta_system and system
// Binary comparison for each vbmeta image.
EXPECT_TRUE(CompareVBMeta(vbmeta_path, vbmeta_images[0]));
EXPECT_TRUE(CompareVBMeta(boot_path, vbmeta_images[1]));
EXPECT_TRUE(CompareVBMeta(vbmeta_system_path, vbmeta_images[2]));
EXPECT_TRUE(CompareVBMeta(system_path, vbmeta_images[3]));
// Sets VERIFICATION_DISABLED to the top-level vbmeta.img
SetVBMetaFlags(vbmeta_path, AVB_VBMETA_IMAGE_FLAGS_VERIFICATION_DISABLED);
vbmeta_images.clear();
EXPECT_EQ(VBMetaVerifyResult::kErrorVerification,
LoadAndVerifyVbmetaByPartition(
"vbmeta" /* partition_name */, "" /* ab_suffix */, "" /* other_suffix */,
"" /* expected_public_key_blob*/, true /* allow_verification_error */,
true /* load_chained_vbmeta */, true /* rollback_protection */, vbmeta_image_path,
false /* is_chained_vbmeta*/, &vbmeta_images));
EXPECT_EQ(1UL, vbmeta_images.size()); // Only vbmeta is loaded
EXPECT_TRUE(CompareVBMeta(vbmeta_path, vbmeta_images[0]));
// HASHTREE_DISABLED still loads the chained vbmeta.
SetVBMetaFlags(vbmeta_path, AVB_VBMETA_IMAGE_FLAGS_HASHTREE_DISABLED);
vbmeta_images.clear();
EXPECT_EQ(VBMetaVerifyResult::kErrorVerification,
LoadAndVerifyVbmetaByPartition(
"vbmeta" /* partition_name */, "" /* ab_suffix */, "" /* other_suffix */,
"" /* expected_public_key_blob*/, true /* allow_verification_error */,
true /* load_chained_vbmeta */, true /* rollback_protection */, vbmeta_image_path,
false /* is_chained_vbmeta*/, &vbmeta_images));
EXPECT_EQ(4UL, vbmeta_images.size()); // vbmeta, boot, vbmeta_system and system
// Binary comparison for each vbmeta image.
EXPECT_TRUE(CompareVBMeta(vbmeta_path, vbmeta_images[0]));
EXPECT_TRUE(CompareVBMeta(boot_path, vbmeta_images[1]));
EXPECT_TRUE(CompareVBMeta(vbmeta_system_path, vbmeta_images[2]));
EXPECT_TRUE(CompareVBMeta(system_path, vbmeta_images[3]));
}
TEST_F(AvbUtilTest, LoadAndVerifyVbmetaByPartitionUnexpectedPublicKey) {
// Generates chain partition descriptors.
base::FilePath rsa2048_public_key =
ExtractPublicKeyAvb(data_dir_.Append("testkey_rsa2048.pem"));
base::FilePath rsa4096_public_key =
ExtractPublicKeyAvb(data_dir_.Append("testkey_rsa4096.pem"));
base::FilePath rsa8192_public_key =
ExtractPublicKeyAvb(data_dir_.Append("testkey_rsa8192.pem"));
// Makes a vbmeta image includeing 'boot' and 'vbmeta_system' chained descriptors.
auto vbmeta_path = GenerateVBMetaImage("vbmeta.img", "SHA256_RSA8192", 0,
data_dir_.Append("testkey_rsa8192.pem"),
{}, /* include_descriptor_image_paths */
{{"boot", 1, rsa2048_public_key}, /* chain_partitions */
{"system", 2, rsa4096_public_key}},
"--internal_release_string \"unit test\"");
std::string expected_key_blob_4096;
EXPECT_TRUE(base::ReadFileToString(rsa4096_public_key, &expected_key_blob_4096));
std::string expected_key_blob_8192;
EXPECT_TRUE(base::ReadFileToString(rsa8192_public_key, &expected_key_blob_8192));
auto vbmeta_image_path = [this](const std::string& partition_name) {
return test_dir_.Append(partition_name + ".img").value();
};
std::vector<VBMetaData> vbmeta_images;
// Uses the correct expected public key.
EXPECT_EQ(VBMetaVerifyResult::kSuccess,
LoadAndVerifyVbmetaByPartition(
"vbmeta" /* partition_name */, "" /* ab_suffix */, "" /* other_suffix */,
expected_key_blob_8192, true /* allow_verification_error */,
false /* load_chained_vbmeta */, true /* rollback_protection */,
vbmeta_image_path, false /* is_chained_vbmeta*/, &vbmeta_images));
// Uses the wrong expected public key with allow_verification_error set to true.
vbmeta_images.clear();
EXPECT_EQ(VBMetaVerifyResult::kErrorVerification,
LoadAndVerifyVbmetaByPartition(
"vbmeta" /* partition_name */, "" /* ab_suffix */, "" /* other_suffix */,
expected_key_blob_4096, true /* allow_verification_error */,
false /* load_chained_vbmeta */, true /* rollback_protection */,
vbmeta_image_path, false /* is_chained_vbmeta*/, &vbmeta_images));
// Uses the wrong expected public key with allow_verification_error set to false.
vbmeta_images.clear();
EXPECT_EQ(VBMetaVerifyResult::kError,
LoadAndVerifyVbmetaByPartition(
"vbmeta" /* partition_name */, "" /* ab_suffix */, "" /* other_suffix */,
expected_key_blob_4096, false /* allow_verification_error */,
false /* load_chained_vbmeta */, true /* rollback_protection */,
vbmeta_image_path, false /* is_chained_vbmeta*/, &vbmeta_images));
}
} // namespace fs_avb_host_test