Make it possible to include public key metadata.
am: 18666abc5d
Change-Id: Ia6a69ce521b8a5b58610d4ae3cbfe62596725c98
diff --git a/README b/README
index f1dd122..7bea96c 100644
--- a/README
+++ b/README
@@ -182,8 +182,8 @@
$ avbtool make_vbmeta_image \
--output OUTPUT \
- [--algorithm ALGORITHM] [--key /path/to/key_used_for_signing.bin] \
- [--rollback_index NUMBER] \
+ [--algorithm ALGORITHM] [--key /path/to/key_used_for_signing] \
+ [--public_key_metadata /path/to/pkmd.bin] [--rollback_index NUMBER] \
[--include_descriptors_from_footer /path/to/image.bin] \
[--generate_dm_verity_cmdline_from_footer /path/to/image.bin] \
[--chain_partition part_name:rollback_index_slot:/path/to/key1.bin]
@@ -191,26 +191,26 @@
An integrity footer containing the hash for an entire partition can be
added to an existing image as follows:
- $ avbtool add_hash_footer \
- --image IMAGE \
- --partition_name PARTNAME --partition_size SIZE \
- [--rollback_index NUMBER] \
- [--algorithm ALGORITHM] [--key /path/to/key_used_for_signing.bin] \
- [--hash_algorithm HASH_ALG] [--salt HEX] \
- [--include_descriptors_from_footer /path/to/image.bin] \
+ $ avbtool add_hash_footer \
+ --image IMAGE \
+ --partition_name PARTNAME --partition_size SIZE \
+ [--algorithm ALGORITHM] [--key /path/to/key_used_for_signing] \
+ [--public_key_metadata /path/to/pkmd.bin] [--rollback_index NUMBER] \
+ [--hash_algorithm HASH_ALG] [--salt HEX] \
+ [--include_descriptors_from_footer /path/to/image.bin] \
[--generate_dm_verity_cmdline_from_footer /path/to/image.bin]
An integrity footer containing the root digest and salt for a hashtree
for a partition can be added to an existing image as follows. The
hashtree is also appended to the image.
- $ avbtool add_hashtree_footer \
- --image IMAGE \
- --partition_name PARTNAME --partition_size SIZE \
- [--rollback_index NUMBER] \
- [--algorithm ALGORITHM] [--key /path/to/key_used_for_signing.bin] \
- [--hash_algorithm HASH_ALG] [--salt HEX] [--block_size SIZE] \
- [--include_descriptors_from_footer /path/to/image.bin] \
+ $ avbtool add_hashtree_footer \
+ --image IMAGE \
+ --partition_name PARTNAME --partition_size SIZE \
+ [--algorithm ALGORITHM] [--key /path/to/key_used_for_signing] \
+ [--public_key_metadata /path/to/pkmd.bin] [--rollback_index NUMBER] \
+ [--hash_algorithm HASH_ALG] [--salt HEX] [--block_size SIZE] \
+ [--include_descriptors_from_footer /path/to/image.bin] \
[--generate_dm_verity_cmdline_from_footer /path/to/image.bin]
The integrity footer on an image can be removed from an image. The
@@ -245,9 +245,14 @@
BOARD_AVB_ALGORITHM := SHA512_RSA4096
BOARD_AVB_KEY_PATH := /path/to/rsa_key_4096bits.pem
-Remember that the public part of this key needs to be embedded in the
-bootloader of the device expected to process resulting images. Use
-'avbtool extract_public_key' to do this.
+Remember that the public part of this key needs to be available to the
+bootloader of the device expected to verify resulting images. Use
+'avbtool extract_public_key' to extract the key in the expected format
+("AVB_pk" in the following). If the device is using a different root
+of trust than AVB_pk the --public_key_metadata option can be used to
+embed a blob ("AVB_pkmd" in the following) that can be used to
+e.g. derive AVB_pk. Both AVB_pk and AVB_pkmd is passed to the
+bootloader for validation as part of verifying a slot.
To prevent rollback attakcs, the rollback index should be increased on
a regular basis. The rollback index can be set with the
diff --git a/avbtool b/avbtool
index 599100b..3ace1e3 100755
--- a/avbtool
+++ b/avbtool
@@ -1464,7 +1464,7 @@
SIZE = 256
# Keep in sync with |reserved| field of |AvbVBMetaImageHeader|.
- RESERVED = 152
+ RESERVED = 136
# Keep in sync with |AvbVBMetaImageHeader|.
FORMAT_STRING = ('!4s2L' # magic, 2 x version
@@ -1473,6 +1473,7 @@
'2Q' # offset, size (hash)
'2Q' # offset, size (signature)
'2Q' # offset, size (public key)
+ '2Q' # offset, size (public key metadata)
'2Q' # offset, size (descriptors)
'Q' + # rollback_index
str(RESERVED) + 'x') # padding for reserved bytes
@@ -1493,7 +1494,9 @@
self.authentication_data_block_size, self.auxiliary_data_block_size,
self.algorithm_type, self.hash_offset, self.hash_size,
self.signature_offset, self.signature_size, self.public_key_offset,
- self.public_key_size, self.descriptors_offset, self.descriptors_size,
+ self.public_key_size, self.public_key_metadata_offset,
+ self.public_key_metadata_size, self.descriptors_offset,
+ self.descriptors_size,
self.rollback_index) = struct.unpack(self.FORMAT_STRING, data)
# Nuke NUL-bytes at the end of the string.
if self.magic != 'AVB0':
@@ -1511,6 +1514,8 @@
self.signature_size = 0
self.public_key_offset = 0
self.public_key_size = 0
+ self.public_key_metadata_offset = 0
+ self.public_key_metadata_size = 0
self.descriptors_offset = 0
self.descriptors_size = 0
self.rollback_index = 0
@@ -1526,8 +1531,9 @@
self.header_version_minor, self.authentication_data_block_size,
self.auxiliary_data_block_size, self.algorithm_type, self.hash_offset,
self.hash_size, self.signature_offset, self.signature_size,
- self.public_key_offset, self.public_key_size, self.descriptors_offset,
- self.descriptors_size, self.rollback_index))
+ self.public_key_offset, self.public_key_size,
+ self.public_key_metadata_offset, self.public_key_metadata_size,
+ self.descriptors_offset, self.descriptors_size, self.rollback_index))
def encode(self):
"""Serializes the header (256) to a bytearray().
@@ -1541,7 +1547,8 @@
self.auxiliary_data_block_size, self.algorithm_type,
self.hash_offset, self.hash_size, self.signature_offset,
self.signature_size, self.public_key_offset,
- self.public_key_size, self.descriptors_offset,
+ self.public_key_size, self.public_key_metadata_offset,
+ self.public_key_metadata_size, self.descriptors_offset,
self.descriptors_size, self.rollback_index)
@@ -1777,8 +1784,8 @@
return desc
def make_vbmeta_image(self, output, chain_partitions, algorithm_name,
- key_path, rollback_index, props, props_from_file,
- kernel_cmdlines,
+ key_path, public_key_metadata_path, rollback_index,
+ props, props_from_file, kernel_cmdlines,
generate_dm_verity_cmdline_from_hashtree,
include_descriptors_from_image):
"""Implements the 'make_vbmeta_image' command.
@@ -1788,6 +1795,7 @@
chain_partitions: List of partitions to chain.
algorithm_name: Name of algorithm to use.
key_path: Path to key to use or None.
+ public_key_metadata_path: Path to public key metadata or None.
rollback_index: The rollback index to use.
props: Properties to insert (list of strings of the form 'key:value').
props_from_file: Properties to insert (list of strings 'key:<path>').
@@ -1817,8 +1825,8 @@
descriptors.append(desc)
vbmeta_blob = self._generate_vbmeta_blob(
- algorithm_name, key_path, descriptors, rollback_index, props,
- props_from_file, kernel_cmdlines,
+ algorithm_name, key_path, public_key_metadata_path, descriptors,
+ rollback_index, props, props_from_file, kernel_cmdlines,
generate_dm_verity_cmdline_from_hashtree,
include_descriptors_from_image)
@@ -1826,7 +1834,8 @@
output.seek(0)
output.write(vbmeta_blob)
- def _generate_vbmeta_blob(self, algorithm_name, key_path, descriptors,
+ def _generate_vbmeta_blob(self, algorithm_name, key_path,
+ public_key_metadata_path, descriptors,
rollback_index, props, props_from_file,
kernel_cmdlines,
generate_dm_verity_cmdline_from_hashtree,
@@ -1844,6 +1853,7 @@
Arguments:
algorithm_name: The algorithm name as per the ALGORITHMS dict.
key_path: The path to the .pem file used to sign the blob.
+ public_key_metadata_path: Path to public key metadata or None.
descriptors: A list of descriptors to insert or None.
rollback_index: The rollback index to use.
props: Properties to insert (List of strings of the form 'key:value').
@@ -1918,6 +1928,12 @@
for desc in image_descriptors:
encoded_descriptors.extend(desc.encode())
+ # Load public key metadata blob, if requested.
+ pkmd_blob = []
+ if public_key_metadata_path:
+ with open(public_key_metadata_path) as f:
+ pkmd_blob = f.read()
+
key = None
encoded_key = bytearray()
if alg.public_key_num_bytes > 0:
@@ -1932,14 +1948,16 @@
h = AvbVBMetaHeader()
- # For the Auxiliary data block, descriptors are stored at offset 0
- # and the public key is immediately after that.
+ # For the Auxiliary data block, descriptors are stored at offset 0,
+ # followed by the public key, followed by the public key metadata blob.
h.auxiliary_data_block_size = round_to_multiple(
- len(encoded_descriptors) + len(encoded_key), 64)
+ len(encoded_descriptors) + len(encoded_key) + len(pkmd_blob), 64)
h.descriptors_offset = 0
h.descriptors_size = len(encoded_descriptors)
h.public_key_offset = h.descriptors_size
h.public_key_size = len(encoded_key)
+ h.public_key_metadata_offset = h.public_key_offset + h.public_key_size
+ h.public_key_metadata_size = len(pkmd_blob)
# For the Authentication data block, the hash is first and then
# the signature.
@@ -1962,6 +1980,7 @@
aux_data_blob = bytearray()
aux_data_blob.extend(encoded_descriptors)
aux_data_blob.extend(encoded_key)
+ aux_data_blob.extend(pkmd_blob)
padding_bytes = h.auxiliary_data_block_size - len(aux_data_blob)
aux_data_blob.extend('\0' * padding_bytes)
@@ -2013,7 +2032,8 @@
def add_hash_footer(self, image_filename, partition_size, partition_name,
hash_algorithm, salt, algorithm_name, key_path,
- rollback_index, props, props_from_file, kernel_cmdlines,
+ public_key_metadata_path, rollback_index, props,
+ props_from_file, kernel_cmdlines,
generate_dm_verity_cmdline_from_hashtree,
include_descriptors_from_image):
"""Implementation of the add_hash_footer on unsparse images.
@@ -2026,6 +2046,7 @@
salt: Salt to use as a hexadecimal string or None to use /dev/urandom.
algorithm_name: Name of algorithm to use.
key_path: Path to key to use or None.
+ public_key_metadata_path: Path to public key metadata or None.
rollback_index: Rollback index.
props: Properties to insert (List of strings of the form 'key:value').
props_from_file: Properties to insert (List of strings 'key:<path>').
@@ -2102,8 +2123,8 @@
# Generate the VBMeta footer.
vbmeta_blob = self._generate_vbmeta_blob(
- algorithm_name, key_path, [h_desc], rollback_index, props,
- props_from_file, kernel_cmdlines,
+ algorithm_name, key_path, public_key_metadata_path, [h_desc],
+ rollback_index, props, props_from_file, kernel_cmdlines,
generate_dm_verity_cmdline_from_hashtree,
include_descriptors_from_image)
@@ -2150,8 +2171,8 @@
def add_hashtree_footer(self, image_filename, partition_size, partition_name,
generate_fec, fec_num_roots, hash_algorithm,
block_size, salt, algorithm_name, key_path,
- rollback_index, props, props_from_file,
- kernel_cmdlines,
+ public_key_metadata_path, rollback_index, props,
+ props_from_file, kernel_cmdlines,
generate_dm_verity_cmdline_from_hashtree,
include_descriptors_from_image,
calc_max_image_size):
@@ -2171,6 +2192,7 @@
salt: Salt to use as a hexadecimal string or None to use /dev/urandom.
algorithm_name: Name of algorithm to use.
key_path: Path to key to use or None.
+ public_key_metadata_path: Path to public key metadata or None.
rollback_index: Rollback index.
props: Properties to insert (List of strings of the form 'key:value').
props_from_file: Properties to insert (List of strings 'key:<path>').
@@ -2312,8 +2334,8 @@
# Generate the VBMeta footer and add padding as needed.
vbmeta_offset = tree_offset + len_hashtree_and_fec
vbmeta_blob = self._generate_vbmeta_blob(
- algorithm_name, key_path, [ht_desc], rollback_index, props,
- props_from_file, kernel_cmdlines,
+ algorithm_name, key_path, public_key_metadata_path, [ht_desc],
+ rollback_index, props, props_from_file, kernel_cmdlines,
generate_dm_verity_cmdline_from_hashtree,
include_descriptors_from_image)
padding_needed = (round_to_multiple(len(vbmeta_blob), image.block_size) -
@@ -2522,6 +2544,10 @@
help='Path to RSA private key file',
metavar='KEY',
required=False)
+ sub_parser.add_argument('--public_key_metadata',
+ help='Path to public key metadata file',
+ metavar='KEY_METADATA',
+ required=False)
sub_parser.add_argument('--rollback_index',
help='Rollback Index',
type=parse_number,
@@ -2701,7 +2727,8 @@
def make_vbmeta_image(self, args):
"""Implements the 'make_vbmeta_image' sub-command."""
self.avb.make_vbmeta_image(args.output, args.chain_partition,
- args.algorithm, args.key, args.rollback_index,
+ args.algorithm, args.key,
+ args.public_key_metadata, args.rollback_index,
args.prop, args.prop_from_file,
args.kernel_cmdline,
args.generate_dm_verity_cmdline_from_hashtree,
@@ -2712,8 +2739,9 @@
self.avb.add_hash_footer(args.image.name, args.partition_size,
args.partition_name, args.hash_algorithm,
args.salt, args.algorithm, args.key,
- args.rollback_index, args.prop,
- args.prop_from_file, args.kernel_cmdline,
+ args.public_key_metadata, args.rollback_index,
+ args.prop, args.prop_from_file,
+ args.kernel_cmdline,
args.generate_dm_verity_cmdline_from_hashtree,
args.include_descriptors_from_image)
@@ -2725,6 +2753,7 @@
args.generate_fec, args.fec_num_roots,
args.hash_algorithm, args.block_size,
args.salt, args.algorithm, args.key,
+ args.public_key_metadata,
args.rollback_index, args.prop,
args.prop_from_file,
args.kernel_cmdline,
diff --git a/libavb/avb_ops.h b/libavb/avb_ops.h
index 30309c5..cdc04af 100644
--- a/libavb/avb_ops.h
+++ b/libavb/avb_ops.h
@@ -115,12 +115,22 @@
* embedded key material generated with 'avbtool
* extract_public_key'.
*
+ * The public key is in the array pointed to by |public_key_data|
+ * and is of |public_key_length| bytes.
+ *
+ * If there is no public key metadata (set with the avbtool option
+ * --public_key_metadata) then |public_key_metadata| will be set to
+ * NULL. Otherwise this field points to the data which is
+ * |public_key_metadata_length| bytes long.
+ *
* If AVB_IO_RESULT_OK is returned then |out_is_trusted| is set -
* true if trusted or false if untrusted.
*/
AvbIOResult (*validate_vbmeta_public_key)(AvbOps* ops,
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);
/* Gets the rollback index corresponding to the slot given by
diff --git a/libavb/avb_slot_verify.c b/libavb/avb_slot_verify.c
index 57477d2..82a33a2 100644
--- a/libavb/avb_slot_verify.c
+++ b/libavb/avb_slot_verify.c
@@ -286,6 +286,10 @@
goto out;
}
+ /* Byteswap the header. */
+ avb_vbmeta_image_header_to_host_byte_order((AvbVBMetaImageHeader*)vbmeta_buf,
+ &vbmeta_header);
+
/* Check if key used to make signature matches what is expected. */
if (expected_public_key != NULL) {
avb_assert(!is_main_vbmeta);
@@ -300,10 +304,19 @@
}
} else {
bool key_is_trusted = false;
+ const uint8_t* pk_metadata = NULL;
+ size_t pk_metadata_len = 0;
+
+ if (vbmeta_header.public_key_metadata_size > 0) {
+ pk_metadata = vbmeta_buf + sizeof(AvbVBMetaImageHeader) +
+ vbmeta_header.authentication_data_block_size +
+ vbmeta_header.public_key_metadata_offset;
+ 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, &key_is_trusted);
+ 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;
@@ -322,9 +335,6 @@
}
}
- avb_vbmeta_image_header_to_host_byte_order((AvbVBMetaImageHeader*)vbmeta_buf,
- &vbmeta_header);
-
/* Check rollback index. */
io_ret = ops->read_rollback_index(ops, rollback_index_slot,
&stored_rollback_index);
diff --git a/libavb/avb_vbmeta_image.c b/libavb/avb_vbmeta_image.c
index 23607ed..b4e732a 100644
--- a/libavb/avb_vbmeta_image.c
+++ b/libavb/avb_vbmeta_image.c
@@ -449,6 +449,18 @@
goto out;
}
+ /* Ensure public key metadata (if set) is entirely in the Auxiliary
+ * data block. */
+ if (h.public_key_metadata_size > 0) {
+ uint64_t pubkey_md_end;
+ if (!avb_safe_add(&pubkey_md_end, h.public_key_metadata_offset,
+ h.public_key_metadata_size) ||
+ pubkey_md_end > h.auxiliary_data_block_size) {
+ avb_error("Public key metadata is not entirely in its block.\n");
+ goto out;
+ }
+ }
+
/* Ensure algorithm field is supported. */
if (h.algorithm_type >= _AVB_ALGORITHM_NUM_TYPES) {
avb_error("Invalid or unknown algorithm.\n");
@@ -555,6 +567,10 @@
dest->public_key_offset = avb_be64toh(dest->public_key_offset);
dest->public_key_size = avb_be64toh(dest->public_key_size);
+ dest->public_key_metadata_offset =
+ avb_be64toh(dest->public_key_metadata_offset);
+ dest->public_key_metadata_size = avb_be64toh(dest->public_key_metadata_size);
+
dest->descriptors_offset = avb_be64toh(dest->descriptors_offset);
dest->descriptors_size = avb_be64toh(dest->descriptors_size);
diff --git a/libavb/avb_vbmeta_image.h b/libavb/avb_vbmeta_image.h
index 25d3689..adcb4d4 100644
--- a/libavb/avb_vbmeta_image.h
+++ b/libavb/avb_vbmeta_image.h
@@ -137,20 +137,27 @@
/* 72: Length of the public key data. */
uint64_t public_key_size;
- /* 80: Offset into the "Auxiliary data" block of descriptor data. */
+ /* 80: Offset into the "Auxiliary data" block of public key metadata. */
+ uint64_t public_key_metadata_offset;
+ /* 88: Length of the public key metadata. Must be set to zero if there
+ * is no public key metadata.
+ */
+ uint64_t public_key_metadata_size;
+
+ /* 96: Offset into the "Auxiliary data" block of descriptor data. */
uint64_t descriptors_offset;
- /* 88: Length of descriptor data. */
+ /* 104: Length of descriptor data. */
uint64_t descriptors_size;
- /* 96: The rollback index which can be used to prevent rollback to
+ /* 112: The rollback index which can be used to prevent rollback to
* older versions.
*/
uint64_t rollback_index;
- /* 104: Padding to ensure struct is size AVB_VBMETA_IMAGE_HEADER_SIZE
+ /* 120: Padding to ensure struct is size AVB_VBMETA_IMAGE_HEADER_SIZE
* bytes. This must be set to zeroes.
*/
- uint8_t reserved[152];
+ uint8_t reserved[136];
} AVB_ATTR_PACKED AvbVBMetaImageHeader;
/* Copies |src| to |dest|, byte-swapping fields in the process.
diff --git a/test/avb_slot_verify_unittest.cc b/test/avb_slot_verify_unittest.cc
index df82d02..4d4f565 100644
--- a/test/avb_slot_verify_unittest.cc
+++ b/test/avb_slot_verify_unittest.cc
@@ -62,7 +62,7 @@
"androidboot.slot_suffix=_a androidboot.vbmeta.device_state=locked "
"androidboot.vbmeta.hash_alg=sha256 androidboot.vbmeta.size=1408 "
"androidboot.vbmeta.digest="
- "22cda7342f5ba915f41662975f96f0810ba097399d9d4d4d3847f59c1fe8dfc9",
+ "812d4f9c27f3ae1b3d1448f276b519b85eed0a35af69656b9fd14ec72986af0a",
std::string(slot_data->cmdline));
avb_slot_verify_data_free(slot_data);
}
@@ -84,8 +84,8 @@
"androidboot.slot_suffix=_a androidboot.vbmeta.device_state=locked "
"androidboot.vbmeta.hash_alg=sha512 androidboot.vbmeta.size=1472 "
"androidboot.vbmeta.digest="
- "125592a19a266efe6683de1afee53e2585ccfcf33adb5d6485e6fbfeabccf57134aa8365"
- "aa949a5c6b253bf34956b80e304b7668ee599d207047c8d1bf9574d9",
+ "9bfb82f10fd5436c2f1739a7a2c71f441aa3349aa76a219d1978705092a7d791b291908b"
+ "7b85ac6818fa5bcbdefdf1c3af6b1e56b0a5b9faff73d359258fc4dd",
std::string(slot_data->cmdline));
avb_slot_verify_data_free(slot_data);
}
@@ -109,7 +109,7 @@
"androidboot.slot_suffix=_a androidboot.vbmeta.device_state=unlocked "
"androidboot.vbmeta.hash_alg=sha256 androidboot.vbmeta.size=1408 "
"androidboot.vbmeta.digest="
- "22cda7342f5ba915f41662975f96f0810ba097399d9d4d4d3847f59c1fe8dfc9",
+ "812d4f9c27f3ae1b3d1448f276b519b85eed0a35af69656b9fd14ec72986af0a",
std::string(slot_data->cmdline));
avb_slot_verify_data_free(slot_data);
}
@@ -281,7 +281,7 @@
"androidboot.vbmeta.device_state=locked "
"androidboot.vbmeta.hash_alg=sha256 androidboot.vbmeta.size=1664 "
"androidboot.vbmeta.digest="
- "76b7864c5ff10ed816d9fa973db2abec562badf1e5a0488d8f0240921ad0606a",
+ "90236fbd72c81783915483a54d7c5d26ec9107e708cd95b3052a569d506984a5",
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++) {
@@ -412,7 +412,7 @@
"androidboot.vbmeta.device_state=locked "
"androidboot.vbmeta.hash_alg=sha256 androidboot.vbmeta.size=2560 "
"androidboot.vbmeta.digest="
- "b77c1d6e09dad41563334c605cc0f565b2be221dcd523267a94b9e8ec3aba5f7",
+ "42574881ed55f944e68169918609403e3e74564897d9a4da72d31148b390b34f",
std::string(slot_data->cmdline));
EXPECT_EQ(11UL, slot_data->rollback_indexes[0]);
EXPECT_EQ(12UL, slot_data->rollback_indexes[1]);
@@ -640,7 +640,7 @@
"androidboot.vbmeta.device_state=locked "
"androidboot.vbmeta.hash_alg=sha256 androidboot.vbmeta.size=2560 "
"androidboot.vbmeta.digest="
- "b77c1d6e09dad41563334c605cc0f565b2be221dcd523267a94b9e8ec3aba5f7",
+ "42574881ed55f944e68169918609403e3e74564897d9a4da72d31148b390b34f",
std::string(slot_data->cmdline));
EXPECT_EQ(11UL, slot_data->rollback_indexes[0]);
EXPECT_EQ(12UL, slot_data->rollback_indexes[1]);
@@ -737,3 +737,33 @@
avb_slot_verify_data_free(slot_data);
}
+
+TEST_F(AvbSlotVerifyTest, PublicKeyMetadata) {
+ base::FilePath md_path = GenerateImage("md.bin", 1536);
+
+ GenerateVBMetaImage(
+ "vbmeta_a.img", "SHA256_RSA2048", 0,
+ base::FilePath("test/data/testkey_rsa2048.pem"),
+ base::StringPrintf("--public_key_metadata %s", md_path.value().c_str()));
+
+ ops_.set_expected_public_key(
+ PublicKeyAVB(base::FilePath("test/data/testkey_rsa2048.pem")));
+
+ std::string md_data;
+ ASSERT_TRUE(base::ReadFileToString(md_path, &md_data));
+ ops_.set_expected_public_key_metadata(md_data);
+
+ AvbSlotVerifyData* slot_data = NULL;
+ const char* requested_partitions[] = {"boot", NULL};
+ EXPECT_EQ(
+ AVB_SLOT_VERIFY_RESULT_OK,
+ avb_slot_verify(ops_.avb_ops(), requested_partitions, "_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=2944 "
+ "androidboot.vbmeta.digest="
+ "eb65f3384a8e37b164743d35f70c527769f4a2152f5129151a7987d5d82efa6d",
+ std::string(slot_data->cmdline));
+ avb_slot_verify_data_free(slot_data);
+}
diff --git a/test/avb_vbmeta_image_unittest.cc b/test/avb_vbmeta_image_unittest.cc
index 254feb5..197fdd6 100644
--- a/test/avb_vbmeta_image_unittest.cc
+++ b/test/avb_vbmeta_image_unittest.cc
@@ -289,6 +289,28 @@
NULL, NULL));
}
+TEST_F(VerifyTest, PublicKeyMetadataOutOfBounds) {
+ GenerateVBMetaImage("vbmeta.img", "SHA256_RSA2048", 0,
+ base::FilePath("test/data/testkey_rsa2048.pem"));
+
+ AvbVBMetaImageHeader *h =
+ reinterpret_cast<AvbVBMetaImageHeader *>(vbmeta_image_.data());
+
+ // Check we catch when public key metadata data goes out of bounds.
+ h->public_key_metadata_offset = htobe64(4);
+ h->public_key_metadata_size = htobe64(be64toh(h->auxiliary_data_block_size));
+ EXPECT_EQ(AVB_VBMETA_VERIFY_RESULT_INVALID_VBMETA_HEADER,
+ avb_vbmeta_image_verify(vbmeta_image_.data(), vbmeta_image_.size(),
+ NULL, NULL));
+
+ // Overflow checks.
+ h->public_key_metadata_offset = htobe64(4);
+ h->public_key_metadata_size = htobe64(0xfffffffffffffffeUL);
+ EXPECT_EQ(AVB_VBMETA_VERIFY_RESULT_INVALID_VBMETA_HEADER,
+ avb_vbmeta_image_verify(vbmeta_image_.data(), vbmeta_image_.size(),
+ NULL, NULL));
+}
+
TEST_F(VerifyTest, InvalidAlgorithmField) {
GenerateVBMetaImage("vbmeta.img", "SHA256_RSA2048", 0,
base::FilePath("test/data/testkey_rsa2048.pem"));
@@ -438,6 +460,10 @@
n64++;
h.public_key_size = htobe64(n64);
n64++;
+ h.public_key_metadata_offset = htobe64(n64);
+ n64++;
+ h.public_key_metadata_size = htobe64(n64);
+ n64++;
h.descriptors_offset = htobe64(n64);
n64++;
h.descriptors_size = htobe64(n64);
@@ -472,6 +498,10 @@
n64++;
EXPECT_EQ(n64, s.public_key_size);
n64++;
+ EXPECT_EQ(n64, s.public_key_metadata_offset);
+ n64++;
+ EXPECT_EQ(n64, s.public_key_metadata_size);
+ n64++;
EXPECT_EQ(n64, s.descriptors_offset);
n64++;
EXPECT_EQ(n64, s.descriptors_size);
@@ -482,6 +512,6 @@
// If new fields are added, the following will fail. This is to
// remind that byteswapping code (in avb_util.c) and unittests for
// this should be updated.
- static_assert(offsetof(AvbVBMetaImageHeader, reserved) == 104,
+ static_assert(offsetof(AvbVBMetaImageHeader, reserved) == 120,
"Remember to unittest byteswapping of newly added fields");
}
diff --git a/test/fake_avb_ops.cc b/test/fake_avb_ops.cc
index e4992fb..4a63641 100644
--- a/test/fake_avb_ops.cc
+++ b/test/fake_avb_ops.cc
@@ -129,11 +129,17 @@
AvbIOResult FakeAvbOps::validate_vbmeta_public_key(
AvbOps* ops, 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) {
if (out_key_is_trusted != NULL) {
- *out_key_is_trusted = (public_key_length == expected_public_key_.size() &&
- (memcmp(expected_public_key_.c_str(),
- public_key_data, public_key_length) == 0));
+ bool pk_matches = (public_key_length == expected_public_key_.size() &&
+ (memcmp(expected_public_key_.c_str(), public_key_data,
+ public_key_length) == 0));
+ bool pkmd_matches =
+ (public_key_metadata_length == expected_public_key_metadata_.size() &&
+ (memcmp(expected_public_key_metadata_.c_str(), public_key_metadata,
+ public_key_metadata_length) == 0));
+ *out_key_is_trusted = pk_matches && pkmd_matches;
}
return AVB_IO_RESULT_OK;
}
@@ -203,10 +209,12 @@
static AvbIOResult my_ops_validate_vbmeta_public_key(
AvbOps* ops, 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) {
return ((FakeAvbOpsC*)ops)
->my_ops->validate_vbmeta_public_key(
- ops, public_key_data, public_key_length, out_key_is_trusted);
+ ops, public_key_data, public_key_length, public_key_metadata,
+ public_key_metadata_length, out_key_is_trusted);
}
static AvbIOResult my_ops_read_rollback_index(AvbOps* ops,
diff --git a/test/fake_avb_ops.h b/test/fake_avb_ops.h
index 2a81e17..76d452d 100644
--- a/test/fake_avb_ops.h
+++ b/test/fake_avb_ops.h
@@ -51,6 +51,11 @@
expected_public_key_ = expected_public_key;
}
+ void set_expected_public_key_metadata(
+ const std::string& expected_public_key_metadata) {
+ expected_public_key_metadata_ = expected_public_key_metadata;
+ }
+
void set_stored_rollback_indexes(
const std::vector<uint64_t>& stored_rollback_indexes) {
stored_rollback_indexes_ = stored_rollback_indexes;
@@ -74,6 +79,8 @@
AvbIOResult validate_vbmeta_public_key(AvbOps* ops,
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);
AvbIOResult read_rollback_index(AvbOps* ops, size_t rollback_index_slot,
@@ -95,6 +102,7 @@
base::FilePath partition_dir_;
std::string expected_public_key_;
+ std::string expected_public_key_metadata_;
std::vector<uint64_t> stored_rollback_indexes_;