| /* |
| * Copyright (C) 2016 The Android Open Source Project |
| * |
| * Permission is hereby granted, free of charge, to any person |
| * obtaining a copy of this software and associated documentation |
| * files (the "Software"), to deal in the Software without |
| * restriction, including without limitation the rights to use, copy, |
| * modify, merge, publish, distribute, sublicense, and/or sell copies |
| * of the Software, and to permit persons to whom the Software is |
| * furnished to do so, subject to the following conditions: |
| * |
| * The above copyright notice and this permission notice shall be |
| * included in all copies or substantial portions of the Software. |
| * |
| * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, |
| * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF |
| * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
| * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS |
| * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN |
| * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN |
| * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE |
| * SOFTWARE. |
| */ |
| |
| #include <iostream> |
| |
| #include <base/files/file_util.h> |
| #include <base/strings/string_util.h> |
| #include <base/strings/stringprintf.h> |
| |
| #include "avb_unittest_util.h" |
| #include "fake_avb_ops.h" |
| |
| class AvbSlotVerifyTest : public BaseAvbToolTest { |
| public: |
| AvbSlotVerifyTest() {} |
| |
| virtual void SetUp() override { |
| BaseAvbToolTest::SetUp(); |
| ops_.set_partition_dir(testdir_); |
| ops_.set_stored_rollback_indexes({0, 0, 0, 0}); |
| ops_.set_stored_is_device_unlocked(false); |
| } |
| |
| FakeAvbOps ops_; |
| }; |
| |
| TEST_F(AvbSlotVerifyTest, Basic) { |
| GenerateVBMetaImage("vbmeta_a.img", "SHA256_RSA2048", 0, |
| base::FilePath("test/data/testkey_rsa2048.pem")); |
| |
| ops_.set_expected_public_key( |
| PublicKeyAVB(base::FilePath("test/data/testkey_rsa2048.pem"))); |
| |
| AvbSlotVerifyData* slot_data = NULL; |
| EXPECT_EQ(AVB_SLOT_VERIFY_RESULT_OK, |
| avb_slot_verify(ops_.avb_ops(), "_a", &slot_data)); |
| EXPECT_NE(nullptr, slot_data); |
| EXPECT_EQ( |
| "androidboot.slot_suffix=_a androidboot.vbmeta.device_state=locked " |
| "androidboot.vbmeta.hash_alg=sha256 androidboot.vbmeta.size=1408 " |
| "androidboot.vbmeta.digest=" |
| "22cda7342f5ba915f41662975f96f0810ba097399d9d4d4d3847f59c1fe8dfc9", |
| std::string(slot_data->cmdline)); |
| avb_slot_verify_data_free(slot_data); |
| } |
| |
| TEST_F(AvbSlotVerifyTest, BasicSha512) { |
| GenerateVBMetaImage("vbmeta_a.img", "SHA512_RSA2048", 0, |
| base::FilePath("test/data/testkey_rsa2048.pem")); |
| |
| ops_.set_expected_public_key( |
| PublicKeyAVB(base::FilePath("test/data/testkey_rsa2048.pem"))); |
| |
| AvbSlotVerifyData* slot_data = NULL; |
| EXPECT_EQ(AVB_SLOT_VERIFY_RESULT_OK, |
| avb_slot_verify(ops_.avb_ops(), "_a", &slot_data)); |
| EXPECT_NE(nullptr, slot_data); |
| EXPECT_EQ( |
| "androidboot.slot_suffix=_a androidboot.vbmeta.device_state=locked " |
| "androidboot.vbmeta.hash_alg=sha512 androidboot.vbmeta.size=1472 " |
| "androidboot.vbmeta.digest=" |
| "125592a19a266efe6683de1afee53e2585ccfcf33adb5d6485e6fbfeabccf57134aa8365" |
| "aa949a5c6b253bf34956b80e304b7668ee599d207047c8d1bf9574d9", |
| std::string(slot_data->cmdline)); |
| avb_slot_verify_data_free(slot_data); |
| } |
| |
| TEST_F(AvbSlotVerifyTest, BasicUnlocked) { |
| GenerateVBMetaImage("vbmeta_a.img", "SHA256_RSA2048", 0, |
| base::FilePath("test/data/testkey_rsa2048.pem")); |
| |
| ops_.set_expected_public_key( |
| PublicKeyAVB(base::FilePath("test/data/testkey_rsa2048.pem"))); |
| |
| ops_.set_stored_is_device_unlocked(true); |
| |
| AvbSlotVerifyData* slot_data = NULL; |
| EXPECT_EQ(AVB_SLOT_VERIFY_RESULT_OK, |
| avb_slot_verify(ops_.avb_ops(), "_a", &slot_data)); |
| EXPECT_NE(nullptr, slot_data); |
| EXPECT_EQ( |
| "androidboot.slot_suffix=_a androidboot.vbmeta.device_state=unlocked " |
| "androidboot.vbmeta.hash_alg=sha256 androidboot.vbmeta.size=1408 " |
| "androidboot.vbmeta.digest=" |
| "22cda7342f5ba915f41662975f96f0810ba097399d9d4d4d3847f59c1fe8dfc9", |
| std::string(slot_data->cmdline)); |
| avb_slot_verify_data_free(slot_data); |
| } |
| |
| TEST_F(AvbSlotVerifyTest, SlotDataIsCorrect) { |
| GenerateVBMetaImage("vbmeta_a.img", "SHA256_RSA2048", 0, |
| base::FilePath("test/data/testkey_rsa2048.pem")); |
| |
| ops_.set_expected_public_key( |
| PublicKeyAVB(base::FilePath("test/data/testkey_rsa2048.pem"))); |
| |
| EXPECT_EQ(AVB_SLOT_VERIFY_RESULT_OK, |
| avb_slot_verify(ops_.avb_ops(), "_a", NULL)); |
| } |
| |
| TEST_F(AvbSlotVerifyTest, WrongPublicKey) { |
| GenerateVBMetaImage("vbmeta_a.img", "SHA256_RSA2048", 0, |
| base::FilePath("test/data/testkey_rsa2048.pem")); |
| |
| EXPECT_EQ(AVB_SLOT_VERIFY_RESULT_ERROR_PUBLIC_KEY_REJECTED, |
| avb_slot_verify(ops_.avb_ops(), "_a", NULL)); |
| } |
| |
| TEST_F(AvbSlotVerifyTest, NoImage) { |
| EXPECT_EQ(AVB_SLOT_VERIFY_RESULT_ERROR_IO, |
| avb_slot_verify(ops_.avb_ops(), "_a", NULL)); |
| } |
| |
| TEST_F(AvbSlotVerifyTest, UnsignedVBMeta) { |
| GenerateVBMetaImage("vbmeta_a.img", "", 0, base::FilePath("")); |
| |
| EXPECT_EQ(AVB_SLOT_VERIFY_RESULT_ERROR_VERIFICATION, |
| avb_slot_verify(ops_.avb_ops(), "_a", NULL)); |
| } |
| |
| TEST_F(AvbSlotVerifyTest, CorruptedImage) { |
| GenerateVBMetaImage("vbmeta_a.img", "SHA256_RSA2048", 0, |
| base::FilePath("test/data/testkey_rsa2048.pem")); |
| |
| // Corrupt four bytes of data in the end of the image. Since the aux |
| // data is at the end and this data is signed, this will change the |
| // value of the computed hash. |
| uint8_t corrupt_data[4] = {0xff, 0xff, 0xff, 0xff}; |
| EXPECT_EQ(AVB_IO_RESULT_OK, ops_.avb_ops()->write_to_partition( |
| ops_.avb_ops(), "vbmeta_a", |
| -sizeof corrupt_data, // offset from end |
| sizeof corrupt_data, corrupt_data)); |
| |
| EXPECT_EQ(AVB_SLOT_VERIFY_RESULT_ERROR_VERIFICATION, |
| avb_slot_verify(ops_.avb_ops(), "_a", NULL)); |
| } |
| |
| TEST_F(AvbSlotVerifyTest, RollbackIndex) { |
| GenerateVBMetaImage("vbmeta_a.img", "SHA256_RSA2048", 42, |
| base::FilePath("test/data/testkey_rsa2048.pem")); |
| |
| ops_.set_expected_public_key( |
| PublicKeyAVB(base::FilePath("test/data/testkey_rsa2048.pem"))); |
| |
| // First try with 42 as the stored rollback index - this should |
| // succeed since the image rollback index is 42 (as set above). |
| ops_.set_stored_rollback_indexes({42}); |
| EXPECT_EQ(AVB_SLOT_VERIFY_RESULT_OK, |
| avb_slot_verify(ops_.avb_ops(), "_a", NULL)); |
| |
| // Then try with 43 for the stored rollback index - this should fail |
| // because the image has rollback index 42 which is less than 43. |
| ops_.set_stored_rollback_indexes({43}); |
| EXPECT_EQ(AVB_SLOT_VERIFY_RESULT_ERROR_ROLLBACK_INDEX, |
| avb_slot_verify(ops_.avb_ops(), "_a", NULL)); |
| } |
| |
| TEST_F(AvbSlotVerifyTest, HashDescriptorInVBMeta) { |
| const size_t boot_partition_size = 16 * 1024 * 1024; |
| const size_t boot_image_size = 5 * 1024 * 1024; |
| base::FilePath boot_path = GenerateImage("boot_a.img", boot_image_size); |
| |
| EXPECT_COMMAND( |
| 0, |
| "./avbtool add_hash_footer" |
| " --image %s" |
| " --rollback_index 0" |
| " --partition_name boot" |
| " --partition_size %zd" |
| " --kernel_cmdline 'cmdline in hash footer $(ANDROID_SYSTEM_PARTUUID)'" |
| " --salt deadbeef", |
| boot_path.value().c_str(), boot_partition_size); |
| |
| GenerateVBMetaImage( |
| "vbmeta_a.img", "SHA256_RSA2048", 4, |
| base::FilePath("test/data/testkey_rsa2048.pem"), |
| base::StringPrintf( |
| "--include_descriptors_from_image %s" |
| " --kernel_cmdline 'cmdline in vbmeta $(ANDROID_BOOT_PARTUUID)'", |
| boot_path.value().c_str())); |
| |
| EXPECT_EQ( |
| "VBMeta image version: 1.0\n" |
| "Header Block: 256 bytes\n" |
| "Authentication Block: 576 bytes\n" |
| "Auxiliary Block: 768 bytes\n" |
| "Algorithm: SHA256_RSA2048\n" |
| "Rollback Index: 4\n" |
| "Descriptors:\n" |
| " Kernel Cmdline descriptor:\n" |
| " Kernel Cmdline: 'cmdline in vbmeta " |
| "$(ANDROID_BOOT_PARTUUID)'\n" |
| " Hash descriptor:\n" |
| " Image Size: 5242880 bytes\n" |
| " Hash Algorithm: sha256\n" |
| " Partition Name: boot\n" |
| " Salt: deadbeef\n" |
| " Digest: " |
| "184cb36243adb8b87d2d8c4802de32125fe294ec46753d732144ee65df68a23d\n" |
| " Kernel Cmdline descriptor:\n" |
| " Kernel Cmdline: 'cmdline in hash footer " |
| "$(ANDROID_SYSTEM_PARTUUID)'\n", |
| InfoImage(vbmeta_image_path_)); |
| |
| EXPECT_COMMAND(0, |
| "./avbtool erase_footer" |
| " --image %s", |
| boot_path.value().c_str()); |
| |
| // With no footer, 'avbtool info_image' should fail (exit status 1). |
| EXPECT_COMMAND(1, "./avbtool info_image --image %s", |
| boot_path.value().c_str()); |
| |
| ops_.set_expected_public_key( |
| PublicKeyAVB(base::FilePath("test/data/testkey_rsa2048.pem"))); |
| |
| AvbSlotVerifyData* slot_data = NULL; |
| EXPECT_EQ(AVB_SLOT_VERIFY_RESULT_OK, |
| avb_slot_verify(ops_.avb_ops(), "_a", &slot_data)); |
| EXPECT_NE(nullptr, slot_data); |
| |
| // Now verify the slot data. The vbmeta data should match our |
| // vbmeta_image_ member. |
| EXPECT_EQ(slot_data->vbmeta_size, vbmeta_image_.size()); |
| EXPECT_EQ(0, memcmp(vbmeta_image_.data(), slot_data->vbmeta_data, |
| slot_data->vbmeta_size)); |
| |
| // The boot image data should match what is generated above with |
| // GenerateImage(). |
| EXPECT_EQ(boot_image_size, slot_data->boot_size); |
| for (size_t n = 0; n < slot_data->boot_size; n++) { |
| EXPECT_EQ(slot_data->boot_data[n], uint8_t(n)); |
| } |
| |
| // This should match the two cmdlines with a space (U+0020) between |
| // them and the $(ANDROID_SYSTEM_PARTUUID) and |
| // $(ANDROID_BOOT_PARTUUID) variables replaced. |
| EXPECT_EQ( |
| "cmdline in vbmeta 1234-fake-guid-for:boot_a " |
| "cmdline in hash footer 1234-fake-guid-for:system_a " |
| "androidboot.slot_suffix=_a " |
| "androidboot.vbmeta.device_state=locked " |
| "androidboot.vbmeta.hash_alg=sha256 androidboot.vbmeta.size=1600 " |
| "androidboot.vbmeta.digest=" |
| "844308149e43d5db7b14cd5747def40aadf2f0e4716d6435242f90aac9d883d6", |
| std::string(slot_data->cmdline)); |
| EXPECT_EQ(4UL, slot_data->rollback_indexes[0]); |
| for (size_t n = 1; n < AVB_MAX_NUMBER_OF_ROLLBACK_INDEX_SLOTS; n++) { |
| EXPECT_EQ(0UL, slot_data->rollback_indexes[n]); |
| } |
| avb_slot_verify_data_free(slot_data); |
| } |
| |
| TEST_F(AvbSlotVerifyTest, HashDescriptorInVBMetaCorruptBoot) { |
| size_t boot_partition_size = 16 * 1024 * 1024; |
| base::FilePath boot_path = GenerateImage("boot_a.img", 5 * 1024 * 1024); |
| |
| EXPECT_COMMAND(0, |
| "./avbtool add_hash_footer" |
| " --image %s" |
| " --rollback_index 0" |
| " --partition_name boot" |
| " --partition_size %zd" |
| " --salt deadbeef", |
| boot_path.value().c_str(), boot_partition_size); |
| |
| GenerateVBMetaImage("vbmeta_a.img", "SHA256_RSA2048", 0, |
| base::FilePath("test/data/testkey_rsa2048.pem"), |
| base::StringPrintf("--include_descriptors_from_image %s", |
| boot_path.value().c_str())); |
| |
| EXPECT_COMMAND(0, |
| "./avbtool erase_footer" |
| " --image %s", |
| boot_path.value().c_str()); |
| |
| ops_.set_expected_public_key( |
| PublicKeyAVB(base::FilePath("test/data/testkey_rsa2048.pem"))); |
| |
| // So far, so good. |
| EXPECT_EQ(AVB_SLOT_VERIFY_RESULT_OK, |
| avb_slot_verify(ops_.avb_ops(), "_a", NULL)); |
| |
| // Now corrupt boot_a.img and expect verification error. |
| uint8_t corrupt_data[4] = {0xff, 0xff, 0xff, 0xff}; |
| EXPECT_EQ(AVB_IO_RESULT_OK, ops_.avb_ops()->write_to_partition( |
| ops_.avb_ops(), "boot_a", |
| 1024 * 1024, // offset: 1 MiB |
| sizeof corrupt_data, corrupt_data)); |
| |
| EXPECT_EQ(AVB_SLOT_VERIFY_RESULT_ERROR_VERIFICATION, |
| avb_slot_verify(ops_.avb_ops(), "_a", NULL)); |
| } |
| |
| TEST_F(AvbSlotVerifyTest, HashDescriptorInChainedPartition) { |
| size_t boot_partition_size = 16 * 1024 * 1024; |
| const size_t boot_image_size = 5 * 1024 * 1024; |
| base::FilePath boot_path = GenerateImage("boot_a.img", boot_image_size); |
| |
| EXPECT_COMMAND(0, |
| "./avbtool add_hash_footer" |
| " --image %s" |
| " --kernel_cmdline 'cmdline2 in hash footer'" |
| " --rollback_index 12" |
| " --partition_name boot" |
| " --partition_size %zd" |
| " --algorithm SHA256_RSA4096" |
| " --key test/data/testkey_rsa4096.pem" |
| " --salt deadbeef", |
| boot_path.value().c_str(), boot_partition_size); |
| |
| base::FilePath pk_path = testdir_.Append("testkey_rsa4096.avbpubkey"); |
| EXPECT_COMMAND( |
| 0, |
| "./avbtool extract_public_key --key test/data/testkey_rsa4096.pem" |
| " --output %s", |
| pk_path.value().c_str()); |
| |
| GenerateVBMetaImage( |
| "vbmeta_a.img", "SHA256_RSA2048", 11, |
| base::FilePath("test/data/testkey_rsa2048.pem"), |
| base::StringPrintf("--chain_partition boot:1:%s" |
| " --kernel_cmdline 'cmdline2 in vbmeta'", |
| pk_path.value().c_str())); |
| |
| EXPECT_EQ( |
| "VBMeta image version: 1.0\n" |
| "Header Block: 256 bytes\n" |
| "Authentication Block: 576 bytes\n" |
| "Auxiliary Block: 1664 bytes\n" |
| "Algorithm: SHA256_RSA2048\n" |
| "Rollback Index: 11\n" |
| "Descriptors:\n" |
| " Chain Partition descriptor:\n" |
| " Partition Name: boot\n" |
| " Rollback Index Slot: 1\n" |
| " Public key (sha1): 2597c218aae470a130f61162feaae70afd97f011\n" |
| " Kernel Cmdline descriptor:\n" |
| " Kernel Cmdline: 'cmdline2 in vbmeta'\n", |
| InfoImage(vbmeta_image_path_)); |
| |
| ops_.set_expected_public_key( |
| PublicKeyAVB(base::FilePath("test/data/testkey_rsa2048.pem"))); |
| |
| AvbSlotVerifyData* slot_data = NULL; |
| EXPECT_EQ(AVB_SLOT_VERIFY_RESULT_OK, |
| avb_slot_verify(ops_.avb_ops(), "_a", &slot_data)); |
| EXPECT_NE(nullptr, slot_data); |
| |
| // Now verify the slot data. The vbmeta data should match our |
| // vbmeta_image_ member. |
| EXPECT_EQ(slot_data->vbmeta_size, vbmeta_image_.size()); |
| EXPECT_EQ(0, memcmp(vbmeta_image_.data(), slot_data->vbmeta_data, |
| slot_data->vbmeta_size)); |
| |
| // The boot image data should match what is generated above with |
| // GenerateImage(). |
| EXPECT_EQ(boot_image_size, slot_data->boot_size); |
| for (size_t n = 0; n < slot_data->boot_size; n++) { |
| EXPECT_EQ(slot_data->boot_data[n], uint8_t(n)); |
| } |
| |
| // This should match the two cmdlines with a space (U+0020) between them. |
| EXPECT_EQ( |
| "cmdline2 in hash footer cmdline2 in vbmeta " |
| "androidboot.slot_suffix=_a " |
| "androidboot.vbmeta.device_state=locked " |
| "androidboot.vbmeta.hash_alg=sha256 androidboot.vbmeta.size=2496 " |
| "androidboot.vbmeta.digest=" |
| "3924a4e4cdf9a4e6e77b0d87e6e9b4648621e43c2a20988a86c1eb9a56bef338", |
| std::string(slot_data->cmdline)); |
| EXPECT_EQ(11UL, slot_data->rollback_indexes[0]); |
| EXPECT_EQ(12UL, slot_data->rollback_indexes[1]); |
| for (size_t n = 2; n < AVB_MAX_NUMBER_OF_ROLLBACK_INDEX_SLOTS; n++) { |
| EXPECT_EQ(0UL, slot_data->rollback_indexes[n]); |
| } |
| avb_slot_verify_data_free(slot_data); |
| } |
| |
| TEST_F(AvbSlotVerifyTest, HashDescriptorInChainedPartitionCorruptBoot) { |
| size_t boot_partition_size = 16 * 1024 * 1024; |
| base::FilePath boot_path = GenerateImage("boot_a.img", 5 * 1024 * 1024); |
| |
| EXPECT_COMMAND(0, |
| "./avbtool add_hash_footer" |
| " --image %s" |
| " --rollback_index 0" |
| " --partition_name boot" |
| " --partition_size %zd" |
| " --algorithm SHA256_RSA4096" |
| " --key test/data/testkey_rsa4096.pem" |
| " --salt deadbeef", |
| boot_path.value().c_str(), boot_partition_size); |
| |
| base::FilePath pk_path = testdir_.Append("testkey_rsa4096.avbpubkey"); |
| EXPECT_COMMAND( |
| 0, |
| "./avbtool extract_public_key --key test/data/testkey_rsa4096.pem" |
| " --output %s", |
| pk_path.value().c_str()); |
| |
| GenerateVBMetaImage("vbmeta_a.img", "SHA256_RSA2048", 0, |
| base::FilePath("test/data/testkey_rsa2048.pem"), |
| base::StringPrintf("--chain_partition boot:1:%s", |
| pk_path.value().c_str())); |
| |
| ops_.set_expected_public_key( |
| PublicKeyAVB(base::FilePath("test/data/testkey_rsa2048.pem"))); |
| |
| EXPECT_EQ(AVB_SLOT_VERIFY_RESULT_OK, |
| avb_slot_verify(ops_.avb_ops(), "_a", NULL)); |
| |
| // Now corrupt boot_a.img and expect verification error. |
| uint8_t corrupt_data[4] = {0xff, 0xff, 0xff, 0xff}; |
| EXPECT_EQ(AVB_IO_RESULT_OK, ops_.avb_ops()->write_to_partition( |
| ops_.avb_ops(), "boot_a", |
| 1024 * 1024, // offset: 1 MiB |
| sizeof corrupt_data, corrupt_data)); |
| |
| EXPECT_EQ(AVB_SLOT_VERIFY_RESULT_ERROR_VERIFICATION, |
| avb_slot_verify(ops_.avb_ops(), "_a", NULL)); |
| } |
| |
| TEST_F(AvbSlotVerifyTest, HashDescriptorInChainedPartitionKeyMismatch) { |
| size_t boot_partition_size = 16 * 1024 * 1024; |
| base::FilePath boot_path = GenerateImage("boot_a.img", 5 * 1024 * 1024); |
| |
| // Use different key to sign vbmeta in boot_a (we use the 8192 bit |
| // key) than what's in the chained partition descriptor (which is |
| // the 4096 bit key) and expect |
| // AVB_SLOT_VERIFY_RESULT_ERROR_PUBLIC_KEY_REJECTED. |
| |
| EXPECT_COMMAND(0, |
| "./avbtool add_hash_footer" |
| " --image %s" |
| " --rollback_index 0" |
| " --partition_name boot" |
| " --partition_size %zd" |
| " --algorithm SHA256_RSA8192" |
| " --key test/data/testkey_rsa8192.pem" |
| " --salt deadbeef", |
| boot_path.value().c_str(), boot_partition_size); |
| |
| base::FilePath pk_path = testdir_.Append("testkey_rsa4096.avbpubkey"); |
| EXPECT_COMMAND( |
| 0, |
| "./avbtool extract_public_key --key test/data/testkey_rsa4096.pem" |
| " --output %s", |
| pk_path.value().c_str()); |
| |
| GenerateVBMetaImage("vbmeta_a.img", "SHA256_RSA2048", 0, |
| base::FilePath("test/data/testkey_rsa2048.pem"), |
| base::StringPrintf("--chain_partition boot:1:%s", |
| pk_path.value().c_str())); |
| |
| ops_.set_expected_public_key( |
| PublicKeyAVB(base::FilePath("test/data/testkey_rsa2048.pem"))); |
| |
| EXPECT_EQ(AVB_SLOT_VERIFY_RESULT_ERROR_PUBLIC_KEY_REJECTED, |
| avb_slot_verify(ops_.avb_ops(), "_a", NULL)); |
| } |
| |
| TEST_F(AvbSlotVerifyTest, HashDescriptorInChainedPartitionRollbackIndexFail) { |
| size_t boot_partition_size = 16 * 1024 * 1024; |
| base::FilePath boot_path = GenerateImage("boot_a.img", 5 * 1024 * 1024); |
| |
| EXPECT_COMMAND(0, |
| "./avbtool add_hash_footer" |
| " --image %s" |
| " --rollback_index 10" |
| " --partition_name boot" |
| " --partition_size %zd" |
| " --algorithm SHA256_RSA4096" |
| " --key test/data/testkey_rsa4096.pem" |
| " --salt deadbeef", |
| boot_path.value().c_str(), boot_partition_size); |
| |
| base::FilePath pk_path = testdir_.Append("testkey_rsa4096.avbpubkey"); |
| EXPECT_COMMAND( |
| 0, |
| "./avbtool extract_public_key --key test/data/testkey_rsa4096.pem" |
| " --output %s", |
| pk_path.value().c_str()); |
| |
| GenerateVBMetaImage("vbmeta_a.img", "SHA256_RSA2048", 110, |
| base::FilePath("test/data/testkey_rsa2048.pem"), |
| base::StringPrintf("--chain_partition boot:1:%s", |
| pk_path.value().c_str())); |
| |
| ops_.set_expected_public_key( |
| PublicKeyAVB(base::FilePath("test/data/testkey_rsa2048.pem"))); |
| |
| // Both images (vbmeta_a and boot_a) have rollback index 10 and 11 |
| // so it should work if the stored rollback indexes are 0 and 0. |
| ops_.set_stored_rollback_indexes({0, 0}); |
| EXPECT_EQ(AVB_SLOT_VERIFY_RESULT_OK, |
| avb_slot_verify(ops_.avb_ops(), "_a", NULL)); |
| |
| // Check failure if we set the stored rollback index of the chained |
| // partition to 20 (see AvbSlotVerifyTest.RollbackIndex above |
| // where we test rollback index checks for the vbmeta partition). |
| ops_.set_stored_rollback_indexes({0, 20}); |
| EXPECT_EQ(AVB_SLOT_VERIFY_RESULT_ERROR_ROLLBACK_INDEX, |
| avb_slot_verify(ops_.avb_ops(), "_a", NULL)); |
| |
| // Check failure if there is no rollback index slot 1 - in that case |
| // we expect an I/O error since ops->read_rollback_index() will |
| // fail. |
| ops_.set_stored_rollback_indexes({0}); |
| EXPECT_EQ(AVB_SLOT_VERIFY_RESULT_ERROR_IO, |
| avb_slot_verify(ops_.avb_ops(), "_a", NULL)); |
| } |
| |
| TEST_F(AvbSlotVerifyTest, ChainedPartitionNoSlots) { |
| size_t boot_partition_size = 16 * 1024 * 1024; |
| const size_t boot_image_size = 5 * 1024 * 1024; |
| base::FilePath boot_path = GenerateImage("boot.img", boot_image_size); |
| |
| EXPECT_COMMAND(0, |
| "./avbtool add_hash_footer" |
| " --image %s" |
| " --kernel_cmdline 'cmdline2 in hash footer'" |
| " --rollback_index 12" |
| " --partition_name boot" |
| " --partition_size %zd" |
| " --algorithm SHA256_RSA4096" |
| " --key test/data/testkey_rsa4096.pem" |
| " --salt deadbeef", |
| boot_path.value().c_str(), boot_partition_size); |
| |
| base::FilePath pk_path = testdir_.Append("testkey_rsa4096.avbpubkey"); |
| EXPECT_COMMAND( |
| 0, |
| "./avbtool extract_public_key --key test/data/testkey_rsa4096.pem" |
| " --output %s", |
| pk_path.value().c_str()); |
| |
| GenerateVBMetaImage( |
| "vbmeta.img", "SHA256_RSA2048", 11, |
| base::FilePath("test/data/testkey_rsa2048.pem"), |
| base::StringPrintf("--chain_partition boot:1:%s" |
| " --kernel_cmdline 'cmdline2 in vbmeta'", |
| pk_path.value().c_str())); |
| |
| EXPECT_EQ( |
| "VBMeta image version: 1.0\n" |
| "Header Block: 256 bytes\n" |
| "Authentication Block: 576 bytes\n" |
| "Auxiliary Block: 1664 bytes\n" |
| "Algorithm: SHA256_RSA2048\n" |
| "Rollback Index: 11\n" |
| "Descriptors:\n" |
| " Chain Partition descriptor:\n" |
| " Partition Name: boot\n" |
| " Rollback Index Slot: 1\n" |
| " Public key (sha1): 2597c218aae470a130f61162feaae70afd97f011\n" |
| " Kernel Cmdline descriptor:\n" |
| " Kernel Cmdline: 'cmdline2 in vbmeta'\n", |
| InfoImage(vbmeta_image_path_)); |
| |
| ops_.set_expected_public_key( |
| PublicKeyAVB(base::FilePath("test/data/testkey_rsa2048.pem"))); |
| |
| AvbSlotVerifyData* slot_data = NULL; |
| EXPECT_EQ(AVB_SLOT_VERIFY_RESULT_OK, |
| avb_slot_verify(ops_.avb_ops(), "", &slot_data)); |
| EXPECT_NE(nullptr, slot_data); |
| |
| // Now verify the slot data. The vbmeta data should match our |
| // vbmeta_image_ member. |
| EXPECT_EQ(slot_data->vbmeta_size, vbmeta_image_.size()); |
| EXPECT_EQ(0, memcmp(vbmeta_image_.data(), slot_data->vbmeta_data, |
| slot_data->vbmeta_size)); |
| |
| // The boot image data should match what is generated above with |
| // GenerateImage(). |
| EXPECT_EQ(boot_image_size, slot_data->boot_size); |
| for (size_t n = 0; n < slot_data->boot_size; n++) { |
| EXPECT_EQ(slot_data->boot_data[n], uint8_t(n)); |
| } |
| |
| // This should match the two cmdlines with a space (U+0020) between |
| // them - note that androidboot.slot_suffix is not set since we |
| // don't have any slots in this setup. |
| EXPECT_EQ( |
| "cmdline2 in hash footer cmdline2 in vbmeta " |
| "androidboot.vbmeta.device_state=locked " |
| "androidboot.vbmeta.hash_alg=sha256 androidboot.vbmeta.size=2496 " |
| "androidboot.vbmeta.digest=" |
| "3924a4e4cdf9a4e6e77b0d87e6e9b4648621e43c2a20988a86c1eb9a56bef338", |
| std::string(slot_data->cmdline)); |
| EXPECT_EQ(11UL, slot_data->rollback_indexes[0]); |
| EXPECT_EQ(12UL, slot_data->rollback_indexes[1]); |
| for (size_t n = 2; n < AVB_MAX_NUMBER_OF_ROLLBACK_INDEX_SLOTS; n++) { |
| EXPECT_EQ(0UL, slot_data->rollback_indexes[n]); |
| } |
| avb_slot_verify_data_free(slot_data); |
| } |