diff options
-rw-r--r-- | README.md | 14 | ||||
-rw-r--r-- | libavb/avb_cmdline.c | 27 | ||||
-rw-r--r-- | libavb/avb_cmdline.h | 1 | ||||
-rw-r--r-- | libavb/avb_ops.h | 23 | ||||
-rw-r--r-- | libavb/avb_slot_verify.c | 133 | ||||
-rw-r--r-- | libavb/avb_slot_verify.h | 16 | ||||
-rw-r--r-- | test/avb_slot_verify_unittest.cc | 109 | ||||
-rw-r--r-- | test/fake_avb_ops.cc | 47 | ||||
-rw-r--r-- | test/fake_avb_ops.h | 53 |
9 files changed, 388 insertions, 35 deletions
@@ -27,6 +27,7 @@ Verified Boot 2.0. Usually AVB is used to refer to this codebase. + [Persistent Digests](#Persistent-Digests) + [Updating Stored Rollback Indexes](#Updating-Stored-Rollback-Indexes) + [Recommended Bootflow](#Recommended-Bootflow) + + [Booting Into Recovery](#Booting-Into-Recovery) + [Handling dm-verity Errors](#Handling-dm_verity-Errors) + [Android Specific Integration](#Android-Specific-Integration) + [Device Specific Notes](#Device-Specific-Notes) @@ -917,6 +918,19 @@ Notes: be used to convey that the device is UNLOCKED (lightbars, LEDs, etc.). +### Booting Into Recovery + +On Android devices not using A/B, the `recovery` partition usually isn't +updated along with other partitions and therefore can't be referenced +from the main `vbmeta` partition. + +It's still possible to use AVB to protect this partition (and others) +by signing these partitions and passing the +`AVB_SLOT_VERIFY_FLAGS_NO_VBMETA_PARTITION` flag to `avb_slot_verify()`. +In this mode, the key used to sign each requested partition is verified +by the `validate_public_key_for_partition()` operation which is also +used to return the rollback index location to be used. + ## Handling dm-verity Errors By design, hashtree verification errors are detected by the HLOS and diff --git a/libavb/avb_cmdline.c b/libavb/avb_cmdline.c index bf10865..f87e18c 100644 --- a/libavb/avb_cmdline.c +++ b/libavb/avb_cmdline.c @@ -97,7 +97,15 @@ char* avb_sub_cmdline(AvbOps* ops, } } - avb_assert(ret != NULL); + /* It's possible there is no _PARTUUID for replacement above. + * Duplicate cmdline to ret for additional substitutions below. + */ + if (ret == NULL) { + ret = avb_strdup(cmdline); + if (ret == NULL) { + goto fail; + } + } /* Replace any additional substitutions. */ if (additional_substitutions != NULL) { @@ -225,6 +233,7 @@ static int cmdline_append_hex(AvbSlotVerifyData* slot_data, AvbSlotVerifyResult avb_append_options( AvbOps* ops, + AvbSlotVerifyFlags flags, AvbSlotVerifyData* slot_data, AvbVBMetaImageHeader* toplevel_vbmeta, AvbAlgorithmType algorithm_type, @@ -235,12 +244,16 @@ AvbSlotVerifyResult avb_append_options( bool is_device_unlocked; AvbIOResult io_ret; - /* Add androidboot.vbmeta.device option. */ - if (!cmdline_append_option(slot_data, - "androidboot.vbmeta.device", - "PARTUUID=$(ANDROID_VBMETA_PARTUUID)")) { - ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM; - goto out; + /* Add androidboot.vbmeta.device option... except if not using a vbmeta + * partition since it doesn't make sense in that case. + */ + if (!(flags & AVB_SLOT_VERIFY_FLAGS_NO_VBMETA_PARTITION)) { + if (!cmdline_append_option(slot_data, + "androidboot.vbmeta.device", + "PARTUUID=$(ANDROID_VBMETA_PARTUUID)")) { + ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM; + goto out; + } } /* Add androidboot.vbmeta.avb_version option. */ diff --git a/libavb/avb_cmdline.h b/libavb/avb_cmdline.h index e1f5b1b..377783f 100644 --- a/libavb/avb_cmdline.h +++ b/libavb/avb_cmdline.h @@ -62,6 +62,7 @@ char* avb_sub_cmdline(AvbOps* ops, AvbSlotVerifyResult avb_append_options( AvbOps* ops, + AvbSlotVerifyFlags flags, AvbSlotVerifyData* slot_data, AvbVBMetaImageHeader* toplevel_vbmeta, AvbAlgorithmType algorithm_type, diff --git a/libavb/avb_ops.h b/libavb/avb_ops.h index 7f86386..dec163d 100644 --- a/libavb/avb_ops.h +++ b/libavb/avb_ops.h @@ -191,6 +191,10 @@ struct AvbOps { * * If AVB_IO_RESULT_OK is returned then |out_is_trusted| is set - * true if trusted or false if untrusted. + * + * NOTE: If AVB_SLOT_VERIFY_FLAGS_NO_VBMETA_PARTITION is passed to + * avb_slot_verify() then this operation is never used. Instead, the + * validate_public_key_for_partition() operation is used */ AvbIOResult (*validate_vbmeta_public_key)(AvbOps* ops, const uint8_t* public_key_data, @@ -308,6 +312,25 @@ struct AvbOps { const char* name, size_t value_size, const uint8_t* value); + + /* Like validate_vbmeta_public_key() but for when the flag + * AVB_SLOT_VERIFY_FLAGS_NO_VBMETA_PARTITION is being used. The name of the + * partition to get the public key for is passed in |partition_name|. + * + * Also returns the rollback index location to use for the partition, in + * |out_rollback_index_location|. + * + * Returns AVB_IO_RESULT_OK on success, otherwise an error code. + */ + AvbIOResult (*validate_public_key_for_partition)( + AvbOps* ops, + const char* partition, + const uint8_t* public_key_data, + size_t public_key_length, + const uint8_t* public_key_metadata, + size_t public_key_metadata_length, + bool* out_is_trusted, + uint32_t* out_rollback_index_location); }; #ifdef __cplusplus diff --git a/libavb/avb_slot_verify.c b/libavb/avb_slot_verify.c index 9124b24..30faac8 100644 --- a/libavb/avb_slot_verify.c +++ b/libavb/avb_slot_verify.c @@ -558,6 +558,7 @@ static AvbSlotVerifyResult load_and_verify_vbmeta( AvbOps* ops, const char* const* requested_partitions, const char* ab_suffix, + AvbSlotVerifyFlags flags, bool allow_verification_error, AvbVBMetaImageFlags toplevel_vbmeta_flags, int rollback_index_location, @@ -595,7 +596,12 @@ static AvbSlotVerifyResult load_and_verify_vbmeta( * rollback_index_location to determine whether we're the main * vbmeta struct. */ - is_main_vbmeta = (rollback_index_location == 0); + is_main_vbmeta = false; + if (rollback_index_location == 0) { + if ((flags & AVB_SLOT_VERIFY_FLAGS_NO_VBMETA_PARTITION) == 0) { + is_main_vbmeta = true; + } + } /* Don't use footers for vbmeta partitions ('vbmeta' or * 'vbmeta_<partition_name>'). @@ -706,6 +712,7 @@ static AvbSlotVerifyResult load_and_verify_vbmeta( ret = load_and_verify_vbmeta(ops, requested_partitions, ab_suffix, + flags, allow_verification_error, 0 /* toplevel_vbmeta_flags */, 0 /* rollback_index_location */, @@ -783,6 +790,8 @@ static AvbSlotVerifyResult load_and_verify_vbmeta( } } + uint32_t rollback_index_location_to_use = rollback_index_location; + /* Check if key used to make signature matches what is expected. */ if (pk_data != NULL) { if (expected_public_key != NULL) { @@ -810,9 +819,27 @@ static AvbSlotVerifyResult load_and_verify_vbmeta( pk_metadata_len = vbmeta_header.public_key_metadata_size; } - avb_assert(is_main_vbmeta); - io_ret = ops->validate_vbmeta_public_key( - ops, pk_data, pk_len, pk_metadata, pk_metadata_len, &key_is_trusted); + // If we're not using a vbmeta partition, need to use another AvbOps... + if (flags & AVB_SLOT_VERIFY_FLAGS_NO_VBMETA_PARTITION) { + io_ret = ops->validate_public_key_for_partition( + ops, + full_partition_name, + pk_data, + pk_len, + pk_metadata, + pk_metadata_len, + &key_is_trusted, + &rollback_index_location_to_use); + } else { + avb_assert(is_main_vbmeta); + io_ret = ops->validate_vbmeta_public_key(ops, + pk_data, + pk_len, + pk_metadata, + pk_metadata_len, + &key_is_trusted); + } + if (io_ret == AVB_IO_RESULT_ERROR_OOM) { ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM; goto out; @@ -837,7 +864,7 @@ static AvbSlotVerifyResult load_and_verify_vbmeta( /* Check rollback index. */ io_ret = ops->read_rollback_index( - ops, rollback_index_location, &stored_rollback_index); + ops, rollback_index_location_to_use, &stored_rollback_index); if (io_ret == AVB_IO_RESULT_ERROR_OOM) { ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM; goto out; @@ -863,7 +890,9 @@ static AvbSlotVerifyResult load_and_verify_vbmeta( if (is_main_vbmeta) { avb_assert(slot_data->num_vbmeta_images == 0); } else { - avb_assert(slot_data->num_vbmeta_images > 0); + if (!(flags & AVB_SLOT_VERIFY_FLAGS_NO_VBMETA_PARTITION)) { + avb_assert(slot_data->num_vbmeta_images > 0); + } } if (slot_data->num_vbmeta_images == MAX_NUMBER_OF_VBMETA_IMAGES) { avb_errorv(full_partition_name, ": Too many vbmeta images.\n", NULL); @@ -987,6 +1016,7 @@ static AvbSlotVerifyResult load_and_verify_vbmeta( load_and_verify_vbmeta(ops, requested_partitions, ab_suffix, + flags, allow_verification_error, toplevel_vbmeta_flags, chain_desc.rollback_index_location, @@ -1348,7 +1378,6 @@ AvbSlotVerifyResult avb_slot_verify(AvbOps* ops, avb_assert(ops->read_is_device_unlocked != NULL); avb_assert(ops->read_from_partition != NULL); avb_assert(ops->get_size_of_partition != NULL); - avb_assert(ops->validate_vbmeta_public_key != NULL); avb_assert(ops->read_rollback_index != NULL); avb_assert(ops->get_unique_guid_for_partition != NULL); @@ -1381,6 +1410,21 @@ AvbSlotVerifyResult avb_slot_verify(AvbOps* ops, } } + /* Make sure passed-in AvbOps support verifying public keys and getting + * rollback index location if not using a vbmeta partition. + */ + if (flags & AVB_SLOT_VERIFY_FLAGS_NO_VBMETA_PARTITION) { + if (ops->validate_public_key_for_partition == NULL) { + avb_error( + "AVB_SLOT_VERIFY_FLAGS_NO_VBMETA_PARTITION was passed but the " + "validate_public_key_for_partition() operation isn't implemented.\n"); + ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_ARGUMENT; + goto fail; + } + } else { + avb_assert(ops->validate_vbmeta_public_key != NULL); + } + slot_data = avb_calloc(sizeof(AvbSlotVerifyData)); if (slot_data == NULL) { ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM; @@ -1405,21 +1449,55 @@ AvbSlotVerifyResult avb_slot_verify(AvbOps* ops, goto fail; } - ret = load_and_verify_vbmeta(ops, - requested_partitions, - ab_suffix, - allow_verification_error, - 0 /* toplevel_vbmeta_flags */, - 0 /* rollback_index_location */, - "vbmeta", - avb_strlen("vbmeta"), - NULL /* expected_public_key */, - 0 /* expected_public_key_length */, - slot_data, - &algorithm_type, - additional_cmdline_subst); - if (!allow_verification_error && ret != AVB_SLOT_VERIFY_RESULT_OK) { - goto fail; + if (flags & AVB_SLOT_VERIFY_FLAGS_NO_VBMETA_PARTITION) { + if (requested_partitions == NULL || requested_partitions[0] == NULL) { + avb_fatal( + "Requested partitions cannot be empty when using " + "AVB_SLOT_VERIFY_FLAGS_NO_VBMETA_PARTITION"); + ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_ARGUMENT; + goto fail; + } + + /* No vbmeta partition, go through each of the requested partitions... */ + for (size_t n = 0; requested_partitions[n] != NULL; n++) { + ret = load_and_verify_vbmeta(ops, + requested_partitions, + ab_suffix, + flags, + allow_verification_error, + 0 /* toplevel_vbmeta_flags */, + 0 /* rollback_index_location */, + requested_partitions[n], + avb_strlen(requested_partitions[n]), + NULL /* expected_public_key */, + 0 /* expected_public_key_length */, + slot_data, + &algorithm_type, + additional_cmdline_subst); + if (!allow_verification_error && ret != AVB_SLOT_VERIFY_RESULT_OK) { + goto fail; + } + } + + } else { + /* Usual path, load "vbmeta"... */ + ret = load_and_verify_vbmeta(ops, + requested_partitions, + ab_suffix, + flags, + allow_verification_error, + 0 /* toplevel_vbmeta_flags */, + 0 /* rollback_index_location */, + "vbmeta", + avb_strlen("vbmeta"), + NULL /* expected_public_key */, + 0 /* expected_public_key_length */, + slot_data, + &algorithm_type, + additional_cmdline_subst); + if (!allow_verification_error && ret != AVB_SLOT_VERIFY_RESULT_OK) { + goto fail; + } } if (!result_should_continue(ret)) { @@ -1427,10 +1505,12 @@ AvbSlotVerifyResult avb_slot_verify(AvbOps* ops, } /* If things check out, mangle the kernel command-line as needed. */ - if (avb_strcmp(slot_data->vbmeta_images[0].partition_name, "vbmeta") != 0) { - avb_assert( - avb_strcmp(slot_data->vbmeta_images[0].partition_name, "boot") == 0); - using_boot_for_vbmeta = true; + if (!(flags & AVB_SLOT_VERIFY_FLAGS_NO_VBMETA_PARTITION)) { + if (avb_strcmp(slot_data->vbmeta_images[0].partition_name, "vbmeta") != 0) { + avb_assert( + avb_strcmp(slot_data->vbmeta_images[0].partition_name, "boot") == 0); + using_boot_for_vbmeta = true; + } } /* Byteswap top-level vbmeta header since we'll need it below. */ @@ -1490,6 +1570,7 @@ AvbSlotVerifyResult avb_slot_verify(AvbOps* ops, /* Add options... */ AvbSlotVerifyResult sub_ret; sub_ret = avb_append_options(ops, + flags, slot_data, &toplevel_vbmeta, algorithm_type, diff --git a/libavb/avb_slot_verify.h b/libavb/avb_slot_verify.h index d42d64c..a2c98f4 100644 --- a/libavb/avb_slot_verify.h +++ b/libavb/avb_slot_verify.h @@ -117,11 +117,21 @@ typedef enum { * should be set if using AVB_HASHTREE_ERROR_MODE_MANAGED_RESTART_AND_EIO * and the reason the boot loader is running is because the device * was restarted by the dm-verity driver. + * + * If the AVB_SLOT_VERIFY_FLAGS_NO_VBMETA_PARTITION flag is set then + * data won't be loaded from the "vbmeta" partition and the + * |validate_vbmeta_public_key| operation is never called. Instead, the + * vbmeta structs in |requested_partitions| are loaded and processed and the + * |validate_public_key_for_partition| operation is called for each of these + * vbmeta structs. This flag is useful when booting into recovery on a device + * not using A/B - see section "Booting into recovery" in README.md for + * more information. */ typedef enum { AVB_SLOT_VERIFY_FLAGS_NONE = 0, AVB_SLOT_VERIFY_FLAGS_ALLOW_VERIFICATION_ERROR = (1 << 0), - AVB_SLOT_VERIFY_FLAGS_RESTART_CAUSED_BY_HASHTREE_CORRUPTION = (1 << 1) + AVB_SLOT_VERIFY_FLAGS_RESTART_CAUSED_BY_HASHTREE_CORRUPTION = (1 << 1), + AVB_SLOT_VERIFY_FLAGS_NO_VBMETA_PARTITION = (1 << 2), } AvbSlotVerifyFlags; /* Get a textual representation of |result|. */ @@ -245,7 +255,9 @@ typedef struct { * PARTUUID=$(ANDROID_VBMETA_PARTUUID) before substitution so it * will end up pointing to the vbmeta partition for the verified * slot. If there is no vbmeta partition it will point to the boot - * partition of the verified slot. + * partition of the verified slot. If the flag + * AVB_SLOT_VERIFY_FLAGS_NO_VBMETA_PARTITION is used, this is not + * set. * * androidboot.vbmeta.avb_version: This is set to the decimal value * of AVB_VERSION_MAJOR followed by a dot followed by the decimal diff --git a/test/avb_slot_verify_unittest.cc b/test/avb_slot_verify_unittest.cc index d27e6e0..28ec151 100644 --- a/test/avb_slot_verify_unittest.cc +++ b/test/avb_slot_verify_unittest.cc @@ -1728,6 +1728,115 @@ TEST_F(AvbSlotVerifyTest, OnlyLoadWhatHasBeenRequested) { EXPECT_TRUE(partitions.find("bar_a") == partitions.end()); } +TEST_F(AvbSlotVerifyTest, NoVBMetaPartitionFlag) { + const size_t foo_partition_size = 16 * 1024 * 1024; + const size_t bar_partition_size = 32 * 1024 * 1024; + const size_t foo_image_size = 5 * 1024 * 1024; + const size_t bar_image_size = 10 * 1024 * 1024; + base::FilePath foo_path = GenerateImage("foo_a.img", foo_image_size); + base::FilePath bar_path = GenerateImage("bar_a.img", bar_image_size); + + EXPECT_COMMAND(0, + "./avbtool add_hash_footer" + " --image %s" + " --kernel_cmdline 'this is=5 from foo=42'" + " --partition_name foo" + " --partition_size %zd" + " --salt deadbeef" + " --internal_release_string \"\"" + " --algorithm SHA256_RSA4096" + " --salt deadbeef" + " --key test/data/testkey_rsa4096.pem" + " --rollback_index 42", + foo_path.value().c_str(), + foo_partition_size); + + EXPECT_COMMAND(0, + "./avbtool add_hash_footer" + " --image %s" + " --kernel_cmdline 'and=43 from bar'" + " --partition_name bar" + " --partition_size %zd" + " --salt deadbeef" + " --internal_release_string \"\"" + " --algorithm SHA256_RSA2048" + " --salt deadbeef" + " --key test/data/testkey_rsa2048.pem" + " --rollback_index 43", + bar_path.value().c_str(), + bar_partition_size); + + ops_.set_expected_public_key_for_partition( + "foo_a", + PublicKeyAVB(base::FilePath("test/data/testkey_rsa4096.pem")), + 1); + ops_.set_expected_public_key_for_partition( + "bar_a", + PublicKeyAVB(base::FilePath("test/data/testkey_rsa2048.pem")), + 2); + ops_.set_stored_rollback_indexes({{0, 1000}, {1, 10}, {2, 11}}); + AvbSlotVerifyData* slot_data = NULL; + const char* requested_partitions[] = {"foo", "bar", NULL}; + + // Without AVB_SLOT_VERIFY_FLAGS_NO_VBMETA_PARTITION, this should fail because + // vbmeta_a (or boot_a) cannot not be found. + EXPECT_EQ(AVB_SLOT_VERIFY_RESULT_ERROR_IO, + avb_slot_verify(ops_.avb_ops(), + requested_partitions, + "_a", + AVB_SLOT_VERIFY_FLAGS_NONE, + AVB_HASHTREE_ERROR_MODE_RESTART_AND_INVALIDATE, + &slot_data)); + + // However, with this flag it should succeed (note that rollback indexes in + // the images exceed the stored rollback indexes) + EXPECT_EQ(AVB_SLOT_VERIFY_RESULT_OK, + avb_slot_verify(ops_.avb_ops(), + requested_partitions, + "_a", + AVB_SLOT_VERIFY_FLAGS_NO_VBMETA_PARTITION, + AVB_HASHTREE_ERROR_MODE_RESTART_AND_INVALIDATE, + &slot_data)); + EXPECT_NE(nullptr, slot_data); + EXPECT_EQ(size_t(2), slot_data->num_loaded_partitions); + EXPECT_EQ("foo", std::string(slot_data->loaded_partitions[0].partition_name)); + EXPECT_EQ("bar", std::string(slot_data->loaded_partitions[1].partition_name)); + // Note the absence of 'androidboot.vbmeta.device' + EXPECT_EQ( + "this is=5 from foo=42 and=43 from bar " + "androidboot.vbmeta.avb_version=1.1 " + "androidboot.vbmeta.device_state=locked " + "androidboot.vbmeta.hash_alg=sha256 " + "androidboot.vbmeta.size=3456 " + "androidboot.vbmeta.digest=" + "b5dbfb1743073f9a4cb45f94d1d849f89ca9777d158a2a06d09517c79ffd86cd " + "androidboot.vbmeta.invalidate_on_error=yes " + "androidboot.veritymode=enforcing", + std::string(slot_data->cmdline)); + avb_slot_verify_data_free(slot_data); + + // Check that rollback protection works if we increase the stored rollback + // indexes to exceed that of the image... do a check for each location. + ops_.set_stored_rollback_indexes({{0, 1000}, {1, 10}, {2, 100}}); + EXPECT_EQ(AVB_SLOT_VERIFY_RESULT_ERROR_ROLLBACK_INDEX, + avb_slot_verify(ops_.avb_ops(), + requested_partitions, + "_a", + AVB_SLOT_VERIFY_FLAGS_NO_VBMETA_PARTITION, + AVB_HASHTREE_ERROR_MODE_RESTART_AND_INVALIDATE, + &slot_data)); + EXPECT_EQ(nullptr, slot_data); + ops_.set_stored_rollback_indexes({{0, 1000}, {1, 100}, {2, 10}}); + EXPECT_EQ(AVB_SLOT_VERIFY_RESULT_ERROR_ROLLBACK_INDEX, + avb_slot_verify(ops_.avb_ops(), + requested_partitions, + "_a", + AVB_SLOT_VERIFY_FLAGS_NO_VBMETA_PARTITION, + AVB_HASHTREE_ERROR_MODE_RESTART_AND_INVALIDATE, + &slot_data)); + EXPECT_EQ(nullptr, slot_data); +} + TEST_F(AvbSlotVerifyTest, PublicKeyMetadata) { base::FilePath md_path = GenerateImage("md.bin", 1536); diff --git a/test/fake_avb_ops.cc b/test/fake_avb_ops.cc index 2fdba10..6e8ab8c 100644 --- a/test/fake_avb_ops.cc +++ b/test/fake_avb_ops.cc @@ -262,6 +262,30 @@ AvbIOResult FakeAvbOps::validate_vbmeta_public_key( return AVB_IO_RESULT_OK; } +AvbIOResult FakeAvbOps::validate_public_key_for_partition( + AvbOps* ops, + const char* partition, + const uint8_t* public_key_data, + size_t public_key_length, + const uint8_t* public_key_metadata, + size_t public_key_metadata_length, + bool* out_key_is_trusted, + uint32_t* out_rollback_index_location) { + std::string expected_public_key = + expected_public_key_for_partition_map_[partition]; + uint32_t rollback_index_location = + rollback_index_location_for_partition_map_[partition]; + if (out_key_is_trusted != NULL) { + bool pk_matches = (public_key_length == expected_public_key.size() && + (memcmp(expected_public_key.c_str(), + public_key_data, + public_key_length) == 0)); + *out_key_is_trusted = pk_matches; + *out_rollback_index_location = rollback_index_location; + } + return AVB_IO_RESULT_OK; +} + AvbIOResult FakeAvbOps::read_rollback_index(AvbOps* ops, size_t rollback_index_location, uint64_t* out_rollback_index) { @@ -436,6 +460,27 @@ static AvbIOResult my_ops_validate_vbmeta_public_key( out_key_is_trusted); } +static AvbIOResult my_ops_validate_public_key_for_partition( + AvbOps* ops, + const char* partition, + const uint8_t* public_key_data, + size_t public_key_length, + const uint8_t* public_key_metadata, + size_t public_key_metadata_length, + bool* out_key_is_trusted, + uint32_t* out_rollback_index_location) { + return FakeAvbOps::GetInstanceFromAvbOps(ops) + ->delegate() + ->validate_public_key_for_partition(ops, + partition, + public_key_data, + public_key_length, + public_key_metadata, + public_key_metadata_length, + out_key_is_trusted, + out_rollback_index_location); +} + static AvbIOResult my_ops_read_rollback_index(AvbOps* ops, size_t rollback_index_location, uint64_t* out_rollback_index) { @@ -541,6 +586,8 @@ FakeAvbOps::FakeAvbOps() { avb_ops_.get_size_of_partition = my_ops_get_size_of_partition; avb_ops_.read_persistent_value = my_ops_read_persistent_value; avb_ops_.write_persistent_value = my_ops_write_persistent_value; + avb_ops_.validate_public_key_for_partition = + my_ops_validate_public_key_for_partition; // Just use the built-in A/B metadata read/write routines. avb_ab_ops_.ops = &avb_ops_; diff --git a/test/fake_avb_ops.h b/test/fake_avb_ops.h index 935dbf4..2cc12d8 100644 --- a/test/fake_avb_ops.h +++ b/test/fake_avb_ops.h @@ -95,6 +95,16 @@ class FakeAvbOpsDelegate { size_t value_size, const uint8_t* value) = 0; + virtual AvbIOResult validate_public_key_for_partition( + AvbOps* ops, + const char* partition, + const uint8_t* public_key_data, + size_t public_key_length, + const uint8_t* public_key_metadata, + size_t public_key_metadata_length, + bool* out_is_trusted, + uint32_t* out_rollback_index_location) = 0; + virtual AvbIOResult read_permanent_attributes( AvbAtxPermanentAttributes* attributes) = 0; @@ -150,6 +160,16 @@ class FakeAvbOps : public FakeAvbOpsDelegate { expected_public_key_ = expected_public_key; } + void set_expected_public_key_for_partition( + const std::string& partition_name, + const std::string& expected_public_key, + uint32_t rollback_index_location) { + expected_public_key_for_partition_map_[partition_name] = + expected_public_key; + rollback_index_location_for_partition_map_[partition_name] = + rollback_index_location; + } + void set_expected_public_key_metadata( const std::string& expected_public_key_metadata) { expected_public_key_metadata_ = expected_public_key_metadata; @@ -248,6 +268,16 @@ class FakeAvbOps : public FakeAvbOpsDelegate { size_t value_size, const uint8_t* value) override; + AvbIOResult validate_public_key_for_partition( + AvbOps* ops, + const char* partition, + const uint8_t* public_key_data, + size_t public_key_length, + const uint8_t* public_key_metadata, + size_t public_key_metadata_length, + bool* out_is_trusted, + uint32_t* out_rollback_index_location) override; + AvbIOResult read_permanent_attributes( AvbAtxPermanentAttributes* attributes) override; @@ -271,6 +301,10 @@ class FakeAvbOps : public FakeAvbOpsDelegate { std::string expected_public_key_; std::string expected_public_key_metadata_; + std::map<std::string, std::string> expected_public_key_for_partition_map_; + + std::map<std::string, uint32_t> rollback_index_location_for_partition_map_; + std::map<size_t, uint64_t> stored_rollback_indexes_; std::map<size_t, uint64_t> verified_rollback_indexes_; @@ -328,6 +362,25 @@ class FakeAvbOpsDelegateWithDefaults : public FakeAvbOpsDelegate { out_key_is_trusted); } + AvbIOResult validate_public_key_for_partition( + AvbOps* ops, + const char* partition, + const uint8_t* public_key_data, + size_t public_key_length, + const uint8_t* public_key_metadata, + size_t public_key_metadata_length, + bool* out_key_is_trusted, + uint32_t* out_rollback_index_location) override { + return ops_.validate_public_key_for_partition(ops, + partition, + public_key_data, + public_key_length, + public_key_metadata, + public_key_metadata_length, + out_key_is_trusted, + out_rollback_index_location); + } + AvbIOResult read_rollback_index(AvbOps* ops, size_t rollback_index_slot, uint64_t* out_rollback_index) override { |