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_;