All of lore.kernel.org
 help / color / mirror / Atom feed
* [U-Boot] [PATCH 0/8] Initial integration of AVB2.0
@ 2018-04-25 13:17 Igor Opaniuk
  2018-04-25 13:17 ` [U-Boot] [PATCH 1/8] avb2.0: add Android Verified Boot 2.0 libraries Igor Opaniuk
                   ` (9 more replies)
  0 siblings, 10 replies; 30+ messages in thread
From: Igor Opaniuk @ 2018-04-25 13:17 UTC (permalink / raw)
  To: u-boot

This series of patches introduces support of Android Verified Boot 2.0,
which provides integrity checking of Android partitions on MMC.

It integrates libavb/libavb_ab into the U-boot, provides implementation of
AvbOps, subset of `avb` commands to run verification chain (and for debugging
purposes), and it enables AVB2.0 verification on AM57xx HS SoC by default. 

Currently, there is still no support for verification of A/B boot slots 
and no rollback protection (for storing rollback indexes 
there are plans to use eMMC RPMB)

Libavb/libavb_ab will be deviated from AOSP upstream in the future,
that's why minimal amount of changes were introduced into the lib sources, 
so checkpatch may fail.

For additional details check [1] AVB 2.0 README and doc/README.avb2, which
is a part of this patchset.

[1] https://android.googlesource.com/platform/external/avb/+/master/README.md

Igor Opaniuk (8):
  avb2.0: add Android Verified Boot 2.0 libraries
  avb2.0: integrate avb 2.0 into the build system
  avb2.0: implement AVB ops
  cmd: avb2.0: avb command for performing verification
  avb2.0: add boot states and dm-verity support
  am57xx_hs: avb2.0: add support of AVB 2.0
  test/py: avb2.0: add tests for avb commands
  doc: avb2.0: add README about AVB2.0 integration

 cmd/Kconfig                                  |   15 +
 cmd/Makefile                                 |    3 +
 cmd/avb.c                                    |  366 ++++++++
 common/Makefile                              |    2 +
 common/avb_verify.c                          |  748 ++++++++++++++++
 configs/am57xx_hs_evm_defconfig              |    3 +
 doc/README.avb2                              |  100 +++
 include/avb/avb_ab_flow.h                    |  235 ++++++
 include/avb/avb_ab_ops.h                     |   61 ++
 include/avb/avb_chain_partition_descriptor.h |   54 ++
 include/avb/avb_crypto.h                     |  147 ++++
 include/avb/avb_descriptor.h                 |  113 +++
 include/avb/avb_footer.h                     |   68 ++
 include/avb/avb_hash_descriptor.h            |   55 ++
 include/avb/avb_hashtree_descriptor.h        |   65 ++
 include/avb/avb_kernel_cmdline_descriptor.h  |   63 ++
 include/avb/avb_ops.h                        |  196 +++++
 include/avb/avb_property_descriptor.h        |   89 ++
 include/avb/avb_rsa.h                        |   55 ++
 include/avb/avb_sha.h                        |   72 ++
 include/avb/avb_slot_verify.h                |  239 ++++++
 include/avb/avb_sysdeps.h                    |   97 +++
 include/avb/avb_util.h                       |  259 ++++++
 include/avb/avb_vbmeta_image.h               |  272 ++++++
 include/avb/avb_version.h                    |   45 +
 include/avb/libavb.h                         |   32 +
 include/avb/libavb_ab.h                      |   22 +
 include/avb_verify.h                         |   97 +++
 include/configs/am57xx_evm.h                 |   11 +
 include/environment/ti/boot.h                |   15 +
 lib/Kconfig                                  |   20 +
 lib/Makefile                                 |    2 +
 lib/libavb/Makefile                          |   15 +
 lib/libavb/avb_chain_partition_descriptor.c  |   46 +
 lib/libavb/avb_crypto.c                      |  355 ++++++++
 lib/libavb/avb_descriptor.c                  |  142 ++++
 lib/libavb/avb_footer.c                      |   36 +
 lib/libavb/avb_hash_descriptor.c             |   43 +
 lib/libavb/avb_hashtree_descriptor.c         |   51 ++
 lib/libavb/avb_kernel_cmdline_descriptor.c   |   40 +
 lib/libavb/avb_property_descriptor.c         |  167 ++++
 lib/libavb/avb_rsa.c                         |  277 ++++++
 lib/libavb/avb_sha256.c                      |  364 ++++++++
 lib/libavb/avb_sha512.c                      |  362 ++++++++
 lib/libavb/avb_slot_verify.c                 | 1169 ++++++++++++++++++++++++++
 lib/libavb/avb_sysdeps_posix.c               |   57 ++
 lib/libavb/avb_util.c                        |  385 +++++++++
 lib/libavb/avb_vbmeta_image.c                |  290 +++++++
 lib/libavb/avb_version.c                     |   16 +
 lib/libavb_ab/Makefile                       |    9 +
 lib/libavb_ab/avb_ab_flow.c                  |  502 +++++++++++
 test/py/tests/test_avb.py                    |  111 +++
 52 files changed, 8058 insertions(+)
 create mode 100644 cmd/avb.c
 create mode 100644 common/avb_verify.c
 create mode 100644 doc/README.avb2
 create mode 100644 include/avb/avb_ab_flow.h
 create mode 100644 include/avb/avb_ab_ops.h
 create mode 100644 include/avb/avb_chain_partition_descriptor.h
 create mode 100644 include/avb/avb_crypto.h
 create mode 100644 include/avb/avb_descriptor.h
 create mode 100644 include/avb/avb_footer.h
 create mode 100644 include/avb/avb_hash_descriptor.h
 create mode 100644 include/avb/avb_hashtree_descriptor.h
 create mode 100644 include/avb/avb_kernel_cmdline_descriptor.h
 create mode 100644 include/avb/avb_ops.h
 create mode 100644 include/avb/avb_property_descriptor.h
 create mode 100644 include/avb/avb_rsa.h
 create mode 100644 include/avb/avb_sha.h
 create mode 100644 include/avb/avb_slot_verify.h
 create mode 100644 include/avb/avb_sysdeps.h
 create mode 100644 include/avb/avb_util.h
 create mode 100644 include/avb/avb_vbmeta_image.h
 create mode 100644 include/avb/avb_version.h
 create mode 100644 include/avb/libavb.h
 create mode 100644 include/avb/libavb_ab.h
 create mode 100644 include/avb_verify.h
 create mode 100644 lib/libavb/Makefile
 create mode 100644 lib/libavb/avb_chain_partition_descriptor.c
 create mode 100644 lib/libavb/avb_crypto.c
 create mode 100644 lib/libavb/avb_descriptor.c
 create mode 100644 lib/libavb/avb_footer.c
 create mode 100644 lib/libavb/avb_hash_descriptor.c
 create mode 100644 lib/libavb/avb_hashtree_descriptor.c
 create mode 100644 lib/libavb/avb_kernel_cmdline_descriptor.c
 create mode 100644 lib/libavb/avb_property_descriptor.c
 create mode 100644 lib/libavb/avb_rsa.c
 create mode 100644 lib/libavb/avb_sha256.c
 create mode 100644 lib/libavb/avb_sha512.c
 create mode 100644 lib/libavb/avb_slot_verify.c
 create mode 100644 lib/libavb/avb_sysdeps_posix.c
 create mode 100644 lib/libavb/avb_util.c
 create mode 100644 lib/libavb/avb_vbmeta_image.c
 create mode 100644 lib/libavb/avb_version.c
 create mode 100644 lib/libavb_ab/Makefile
 create mode 100644 lib/libavb_ab/avb_ab_flow.c
 create mode 100644 test/py/tests/test_avb.py

-- 
2.7.4

^ permalink raw reply	[flat|nested] 30+ messages in thread

* [U-Boot] [PATCH 1/8] avb2.0: add Android Verified Boot 2.0 libraries
  2018-04-25 13:17 [U-Boot] [PATCH 0/8] Initial integration of AVB2.0 Igor Opaniuk
@ 2018-04-25 13:17 ` Igor Opaniuk
  2018-04-25 13:17 ` [U-Boot] [PATCH 2/8] avb2.0: integrate avb 2.0 into the build system Igor Opaniuk
                   ` (8 subsequent siblings)
  9 siblings, 0 replies; 30+ messages in thread
From: Igor Opaniuk @ 2018-04-25 13:17 UTC (permalink / raw)
  To: u-boot

Add libavb and libavb_ab libs (3rd party libraries from AOSP),
that implement support of AVB 2.0. These libraries are utilized for
integrity checking of Android partitions on eMMC (including
A/B configurations, that can be used for seamless system updates)

Libraries were added as it is and minimal changes were introduced
(license text were replaced with SPDX identifiers), because they would be
probably deviated from AOSP upstream in the future

For additional details check [1] AVB 2.0 README.

As libavb/libavb_ab will be deviated from AOSP upstream in the future,
minimal amount of changes were introduces into lib sources, so checkpatch
checks may fail.

[1] https://android.googlesource.com/platform/external/avb/+/master/README.md

Signed-off-by: Igor Opaniuk <igor.opaniuk@linaro.org>
---
 include/avb/avb_ab_flow.h                    |  235 ++++++
 include/avb/avb_ab_ops.h                     |   61 ++
 include/avb/avb_chain_partition_descriptor.h |   54 ++
 include/avb/avb_crypto.h                     |  147 ++++
 include/avb/avb_descriptor.h                 |  113 +++
 include/avb/avb_footer.h                     |   68 ++
 include/avb/avb_hash_descriptor.h            |   55 ++
 include/avb/avb_hashtree_descriptor.h        |   65 ++
 include/avb/avb_kernel_cmdline_descriptor.h  |   63 ++
 include/avb/avb_ops.h                        |  196 +++++
 include/avb/avb_property_descriptor.h        |   89 ++
 include/avb/avb_rsa.h                        |   55 ++
 include/avb/avb_sha.h                        |   72 ++
 include/avb/avb_slot_verify.h                |  239 ++++++
 include/avb/avb_sysdeps.h                    |   97 +++
 include/avb/avb_util.h                       |  259 ++++++
 include/avb/avb_vbmeta_image.h               |  272 ++++++
 include/avb/avb_version.h                    |   45 +
 include/avb/libavb.h                         |   32 +
 include/avb/libavb_ab.h                      |   22 +
 lib/libavb/avb_chain_partition_descriptor.c  |   46 +
 lib/libavb/avb_crypto.c                      |  355 ++++++++
 lib/libavb/avb_descriptor.c                  |  142 ++++
 lib/libavb/avb_footer.c                      |   36 +
 lib/libavb/avb_hash_descriptor.c             |   43 +
 lib/libavb/avb_hashtree_descriptor.c         |   51 ++
 lib/libavb/avb_kernel_cmdline_descriptor.c   |   40 +
 lib/libavb/avb_property_descriptor.c         |  167 ++++
 lib/libavb/avb_rsa.c                         |  277 ++++++
 lib/libavb/avb_sha256.c                      |  364 ++++++++
 lib/libavb/avb_sha512.c                      |  362 ++++++++
 lib/libavb/avb_slot_verify.c                 | 1169 ++++++++++++++++++++++++++
 lib/libavb/avb_sysdeps_posix.c               |   57 ++
 lib/libavb/avb_util.c                        |  385 +++++++++
 lib/libavb/avb_vbmeta_image.c                |  290 +++++++
 lib/libavb/avb_version.c                     |   16 +
 lib/libavb_ab/avb_ab_flow.c                  |  502 +++++++++++
 37 files changed, 6541 insertions(+)
 create mode 100644 include/avb/avb_ab_flow.h
 create mode 100644 include/avb/avb_ab_ops.h
 create mode 100644 include/avb/avb_chain_partition_descriptor.h
 create mode 100644 include/avb/avb_crypto.h
 create mode 100644 include/avb/avb_descriptor.h
 create mode 100644 include/avb/avb_footer.h
 create mode 100644 include/avb/avb_hash_descriptor.h
 create mode 100644 include/avb/avb_hashtree_descriptor.h
 create mode 100644 include/avb/avb_kernel_cmdline_descriptor.h
 create mode 100644 include/avb/avb_ops.h
 create mode 100644 include/avb/avb_property_descriptor.h
 create mode 100644 include/avb/avb_rsa.h
 create mode 100644 include/avb/avb_sha.h
 create mode 100644 include/avb/avb_slot_verify.h
 create mode 100644 include/avb/avb_sysdeps.h
 create mode 100644 include/avb/avb_util.h
 create mode 100644 include/avb/avb_vbmeta_image.h
 create mode 100644 include/avb/avb_version.h
 create mode 100644 include/avb/libavb.h
 create mode 100644 include/avb/libavb_ab.h
 create mode 100644 lib/libavb/avb_chain_partition_descriptor.c
 create mode 100644 lib/libavb/avb_crypto.c
 create mode 100644 lib/libavb/avb_descriptor.c
 create mode 100644 lib/libavb/avb_footer.c
 create mode 100644 lib/libavb/avb_hash_descriptor.c
 create mode 100644 lib/libavb/avb_hashtree_descriptor.c
 create mode 100644 lib/libavb/avb_kernel_cmdline_descriptor.c
 create mode 100644 lib/libavb/avb_property_descriptor.c
 create mode 100644 lib/libavb/avb_rsa.c
 create mode 100644 lib/libavb/avb_sha256.c
 create mode 100644 lib/libavb/avb_sha512.c
 create mode 100644 lib/libavb/avb_slot_verify.c
 create mode 100644 lib/libavb/avb_sysdeps_posix.c
 create mode 100644 lib/libavb/avb_util.c
 create mode 100644 lib/libavb/avb_vbmeta_image.c
 create mode 100644 lib/libavb/avb_version.c
 create mode 100644 lib/libavb_ab/avb_ab_flow.c

diff --git a/include/avb/avb_ab_flow.h b/include/avb/avb_ab_flow.h
new file mode 100644
index 0000000..07db2d5
--- /dev/null
+++ b/include/avb/avb_ab_flow.h
@@ -0,0 +1,235 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * SPDX-License-Identifier:	MIT
+ */
+
+#if !defined(AVB_INSIDE_LIBAVB_AB_H) && !defined(AVB_COMPILATION)
+#error \
+    "Never include this file directly, include libavb_ab/libavb_ab.h instead."
+#endif
+
+#ifndef AVB_AB_FLOW_H_
+#define AVB_AB_FLOW_H_
+
+#include "avb/avb_ab_ops.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Magic for the A/B struct when serialized. */
+#define AVB_AB_MAGIC "\0AB0"
+#define AVB_AB_MAGIC_LEN 4
+
+/* Versioning for the on-disk A/B metadata - keep in sync with avbtool. */
+#define AVB_AB_MAJOR_VERSION 1
+#define AVB_AB_MINOR_VERSION 0
+
+/* Size of AvbABData struct. */
+#define AVB_AB_DATA_SIZE 32
+
+/* Maximum values for slot data */
+#define AVB_AB_MAX_PRIORITY 15
+#define AVB_AB_MAX_TRIES_REMAINING 7
+
+/* Struct used for recording per-slot metadata.
+ *
+ * When serialized, data is stored in network byte-order.
+ */
+typedef struct AvbABSlotData {
+  /* Slot priority. Valid values range from 0 to AVB_AB_MAX_PRIORITY,
+   * both inclusive with 1 being the lowest and AVB_AB_MAX_PRIORITY
+   * being the highest. The special value 0 is used to indicate the
+   * slot is unbootable.
+   */
+  uint8_t priority;
+
+  /* Number of times left attempting to boot this slot ranging from 0
+   * to AVB_AB_MAX_TRIES_REMAINING.
+   */
+  uint8_t tries_remaining;
+
+  /* Non-zero if this slot has booted successfully, 0 otherwise. */
+  uint8_t successful_boot;
+
+  /* Reserved for future use. */
+  uint8_t reserved[1];
+} AVB_ATTR_PACKED AvbABSlotData;
+
+/* Struct used for recording A/B metadata.
+ *
+ * When serialized, data is stored in network byte-order.
+ */
+typedef struct AvbABData {
+  /* Magic number used for identification - see AVB_AB_MAGIC. */
+  uint8_t magic[AVB_AB_MAGIC_LEN];
+
+  /* Version of on-disk struct - see AVB_AB_{MAJOR,MINOR}_VERSION. */
+  uint8_t version_major;
+  uint8_t version_minor;
+
+  /* Padding to ensure |slots| field start eight bytes in. */
+  uint8_t reserved1[2];
+
+  /* Per-slot metadata. */
+  AvbABSlotData slots[2];
+
+  /* Reserved for future use. */
+  uint8_t reserved2[12];
+
+  /* CRC32 of all 28 bytes preceding this field. */
+  uint32_t crc32;
+} AVB_ATTR_PACKED AvbABData;
+
+/* Copies |src| to |dest|, byte-swapping fields in the
+ * process. Returns false if the data is invalid (e.g. wrong magic,
+ * wrong CRC32 etc.), true otherwise.
+ */
+bool avb_ab_data_verify_and_byteswap(const AvbABData* src, AvbABData* dest);
+
+/* Copies |src| to |dest|, byte-swapping fields in the process. Also
+ * updates the |crc32| field in |dest|.
+ */
+void avb_ab_data_update_crc_and_byteswap(const AvbABData* src, AvbABData* dest);
+
+/* Initializes |data| such that it has two slots and both slots have
+ * maximum tries remaining. The CRC is not set.
+ */
+void avb_ab_data_init(AvbABData* data);
+
+/* Reads A/B metadata from the 'misc' partition using |ops|. Returned
+ * data is properly byteswapped. Returns AVB_IO_RESULT_OK on
+ * success, error code otherwise.
+ *
+ * If the data read from disk is invalid (e.g. wrong magic or CRC
+ * checksum failure), the metadata will be reset using
+ * avb_ab_data_init() and then written to disk.
+ */
+AvbIOResult avb_ab_data_read(AvbABOps* ab_ops, AvbABData* data);
+
+/* Writes A/B metadata to the 'misc' partition using |ops|. This will
+ * byteswap and update the CRC as needed. Returns AVB_IO_RESULT_OK on
+ * success, error code otherwise.
+ */
+AvbIOResult avb_ab_data_write(AvbABOps* ab_ops, const AvbABData* data);
+
+/* Return codes used in avb_ab_flow(), see that function for
+ * documentation of each value.
+ */
+typedef enum {
+  AVB_AB_FLOW_RESULT_OK,
+  AVB_AB_FLOW_RESULT_OK_WITH_VERIFICATION_ERROR,
+  AVB_AB_FLOW_RESULT_ERROR_OOM,
+  AVB_AB_FLOW_RESULT_ERROR_IO,
+  AVB_AB_FLOW_RESULT_ERROR_NO_BOOTABLE_SLOTS
+} AvbABFlowResult;
+
+/* Get a textual representation of |result|. */
+const char* avb_ab_flow_result_to_string(AvbABFlowResult result);
+
+/* High-level function to select a slot to boot. The following
+ * algorithm is used:
+ *
+ * 1. A/B metadata is loaded and validated using the
+ * read_ab_metadata() operation. Typically this means it's read from
+ * the 'misc' partition and if it's invalid then it's reset using
+ * avb_ab_data_init() and this reset metadata is returned.
+ *
+ * 2. All bootable slots listed in the A/B metadata are verified using
+ * avb_slot_verify(). If a slot is invalid or if it fails verification
+ * (and |allow_verification_error| is false, see below), it will be
+ * marked as unbootable in the A/B metadata and the metadata will be
+ * saved to disk before returning.
+ *
+ * 3. If there are no bootable slots, the value
+ * AVB_AB_FLOW_RESULT_ERROR_NO_BOOTABLE_SLOTS is returned.
+ *
+ * 4. For each bootable slot, the Stored Rollback Indexes are updated
+ * such that for each rollback index location, the Stored Rollback
+ * Index is the largest number smaller than or equal to the Rollback
+ * Index of each slot.
+ *
+ * 5. The bootable slot with the highest priority is selected and
+ * returned in |out_data|. If this slot is already marked as
+ * successful, the A/B metadata is not modified. However, if the slot
+ * is not marked as bootable its |tries_remaining| count is
+ * decremented and the A/B metadata is saved to disk before returning.
+ * In either case the value AVB_AB_FLOW_RESULT_OK is returning.
+ *
+ * The partitions to load is given in |requested_partitions| as a
+ * NULL-terminated array of NUL-terminated strings. Typically the
+ * |requested_partitions| array only contains a single item for the
+ * boot partition, 'boot'.
+ *
+ * If the device is unlocked (and _only_ if it's unlocked), true
+ * should be passed in the |allow_verification_error| parameter. This
+ * will allow considering slots as verified even when
+ * avb_slot_verify() returns
+ * AVB_SLOT_VERIFY_RESULT_ERROR_PUBLIC_KEY_REJECTED,
+ * AVB_SLOT_VERIFY_RESULT_ERROR_VERIFICATION, or
+ * AVB_SLOT_VERIFY_RESULT_ERROR_ROLLBACK_INDEX for the slot in
+ * question.
+ *
+ * Note that androidboot.slot_suffix is not set in the |cmdline| field
+ * in |AvbSlotVerifyData| - you will have to pass this command-line
+ * option yourself.
+ *
+ * If a slot was selected and it verified then AVB_AB_FLOW_RESULT_OK
+ * is returned.
+ *
+ * If a slot was selected but it didn't verify then
+ * AVB_AB_FLOW_RESULT_OK_WITH_VERIFICATION_ERROR is returned. This can
+ * only happen when |allow_verification_error| is true.
+ *
+ * If an I/O operation - such as loading/saving metadata or checking
+ * rollback indexes - fail, the value AVB_AB_FLOW_RESULT_ERROR_IO is
+ * returned.
+ *
+ * If memory allocation fails, AVB_AB_FLOW_RESULT_ERROR_OOM is
+ * returned.
+ *
+ * Reasonable behavior for handling AVB_AB_FLOW_RESULT_ERROR_NO_BOOTABLE_SLOTS
+ * is to initiate device repair (which is device-dependent).
+ */
+AvbABFlowResult avb_ab_flow(AvbABOps* ab_ops,
+                            const char* const* requested_partitions,
+                            bool allow_verification_error,
+                            AvbSlotVerifyData** out_data);
+
+/* Marks the slot with the given slot number as active. Returns
+ * AVB_IO_RESULT_OK on success, error code otherwise.
+ *
+ * This function is typically used by the OS updater when completing
+ * an update. It can also used by the firmware for implementing the
+ * "set_active" command.
+ */
+AvbIOResult avb_ab_mark_slot_active(AvbABOps* ab_ops, unsigned int slot_number);
+
+/* Marks the slot with the given slot number as unbootable. Returns
+ * AVB_IO_RESULT_OK on success, error code otherwise.
+ *
+ * This function is typically used by the OS updater before writing to
+ * a slot.
+ */
+AvbIOResult avb_ab_mark_slot_unbootable(AvbABOps* ab_ops,
+                                        unsigned int slot_number);
+
+/* Marks the slot with the given slot number as having booted
+ * successfully. Returns AVB_IO_RESULT_OK on success, error code
+ * otherwise.
+ *
+ * Calling this on an unbootable slot is an error - AVB_IO_RESULT_OK
+ * will be returned yet the function will have no side-effects.
+ *
+ * This function is typically used by the OS updater after having
+ * confirmed that the slot works as intended.
+ */
+AvbIOResult avb_ab_mark_slot_successful(AvbABOps* ab_ops,
+                                        unsigned int slot_number);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* AVB_AB_FLOW_H_ */
diff --git a/include/avb/avb_ab_ops.h b/include/avb/avb_ab_ops.h
new file mode 100644
index 0000000..2e0055c
--- /dev/null
+++ b/include/avb/avb_ab_ops.h
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * SPDX-License-Identifier:	MIT
+ */
+
+#if !defined(AVB_INSIDE_LIBAVB_AB_H) && !defined(AVB_COMPILATION)
+#error \
+    "Never include this file directly, include libavb_ab/libavb_ab.h instead."
+#endif
+
+#ifndef AVB_AB_OPS_H_
+#define AVB_AB_OPS_H_
+
+#include <avb/libavb.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct AvbABOps;
+typedef struct AvbABOps AvbABOps;
+
+struct AvbABData;
+
+/* High-level operations/functions/methods for A/B that are platform
+ * dependent.
+ */
+struct AvbABOps {
+  /* Operations from libavb. */
+  AvbOps* ops;
+
+  /* Reads A/B metadata from persistent storage. Returned data is
+   * properly byteswapped. Returns AVB_IO_RESULT_OK on success, error
+   * code otherwise.
+   *
+   * If the data read is invalid (e.g. wrong magic or CRC checksum
+   * failure), the metadata shoule be reset using avb_ab_data_init()
+   * and then written to persistent storage.
+   *
+   * Implementations will typically want to use avb_ab_data_read()
+   * here to use the 'misc' partition for persistent storage.
+   */
+  AvbIOResult (*read_ab_metadata)(AvbABOps* ab_ops, struct AvbABData* data);
+
+  /* Writes A/B metadata to persistent storage. This will byteswap and
+   * update the CRC as needed. Returns AVB_IO_RESULT_OK on success,
+   * error code otherwise.
+   *
+   * Implementations will typically want to use avb_ab_data_write()
+   * here to use the 'misc' partition for persistent storage.
+   */
+  AvbIOResult (*write_ab_metadata)(AvbABOps* ab_ops,
+                                   const struct AvbABData* data);
+};
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* AVB_AB_OPS_H_ */
diff --git a/include/avb/avb_chain_partition_descriptor.h b/include/avb/avb_chain_partition_descriptor.h
new file mode 100644
index 0000000..a841828
--- /dev/null
+++ b/include/avb/avb_chain_partition_descriptor.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * SPDX-License-Identifier:	MIT
+ */
+
+#if !defined(AVB_INSIDE_LIBAVB_H) && !defined(AVB_COMPILATION)
+#error "Never include this file directly, include libavb.h instead."
+#endif
+
+#ifndef AVB_CHAIN_PARTITION_DESCRIPTOR_H_
+#define AVB_CHAIN_PARTITION_DESCRIPTOR_H_
+
+#include "avb_descriptor.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* A descriptor containing a pointer to signed integrity data stored
+ * on another partition. The descriptor contains the partition name in
+ * question (without the A/B suffix), the public key used to sign the
+ * integrity data, and rollback index location to use for rollback
+ * protection.
+ *
+ * Following this struct are |partition_name_len| bytes of the
+ * partition name (UTF-8 encoded) and |public_key_len| bytes of the
+ * public key.
+ *
+ * The |reserved| field is for future expansion and must be set to NUL
+ * bytes.
+ */
+typedef struct AvbChainPartitionDescriptor {
+  AvbDescriptor parent_descriptor;
+  uint32_t rollback_index_location;
+  uint32_t partition_name_len;
+  uint32_t public_key_len;
+  uint8_t reserved[64];
+} AVB_ATTR_PACKED AvbChainPartitionDescriptor;
+
+/* Copies |src| to |dest| and validates, byte-swapping fields in the
+ * process if needed. Returns true if valid, false if invalid.
+ *
+ * Data following the struct is not validated nor copied.
+ */
+bool avb_chain_partition_descriptor_validate_and_byteswap(
+    const AvbChainPartitionDescriptor* src,
+    AvbChainPartitionDescriptor* dest) AVB_ATTR_WARN_UNUSED_RESULT;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* AVB_CHAIN_PARTITION_DESCRIPTOR_H_ */
diff --git a/include/avb/avb_crypto.h b/include/avb/avb_crypto.h
new file mode 100644
index 0000000..dbc7498
--- /dev/null
+++ b/include/avb/avb_crypto.h
@@ -0,0 +1,147 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * SPDX-License-Identifier:	MIT
+ */
+
+#if !defined(AVB_INSIDE_LIBAVB_H) && !defined(AVB_COMPILATION)
+#error "Never include this file directly, include libavb.h instead."
+#endif
+
+#ifndef AVB_CRYPTO_H_
+#define AVB_CRYPTO_H_
+
+#include "avb_sysdeps.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Size of a RSA-2048 signature. */
+#define AVB_RSA2048_NUM_BYTES 256
+
+/* Size of a RSA-4096 signature. */
+#define AVB_RSA4096_NUM_BYTES 512
+
+/* Size of a RSA-8192 signature. */
+#define AVB_RSA8192_NUM_BYTES 1024
+
+/* Size in bytes of a SHA-256 digest. */
+#define AVB_SHA256_DIGEST_SIZE 32
+
+/* Size in bytes of a SHA-512 digest. */
+#define AVB_SHA512_DIGEST_SIZE 64
+
+/* Algorithms that can be used in the vbmeta image for
+ * verification. An algorithm consists of a hash type and a signature
+ * type.
+ *
+ * The data used to calculate the hash is the three blocks mentioned
+ * in the documentation for |AvbVBMetaImageHeader| except for the data
+ * in the "Authentication data" block.
+ *
+ * For signatures with RSA keys, PKCS v1.5 padding is used. The public
+ * key data is stored in the auxiliary data block, see
+ * |AvbRSAPublicKeyHeader| for the serialization format.
+ *
+ * Each algorithm type is described below:
+ *
+ * AVB_ALGORITHM_TYPE_NONE: There is no hash, no signature of the
+ * data, and no public key. The data cannot be verified. The fields
+ * |hash_size|, |signature_size|, and |public_key_size| must be zero.
+ *
+ * AVB_ALGORITHM_TYPE_SHA256_RSA2048: The hash function used is
+ * SHA-256, resulting in 32 bytes of hash digest data. This hash is
+ * signed with a 2048-bit RSA key. The field |hash_size| must be 32,
+ * |signature_size| must be 256, and the public key data must have
+ * |key_num_bits| set to 2048.
+ *
+ * AVB_ALGORITHM_TYPE_SHA256_RSA4096: Like above, but only with
+ * a 4096-bit RSA key and |signature_size| set to 512.
+ *
+ * AVB_ALGORITHM_TYPE_SHA256_RSA8192: Like above, but only with
+ * a 8192-bit RSA key and |signature_size| set to 1024.
+ *
+ * AVB_ALGORITHM_TYPE_SHA512_RSA2048: The hash function used is
+ * SHA-512, resulting in 64 bytes of hash digest data. This hash is
+ * signed with a 2048-bit RSA key. The field |hash_size| must be 64,
+ * |signature_size| must be 256, and the public key data must have
+ * |key_num_bits| set to 2048.
+ *
+ * AVB_ALGORITHM_TYPE_SHA512_RSA4096: Like above, but only with
+ * a 4096-bit RSA key and |signature_size| set to 512.
+ *
+ * AVB_ALGORITHM_TYPE_SHA512_RSA8192: Like above, but only with
+ * a 8192-bit RSA key and |signature_size| set to 1024.
+ */
+typedef enum {
+  AVB_ALGORITHM_TYPE_NONE,
+  AVB_ALGORITHM_TYPE_SHA256_RSA2048,
+  AVB_ALGORITHM_TYPE_SHA256_RSA4096,
+  AVB_ALGORITHM_TYPE_SHA256_RSA8192,
+  AVB_ALGORITHM_TYPE_SHA512_RSA2048,
+  AVB_ALGORITHM_TYPE_SHA512_RSA4096,
+  AVB_ALGORITHM_TYPE_SHA512_RSA8192,
+  _AVB_ALGORITHM_NUM_TYPES
+} AvbAlgorithmType;
+
+/* Holds algorithm-specific data. The |padding| is needed by avb_rsa_verify. */
+typedef struct {
+  const uint8_t* padding;
+  size_t padding_len;
+  size_t hash_len;
+} AvbAlgorithmData;
+
+/* Provides algorithm-specific data for a given |algorithm|. Returns NULL if
+ * |algorithm| is invalid.
+ */
+const AvbAlgorithmData* avb_get_algorithm_data(AvbAlgorithmType algorithm)
+    AVB_ATTR_WARN_UNUSED_RESULT;
+
+/* The header for a serialized RSA public key.
+ *
+ * The size of the key is given by |key_num_bits|, for example 2048
+ * for a RSA-2048 key. By definition, a RSA public key is the pair (n,
+ * e) where |n| is the modulus (which can be represented in
+ * |key_num_bits| bits) and |e| is the public exponent. The exponent
+ * is not stored since it's assumed to always be 65537.
+ *
+ * To optimize verification, the key block includes two precomputed
+ * values, |n0inv| (fits in 32 bits) and |rr| and can always be
+ * represented in |key_num_bits|.
+
+ * The value |n0inv| is the value -1/n[0] (mod 2^32). The value |rr|
+ * is (2^key_num_bits)^2 (mod n).
+ *
+ * Following this header is |key_num_bits| bits of |n|, then
+ * |key_num_bits| bits of |rr|. Both values are stored with most
+ * significant bit first. Each serialized number takes up
+ * |key_num_bits|/8 bytes.
+ *
+ * All fields in this struct are stored in network byte order when
+ * serialized.  To generate a copy with fields swapped to native byte
+ * order, use the function avb_rsa_public_key_header_validate_and_byteswap().
+ *
+ * The avb_rsa_verify() function expects a key in this serialized
+ * format.
+ *
+ * The 'avbtool extract_public_key' command can be used to generate a
+ * serialized RSA public key.
+ */
+typedef struct AvbRSAPublicKeyHeader {
+  uint32_t key_num_bits;
+  uint32_t n0inv;
+} AVB_ATTR_PACKED AvbRSAPublicKeyHeader;
+
+/* Copies |src| to |dest| and validates, byte-swapping fields in the
+ * process if needed. Returns true if valid, false if invalid.
+ */
+bool avb_rsa_public_key_header_validate_and_byteswap(
+    const AvbRSAPublicKeyHeader* src,
+    AvbRSAPublicKeyHeader* dest) AVB_ATTR_WARN_UNUSED_RESULT;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* AVB_CRYPTO_H_ */
diff --git a/include/avb/avb_descriptor.h b/include/avb/avb_descriptor.h
new file mode 100644
index 0000000..13a3efd
--- /dev/null
+++ b/include/avb/avb_descriptor.h
@@ -0,0 +1,113 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * SPDX-License-Identifier:	MIT
+ */
+
+#if !defined(AVB_INSIDE_LIBAVB_H) && !defined(AVB_COMPILATION)
+#error "Never include this file directly, include libavb.h instead."
+#endif
+
+#ifndef AVB_DESCRIPTOR_H_
+#define AVB_DESCRIPTOR_H_
+
+#include "avb_sysdeps.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Well-known descriptor tags.
+ *
+ * AVB_DESCRIPTOR_TAG_PROPERTY: see |AvbPropertyDescriptor| struct.
+ * AVB_DESCRIPTOR_TAG_HASHTREE: see |AvbHashtreeDescriptor| struct.
+ * AVB_DESCRIPTOR_TAG_HASH: see |AvbHashDescriptor| struct.
+ * AVB_DESCRIPTOR_TAG_KERNEL_CMDLINE: see |AvbKernelCmdlineDescriptor| struct.
+ * AVB_DESCRIPTOR_TAG_CHAIN_PARTITION: see |AvbChainPartitionDescriptor| struct.
+ */
+typedef enum {
+  AVB_DESCRIPTOR_TAG_PROPERTY,
+  AVB_DESCRIPTOR_TAG_HASHTREE,
+  AVB_DESCRIPTOR_TAG_HASH,
+  AVB_DESCRIPTOR_TAG_KERNEL_CMDLINE,
+  AVB_DESCRIPTOR_TAG_CHAIN_PARTITION,
+} AvbDescriptorTag;
+
+/* The header for a serialized descriptor.
+ *
+ * A descriptor always have two fields, a |tag| (denoting its type,
+ * see the |AvbDescriptorTag| enumeration) and the size of the bytes
+ * following, |num_bytes_following|.
+ *
+ * For padding, |num_bytes_following| is always a multiple of 8.
+ */
+typedef struct AvbDescriptor {
+  uint64_t tag;
+  uint64_t num_bytes_following;
+} AVB_ATTR_PACKED AvbDescriptor;
+
+/* Copies |src| to |dest| and validates, byte-swapping fields in the
+ * process if needed. Returns true if valid, false if invalid.
+ *
+ * Data following the struct is not validated nor copied.
+ */
+bool avb_descriptor_validate_and_byteswap(
+    const AvbDescriptor* src, AvbDescriptor* dest) AVB_ATTR_WARN_UNUSED_RESULT;
+
+/* Signature for callback function used in avb_descriptor_foreach().
+ * The passed in descriptor is given by |descriptor| and the
+ * |user_data| passed to avb_descriptor_foreach() function is in
+ * |user_data|. Return true to continue iterating, false to stop
+ * iterating.
+ *
+ * Note that |descriptor| points into the image passed to
+ * avb_descriptor_foreach() - all fields need to be byteswapped!
+ */
+typedef bool AvbDescriptorForeachFunc(const AvbDescriptor* descriptor,
+                                      void* user_data);
+
+/* Convenience function to iterate over all descriptors in an vbmeta
+ * image.
+ *
+ * The function given by |foreach_func| will be called for each
+ * descriptor. The given function should return true to continue
+ * iterating, false to stop.
+ *
+ * The |user_data| parameter will be passed to |foreach_func|.
+ *
+ * Returns false if the iteration was short-circuited, that is if
+ * an invocation of |foreach_func| returned false.
+ *
+ * Before using this function, you MUST verify |image_data| with
+ * avb_vbmeta_image_verify() and reject it unless it's signed by a known
+ * good public key. Additionally, |image_data| must be word-aligned.
+ */
+bool avb_descriptor_foreach(const uint8_t* image_data,
+                            size_t image_size,
+                            AvbDescriptorForeachFunc foreach_func,
+                            void* user_data);
+
+/* Gets all descriptors in a vbmeta image.
+ *
+ * The return value is a NULL-pointer terminated array of
+ * AvbDescriptor pointers. Free with avb_free() when you are done with
+ * it. If |out_num_descriptors| is non-NULL, the number of descriptors
+ * will be returned there.
+ *
+ * Note that each AvbDescriptor pointer in the array points into
+ * |image_data| - all fields need to be byteswapped!
+ *
+ * Before using this function, you MUST verify |image_data| with
+ * avb_vbmeta_image_verify() and reject it unless it's signed by a known
+ * good public key. Additionally, |image_data| must be word-aligned.
+ */
+const AvbDescriptor** avb_descriptor_get_all(const uint8_t* image_data,
+                                             size_t image_size,
+                                             size_t* out_num_descriptors)
+    AVB_ATTR_WARN_UNUSED_RESULT;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* AVB_DESCRIPTOR_H_ */
diff --git a/include/avb/avb_footer.h b/include/avb/avb_footer.h
new file mode 100644
index 0000000..975136a
--- /dev/null
+++ b/include/avb/avb_footer.h
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * SPDX-License-Identifier:	MIT
+ */
+
+#if !defined(AVB_INSIDE_LIBAVB_H) && !defined(AVB_COMPILATION)
+#error "Never include this file directly, include libavb.h instead."
+#endif
+
+#ifndef AVB_FOOTER_H_
+#define AVB_FOOTER_H_
+
+#include "avb_sysdeps.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Magic for the footer. */
+#define AVB_FOOTER_MAGIC "AVBf"
+#define AVB_FOOTER_MAGIC_LEN 4
+
+/* Size of the footer. */
+#define AVB_FOOTER_SIZE 64
+
+/* The current footer version used - keep in sync with avbtool. */
+#define AVB_FOOTER_VERSION_MAJOR 1
+#define AVB_FOOTER_VERSION_MINOR 0
+
+/* The struct used as a footer used on partitions, used to find the
+ * AvbVBMetaImageHeader struct. This struct is always stored at the
+ * end of a partition.
+ */
+typedef struct AvbFooter {
+  /*   0: Four bytes equal to "AVBf" (AVB_FOOTER_MAGIC). */
+  uint8_t magic[AVB_FOOTER_MAGIC_LEN];
+  /*   4: The major version of the footer struct. */
+  uint32_t version_major;
+  /*   8: The minor version of the footer struct. */
+  uint32_t version_minor;
+
+  /*  12: The original size of the image on the partition. */
+  uint64_t original_image_size;
+
+  /*  20: The offset of the |AvbVBMetaImageHeader| struct. */
+  uint64_t vbmeta_offset;
+
+  /*  28: The size of the vbmeta block (header + auth + aux blocks). */
+  uint64_t vbmeta_size;
+
+  /*  36: Padding to ensure struct is size AVB_FOOTER_SIZE bytes. This
+   * must be set to zeroes.
+   */
+  uint8_t reserved[28];
+} AVB_ATTR_PACKED AvbFooter;
+
+/* Copies |src| to |dest| and validates, byte-swapping fields in the
+ * process if needed. Returns true if valid, false if invalid.
+ */
+bool avb_footer_validate_and_byteswap(const AvbFooter* src, AvbFooter* dest)
+    AVB_ATTR_WARN_UNUSED_RESULT;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* AVB_FOOTER_H_ */
diff --git a/include/avb/avb_hash_descriptor.h b/include/avb/avb_hash_descriptor.h
new file mode 100644
index 0000000..1e4f81c
--- /dev/null
+++ b/include/avb/avb_hash_descriptor.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * SPDX-License-Identifier:	MIT
+ */
+
+#if !defined(AVB_INSIDE_LIBAVB_H) && !defined(AVB_COMPILATION)
+#error "Never include this file directly, include libavb.h instead."
+#endif
+
+#ifndef AVB_HASH_DESCRIPTOR_H_
+#define AVB_HASH_DESCRIPTOR_H_
+
+#include "avb_descriptor.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* A descriptor containing information about hash for an image.
+ *
+ * This descriptor is typically used for boot partitions to verify the
+ * entire kernel+initramfs image before executing it.
+ *
+ * Following this struct are |partition_name_len| bytes of the
+ * partition name (UTF-8 encoded), |salt_len| bytes of salt, and then
+ * |digest_len| bytes of the digest.
+ *
+ * The |reserved| field is for future expansion and must be set to NUL
+ * bytes.
+ */
+typedef struct AvbHashDescriptor {
+  AvbDescriptor parent_descriptor;
+  uint64_t image_size;
+  uint8_t hash_algorithm[32];
+  uint32_t partition_name_len;
+  uint32_t salt_len;
+  uint32_t digest_len;
+  uint8_t reserved[64];
+} AVB_ATTR_PACKED AvbHashDescriptor;
+
+/* Copies |src| to |dest| and validates, byte-swapping fields in the
+ * process if needed. Returns true if valid, false if invalid.
+ *
+ * Data following the struct is not validated nor copied.
+ */
+bool avb_hash_descriptor_validate_and_byteswap(const AvbHashDescriptor* src,
+                                               AvbHashDescriptor* dest)
+    AVB_ATTR_WARN_UNUSED_RESULT;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* AVB_HASH_DESCRIPTOR_H_ */
diff --git a/include/avb/avb_hashtree_descriptor.h b/include/avb/avb_hashtree_descriptor.h
new file mode 100644
index 0000000..3325115
--- /dev/null
+++ b/include/avb/avb_hashtree_descriptor.h
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * SPDX-License-Identifier:	MIT
+ */
+
+#if !defined(AVB_INSIDE_LIBAVB_H) && !defined(AVB_COMPILATION)
+#error "Never include this file directly, include libavb.h instead."
+#endif
+
+#ifndef AVB_HASHTREE_DESCRIPTOR_H_
+#define AVB_HASHTREE_DESCRIPTOR_H_
+
+#include "avb_descriptor.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* A descriptor containing information about a dm-verity hashtree.
+ *
+ * Hash-trees are used to verify large partitions typically containing
+ * file systems. See
+ * https://gitlab.com/cryptsetup/cryptsetup/wikis/DMVerity for more
+ * information about dm-verity.
+ *
+ * Following this struct are |partition_name_len| bytes of the
+ * partition name (UTF-8 encoded), |salt_len| bytes of salt, and then
+ * |root_digest_len| bytes of the root digest.
+ *
+ * The |reserved| field is for future expansion and must be set to NUL
+ * bytes.
+ */
+typedef struct AvbHashtreeDescriptor {
+  AvbDescriptor parent_descriptor;
+  uint32_t dm_verity_version;
+  uint64_t image_size;
+  uint64_t tree_offset;
+  uint64_t tree_size;
+  uint32_t data_block_size;
+  uint32_t hash_block_size;
+  uint32_t fec_num_roots;
+  uint64_t fec_offset;
+  uint64_t fec_size;
+  uint8_t hash_algorithm[32];
+  uint32_t partition_name_len;
+  uint32_t salt_len;
+  uint32_t root_digest_len;
+  uint8_t reserved[64];
+} AVB_ATTR_PACKED AvbHashtreeDescriptor;
+
+/* Copies |src| to |dest| and validates, byte-swapping fields in the
+ * process if needed. Returns true if valid, false if invalid.
+ *
+ * Data following the struct is not validated nor copied.
+ */
+bool avb_hashtree_descriptor_validate_and_byteswap(
+    const AvbHashtreeDescriptor* src,
+    AvbHashtreeDescriptor* dest) AVB_ATTR_WARN_UNUSED_RESULT;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* AVB_HASHTREE_DESCRIPTOR_H_ */
diff --git a/include/avb/avb_kernel_cmdline_descriptor.h b/include/avb/avb_kernel_cmdline_descriptor.h
new file mode 100644
index 0000000..655918d
--- /dev/null
+++ b/include/avb/avb_kernel_cmdline_descriptor.h
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * SPDX-License-Identifier:	MIT
+ */
+
+#if !defined(AVB_INSIDE_LIBAVB_H) && !defined(AVB_COMPILATION)
+#error "Never include this file directly, include libavb.h instead."
+#endif
+
+#ifndef AVB_KERNEL_CMDLINE_DESCRIPTOR_H_
+#define AVB_KERNEL_CMDLINE_DESCRIPTOR_H_
+
+#include "avb_descriptor.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Flags for kernel command-line descriptors.
+ *
+ * AVB_KERNEL_CMDLINE_FLAGS_USE_ONLY_IF_HASHTREE_NOT_DISABLED: The
+ * cmdline will only be applied if hashtree verification is not
+ * disabled (cf. AVB_VBMETA_IMAGE_FLAGS_HASHTREE_DISABLED).
+ *
+ * AVB_KERNEL_CMDLINE_FLAGS_USE_ONLY_IF_HASHTREE_DISABLED: The cmdline
+ * will only be applied if hashtree verification is disabled
+ * (cf. AVB_VBMETA_IMAGE_FLAGS_HASHTREE_DISABLED).
+ */
+typedef enum {
+  AVB_KERNEL_CMDLINE_FLAGS_USE_ONLY_IF_HASHTREE_NOT_DISABLED = (1 << 0),
+  AVB_KERNEL_CMDLINE_FLAGS_USE_ONLY_IF_HASHTREE_DISABLED = (1 << 1)
+} AvbKernelCmdlineFlags;
+
+/* A descriptor containing information to be appended to the kernel
+ * command-line.
+ *
+ * The |flags| field contains flags from the AvbKernelCmdlineFlags
+ * enumeration.
+ *
+ * Following this struct are |kernel_cmdline_len| bytes with the
+ * kernel command-line (UTF-8 encoded).
+ */
+typedef struct AvbKernelCmdlineDescriptor {
+  AvbDescriptor parent_descriptor;
+  uint32_t flags;
+  uint32_t kernel_cmdline_length;
+} AVB_ATTR_PACKED AvbKernelCmdlineDescriptor;
+
+/* Copies |src| to |dest| and validates, byte-swapping fields in the
+ * process if needed. Returns true if valid, false if invalid.
+ *
+ * Data following the struct is not validated nor copied.
+ */
+bool avb_kernel_cmdline_descriptor_validate_and_byteswap(
+    const AvbKernelCmdlineDescriptor* src,
+    AvbKernelCmdlineDescriptor* dest) AVB_ATTR_WARN_UNUSED_RESULT;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* AVB_KERNEL_CMDLINE_DESCRIPTOR_H_ */
diff --git a/include/avb/avb_ops.h b/include/avb/avb_ops.h
new file mode 100644
index 0000000..27a55b0
--- /dev/null
+++ b/include/avb/avb_ops.h
@@ -0,0 +1,196 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * SPDX-License-Identifier:	MIT
+ */
+
+#if !defined(AVB_INSIDE_LIBAVB_H) && !defined(AVB_COMPILATION)
+#error "Never include this file directly, include libavb.h instead."
+#endif
+
+#ifndef AVB_OPS_H_
+#define AVB_OPS_H_
+
+#include "avb_sysdeps.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Return codes used for I/O operations.
+ *
+ * AVB_IO_RESULT_OK is returned if the requested operation was
+ * successful.
+ *
+ * AVB_IO_RESULT_ERROR_IO is returned if the underlying hardware (disk
+ * or other subsystem) encountered an I/O error.
+ *
+ * AVB_IO_RESULT_ERROR_OOM is returned if unable to allocate memory.
+ *
+ * AVB_IO_RESULT_ERROR_NO_SUCH_PARTITION is returned if the requested
+ * partition does not exist.
+ *
+ * AVB_IO_RESULT_ERROR_RANGE_OUTSIDE_PARTITION is returned if the
+ * range of bytes requested to be read or written is outside the range
+ * of the partition.
+ */
+typedef enum {
+  AVB_IO_RESULT_OK,
+  AVB_IO_RESULT_ERROR_OOM,
+  AVB_IO_RESULT_ERROR_IO,
+  AVB_IO_RESULT_ERROR_NO_SUCH_PARTITION,
+  AVB_IO_RESULT_ERROR_RANGE_OUTSIDE_PARTITION
+} AvbIOResult;
+
+struct AvbOps;
+typedef struct AvbOps AvbOps;
+
+/* Forward-declaration of operations in libavb_ab. */
+struct AvbABOps;
+
+/* Forward-declaration of operations in libavb_atx. */
+struct AvbAtxOps;
+
+/* High-level operations/functions/methods that are platform
+ * dependent.
+ */
+struct AvbOps {
+  /* This pointer can be used by the application/bootloader using
+   * libavb and is typically used in each operation to get a pointer
+   * to platform-specific resources. It cannot be used by libraries.
+   */
+  void* user_data;
+
+  /* If libavb_ab is used, this should point to the
+   * AvbABOps. Otherwise it must be set to NULL.
+   */
+  struct AvbABOps* ab_ops;
+
+  /* If libavb_atx is used, this should point to the
+   * AvbAtxOps. Otherwise it must be set to NULL.
+   */
+  struct AvbAtxOps* atx_ops;
+
+  /* Reads |num_bytes| from offset |offset| from partition with name
+   * |partition| (NUL-terminated UTF-8 string). If |offset| is
+   * negative, its absolute value should be interpreted as the number
+   * of bytes from the end of the partition.
+   *
+   * This function returns AVB_IO_RESULT_ERROR_NO_SUCH_PARTITION if
+   * there is no partition with the given name,
+   * AVB_IO_RESULT_ERROR_RANGE_OUTSIDE_PARTITION if the requested
+   * |offset| is outside the partition, and AVB_IO_RESULT_ERROR_IO if
+   * there was an I/O error from the underlying I/O subsystem.  If the
+   * operation succeeds as requested AVB_IO_RESULT_OK is returned and
+   * the data is available in |buffer|.
+   *
+   * The only time partial I/O may occur is if reading beyond the end
+   * of the partition. In this case the value returned in
+   * |out_num_read| may be smaller than |num_bytes|.
+   */
+  AvbIOResult (*read_from_partition)(AvbOps* ops,
+                                     const char* partition,
+                                     int64_t offset,
+                                     size_t num_bytes,
+                                     void* buffer,
+                                     size_t* out_num_read);
+
+  /* Writes |num_bytes| from |bffer| at offset |offset| to partition
+   * with name |partition| (NUL-terminated UTF-8 string). If |offset|
+   * is negative, its absolute value should be interpreted as the
+   * number of bytes from the end of the partition.
+   *
+   * This function returns AVB_IO_RESULT_ERROR_NO_SUCH_PARTITION if
+   * there is no partition with the given name,
+   * AVB_IO_RESULT_ERROR_RANGE_OUTSIDE_PARTITION if the requested
+   * byterange goes outside the partition, and AVB_IO_RESULT_ERROR_IO
+   * if there was an I/O error from the underlying I/O subsystem.  If
+   * the operation succeeds as requested AVB_IO_RESULT_OK is
+   * returned.
+   *
+   * This function never does any partial I/O, it either transfers all
+   * of the requested bytes or returns an error.
+   */
+  AvbIOResult (*write_to_partition)(AvbOps* ops,
+                                    const char* partition,
+                                    int64_t offset,
+                                    size_t num_bytes,
+                                    const void* buffer);
+
+  /* Checks if the given public key used to sign the 'vbmeta'
+   * partition is trusted. Boot loaders typically compare this with
+   * 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 location given by
+   * |rollback_index_location|. The value is returned in
+   * |out_rollback_index|. Returns AVB_IO_RESULT_OK if the rollback
+   * index was retrieved, otherwise an error code.
+   *
+   * A device may have a limited amount of rollback index locations (say,
+   * one or four) so may error out if |rollback_index_location| exceeds
+   * this number.
+   */
+  AvbIOResult (*read_rollback_index)(AvbOps* ops,
+                                     size_t rollback_index_location,
+                                     uint64_t* out_rollback_index);
+
+  /* Sets the rollback index corresponding to the location given by
+   * |rollback_index_location| to |rollback_index|. Returns
+   * AVB_IO_RESULT_OK if the rollback index was set, otherwise an
+   * error code.
+   *
+   * A device may have a limited amount of rollback index locations (say,
+   * one or four) so may error out if |rollback_index_location| exceeds
+   * this number.
+   */
+  AvbIOResult (*write_rollback_index)(AvbOps* ops,
+                                      size_t rollback_index_location,
+                                      uint64_t rollback_index);
+
+  /* Gets whether the device is unlocked. The value is returned in
+   * |out_is_unlocked| (true if unlocked, false otherwise). Returns
+   * AVB_IO_RESULT_OK if the state was retrieved, otherwise an error
+   * code.
+   */
+  AvbIOResult (*read_is_device_unlocked)(AvbOps* ops, bool* out_is_unlocked);
+
+  /* Gets the unique partition GUID for a partition with name in
+   * |partition| (NUL-terminated UTF-8 string). The GUID is copied as
+   * a string into |guid_buf| of size |guid_buf_size| and will be NUL
+   * terminated. The string must be lower-case and properly
+   * hyphenated. For example:
+   *
+   *  527c1c6d-6361-4593-8842-3c78fcd39219
+   *
+   * Returns AVB_IO_RESULT_OK on success, otherwise an error code.
+   */
+  AvbIOResult (*get_unique_guid_for_partition)(AvbOps* ops,
+                                               const char* partition,
+                                               char* guid_buf,
+                                               size_t guid_buf_size);
+};
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* AVB_OPS_H_ */
diff --git a/include/avb/avb_property_descriptor.h b/include/avb/avb_property_descriptor.h
new file mode 100644
index 0000000..2a70896
--- /dev/null
+++ b/include/avb/avb_property_descriptor.h
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * SPDX-License-Identifier:	MIT
+ */
+
+#if !defined(AVB_INSIDE_LIBAVB_H) && !defined(AVB_COMPILATION)
+#error "Never include this file directly, include libavb.h instead."
+#endif
+
+#ifndef AVB_PROPERTY_DESCRIPTOR_H_
+#define AVB_PROPERTY_DESCRIPTOR_H_
+
+#include "avb_descriptor.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* A descriptor for properties (free-form key/value pairs).
+ *
+ * Following this struct are |key_num_bytes| bytes of key data,
+ * followed by a NUL byte, then |value_num_bytes| bytes of value data,
+ * followed by a NUL byte and then enough padding to make the combined
+ * size a multiple of 8.
+ */
+typedef struct AvbPropertyDescriptor {
+  AvbDescriptor parent_descriptor;
+  uint64_t key_num_bytes;
+  uint64_t value_num_bytes;
+} AVB_ATTR_PACKED AvbPropertyDescriptor;
+
+/* Copies |src| to |dest| and validates, byte-swapping fields in the
+ * process if needed. Returns true if valid, false if invalid.
+ *
+ * Data following the struct is not validated nor copied.
+ */
+bool avb_property_descriptor_validate_and_byteswap(
+    const AvbPropertyDescriptor* src,
+    AvbPropertyDescriptor* dest) AVB_ATTR_WARN_UNUSED_RESULT;
+
+/* Convenience function for looking up the value for a property with
+ * name |key| in a vbmeta image. If |key_size| is 0, |key| must be
+ * NUL-terminated.
+ *
+ * The |image_data| parameter must be a pointer to a vbmeta image of
+ * size |image_size|.
+ *
+ * This function returns a pointer to the value inside the passed-in
+ * image or NULL if not found. Note that the value is always
+ * guaranteed to be followed by a NUL byte.
+ *
+ * If the value was found and |out_value_size| is not NULL, the size
+ * of the value is returned there.
+ *
+ * This function is O(n) in number of descriptors so if you need to
+ * look up a lot of values, you may want to build a more efficient
+ * lookup-table by manually walking all descriptors using
+ * avb_descriptor_foreach().
+ *
+ * Before using this function, you MUST verify |image_data| with
+ * avb_vbmeta_image_verify() and reject it unless it's signed by a
+ * known good public key.
+ */
+const char* avb_property_lookup(const uint8_t* image_data,
+                                size_t image_size,
+                                const char* key,
+                                size_t key_size,
+                                size_t* out_value_size)
+    AVB_ATTR_WARN_UNUSED_RESULT;
+
+/* Like avb_property_lookup() but parses the intial portions of the
+ * value as an unsigned 64-bit integer. Both decimal and hexadecimal
+ * representations (e.g. "0x2a") are supported. Returns false on
+ * failure and true on success. On success, the parsed value is
+ * returned in |out_value|.
+ */
+bool avb_property_lookup_uint64(const uint8_t* image_data,
+                                size_t image_size,
+                                const char* key,
+                                size_t key_size,
+                                uint64_t* out_value)
+    AVB_ATTR_WARN_UNUSED_RESULT;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* AVB_PROPERTY_DESCRIPTOR_H_ */
diff --git a/include/avb/avb_rsa.h b/include/avb/avb_rsa.h
new file mode 100644
index 0000000..8f648a2
--- /dev/null
+++ b/include/avb/avb_rsa.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * SPDX-License-Identifier:	MIT
+ */
+
+/* Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifdef AVB_INSIDE_LIBAVB_H
+#error "You can't include avb_rsa.h in the public header libavb.h."
+#endif
+
+#ifndef AVB_COMPILATION
+#error "Never include this file, it may only be used from internal avb code."
+#endif
+
+#ifndef AVB_RSA_H_
+#define AVB_RSA_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "avb_crypto.h"
+#include "avb_sysdeps.h"
+
+/* Using the key given by |key|, verify a RSA signature |sig| of
+ * length |sig_num_bytes| against an expected |hash| of length
+ * |hash_num_bytes|. The padding to expect must be passed in using
+ * |padding| of length |padding_num_bytes|.
+ *
+ * The data in |key| must match the format defined in
+ * |AvbRSAPublicKeyHeader|, including the two large numbers
+ * following. The |key_num_bytes| must be the size of the entire
+ * serialized key.
+ *
+ * Returns false if verification fails, true otherwise.
+ */
+bool avb_rsa_verify(const uint8_t* key,
+                    size_t key_num_bytes,
+                    const uint8_t* sig,
+                    size_t sig_num_bytes,
+                    const uint8_t* hash,
+                    size_t hash_num_bytes,
+                    const uint8_t* padding,
+                    size_t padding_num_bytes) AVB_ATTR_WARN_UNUSED_RESULT;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* AVB_RSA_H_ */
diff --git a/include/avb/avb_sha.h b/include/avb/avb_sha.h
new file mode 100644
index 0000000..f1d5f5a
--- /dev/null
+++ b/include/avb/avb_sha.h
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * SPDX-License-Identifier:	MIT
+ */
+
+#ifdef AVB_INSIDE_LIBAVB_H
+#error "You can't include avb_sha.h in the public header libavb.h."
+#endif
+
+#ifndef AVB_COMPILATION
+#error "Never include this file, it may only be used from internal avb code."
+#endif
+
+#ifndef AVB_SHA_H_
+#define AVB_SHA_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "avb_crypto.h"
+#include "avb_sysdeps.h"
+
+/* Block size in bytes of a SHA-256 digest. */
+#define AVB_SHA256_BLOCK_SIZE 64
+
+
+/* Block size in bytes of a SHA-512 digest. */
+#define AVB_SHA512_BLOCK_SIZE 128
+
+/* Data structure used for SHA-256. */
+typedef struct {
+  uint32_t h[8];
+  uint32_t tot_len;
+  uint32_t len;
+  uint8_t block[2 * AVB_SHA256_BLOCK_SIZE];
+  uint8_t buf[AVB_SHA256_DIGEST_SIZE]; /* Used for storing the final digest. */
+} AvbSHA256Ctx;
+
+/* Data structure used for SHA-512. */
+typedef struct {
+  uint64_t h[8];
+  uint32_t tot_len;
+  uint32_t len;
+  uint8_t block[2 * AVB_SHA512_BLOCK_SIZE];
+  uint8_t buf[AVB_SHA512_DIGEST_SIZE]; /* Used for storing the final digest. */
+} AvbSHA512Ctx;
+
+/* Initializes the SHA-256 context. */
+void avb_sha256_init(AvbSHA256Ctx* ctx);
+
+/* Updates the SHA-256 context with |len| bytes from |data|. */
+void avb_sha256_update(AvbSHA256Ctx* ctx, const uint8_t* data, uint32_t len);
+
+/* Returns the SHA-256 digest. */
+uint8_t* avb_sha256_final(AvbSHA256Ctx* ctx) AVB_ATTR_WARN_UNUSED_RESULT;
+
+/* Initializes the SHA-512 context. */
+void avb_sha512_init(AvbSHA512Ctx* ctx);
+
+/* Updates the SHA-512 context with |len| bytes from |data|. */
+void avb_sha512_update(AvbSHA512Ctx* ctx, const uint8_t* data, uint32_t len);
+
+/* Returns the SHA-512 digest. */
+uint8_t* avb_sha512_final(AvbSHA512Ctx* ctx) AVB_ATTR_WARN_UNUSED_RESULT;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* AVB_SHA_H_ */
diff --git a/include/avb/avb_slot_verify.h b/include/avb/avb_slot_verify.h
new file mode 100644
index 0000000..b40a5b9
--- /dev/null
+++ b/include/avb/avb_slot_verify.h
@@ -0,0 +1,239 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * SPDX-License-Identifier:	MIT
+ */
+
+#if !defined(AVB_INSIDE_LIBAVB_H) && !defined(AVB_COMPILATION)
+#error "Never include this file directly, include libavb.h instead."
+#endif
+
+#ifndef AVB_SLOT_VERIFY_H_
+#define AVB_SLOT_VERIFY_H_
+
+#include "avb_ops.h"
+#include "avb_vbmeta_image.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Return codes used in avb_slot_verify(), see that function for
+ * documentation for each field.
+ *
+ * Use avb_slot_verify_result_to_string() to get a textual
+ * representation usable for error/debug output.
+ */
+typedef enum {
+  AVB_SLOT_VERIFY_RESULT_OK,
+  AVB_SLOT_VERIFY_RESULT_ERROR_OOM,
+  AVB_SLOT_VERIFY_RESULT_ERROR_IO,
+  AVB_SLOT_VERIFY_RESULT_ERROR_VERIFICATION,
+  AVB_SLOT_VERIFY_RESULT_ERROR_ROLLBACK_INDEX,
+  AVB_SLOT_VERIFY_RESULT_ERROR_PUBLIC_KEY_REJECTED,
+  AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA,
+  AVB_SLOT_VERIFY_RESULT_ERROR_UNSUPPORTED_VERSION
+} AvbSlotVerifyResult;
+
+/* Get a textual representation of |result|. */
+const char* avb_slot_verify_result_to_string(AvbSlotVerifyResult result);
+
+/* Maximum number of rollback index locations supported. */
+#define AVB_MAX_NUMBER_OF_ROLLBACK_INDEX_LOCATIONS 32
+
+/* AvbPartitionData contains data loaded from partitions when using
+ * avb_slot_verify(). The |partition_name| field contains the name of
+ * the partition (without A/B suffix), |data| points to the loaded
+ * data which is |data_size| bytes long.
+ *
+ * Note that this is strictly less than the partition size - it's only
+ * the image stored there, not the entire partition nor any of the
+ * metadata.
+ */
+typedef struct {
+  char* partition_name;
+  uint8_t* data;
+  size_t data_size;
+} AvbPartitionData;
+
+/* AvbVBMetaData contains a vbmeta struct loaded from a partition when
+ * using avb_slot_verify(). The |partition_name| field contains the
+ * name of the partition (without A/B suffix), |vbmeta_data| points to
+ * the loaded data which is |vbmeta_size| bytes long.
+ *
+ * The |verify_result| field contains the result of
+ * avb_vbmeta_image_verify() on the data. This is guaranteed to be
+ * AVB_VBMETA_VERIFY_RESULT_OK for all vbmeta images if
+ * avb_slot_verify() returns AVB_SLOT_VERIFY_RESULT_OK.
+ *
+ * You can use avb_descriptor_get_all(), avb_descriptor_foreach(), and
+ * avb_vbmeta_image_header_to_host_byte_order() with this data.
+ */
+typedef struct {
+  char* partition_name;
+  uint8_t* vbmeta_data;
+  size_t vbmeta_size;
+  AvbVBMetaVerifyResult verify_result;
+} AvbVBMetaData;
+
+/* AvbSlotVerifyData contains data needed to boot a particular slot
+ * and is returned by avb_slot_verify() if partitions in a slot are
+ * successfully verified.
+ *
+ * All data pointed to by this struct - including data in each item in
+ * the |partitions| array - will be freed when the
+ * avb_slot_verify_data_free() function is called.
+ *
+ * The |ab_suffix| field is the copy of the of |ab_suffix| field
+ * passed to avb_slot_verify(). It is the A/B suffix of the slot.
+ *
+ * The VBMeta images that were checked are available in the
+ * |vbmeta_images| field. The field |num_vbmeta_images| contains the
+ * number of elements in this array. The first element -
+ * vbmeta_images[0] - is guaranteed to be from the partition with the
+ * top-level vbmeta struct. This is usually the "vbmeta" partition in
+ * the requested slot but if there is no "vbmeta" partition it can
+ * also be the "boot" partition.
+ *
+ * The partitions loaded and verified from from the slot are
+ * accessible in the |loaded_partitions| array. The field
+ * |num_loaded_partitions| contains the number of elements in this
+ * array. The order of partitions in this array may not necessarily be
+ * the same order as in the passed-in |requested_partitions| array.
+ *
+ * Rollback indexes for the verified slot are stored in the
+ * |rollback_indexes| field. Note that avb_slot_verify() will NEVER
+ * modify stored_rollback_index[n] locations e.g. it will never use
+ * the write_rollback_index() AvbOps operation. Instead it is the job
+ * of the caller of avb_slot_verify() to do this based on e.g. A/B
+ * policy and other factors. See libavb_ab/avb_ab_flow.c for an
+ * example of how to do this.
+ *
+ * The |cmdline| field is a NUL-terminated string in UTF-8 resulting
+ * from concatenating all |AvbKernelCmdlineDescriptor| and then
+ * performing proper substitution of the variables
+ * $(ANDROID_SYSTEM_PARTUUID), $(ANDROID_BOOT_PARTUUID), and
+ * $(ANDROID_VBMETA_PARTUUID) using the
+ * get_unique_guid_for_partition() operation in |AvbOps|.
+ *
+ * Additionally, the |cmdline| field will have the following kernel
+ * command-line options set:
+ *
+ *   androidboot.vbmeta.device_state: set to "locked" or "unlocked"
+ *   depending on the result of the result of AvbOps's
+ *   read_is_unlocked() function.
+ *
+ *   androidboot.vbmeta.{hash_alg, size, digest}: Will be set to
+ *   the digest of all images in |vbmeta_images|.
+ *
+ *   androidboot.vbmeta.device: This is set to the value
+ *   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.
+ *
+ *   androidboot.vbmeta.avb_version: This is set to the decimal value
+ *   of AVB_VERSION_MAJOR followed by a dot followed by the decimal
+ *   value of AVB_VERSION_MINOR, for example "1.0" or "1.4". This
+ *   version number represents the vbmeta file format version
+ *   supported by libavb copy used in the boot loader. This is not
+ *   necessarily the same version number of the on-disk metadata for
+ *   the slot that was verified.
+ *
+ * Note that androidboot.slot_suffix is not set in |cmdline| - you
+ * will have to pass this command-line option yourself.
+ *
+ * This struct may grow in the future without it being considered an
+ * ABI break.
+ */
+typedef struct {
+  char* ab_suffix;
+  AvbVBMetaData* vbmeta_images;
+  size_t num_vbmeta_images;
+  AvbPartitionData* loaded_partitions;
+  size_t num_loaded_partitions;
+  char* cmdline;
+  uint64_t rollback_indexes[AVB_MAX_NUMBER_OF_ROLLBACK_INDEX_LOCATIONS];
+} AvbSlotVerifyData;
+
+/* Frees a |AvbSlotVerifyData| including all data it points to. */
+void avb_slot_verify_data_free(AvbSlotVerifyData* data);
+
+/* Performs a full verification of the slot identified by |ab_suffix|
+ * and load the contents of the partitions whose name is in the
+ * NULL-terminated string array |requested_partitions| (each partition
+ * must use hash verification). If not using A/B, pass an empty string
+ * (e.g. "", not NULL) for |ab_suffix|.
+ *
+ * Typically the |requested_partitions| array only contains a single
+ * item for the boot partition, 'boot'.
+ *
+ * Verification includes loading data from the 'vbmeta', all hash
+ * partitions, and possibly other partitions (with |ab_suffix|
+ * appended), inspecting rollback indexes, and checking if the public
+ * key used to sign the data is acceptable. The functions in |ops|
+ * will be used to do this.
+ *
+ * If |out_data| is not NULL, it will be set to a newly allocated
+ * |AvbSlotVerifyData| struct containing all the data needed to
+ * actually boot the slot. This data structure should be freed with
+ * avb_slot_verify_data_free() when you are done with it. See below
+ * for when this is returned.
+ *
+ * If |allow_verification_error| is false this function will bail out
+ * as soon as an error is encountered and |out_data| is set only if
+ * AVB_SLOT_VERIFY_RESULT_OK is returned.
+ *
+ * Otherwise if |allow_verification_error| is true the function will
+ * continue verification efforts and |out_data| is also set if
+ * AVB_SLOT_VERIFY_RESULT_ERROR_PUBLIC_KEY_REJECTED,
+ * AVB_SLOT_VERIFY_RESULT_ERROR_VERIFICATION, or
+ * AVB_SLOT_VERIFY_RESULT_ERROR_ROLLBACK_INDEX is returned. It is
+ * undefined which error is returned if more than one distinct error
+ * is encountered. It is guaranteed that AVB_SLOT_VERIFY_RESULT_OK is
+ * returned if, and only if, there are no errors. This mode is needed
+ * to boot valid but unverified slots when the device is unlocked.
+ *
+ * Also note that |out_data| is never set if
+ * AVB_SLOT_VERIFY_RESULT_ERROR_OOM, AVB_SLOT_VERIFY_RESULT_ERROR_IO,
+ * or AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA is returned.
+ *
+ * AVB_SLOT_VERIFY_RESULT_OK is returned if everything is verified
+ * correctly and all public keys are accepted.
+ *
+ * AVB_SLOT_VERIFY_RESULT_ERROR_PUBLIC_KEY_REJECTED is returned if
+ * everything is verified correctly out but one or more public keys
+ * are not accepted. This includes the case where integrity data is
+ * not signed.
+ *
+ * AVB_SLOT_VERIFY_RESULT_ERROR_OOM is returned if unable to
+ * allocate memory.
+ *
+ * AVB_SLOT_VERIFY_RESULT_ERROR_IO is returned if an I/O error
+ * occurred while trying to load data or get a rollback index.
+ *
+ * AVB_SLOT_VERIFY_RESULT_ERROR_VERIFICATION is returned if the data
+ * did not verify, e.g. the digest didn't match or signature checks
+ * failed.
+ *
+ * AVB_SLOT_VERIFY_RESULT_ERROR_ROLLBACK_INDEX is returned if a
+ * rollback index was less than its stored value.
+ *
+ * AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA is returned if some
+ * of the metadata is invalid or inconsistent.
+ *
+ * AVB_SLOT_VERIFY_RESULT_ERROR_UNSUPPORTED_VERSION is returned if
+ * some of the metadata requires a newer version of libavb than what
+ * is in use.
+ */
+AvbSlotVerifyResult avb_slot_verify(AvbOps* ops,
+                                    const char* const* requested_partitions,
+                                    const char* ab_suffix,
+                                    bool allow_verification_error,
+                                    AvbSlotVerifyData** out_data);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* AVB_SLOT_VERIFY_H_ */
diff --git a/include/avb/avb_sysdeps.h b/include/avb/avb_sysdeps.h
new file mode 100644
index 0000000..27c6651
--- /dev/null
+++ b/include/avb/avb_sysdeps.h
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * SPDX-License-Identifier:	MIT
+ */
+
+#if !defined(AVB_INSIDE_LIBAVB_H) && !defined(AVB_COMPILATION)
+#error "Never include this file directly, include libavb.h instead."
+#endif
+
+#ifndef AVB_SYSDEPS_H_
+#define AVB_SYSDEPS_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Change these includes to match your platform to bring in the
+ * equivalent types available in a normal C runtime. At least things
+ * like uint8_t, uint64_t, and bool (with |false|, |true| keywords)
+ * must be present.
+ */
+#include "common.h"
+
+/* If you don't have gcc or clang, these attribute macros may need to
+ * be adjusted.
+ */
+#define AVB_ATTR_WARN_UNUSED_RESULT __attribute__((warn_unused_result))
+#define AVB_ATTR_PACKED __attribute__((packed))
+#define AVB_ATTR_NO_RETURN __attribute__((noreturn))
+#define AVB_ATTR_SENTINEL __attribute__((__sentinel__))
+
+/* Size in bytes used for alignment. */
+#ifdef __LP64__
+#define AVB_ALIGNMENT_SIZE 8
+#else
+#define AVB_ALIGNMENT_SIZE 4
+#endif
+
+/* Compare |n| bytes in |src1| and |src2|.
+ *
+ * Returns an integer less than, equal to, or greater than zero if the
+ * first |n| bytes of |src1| is found, respectively, to be less than,
+ * to match, or be greater than the first |n| bytes of |src2|. */
+int avb_memcmp(const void* src1,
+               const void* src2,
+               size_t n) AVB_ATTR_WARN_UNUSED_RESULT;
+
+/* Compare two strings.
+ *
+ * Return an integer less than, equal to, or greater than zero if |s1|
+ * is found, respectively, to be less than, to match, or be greater
+ * than |s2|.
+ */
+int avb_strcmp(const char* s1, const char* s2);
+
+/* Copy |n| bytes from |src| to |dest|. */
+void* avb_memcpy(void* dest, const void* src, size_t n);
+
+/* Set |n| bytes starting at |s| to |c|.  Returns |dest|. */
+void* avb_memset(void* dest, const int c, size_t n);
+
+/* Prints out a message. The string passed must be a NUL-terminated
+ * UTF-8 string.
+ */
+void avb_print(const char* message);
+
+/* Prints out a vector of strings. Each argument must point to a
+ * NUL-terminated UTF-8 string and NULL should be the last argument.
+ */
+void avb_printv(const char* message, ...) AVB_ATTR_SENTINEL;
+
+/* Aborts the program or reboots the device. */
+void avb_abort(void) AVB_ATTR_NO_RETURN;
+
+/* Allocates |size| bytes. Returns NULL if no memory is available,
+ * otherwise a pointer to the allocated memory.
+ *
+ * The memory is not initialized.
+ *
+ * The pointer returned is guaranteed to be word-aligned.
+ *
+ * The memory should be freed with avb_free() when you are done with it.
+ */
+void* avb_malloc_(size_t size) AVB_ATTR_WARN_UNUSED_RESULT;
+
+/* Frees memory previously allocated with avb_malloc(). */
+void avb_free(void* ptr);
+
+/* Returns the lenght of |str|, excluding the terminating NUL-byte. */
+size_t avb_strlen(const char* str) AVB_ATTR_WARN_UNUSED_RESULT;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* AVB_SYSDEPS_H_ */
diff --git a/include/avb/avb_util.h b/include/avb/avb_util.h
new file mode 100644
index 0000000..98b8918
--- /dev/null
+++ b/include/avb/avb_util.h
@@ -0,0 +1,259 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * SPDX-License-Identifier:	MIT
+ */
+
+#if !defined(AVB_INSIDE_LIBAVB_H) && !defined(AVB_COMPILATION)
+#error "Never include this file directly, include libavb.h instead."
+#endif
+
+#ifndef AVB_UTIL_H_
+#define AVB_UTIL_H_
+
+#include "avb_sysdeps.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define AVB_STRINGIFY(x) #x
+#define AVB_TO_STRING(x) AVB_STRINGIFY(x)
+
+#ifdef AVB_ENABLE_DEBUG
+/* Aborts the program if |expr| is false.
+ *
+ * This has no effect unless AVB_ENABLE_DEBUG is defined.
+ */
+#define avb_assert(expr)                     \
+  do {                                       \
+    if (!(expr)) {                           \
+      avb_fatal("assert fail: " #expr "\n"); \
+    }                                        \
+  } while (0)
+#else
+#define avb_assert(expr)
+#endif
+
+/* Aborts the program if reached.
+ *
+ * This has no effect unless AVB_ENABLE_DEBUG is defined.
+ */
+#ifdef AVB_ENABLE_DEBUG
+#define avb_assert_not_reached()         \
+  do {                                   \
+    avb_fatal("assert_not_reached()\n"); \
+  } while (0)
+#else
+#define avb_assert_not_reached()
+#endif
+
+/* Aborts the program if |addr| is not word-aligned.
+ *
+ * This has no effect unless AVB_ENABLE_DEBUG is defined.
+ */
+#define avb_assert_aligned(addr) \
+  avb_assert((((uintptr_t)addr) & (AVB_ALIGNMENT_SIZE - 1)) == 0)
+
+#ifdef AVB_ENABLE_DEBUG
+/* Print functions, used for diagnostics.
+ *
+ * These have no effect unless AVB_ENABLE_DEBUG is defined.
+ */
+#define avb_debug(message)              \
+  do {                                  \
+    avb_printv(avb_basename(__FILE__),  \
+               ":",                     \
+               AVB_TO_STRING(__LINE__), \
+               ": DEBUG: ",             \
+               message,                 \
+               NULL);                   \
+  } while (0)
+#define avb_debugv(message, ...)        \
+  do {                                  \
+    avb_printv(avb_basename(__FILE__),  \
+               ":",                     \
+               AVB_TO_STRING(__LINE__), \
+               ": DEBUG: ",             \
+               message,                 \
+               ##__VA_ARGS__);          \
+  } while (0)
+#else
+#define avb_debug(message)
+#define avb_debugv(message, ...)
+#endif
+
+/* Prints out a message. This is typically used if a runtime-error
+ * occurs.
+ */
+#define avb_error(message)              \
+  do {                                  \
+    avb_printv(avb_basename(__FILE__),  \
+               ":",                     \
+               AVB_TO_STRING(__LINE__), \
+               ": ERROR: ",             \
+               message,                 \
+               NULL);                   \
+  } while (0)
+#define avb_errorv(message, ...)        \
+  do {                                  \
+    avb_printv(avb_basename(__FILE__),  \
+               ":",                     \
+               AVB_TO_STRING(__LINE__), \
+               ": ERROR: ",             \
+               message,                 \
+               ##__VA_ARGS__);          \
+  } while (0)
+
+/* Prints out a message and calls avb_abort().
+ */
+#define avb_fatal(message)              \
+  do {                                  \
+    avb_printv(avb_basename(__FILE__),  \
+               ":",                     \
+               AVB_TO_STRING(__LINE__), \
+               ": FATAL: ",             \
+               message,                 \
+               NULL);                   \
+    avb_abort();                        \
+  } while (0)
+#define avb_fatalv(message, ...)        \
+  do {                                  \
+    avb_printv(avb_basename(__FILE__),  \
+               ":",                     \
+               AVB_TO_STRING(__LINE__), \
+               ": FATAL: ",             \
+               message,                 \
+               ##__VA_ARGS__);          \
+    avb_abort();                        \
+  } while (0)
+
+/* Converts a 32-bit unsigned integer from big-endian to host byte order. */
+uint32_t avb_be32toh(uint32_t in) AVB_ATTR_WARN_UNUSED_RESULT;
+
+/* Converts a 64-bit unsigned integer from big-endian to host byte order. */
+uint64_t avb_be64toh(uint64_t in) AVB_ATTR_WARN_UNUSED_RESULT;
+
+/* Converts a 32-bit unsigned integer from host to big-endian byte order. */
+uint32_t avb_htobe32(uint32_t in) AVB_ATTR_WARN_UNUSED_RESULT;
+
+/* Converts a 64-bit unsigned integer from host to big-endian byte order. */
+uint64_t avb_htobe64(uint64_t in) AVB_ATTR_WARN_UNUSED_RESULT;
+
+/* Compare |n| bytes starting at |s1| with |s2| and return 0 if they
+ * match, 1 if they don't.  Returns 0 if |n|==0, since no bytes
+ * mismatched.
+ *
+ * Time taken to perform the comparison is only dependent on |n| and
+ * not on the relationship of the match between |s1| and |s2|.
+ *
+ * Note that unlike avb_memcmp(), this only indicates inequality, not
+ * whether |s1| is less than or greater than |s2|.
+ */
+int avb_safe_memcmp(const void* s1,
+                    const void* s2,
+                    size_t n) AVB_ATTR_WARN_UNUSED_RESULT;
+
+/* Adds |value_to_add| to |value| with overflow protection.
+ *
+ * Returns false if the addition overflows, true otherwise. In either
+ * case, |value| is always modified.
+ */
+bool avb_safe_add_to(uint64_t* value,
+                     uint64_t value_to_add) AVB_ATTR_WARN_UNUSED_RESULT;
+
+/* Adds |a| and |b| with overflow protection, returning the value in
+ * |out_result|.
+ *
+ * It's permissible to pass NULL for |out_result| if you just want to
+ * check that the addition would not overflow.
+ *
+ * Returns false if the addition overflows, true otherwise.
+ */
+bool avb_safe_add(uint64_t* out_result,
+                  uint64_t a,
+                  uint64_t b) AVB_ATTR_WARN_UNUSED_RESULT;
+
+/* Checks if |num_bytes| data at |data| is a valid UTF-8
+ * string. Returns true if valid UTF-8, false otherwise.
+ */
+bool avb_validate_utf8(const uint8_t* data,
+                       size_t num_bytes) AVB_ATTR_WARN_UNUSED_RESULT;
+
+/* Concatenates |str1| (of |str1_len| bytes) and |str2| (of |str2_len|
+ * bytes) and puts the result in |buf| which holds |buf_size|
+ * bytes. The result is also guaranteed to be NUL terminated. Fail if
+ * there is not enough room in |buf| for the resulting string plus
+ * terminating NUL byte.
+ *
+ * Returns true if the operation succeeds, false otherwise.
+ */
+bool avb_str_concat(char* buf,
+                    size_t buf_size,
+                    const char* str1,
+                    size_t str1_len,
+                    const char* str2,
+                    size_t str2_len);
+
+/* Like avb_malloc_() but prints a error using avb_error() if memory
+ * allocation fails.
+ */
+void* avb_malloc(size_t size) AVB_ATTR_WARN_UNUSED_RESULT;
+
+/* Like avb_malloc() but sets the memory with zeroes. */
+void* avb_calloc(size_t size) AVB_ATTR_WARN_UNUSED_RESULT;
+
+/* Duplicates a NUL-terminated string. Returns NULL on OOM. */
+char* avb_strdup(const char* str) AVB_ATTR_WARN_UNUSED_RESULT;
+
+/* Duplicates a NULL-terminated array of NUL-terminated strings by
+ * concatenating them. The returned string will be
+ * NUL-terminated. Returns NULL on OOM.
+ */
+char* avb_strdupv(const char* str,
+                  ...) AVB_ATTR_WARN_UNUSED_RESULT AVB_ATTR_SENTINEL;
+
+/* Finds the first occurrence of |needle| in the string |haystack|
+ * where both strings are NUL-terminated strings. The terminating NUL
+ * bytes are not compared.
+ *
+ * Returns NULL if not found, otherwise points into |haystack| for the
+ * first occurrence of |needle|.
+ */
+const char* avb_strstr(const char* haystack,
+                       const char* needle) AVB_ATTR_WARN_UNUSED_RESULT;
+
+/* Finds the first occurrence of |str| in the NULL-terminated string
+ * array |strings|. Each element in |strings| must be
+ * NUL-terminated. The string given by |str| need not be
+ * NUL-terminated but its size must be given in |str_size|.
+ *
+ * Returns NULL if not found, otherwise points into |strings| for the
+ * first occurrence of |str|.
+ */
+const char* avb_strv_find_str(const char* const* strings,
+                              const char* str,
+                              size_t str_size);
+
+/* Replaces all occurrences of |search| with |replace| in |str|.
+ *
+ * Returns a newly allocated string or NULL if out of memory.
+ */
+char* avb_replace(const char* str,
+                  const char* search,
+                  const char* replace) AVB_ATTR_WARN_UNUSED_RESULT;
+
+/* Calculates the CRC-32 for data in |buf| of size |buf_size|. */
+uint32_t avb_crc32(const uint8_t* buf, size_t buf_size);
+
+/* Returns the basename of |str|. This is defined as the last path
+ * component, assuming the normal POSIX separator '/'. If there are no
+ * separators, returns |str|.
+ */
+const char* avb_basename(const char* str);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* AVB_UTIL_H_ */
diff --git a/include/avb/avb_vbmeta_image.h b/include/avb/avb_vbmeta_image.h
new file mode 100644
index 0000000..abff6e1
--- /dev/null
+++ b/include/avb/avb_vbmeta_image.h
@@ -0,0 +1,272 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * SPDX-License-Identifier:	MIT
+ */
+
+#if !defined(AVB_INSIDE_LIBAVB_H) && !defined(AVB_COMPILATION)
+#error "Never include this file directly, include libavb.h instead."
+#endif
+
+#ifndef AVB_VBMETA_IMAGE_H_
+#define AVB_VBMETA_IMAGE_H_
+
+#include "avb_sysdeps.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "avb_crypto.h"
+#include "avb_descriptor.h"
+
+/* Size of the vbmeta image header. */
+#define AVB_VBMETA_IMAGE_HEADER_SIZE 256
+
+/* Magic for the vbmeta image header. */
+#define AVB_MAGIC "AVB0"
+#define AVB_MAGIC_LEN 4
+
+/* Maximum size of the release string including the terminating NUL byte. */
+#define AVB_RELEASE_STRING_SIZE 48
+
+/* Flags for the vbmeta image.
+ *
+ * AVB_VBMETA_IMAGE_FLAGS_HASHTREE_DISABLED: If this flag is set,
+ * hashtree image verification will be disabled.
+ */
+typedef enum {
+  AVB_VBMETA_IMAGE_FLAGS_HASHTREE_DISABLED = (1 << 0)
+} AvbVBMetaImageFlags;
+
+/* Binary format for header of the vbmeta image.
+ *
+ * The vbmeta image consists of three blocks:
+ *
+ *  +-----------------------------------------+
+ *  | Header data - fixed size                |
+ *  +-----------------------------------------+
+ *  | Authentication data - variable size     |
+ *  +-----------------------------------------+
+ *  | Auxiliary data - variable size          |
+ *  +-----------------------------------------+
+ *
+ * The "Header data" block is described by this struct and is always
+ * |AVB_VBMETA_IMAGE_HEADER_SIZE| bytes long.
+ *
+ * The "Authentication data" block is |authentication_data_block_size|
+ * bytes long and contains the hash and signature used to authenticate
+ * the vbmeta image. The type of the hash and signature is defined by
+ * the |algorithm_type| field.
+ *
+ * The "Auxiliary data" is |auxiliary_data_block_size| bytes long and
+ * contains the auxiliary data including the public key used to make
+ * the signature and descriptors.
+ *
+ * The public key is at offset |public_key_offset| with size
+ * |public_key_size| in this block. The size of the public key data is
+ * defined by the |algorithm_type| field. The format of the public key
+ * data is described in the |AvbRSAPublicKeyHeader| struct.
+ *
+ * The descriptors starts at |descriptors_offset| from the beginning
+ * of the "Auxiliary Data" block and take up |descriptors_size|
+ * bytes. Each descriptor is stored as a |AvbDescriptor| with tag and
+ * number of bytes following. The number of descriptors can be
+ * determined by walking this data until |descriptors_size| is
+ * exhausted.
+ *
+ * The size of each of the "Authentication data" and "Auxiliary data"
+ * blocks must be divisible by 64. This is to ensure proper alignment.
+ *
+ * Descriptors are free-form blocks stored in a part of the vbmeta
+ * image subject to the same integrity checks as the rest of the
+ * image. See the documentation for |AvbDescriptor| for well-known
+ * descriptors. See avb_descriptor_foreach() for a convenience
+ * function to iterate over descriptors.
+ *
+ * This struct is versioned, see the |required_libavb_version_major|
+ * and |required_libavb_version_minor| fields. This represents the
+ * minimum version of libavb required to verify the header and depends
+ * on the features (e.g. algorithms, descriptors) used. Note that this
+ * may be 1.0 even if generated by an avbtool from 1.4 but where no
+ * features introduced after 1.0 has been used. See the "Versioning
+ * and compatibility" section in the README.md file for more details.
+ *
+ * All fields are stored in network byte order when serialized. To
+ * generate a copy with fields swapped to native byte order, use the
+ * function avb_vbmeta_image_header_to_host_byte_order().
+ *
+ * Before reading and/or using any of this data, you MUST verify it
+ * using avb_vbmeta_image_verify() and reject it unless it's signed by
+ * a known good public key.
+ */
+typedef struct AvbVBMetaImageHeader {
+  /*   0: Four bytes equal to "AVB0" (AVB_MAGIC). */
+  uint8_t magic[AVB_MAGIC_LEN];
+
+  /*   4: The major version of libavb required for this header. */
+  uint32_t required_libavb_version_major;
+  /*   8: The minor version of libavb required for this header. */
+  uint32_t required_libavb_version_minor;
+
+  /*  12: The size of the signature block. */
+  uint64_t authentication_data_block_size;
+  /*  20: The size of the auxiliary data block. */
+  uint64_t auxiliary_data_block_size;
+
+  /*  28: The verification algorithm used, see |AvbAlgorithmType| enum. */
+  uint32_t algorithm_type;
+
+  /*  32: Offset into the "Authentication data" block of hash data. */
+  uint64_t hash_offset;
+  /*  40: Length of the hash data. */
+  uint64_t hash_size;
+
+  /*  48: Offset into the "Authentication data" block of signature data. */
+  uint64_t signature_offset;
+  /*  56: Length of the signature data. */
+  uint64_t signature_size;
+
+  /*  64: Offset into the "Auxiliary data" block of public key data. */
+  uint64_t public_key_offset;
+  /*  72: Length of the public key data. */
+  uint64_t public_key_size;
+
+  /*  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;
+  /* 104: Length of descriptor data. */
+  uint64_t descriptors_size;
+
+  /* 112: The rollback index which can be used to prevent rollback to
+   *  older versions.
+   */
+  uint64_t rollback_index;
+
+  /* 120: Flags from the AvbVBMetaImageFlags enumeration. This must be
+   * set to zero if the vbmeta image is not a top-level image.
+   */
+  uint32_t flags;
+
+  /* 124: Reserved to ensure |release_string| start on a 16-byte
+   * boundary. Must be set to zeroes.
+   */
+  uint8_t reserved0[4];
+
+  /* 128: The release string from avbtool, e.g. "avbtool 1.0.0" or
+   * "avbtool 1.0.0 xyz_board Git-234abde89". Is guaranteed to be NUL
+   * terminated. Applications must not make assumptions about how this
+   * string is formatted.
+   */
+  uint8_t release_string[AVB_RELEASE_STRING_SIZE];
+
+  /* 176: Padding to ensure struct is size AVB_VBMETA_IMAGE_HEADER_SIZE
+   * bytes. This must be set to zeroes.
+   */
+  uint8_t reserved[80];
+} AVB_ATTR_PACKED AvbVBMetaImageHeader;
+
+/* Copies |src| to |dest|, byte-swapping fields in the process.
+ *
+ * Make sure you've verified |src| using avb_vbmeta_image_verify()
+ * before accessing the data and/or using this function.
+ */
+void avb_vbmeta_image_header_to_host_byte_order(const AvbVBMetaImageHeader* src,
+                                                AvbVBMetaImageHeader* dest);
+
+/* Return codes used in avb_vbmeta_image_verify().
+ *
+ * AVB_VBMETA_VERIFY_RESULT_OK is returned if the vbmeta image header
+ * is valid, the hash is correct and the signature is correct. Keep in
+ * mind that you still need to check that you know the public key used
+ * to sign the image, see avb_vbmeta_image_verify() for details.
+ *
+ * AVB_VBMETA_VERIFY_RESULT_OK_NOT_SIGNED is returned if the vbmeta
+ * image header is valid but there is no signature or hash.
+ *
+ * AVB_VBMETA_VERIFY_RESULT_INVALID_VBMETA_HEADER is returned if the
+ * header of the vbmeta image is invalid, for example, invalid magic
+ * or inconsistent data.
+ *
+ * AVB_VBMETA_VERIFY_RESULT_UNSUPPORTED_VERSION is returned if a) the
+ * vbmeta image requires a minimum version of libavb which exceeds the
+ * version of libavb used; or b) the vbmeta image major version
+ * differs from the major version of libavb in use.
+ *
+ * AVB_VBMETA_VERIFY_RESULT_HASH_MISMATCH is returned if the hash
+ * stored in the "Authentication data" block does not match the
+ * calculated hash.
+ *
+ * AVB_VBMETA_VERIFY_RESULT_SIGNATURE_MISMATCH is returned if the
+ * signature stored in the "Authentication data" block is invalid or
+ * doesn't match the public key stored in the vbmeta image.
+ */
+typedef enum {
+  AVB_VBMETA_VERIFY_RESULT_OK,
+  AVB_VBMETA_VERIFY_RESULT_OK_NOT_SIGNED,
+  AVB_VBMETA_VERIFY_RESULT_INVALID_VBMETA_HEADER,
+  AVB_VBMETA_VERIFY_RESULT_UNSUPPORTED_VERSION,
+  AVB_VBMETA_VERIFY_RESULT_HASH_MISMATCH,
+  AVB_VBMETA_VERIFY_RESULT_SIGNATURE_MISMATCH,
+} AvbVBMetaVerifyResult;
+
+/* Get a textual representation of |result|. */
+const char* avb_vbmeta_verify_result_to_string(AvbVBMetaVerifyResult result);
+
+/* Checks that vbmeta image@|data| of size |length| is a valid
+ * vbmeta image. The complete contents of the vbmeta image must be
+ * passed in. It's fine if |length| is bigger than the actual image,
+ * typically callers of this function will load the entire contents of
+ * the 'vbmeta_a' or 'vbmeta_b' partition and pass in its length (for
+ * example, 1 MiB).
+ *
+ * See the |AvbVBMetaImageHeader| struct for information about the
+ * three blocks (header, authentication, auxiliary) that make up a
+ * vbmeta image.
+ *
+ * If the function returns |AVB_VBMETA_VERIFY_RESULT_OK| and
+ * |out_public_key_data| is non-NULL, it will be set to point inside
+ * |data| for where the serialized public key data is stored and
+ * |out_public_key_length|, if non-NULL, will be set to the length of
+ * the public key data. If there is no public key in the metadata then
+ * |out_public_key_data| is set to NULL.
+ *
+ * See the |AvbVBMetaVerifyResult| enum for possible return values.
+ *
+ * VERY IMPORTANT:
+ *
+ *   1. Even if |AVB_VBMETA_VERIFY_RESULT_OK| is returned, you still
+ *      need to check that the public key embedded in the image
+ *      matches a known key! You can use 'avbtool extract_public_key'
+ *      to extract the key (at build time, then store it along your
+ *      code) and compare it to what is returned in
+ *      |out_public_key_data|.
+ *
+ *   2. You need to check the |rollback_index| field against a stored
+ *      value in NVRAM and reject the vbmeta image if the value in
+ *      NVRAM is bigger than |rollback_index|. You must also update
+ *      the value stored in NVRAM to the smallest value of
+ *      |rollback_index| field from boot images in all bootable and
+ *      authentic slots marked as GOOD.
+ *
+ * This is a low-level function to only verify the vbmeta data - you
+ * are likely looking for avb_slot_verify() instead for verifying
+ * integrity data for a whole set of partitions.
+ */
+AvbVBMetaVerifyResult avb_vbmeta_image_verify(
+    const uint8_t* data,
+    size_t length,
+    const uint8_t** out_public_key_data,
+    size_t* out_public_key_length) AVB_ATTR_WARN_UNUSED_RESULT;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* AVB_VBMETA_IMAGE_H_ */
diff --git a/include/avb/avb_version.h b/include/avb/avb_version.h
new file mode 100644
index 0000000..4a636d0
--- /dev/null
+++ b/include/avb/avb_version.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * SPDX-License-Identifier:	MIT
+ */
+
+#if !defined(AVB_INSIDE_LIBAVB_H) && !defined(AVB_COMPILATION)
+#error "Never include this file directly, include libavb.h instead."
+#endif
+
+#ifndef AVB_VERSION_H_
+#define AVB_VERSION_H_
+
+#include "avb_sysdeps.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* The version number of AVB - keep in sync with avbtool. */
+#define AVB_VERSION_MAJOR 1
+#define AVB_VERSION_MINOR 0
+#define AVB_VERSION_SUB 0
+
+/* Returns a NUL-terminated string for the libavb version in use.  The
+ * returned string usually looks like "%d.%d.%d". Applications must
+ * not make assumptions about the content of this string.
+ *
+ * Boot loaders should display this string in debug/diagnostics output
+ * to aid with debugging.
+ *
+ * This is similar to the string put in the |release_string| string
+ * field in the VBMeta struct by avbtool.
+ */
+const char* avb_version_string(void);
+
+/* TODO: remove when there are no more users of AVB_{MAJOR,MINOR}_VERSION. */
+#define AVB_MAJOR_VERSION AVB_VERSION_MAJOR
+#define AVB_MINOR_VERSION AVB_VERSION_MINOR
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* AVB_VERSION_H_ */
diff --git a/include/avb/libavb.h b/include/avb/libavb.h
new file mode 100644
index 0000000..dab17ce
--- /dev/null
+++ b/include/avb/libavb.h
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * SPDX-License-Identifier:	MIT
+ */
+
+#ifndef LIBAVB_H_
+#define LIBAVB_H_
+
+/* The AVB_INSIDE_LIBAVB_H preprocessor symbol is used to enforce
+ * library users to include only this file. All public interfaces, and
+ * only public interfaces, must be included here.
+ */
+
+#define AVB_INSIDE_LIBAVB_H
+#include "avb_chain_partition_descriptor.h"
+#include "avb_crypto.h"
+#include "avb_descriptor.h"
+#include "avb_footer.h"
+#include "avb_hash_descriptor.h"
+#include "avb_hashtree_descriptor.h"
+#include "avb_kernel_cmdline_descriptor.h"
+#include "avb_ops.h"
+#include "avb_property_descriptor.h"
+#include "avb_slot_verify.h"
+#include "avb_sysdeps.h"
+#include "avb_util.h"
+#include "avb_vbmeta_image.h"
+#include "avb_version.h"
+#undef AVB_INSIDE_LIBAVB_H
+
+#endif /* LIBAVB_H_ */
diff --git a/include/avb/libavb_ab.h b/include/avb/libavb_ab.h
new file mode 100644
index 0000000..bdbee26
--- /dev/null
+++ b/include/avb/libavb_ab.h
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * SPDX-License-Identifier:	MIT
+ */
+
+#ifndef LIBAVB_AB_H_
+#define LIBAVB_AB_H_
+
+#include <avb/libavb.h>
+
+/* The AVB_INSIDE_LIBAVB_AB_H preprocessor symbol is used to enforce
+ * library users to include only this file. All public interfaces, and
+ * only public interfaces, must be included here.
+ */
+
+#define AVB_INSIDE_LIBAVB_AB_H
+#include "avb_ab_flow.h"
+#include "avb_ab_ops.h"
+#undef AVB_INSIDE_LIBAVB_AB_H
+
+#endif /* LIBAVB_AB_H_ */
diff --git a/lib/libavb/avb_chain_partition_descriptor.c b/lib/libavb/avb_chain_partition_descriptor.c
new file mode 100644
index 0000000..05ac954
--- /dev/null
+++ b/lib/libavb/avb_chain_partition_descriptor.c
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * SPDX-License-Identifier:	MIT
+ */
+
+#include "avb/avb_chain_partition_descriptor.h"
+#include "avb/avb_util.h"
+
+bool avb_chain_partition_descriptor_validate_and_byteswap(
+    const AvbChainPartitionDescriptor* src, AvbChainPartitionDescriptor* dest) {
+  uint64_t expected_size;
+
+  avb_memcpy(dest, src, sizeof(AvbChainPartitionDescriptor));
+
+  if (!avb_descriptor_validate_and_byteswap((const AvbDescriptor*)src,
+                                            (AvbDescriptor*)dest))
+    return false;
+
+  if (dest->parent_descriptor.tag != AVB_DESCRIPTOR_TAG_CHAIN_PARTITION) {
+    avb_error("Invalid tag for chain partition descriptor.\n");
+    return false;
+  }
+
+  dest->rollback_index_location = avb_be32toh(dest->rollback_index_location);
+  dest->partition_name_len = avb_be32toh(dest->partition_name_len);
+  dest->public_key_len = avb_be32toh(dest->public_key_len);
+
+  if (dest->rollback_index_location < 1) {
+    avb_error("Invalid rollback index location value.\n");
+    return false;
+  }
+
+  /* Check that partition_name and public_key are fully contained. */
+  expected_size = sizeof(AvbChainPartitionDescriptor) - sizeof(AvbDescriptor);
+  if (!avb_safe_add_to(&expected_size, dest->partition_name_len) ||
+      !avb_safe_add_to(&expected_size, dest->public_key_len)) {
+    avb_error("Overflow while adding up sizes.\n");
+    return false;
+  }
+  if (expected_size > dest->parent_descriptor.num_bytes_following) {
+    avb_error("Descriptor payload size overflow.\n");
+    return false;
+  }
+  return true;
+}
diff --git a/lib/libavb/avb_crypto.c b/lib/libavb/avb_crypto.c
new file mode 100644
index 0000000..ec3ec91
--- /dev/null
+++ b/lib/libavb/avb_crypto.c
@@ -0,0 +1,355 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * SPDX-License-Identifier:	MIT
+ */
+
+#include "avb/avb_crypto.h"
+#include "avb/avb_rsa.h"
+#include "avb/avb_sha.h"
+#include "avb/avb_util.h"
+
+/* NOTE: The PKC1-v1.5 padding is a blob of binary DER of ASN.1 and is
+ * obtained from section 5.2.2 of RFC 4880.
+ */
+
+static const uint8_t
+    padding_RSA2048_SHA256[AVB_RSA2048_NUM_BYTES - AVB_SHA256_DIGEST_SIZE] = {
+        0x00, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0x00, 0x30, 0x31, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65,
+        0x03, 0x04, 0x02, 0x01, 0x05, 0x00, 0x04, 0x20};
+
+static const uint8_t
+    padding_RSA4096_SHA256[AVB_RSA4096_NUM_BYTES - AVB_SHA256_DIGEST_SIZE] = {
+        0x00, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0x00, 0x30, 0x31, 0x30, 0x0d, 0x06, 0x09, 0x60,
+        0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x05, 0x00, 0x04, 0x20};
+
+static const uint8_t
+    padding_RSA8192_SHA256[AVB_RSA8192_NUM_BYTES - AVB_SHA256_DIGEST_SIZE] = {
+        0x00, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0x00, 0x30, 0x31, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65,
+        0x03, 0x04, 0x02, 0x01, 0x05, 0x00, 0x04, 0x20};
+
+static const uint8_t
+    padding_RSA2048_SHA512[AVB_RSA2048_NUM_BYTES - AVB_SHA512_DIGEST_SIZE] = {
+        0x00, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0x00, 0x30, 0x51, 0x30, 0x0d, 0x06, 0x09, 0x60,
+        0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, 0x05, 0x00, 0x04, 0x40};
+
+static const uint8_t
+    padding_RSA4096_SHA512[AVB_RSA4096_NUM_BYTES - AVB_SHA512_DIGEST_SIZE] = {
+        0x00, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x30, 0x51, 0x30,
+        0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03,
+        0x05, 0x00, 0x04, 0x40};
+
+static const uint8_t
+    padding_RSA8192_SHA512[AVB_RSA8192_NUM_BYTES - AVB_SHA512_DIGEST_SIZE] = {
+        0x00, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0x00, 0x30, 0x51, 0x30, 0x0d, 0x06, 0x09, 0x60,
+        0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, 0x05, 0x00, 0x04, 0x40};
+
+static AvbAlgorithmData algorithm_data[_AVB_ALGORITHM_NUM_TYPES] = {
+    /* AVB_ALGORITHM_TYPE_NONE */
+    {.padding = NULL, .padding_len = 0, .hash_len = 0},
+    /* AVB_ALGORITHM_TYPE_SHA256_RSA2048 */
+    {.padding = padding_RSA2048_SHA256,
+     .padding_len = sizeof(padding_RSA2048_SHA256),
+     .hash_len = AVB_SHA256_DIGEST_SIZE},
+    /* AVB_ALGORITHM_TYPE_SHA256_RSA4096 */
+    {.padding = padding_RSA4096_SHA256,
+     .padding_len = sizeof(padding_RSA4096_SHA256),
+     .hash_len = AVB_SHA256_DIGEST_SIZE},
+    /* AVB_ALGORITHM_TYPE_SHA256_RSA8192 */
+    {.padding = padding_RSA8192_SHA256,
+     .padding_len = sizeof(padding_RSA8192_SHA256),
+     .hash_len = AVB_SHA256_DIGEST_SIZE},
+    /* AVB_ALGORITHM_TYPE_SHA512_RSA2048 */
+    {.padding = padding_RSA2048_SHA512,
+     .padding_len = sizeof(padding_RSA2048_SHA512),
+     .hash_len = AVB_SHA512_DIGEST_SIZE},
+    /* AVB_ALGORITHM_TYPE_SHA512_RSA4096 */
+    {.padding = padding_RSA4096_SHA512,
+     .padding_len = sizeof(padding_RSA4096_SHA512),
+     .hash_len = AVB_SHA512_DIGEST_SIZE},
+    /* AVB_ALGORITHM_TYPE_SHA512_RSA8192 */
+    {.padding = padding_RSA8192_SHA512,
+     .padding_len = sizeof(padding_RSA8192_SHA512),
+     .hash_len = AVB_SHA512_DIGEST_SIZE},
+};
+
+const AvbAlgorithmData* avb_get_algorithm_data(AvbAlgorithmType algorithm) {
+  if (algorithm >= AVB_ALGORITHM_TYPE_NONE &&
+      algorithm < _AVB_ALGORITHM_NUM_TYPES) {
+    return &algorithm_data[algorithm];
+  }
+  return NULL;
+}
+
+bool avb_rsa_public_key_header_validate_and_byteswap(
+    const AvbRSAPublicKeyHeader* src, AvbRSAPublicKeyHeader* dest) {
+  avb_memcpy(dest, src, sizeof(AvbRSAPublicKeyHeader));
+
+  dest->key_num_bits = avb_be32toh(dest->key_num_bits);
+  dest->n0inv = avb_be32toh(dest->n0inv);
+
+  return true;
+}
diff --git a/lib/libavb/avb_descriptor.c b/lib/libavb/avb_descriptor.c
new file mode 100644
index 0000000..a3d5c0b
--- /dev/null
+++ b/lib/libavb/avb_descriptor.c
@@ -0,0 +1,142 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * SPDX-License-Identifier:	MIT
+ */
+
+#include "avb/avb_descriptor.h"
+#include "avb/avb_util.h"
+#include "avb/avb_vbmeta_image.h"
+
+bool avb_descriptor_validate_and_byteswap(const AvbDescriptor* src,
+                                          AvbDescriptor* dest) {
+  dest->tag = avb_be64toh(src->tag);
+  dest->num_bytes_following = avb_be64toh(src->num_bytes_following);
+
+  if ((dest->num_bytes_following & 0x07) != 0) {
+    avb_error("Descriptor size is not divisible by 8.\n");
+    return false;
+  }
+  return true;
+}
+
+bool avb_descriptor_foreach(const uint8_t* image_data,
+                            size_t image_size,
+                            AvbDescriptorForeachFunc foreach_func,
+                            void* user_data) {
+  const AvbVBMetaImageHeader* header = NULL;
+  bool ret = false;
+  const uint8_t* image_end;
+  const uint8_t* desc_start;
+  const uint8_t* desc_end;
+  const uint8_t* p;
+
+  if (image_data == NULL) {
+    avb_error("image_data is NULL\n.");
+    goto out;
+  }
+
+  if (foreach_func == NULL) {
+    avb_error("foreach_func is NULL\n.");
+    goto out;
+  }
+
+  if (image_size < sizeof(AvbVBMetaImageHeader)) {
+    avb_error("Length is smaller than header.\n");
+    goto out;
+  }
+
+  /* Ensure magic is correct. */
+  if (avb_memcmp(image_data, AVB_MAGIC, AVB_MAGIC_LEN) != 0) {
+    avb_error("Magic is incorrect.\n");
+    goto out;
+  }
+
+  /* Careful, not byteswapped - also ensure it's aligned properly. */
+  avb_assert_aligned(image_data);
+  header = (const AvbVBMetaImageHeader*)image_data;
+  image_end = image_data + image_size;
+
+  desc_start = image_data + sizeof(AvbVBMetaImageHeader) +
+               avb_be64toh(header->authentication_data_block_size) +
+               avb_be64toh(header->descriptors_offset);
+
+  desc_end = desc_start + avb_be64toh(header->descriptors_size);
+
+  if (desc_start < image_data || desc_start > image_end ||
+      desc_end < image_data || desc_end > image_end || desc_end < desc_start) {
+    avb_error("Descriptors not inside passed-in data.\n");
+    goto out;
+  }
+
+  for (p = desc_start; p < desc_end;) {
+    const AvbDescriptor* dh = (const AvbDescriptor*)p;
+    avb_assert_aligned(dh);
+    uint64_t nb_following = avb_be64toh(dh->num_bytes_following);
+    uint64_t nb_total = sizeof(AvbDescriptor) + nb_following;
+
+    if ((nb_total & 7) != 0) {
+      avb_error("Invalid descriptor length.\n");
+      goto out;
+    }
+
+    if (nb_total + p < desc_start || nb_total + p > desc_end) {
+      avb_error("Invalid data in descriptors array.\n");
+      goto out;
+    }
+
+    if (foreach_func(dh, user_data) == 0) {
+      goto out;
+    }
+
+    p += nb_total;
+  }
+
+  ret = true;
+
+out:
+  return ret;
+}
+
+static bool count_descriptors(const AvbDescriptor* descriptor,
+                              void* user_data) {
+  size_t* num_descriptors = user_data;
+  *num_descriptors += 1;
+  return true;
+}
+
+typedef struct {
+  size_t descriptor_number;
+  const AvbDescriptor** descriptors;
+} SetDescriptorData;
+
+static bool set_descriptors(const AvbDescriptor* descriptor, void* user_data) {
+  SetDescriptorData* data = user_data;
+  data->descriptors[data->descriptor_number++] = descriptor;
+  return true;
+}
+
+const AvbDescriptor** avb_descriptor_get_all(const uint8_t* image_data,
+                                             size_t image_size,
+                                             size_t* out_num_descriptors) {
+  size_t num_descriptors = 0;
+  SetDescriptorData data;
+
+  avb_descriptor_foreach(
+      image_data, image_size, count_descriptors, &num_descriptors);
+
+  data.descriptor_number = 0;
+  data.descriptors =
+      avb_calloc(sizeof(const AvbDescriptor*) * (num_descriptors + 1));
+  if (data.descriptors == NULL) {
+    return NULL;
+  }
+  avb_descriptor_foreach(image_data, image_size, set_descriptors, &data);
+  avb_assert(data.descriptor_number == num_descriptors);
+
+  if (out_num_descriptors != NULL) {
+    *out_num_descriptors = num_descriptors;
+  }
+
+  return data.descriptors;
+}
diff --git a/lib/libavb/avb_footer.c b/lib/libavb/avb_footer.c
new file mode 100644
index 0000000..ad8ca28
--- /dev/null
+++ b/lib/libavb/avb_footer.c
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * SPDX-License-Identifier:	MIT
+ */
+
+#include "avb/avb_footer.h"
+#include "avb/avb_util.h"
+
+bool avb_footer_validate_and_byteswap(const AvbFooter* src, AvbFooter* dest) {
+  avb_memcpy(dest, src, sizeof(AvbFooter));
+
+  dest->version_major = avb_be32toh(dest->version_major);
+  dest->version_minor = avb_be32toh(dest->version_minor);
+
+  dest->original_image_size = avb_be64toh(dest->original_image_size);
+  dest->vbmeta_offset = avb_be64toh(dest->vbmeta_offset);
+  dest->vbmeta_size = avb_be64toh(dest->vbmeta_size);
+
+  /* Check that magic is correct. */
+  if (avb_safe_memcmp(dest->magic, AVB_FOOTER_MAGIC, AVB_FOOTER_MAGIC_LEN) !=
+      0) {
+    avb_error("Footer magic is incorrect.\n");
+    return false;
+  }
+
+  /* Ensure we don't attempt to access any fields if the footer major
+   * version is not supported.
+   */
+  if (dest->version_major > AVB_FOOTER_VERSION_MAJOR) {
+    avb_error("No support for footer version.\n");
+    return false;
+  }
+
+  return true;
+}
diff --git a/lib/libavb/avb_hash_descriptor.c b/lib/libavb/avb_hash_descriptor.c
new file mode 100644
index 0000000..02547c2
--- /dev/null
+++ b/lib/libavb/avb_hash_descriptor.c
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * SPDX-License-Identifier:	MIT
+ */
+
+#include "avb/avb_hash_descriptor.h"
+#include "avb/avb_util.h"
+
+bool avb_hash_descriptor_validate_and_byteswap(const AvbHashDescriptor* src,
+                                               AvbHashDescriptor* dest) {
+  uint64_t expected_size;
+
+  avb_memcpy(dest, src, sizeof(AvbHashDescriptor));
+
+  if (!avb_descriptor_validate_and_byteswap((const AvbDescriptor*)src,
+                                            (AvbDescriptor*)dest))
+    return false;
+
+  if (dest->parent_descriptor.tag != AVB_DESCRIPTOR_TAG_HASH) {
+    avb_error("Invalid tag for hash descriptor.\n");
+    return false;
+  }
+
+  dest->image_size = avb_be64toh(dest->image_size);
+  dest->partition_name_len = avb_be32toh(dest->partition_name_len);
+  dest->salt_len = avb_be32toh(dest->salt_len);
+  dest->digest_len = avb_be32toh(dest->digest_len);
+
+  /* Check that partition_name, salt, and digest are fully contained. */
+  expected_size = sizeof(AvbHashDescriptor) - sizeof(AvbDescriptor);
+  if (!avb_safe_add_to(&expected_size, dest->partition_name_len) ||
+      !avb_safe_add_to(&expected_size, dest->salt_len) ||
+      !avb_safe_add_to(&expected_size, dest->digest_len)) {
+    avb_error("Overflow while adding up sizes.\n");
+    return false;
+  }
+  if (expected_size > dest->parent_descriptor.num_bytes_following) {
+    avb_error("Descriptor payload size overflow.\n");
+    return false;
+  }
+  return true;
+}
diff --git a/lib/libavb/avb_hashtree_descriptor.c b/lib/libavb/avb_hashtree_descriptor.c
new file mode 100644
index 0000000..bac5157
--- /dev/null
+++ b/lib/libavb/avb_hashtree_descriptor.c
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * SPDX-License-Identifier:	MIT
+ */
+
+#include "avb/avb_hashtree_descriptor.h"
+#include "avb/avb_util.h"
+
+bool avb_hashtree_descriptor_validate_and_byteswap(
+    const AvbHashtreeDescriptor* src, AvbHashtreeDescriptor* dest) {
+  uint64_t expected_size;
+
+  avb_memcpy(dest, src, sizeof(AvbHashtreeDescriptor));
+
+  if (!avb_descriptor_validate_and_byteswap((const AvbDescriptor*)src,
+                                            (AvbDescriptor*)dest))
+    return false;
+
+  if (dest->parent_descriptor.tag != AVB_DESCRIPTOR_TAG_HASHTREE) {
+    avb_error("Invalid tag for hashtree descriptor.\n");
+    return false;
+  }
+
+  dest->dm_verity_version = avb_be32toh(dest->dm_verity_version);
+  dest->image_size = avb_be64toh(dest->image_size);
+  dest->tree_offset = avb_be64toh(dest->tree_offset);
+  dest->tree_size = avb_be64toh(dest->tree_size);
+  dest->data_block_size = avb_be32toh(dest->data_block_size);
+  dest->hash_block_size = avb_be32toh(dest->hash_block_size);
+  dest->fec_num_roots = avb_be32toh(dest->fec_num_roots);
+  dest->fec_offset = avb_be64toh(dest->fec_offset);
+  dest->fec_size = avb_be64toh(dest->fec_size);
+  dest->partition_name_len = avb_be32toh(dest->partition_name_len);
+  dest->salt_len = avb_be32toh(dest->salt_len);
+  dest->root_digest_len = avb_be32toh(dest->root_digest_len);
+
+  /* Check that partition_name, salt, and root_digest are fully contained. */
+  expected_size = sizeof(AvbHashtreeDescriptor) - sizeof(AvbDescriptor);
+  if (!avb_safe_add_to(&expected_size, dest->partition_name_len) ||
+      !avb_safe_add_to(&expected_size, dest->salt_len) ||
+      !avb_safe_add_to(&expected_size, dest->root_digest_len)) {
+    avb_error("Overflow while adding up sizes.\n");
+    return false;
+  }
+  if (expected_size > dest->parent_descriptor.num_bytes_following) {
+    avb_error("Descriptor payload size overflow.\n");
+    return false;
+  }
+  return true;
+}
diff --git a/lib/libavb/avb_kernel_cmdline_descriptor.c b/lib/libavb/avb_kernel_cmdline_descriptor.c
new file mode 100644
index 0000000..0ee6994
--- /dev/null
+++ b/lib/libavb/avb_kernel_cmdline_descriptor.c
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * SPDX-License-Identifier:	MIT
+ */
+
+#include "avb/avb_kernel_cmdline_descriptor.h"
+#include "avb/avb_util.h"
+
+bool avb_kernel_cmdline_descriptor_validate_and_byteswap(
+    const AvbKernelCmdlineDescriptor* src, AvbKernelCmdlineDescriptor* dest) {
+  uint64_t expected_size;
+
+  avb_memcpy(dest, src, sizeof(AvbKernelCmdlineDescriptor));
+
+  if (!avb_descriptor_validate_and_byteswap((const AvbDescriptor*)src,
+                                            (AvbDescriptor*)dest))
+    return false;
+
+  if (dest->parent_descriptor.tag != AVB_DESCRIPTOR_TAG_KERNEL_CMDLINE) {
+    avb_error("Invalid tag for kernel cmdline descriptor.\n");
+    return false;
+  }
+
+  dest->flags = avb_be32toh(dest->flags);
+  dest->kernel_cmdline_length = avb_be32toh(dest->kernel_cmdline_length);
+
+  /* Check that kernel_cmdline is fully contained. */
+  expected_size = sizeof(AvbKernelCmdlineDescriptor) - sizeof(AvbDescriptor);
+  if (!avb_safe_add_to(&expected_size, dest->kernel_cmdline_length)) {
+    avb_error("Overflow while adding up sizes.\n");
+    return false;
+  }
+  if (expected_size > dest->parent_descriptor.num_bytes_following) {
+    avb_error("Descriptor payload size overflow.\n");
+    return false;
+  }
+
+  return true;
+}
diff --git a/lib/libavb/avb_property_descriptor.c b/lib/libavb/avb_property_descriptor.c
new file mode 100644
index 0000000..c1af02f
--- /dev/null
+++ b/lib/libavb/avb_property_descriptor.c
@@ -0,0 +1,167 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * SPDX-License-Identifier:	MIT
+ */
+
+#include "avb/avb_property_descriptor.h"
+#include "avb/avb_util.h"
+
+bool avb_property_descriptor_validate_and_byteswap(
+    const AvbPropertyDescriptor* src, AvbPropertyDescriptor* dest) {
+  uint64_t expected_size;
+
+  avb_memcpy(dest, src, sizeof(AvbPropertyDescriptor));
+
+  if (!avb_descriptor_validate_and_byteswap((const AvbDescriptor*)src,
+                                            (AvbDescriptor*)dest))
+    return false;
+
+  if (dest->parent_descriptor.tag != AVB_DESCRIPTOR_TAG_PROPERTY) {
+    avb_error("Invalid tag for property descriptor.\n");
+    return false;
+  }
+
+  dest->key_num_bytes = avb_be64toh(dest->key_num_bytes);
+  dest->value_num_bytes = avb_be64toh(dest->value_num_bytes);
+
+  /* Check that key and value are fully contained. */
+  expected_size = sizeof(AvbPropertyDescriptor) - sizeof(AvbDescriptor) + 2;
+  if (!avb_safe_add_to(&expected_size, dest->key_num_bytes) ||
+      !avb_safe_add_to(&expected_size, dest->value_num_bytes)) {
+    avb_error("Overflow while adding up sizes.\n");
+    return false;
+  }
+  if (expected_size > dest->parent_descriptor.num_bytes_following) {
+    avb_error("Descriptor payload size overflow.\n");
+    return false;
+  }
+
+  return true;
+}
+
+typedef struct {
+  const char* key;
+  size_t key_size;
+  const char* ret_value;
+  size_t ret_value_size;
+} PropertyIteratorData;
+
+static bool property_lookup_desc_foreach(const AvbDescriptor* header,
+                                         void* user_data) {
+  PropertyIteratorData* data = (PropertyIteratorData*)user_data;
+  AvbPropertyDescriptor prop_desc;
+  const uint8_t* p;
+  bool ret = true;
+
+  if (header->tag != AVB_DESCRIPTOR_TAG_PROPERTY) {
+    goto out;
+  }
+
+  if (!avb_property_descriptor_validate_and_byteswap(
+          (const AvbPropertyDescriptor*)header, &prop_desc)) {
+    goto out;
+  }
+
+  p = (const uint8_t*)header;
+  if (p[sizeof(AvbPropertyDescriptor) + prop_desc.key_num_bytes] != 0) {
+    avb_error("No terminating NUL byte in key.\n");
+    goto out;
+  }
+
+  if (data->key_size == prop_desc.key_num_bytes) {
+    if (avb_memcmp(p + sizeof(AvbPropertyDescriptor),
+                   data->key,
+                   data->key_size) == 0) {
+      data->ret_value = (const char*)(p + sizeof(AvbPropertyDescriptor) +
+                                      prop_desc.key_num_bytes + 1);
+      data->ret_value_size = prop_desc.value_num_bytes;
+      /* Stop iterating. */
+      ret = false;
+      goto out;
+    }
+  }
+
+out:
+  return ret;
+}
+
+const char* avb_property_lookup(const uint8_t* image_data,
+                                size_t image_size,
+                                const char* key,
+                                size_t key_size,
+                                size_t* out_value_size) {
+  PropertyIteratorData data;
+
+  if (key_size == 0) {
+    key_size = avb_strlen(key);
+  }
+
+  data.key = key;
+  data.key_size = key_size;
+
+  if (avb_descriptor_foreach(
+          image_data, image_size, property_lookup_desc_foreach, &data) == 0) {
+    if (out_value_size != NULL) {
+      *out_value_size = data.ret_value_size;
+    }
+    return data.ret_value;
+  }
+
+  if (out_value_size != NULL) {
+    *out_value_size = 0;
+  }
+  return NULL;
+}
+
+bool avb_property_lookup_uint64(const uint8_t* image_data,
+                                size_t image_size,
+                                const char* key,
+                                size_t key_size,
+                                uint64_t* out_value) {
+  const char* value;
+  bool ret = false;
+  uint64_t parsed_val;
+  int base;
+  int n;
+
+  value = avb_property_lookup(image_data, image_size, key, key_size, NULL);
+  if (value == NULL) {
+    goto out;
+  }
+
+  base = 10;
+  if (avb_memcmp(value, "0x", 2) == 0) {
+    base = 16;
+    value += 2;
+  }
+
+  parsed_val = 0;
+  for (n = 0; value[n] != '\0'; n++) {
+    int c = value[n];
+    int digit;
+
+    parsed_val *= base;
+
+    if (c >= '0' && c <= '9') {
+      digit = c - '0';
+    } else if (base == 16 && c >= 'a' && c <= 'f') {
+      digit = c - 'a' + 10;
+    } else if (base == 16 && c >= 'A' && c <= 'F') {
+      digit = c - 'A' + 10;
+    } else {
+      avb_error("Invalid digit.\n");
+      goto out;
+    }
+
+    parsed_val += digit;
+  }
+
+  ret = true;
+  if (out_value != NULL) {
+    *out_value = parsed_val;
+  }
+
+out:
+  return ret;
+}
diff --git a/lib/libavb/avb_rsa.c b/lib/libavb/avb_rsa.c
new file mode 100644
index 0000000..6bb3866
--- /dev/null
+++ b/lib/libavb/avb_rsa.c
@@ -0,0 +1,277 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ * Copyright (c) 2011 The Chromium OS Authors.
+ *
+ * SPDX-License-Identifier:	(BSD-3-Clause or MIT)
+ */
+
+/* Implementation of RSA signature verification which uses a pre-processed
+ * key for computation. The code extends libmincrypt RSA verification code to
+ * support multiple RSA key lengths and hash digest algorithms.
+ */
+
+#include "avb/avb_rsa.h"
+#include "avb/avb_sha.h"
+#include "avb/avb_util.h"
+#include "avb/avb_vbmeta_image.h"
+
+typedef struct Key {
+  unsigned int len; /* Length of n[] in number of uint32_t */
+  uint32_t n0inv;   /* -1 / n[0] mod 2^32 */
+  uint32_t* n;      /* modulus as array (host-byte order) */
+  uint32_t* rr;     /* R^2 as array (host-byte order) */
+} Key;
+
+Key* parse_key_data(const uint8_t* data, size_t length) {
+  AvbRSAPublicKeyHeader h;
+  Key* key = NULL;
+  size_t expected_length;
+  unsigned int i;
+  const uint8_t* n;
+  const uint8_t* rr;
+
+  if (!avb_rsa_public_key_header_validate_and_byteswap(
+          (const AvbRSAPublicKeyHeader*)data, &h)) {
+    avb_error("Invalid key.\n");
+    goto fail;
+  }
+
+  if (!(h.key_num_bits == 2048 || h.key_num_bits == 4096 ||
+        h.key_num_bits == 8192)) {
+    avb_error("Unexpected key length.\n");
+    goto fail;
+  }
+
+  expected_length = sizeof(AvbRSAPublicKeyHeader) + 2 * h.key_num_bits / 8;
+  if (length != expected_length) {
+    avb_error("Key does not match expected length.\n");
+    goto fail;
+  }
+
+  n = data + sizeof(AvbRSAPublicKeyHeader);
+  rr = data + sizeof(AvbRSAPublicKeyHeader) + h.key_num_bits / 8;
+
+  /* Store n and rr following the key header so we only have to do one
+   * allocation.
+   */
+  key = (Key*)(avb_malloc(sizeof(Key) + 2 * h.key_num_bits / 8));
+  if (key == NULL) {
+    goto fail;
+  }
+
+  key->len = h.key_num_bits / 32;
+  key->n0inv = h.n0inv;
+  key->n = (uint32_t*)(key + 1); /* Skip ahead sizeof(Key) bytes. */
+  key->rr = key->n + key->len;
+
+  /* Crypto-code below (modpowF4() and friends) expects the key in
+   * little-endian format (rather than the format we're storing the
+   * key in), so convert it.
+   */
+  for (i = 0; i < key->len; i++) {
+    key->n[i] = avb_be32toh(((uint32_t*)n)[key->len - i - 1]);
+    key->rr[i] = avb_be32toh(((uint32_t*)rr)[key->len - i - 1]);
+  }
+  return key;
+
+fail:
+  if (key != NULL) {
+    avb_free(key);
+  }
+  return NULL;
+}
+
+void free_parsed_key(Key* key) {
+  avb_free(key);
+}
+
+/* a[] -= mod */
+static void subM(const Key* key, uint32_t* a) {
+  int64_t A = 0;
+  uint32_t i;
+  for (i = 0; i < key->len; ++i) {
+    A += (uint64_t)a[i] - key->n[i];
+    a[i] = (uint32_t)A;
+    A >>= 32;
+  }
+}
+
+/* return a[] >= mod */
+static int geM(const Key* key, uint32_t* a) {
+  uint32_t i;
+  for (i = key->len; i;) {
+    --i;
+    if (a[i] < key->n[i]) {
+      return 0;
+    }
+    if (a[i] > key->n[i]) {
+      return 1;
+    }
+  }
+  return 1; /* equal */
+}
+
+/* montgomery c[] += a * b[] / R % mod */
+static void montMulAdd(const Key* key,
+                       uint32_t* c,
+                       const uint32_t a,
+                       const uint32_t* b) {
+  uint64_t A = (uint64_t)a * b[0] + c[0];
+  uint32_t d0 = (uint32_t)A * key->n0inv;
+  uint64_t B = (uint64_t)d0 * key->n[0] + (uint32_t)A;
+  uint32_t i;
+
+  for (i = 1; i < key->len; ++i) {
+    A = (A >> 32) + (uint64_t)a * b[i] + c[i];
+    B = (B >> 32) + (uint64_t)d0 * key->n[i] + (uint32_t)A;
+    c[i - 1] = (uint32_t)B;
+  }
+
+  A = (A >> 32) + (B >> 32);
+
+  c[i - 1] = (uint32_t)A;
+
+  if (A >> 32) {
+    subM(key, c);
+  }
+}
+
+/* montgomery c[] = a[] * b[] / R % mod */
+static void montMul(const Key* key, uint32_t* c, uint32_t* a, uint32_t* b) {
+  uint32_t i;
+  for (i = 0; i < key->len; ++i) {
+    c[i] = 0;
+  }
+  for (i = 0; i < key->len; ++i) {
+    montMulAdd(key, c, a[i], b);
+  }
+}
+
+/* In-place public exponentiation. (65537}
+ * Input and output big-endian byte array in inout.
+ */
+static void modpowF4(const Key* key, uint8_t* inout) {
+  uint32_t* a = (uint32_t*)avb_malloc(key->len * sizeof(uint32_t));
+  uint32_t* aR = (uint32_t*)avb_malloc(key->len * sizeof(uint32_t));
+  uint32_t* aaR = (uint32_t*)avb_malloc(key->len * sizeof(uint32_t));
+  if (a == NULL || aR == NULL || aaR == NULL) {
+    goto out;
+  }
+
+  uint32_t* aaa = aaR; /* Re-use location. */
+  int i;
+
+  /* Convert from big endian byte array to little endian word array. */
+  for (i = 0; i < (int)key->len; ++i) {
+    uint32_t tmp = (inout[((key->len - 1 - i) * 4) + 0] << 24) |
+                   (inout[((key->len - 1 - i) * 4) + 1] << 16) |
+                   (inout[((key->len - 1 - i) * 4) + 2] << 8) |
+                   (inout[((key->len - 1 - i) * 4) + 3] << 0);
+    a[i] = tmp;
+  }
+
+  montMul(key, aR, a, key->rr); /* aR = a * RR / R mod M   */
+  for (i = 0; i < 16; i += 2) {
+    montMul(key, aaR, aR, aR);  /* aaR = aR * aR / R mod M */
+    montMul(key, aR, aaR, aaR); /* aR = aaR * aaR / R mod M */
+  }
+  montMul(key, aaa, aR, a); /* aaa = aR * a / R mod M */
+
+  /* Make sure aaa < mod; aaa is@most 1x mod too large. */
+  if (geM(key, aaa)) {
+    subM(key, aaa);
+  }
+
+  /* Convert to bigendian byte array */
+  for (i = (int)key->len - 1; i >= 0; --i) {
+    uint32_t tmp = aaa[i];
+    *inout++ = (uint8_t)(tmp >> 24);
+    *inout++ = (uint8_t)(tmp >> 16);
+    *inout++ = (uint8_t)(tmp >> 8);
+    *inout++ = (uint8_t)(tmp >> 0);
+  }
+
+out:
+  if (a != NULL) {
+    avb_free(a);
+  }
+  if (aR != NULL) {
+    avb_free(aR);
+  }
+  if (aaR != NULL) {
+    avb_free(aaR);
+  }
+}
+
+/* Verify a RSA PKCS1.5 signature against an expected hash.
+ * Returns false on failure, true on success.
+ */
+bool avb_rsa_verify(const uint8_t* key,
+                    size_t key_num_bytes,
+                    const uint8_t* sig,
+                    size_t sig_num_bytes,
+                    const uint8_t* hash,
+                    size_t hash_num_bytes,
+                    const uint8_t* padding,
+                    size_t padding_num_bytes) {
+  uint8_t* buf = NULL;
+  Key* parsed_key = NULL;
+  bool success = false;
+
+  if (key == NULL || sig == NULL || hash == NULL || padding == NULL) {
+    avb_error("Invalid input.\n");
+    goto out;
+  }
+
+  parsed_key = parse_key_data(key, key_num_bytes);
+  if (parsed_key == NULL) {
+    avb_error("Error parsing key.\n");
+    goto out;
+  }
+
+  if (sig_num_bytes != (parsed_key->len * sizeof(uint32_t))) {
+    avb_error("Signature length does not match key length.\n");
+    goto out;
+  }
+
+  if (padding_num_bytes != sig_num_bytes - hash_num_bytes) {
+    avb_error("Padding length does not match hash and signature lengths.\n");
+    goto out;
+  }
+
+  buf = (uint8_t*)avb_malloc(sig_num_bytes);
+  if (buf == NULL) {
+    avb_error("Error allocating memory.\n");
+    goto out;
+  }
+  avb_memcpy(buf, sig, sig_num_bytes);
+
+  modpowF4(parsed_key, buf);
+
+  /* Check padding bytes.
+   *
+   * Even though there are probably no timing issues here, we use
+   * avb_safe_memcmp() just to be on the safe side.
+   */
+  if (avb_safe_memcmp(buf, padding, padding_num_bytes)) {
+    avb_error("Padding check failed.\n");
+    goto out;
+  }
+
+  /* Check hash. */
+  if (avb_safe_memcmp(buf + padding_num_bytes, hash, hash_num_bytes)) {
+    avb_error("Hash check failed.\n");
+    goto out;
+  }
+
+  success = true;
+
+out:
+  if (parsed_key != NULL) {
+    free_parsed_key(parsed_key);
+  }
+  if (buf != NULL) {
+    avb_free(buf);
+  }
+  return success;
+}
diff --git a/lib/libavb/avb_sha256.c b/lib/libavb/avb_sha256.c
new file mode 100644
index 0000000..110b512
--- /dev/null
+++ b/lib/libavb/avb_sha256.c
@@ -0,0 +1,364 @@
+/*
+ * Copyright (C) 2005, 2007 Olivier Gay <olivier.gay@a3.epfl.ch>
+ * All rights reserved.
+ *
+ * FIPS 180-2 SHA-224/256/384/512 implementation
+ * Last update: 02/02/2007
+ * Issue date:  04/30/2005
+ *
+ * SPDX-License-Identifier:	BSD-3-Clause
+ */
+
+#include "avb/avb_sha.h"
+
+#define SHFR(x, n) (x >> n)
+#define ROTR(x, n) ((x >> n) | (x << ((sizeof(x) << 3) - n)))
+#define ROTL(x, n) ((x << n) | (x >> ((sizeof(x) << 3) - n)))
+#define CH(x, y, z) ((x & y) ^ (~x & z))
+#define MAJ(x, y, z) ((x & y) ^ (x & z) ^ (y & z))
+
+#define SHA256_F1(x) (ROTR(x, 2) ^ ROTR(x, 13) ^ ROTR(x, 22))
+#define SHA256_F2(x) (ROTR(x, 6) ^ ROTR(x, 11) ^ ROTR(x, 25))
+#define SHA256_F3(x) (ROTR(x, 7) ^ ROTR(x, 18) ^ SHFR(x, 3))
+#define SHA256_F4(x) (ROTR(x, 17) ^ ROTR(x, 19) ^ SHFR(x, 10))
+
+#define UNPACK32(x, str)                 \
+  {                                      \
+    *((str) + 3) = (uint8_t)((x));       \
+    *((str) + 2) = (uint8_t)((x) >> 8);  \
+    *((str) + 1) = (uint8_t)((x) >> 16); \
+    *((str) + 0) = (uint8_t)((x) >> 24); \
+  }
+
+#define PACK32(str, x)                                                    \
+  {                                                                       \
+    *(x) = ((uint32_t) * ((str) + 3)) | ((uint32_t) * ((str) + 2) << 8) | \
+           ((uint32_t) * ((str) + 1) << 16) |                             \
+           ((uint32_t) * ((str) + 0) << 24);                              \
+  }
+
+/* Macros used for loops unrolling */
+
+#define SHA256_SCR(i) \
+  { w[i] = SHA256_F4(w[i - 2]) + w[i - 7] + SHA256_F3(w[i - 15]) + w[i - 16]; }
+
+#define SHA256_EXP(a, b, c, d, e, f, g, h, j)                               \
+  {                                                                         \
+    t1 = wv[h] + SHA256_F2(wv[e]) + CH(wv[e], wv[f], wv[g]) + sha256_k[j] + \
+         w[j];                                                              \
+    t2 = SHA256_F1(wv[a]) + MAJ(wv[a], wv[b], wv[c]);                       \
+    wv[d] += t1;                                                            \
+    wv[h] = t1 + t2;                                                        \
+  }
+
+static const uint32_t sha256_h0[8] = {0x6a09e667,
+                                      0xbb67ae85,
+                                      0x3c6ef372,
+                                      0xa54ff53a,
+                                      0x510e527f,
+                                      0x9b05688c,
+                                      0x1f83d9ab,
+                                      0x5be0cd19};
+
+static const uint32_t sha256_k[64] = {
+    0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1,
+    0x923f82a4, 0xab1c5ed5, 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3,
+    0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, 0xe49b69c1, 0xefbe4786,
+    0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
+    0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147,
+    0x06ca6351, 0x14292967, 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13,
+    0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, 0xa2bfe8a1, 0xa81a664b,
+    0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
+    0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a,
+    0x5b9cca4f, 0x682e6ff3, 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208,
+    0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2};
+
+/* SHA-256 implementation */
+void avb_sha256_init(AvbSHA256Ctx* ctx) {
+#ifndef UNROLL_LOOPS
+  int i;
+  for (i = 0; i < 8; i++) {
+    ctx->h[i] = sha256_h0[i];
+  }
+#else
+  ctx->h[0] = sha256_h0[0];
+  ctx->h[1] = sha256_h0[1];
+  ctx->h[2] = sha256_h0[2];
+  ctx->h[3] = sha256_h0[3];
+  ctx->h[4] = sha256_h0[4];
+  ctx->h[5] = sha256_h0[5];
+  ctx->h[6] = sha256_h0[6];
+  ctx->h[7] = sha256_h0[7];
+#endif /* !UNROLL_LOOPS */
+
+  ctx->len = 0;
+  ctx->tot_len = 0;
+}
+
+static void SHA256_transform(AvbSHA256Ctx* ctx,
+                             const uint8_t* message,
+                             unsigned int block_nb) {
+  uint32_t w[64];
+  uint32_t wv[8];
+  uint32_t t1, t2;
+  const unsigned char* sub_block;
+  int i;
+
+#ifndef UNROLL_LOOPS
+  int j;
+#endif
+
+  for (i = 0; i < (int)block_nb; i++) {
+    sub_block = message + (i << 6);
+
+#ifndef UNROLL_LOOPS
+    for (j = 0; j < 16; j++) {
+      PACK32(&sub_block[j << 2], &w[j]);
+    }
+
+    for (j = 16; j < 64; j++) {
+      SHA256_SCR(j);
+    }
+
+    for (j = 0; j < 8; j++) {
+      wv[j] = ctx->h[j];
+    }
+
+    for (j = 0; j < 64; j++) {
+      t1 = wv[7] + SHA256_F2(wv[4]) + CH(wv[4], wv[5], wv[6]) + sha256_k[j] +
+           w[j];
+      t2 = SHA256_F1(wv[0]) + MAJ(wv[0], wv[1], wv[2]);
+      wv[7] = wv[6];
+      wv[6] = wv[5];
+      wv[5] = wv[4];
+      wv[4] = wv[3] + t1;
+      wv[3] = wv[2];
+      wv[2] = wv[1];
+      wv[1] = wv[0];
+      wv[0] = t1 + t2;
+    }
+
+    for (j = 0; j < 8; j++) {
+      ctx->h[j] += wv[j];
+    }
+#else
+    PACK32(&sub_block[0], &w[0]);
+    PACK32(&sub_block[4], &w[1]);
+    PACK32(&sub_block[8], &w[2]);
+    PACK32(&sub_block[12], &w[3]);
+    PACK32(&sub_block[16], &w[4]);
+    PACK32(&sub_block[20], &w[5]);
+    PACK32(&sub_block[24], &w[6]);
+    PACK32(&sub_block[28], &w[7]);
+    PACK32(&sub_block[32], &w[8]);
+    PACK32(&sub_block[36], &w[9]);
+    PACK32(&sub_block[40], &w[10]);
+    PACK32(&sub_block[44], &w[11]);
+    PACK32(&sub_block[48], &w[12]);
+    PACK32(&sub_block[52], &w[13]);
+    PACK32(&sub_block[56], &w[14]);
+    PACK32(&sub_block[60], &w[15]);
+
+    SHA256_SCR(16);
+    SHA256_SCR(17);
+    SHA256_SCR(18);
+    SHA256_SCR(19);
+    SHA256_SCR(20);
+    SHA256_SCR(21);
+    SHA256_SCR(22);
+    SHA256_SCR(23);
+    SHA256_SCR(24);
+    SHA256_SCR(25);
+    SHA256_SCR(26);
+    SHA256_SCR(27);
+    SHA256_SCR(28);
+    SHA256_SCR(29);
+    SHA256_SCR(30);
+    SHA256_SCR(31);
+    SHA256_SCR(32);
+    SHA256_SCR(33);
+    SHA256_SCR(34);
+    SHA256_SCR(35);
+    SHA256_SCR(36);
+    SHA256_SCR(37);
+    SHA256_SCR(38);
+    SHA256_SCR(39);
+    SHA256_SCR(40);
+    SHA256_SCR(41);
+    SHA256_SCR(42);
+    SHA256_SCR(43);
+    SHA256_SCR(44);
+    SHA256_SCR(45);
+    SHA256_SCR(46);
+    SHA256_SCR(47);
+    SHA256_SCR(48);
+    SHA256_SCR(49);
+    SHA256_SCR(50);
+    SHA256_SCR(51);
+    SHA256_SCR(52);
+    SHA256_SCR(53);
+    SHA256_SCR(54);
+    SHA256_SCR(55);
+    SHA256_SCR(56);
+    SHA256_SCR(57);
+    SHA256_SCR(58);
+    SHA256_SCR(59);
+    SHA256_SCR(60);
+    SHA256_SCR(61);
+    SHA256_SCR(62);
+    SHA256_SCR(63);
+
+    wv[0] = ctx->h[0];
+    wv[1] = ctx->h[1];
+    wv[2] = ctx->h[2];
+    wv[3] = ctx->h[3];
+    wv[4] = ctx->h[4];
+    wv[5] = ctx->h[5];
+    wv[6] = ctx->h[6];
+    wv[7] = ctx->h[7];
+
+    SHA256_EXP(0, 1, 2, 3, 4, 5, 6, 7, 0);
+    SHA256_EXP(7, 0, 1, 2, 3, 4, 5, 6, 1);
+    SHA256_EXP(6, 7, 0, 1, 2, 3, 4, 5, 2);
+    SHA256_EXP(5, 6, 7, 0, 1, 2, 3, 4, 3);
+    SHA256_EXP(4, 5, 6, 7, 0, 1, 2, 3, 4);
+    SHA256_EXP(3, 4, 5, 6, 7, 0, 1, 2, 5);
+    SHA256_EXP(2, 3, 4, 5, 6, 7, 0, 1, 6);
+    SHA256_EXP(1, 2, 3, 4, 5, 6, 7, 0, 7);
+    SHA256_EXP(0, 1, 2, 3, 4, 5, 6, 7, 8);
+    SHA256_EXP(7, 0, 1, 2, 3, 4, 5, 6, 9);
+    SHA256_EXP(6, 7, 0, 1, 2, 3, 4, 5, 10);
+    SHA256_EXP(5, 6, 7, 0, 1, 2, 3, 4, 11);
+    SHA256_EXP(4, 5, 6, 7, 0, 1, 2, 3, 12);
+    SHA256_EXP(3, 4, 5, 6, 7, 0, 1, 2, 13);
+    SHA256_EXP(2, 3, 4, 5, 6, 7, 0, 1, 14);
+    SHA256_EXP(1, 2, 3, 4, 5, 6, 7, 0, 15);
+    SHA256_EXP(0, 1, 2, 3, 4, 5, 6, 7, 16);
+    SHA256_EXP(7, 0, 1, 2, 3, 4, 5, 6, 17);
+    SHA256_EXP(6, 7, 0, 1, 2, 3, 4, 5, 18);
+    SHA256_EXP(5, 6, 7, 0, 1, 2, 3, 4, 19);
+    SHA256_EXP(4, 5, 6, 7, 0, 1, 2, 3, 20);
+    SHA256_EXP(3, 4, 5, 6, 7, 0, 1, 2, 21);
+    SHA256_EXP(2, 3, 4, 5, 6, 7, 0, 1, 22);
+    SHA256_EXP(1, 2, 3, 4, 5, 6, 7, 0, 23);
+    SHA256_EXP(0, 1, 2, 3, 4, 5, 6, 7, 24);
+    SHA256_EXP(7, 0, 1, 2, 3, 4, 5, 6, 25);
+    SHA256_EXP(6, 7, 0, 1, 2, 3, 4, 5, 26);
+    SHA256_EXP(5, 6, 7, 0, 1, 2, 3, 4, 27);
+    SHA256_EXP(4, 5, 6, 7, 0, 1, 2, 3, 28);
+    SHA256_EXP(3, 4, 5, 6, 7, 0, 1, 2, 29);
+    SHA256_EXP(2, 3, 4, 5, 6, 7, 0, 1, 30);
+    SHA256_EXP(1, 2, 3, 4, 5, 6, 7, 0, 31);
+    SHA256_EXP(0, 1, 2, 3, 4, 5, 6, 7, 32);
+    SHA256_EXP(7, 0, 1, 2, 3, 4, 5, 6, 33);
+    SHA256_EXP(6, 7, 0, 1, 2, 3, 4, 5, 34);
+    SHA256_EXP(5, 6, 7, 0, 1, 2, 3, 4, 35);
+    SHA256_EXP(4, 5, 6, 7, 0, 1, 2, 3, 36);
+    SHA256_EXP(3, 4, 5, 6, 7, 0, 1, 2, 37);
+    SHA256_EXP(2, 3, 4, 5, 6, 7, 0, 1, 38);
+    SHA256_EXP(1, 2, 3, 4, 5, 6, 7, 0, 39);
+    SHA256_EXP(0, 1, 2, 3, 4, 5, 6, 7, 40);
+    SHA256_EXP(7, 0, 1, 2, 3, 4, 5, 6, 41);
+    SHA256_EXP(6, 7, 0, 1, 2, 3, 4, 5, 42);
+    SHA256_EXP(5, 6, 7, 0, 1, 2, 3, 4, 43);
+    SHA256_EXP(4, 5, 6, 7, 0, 1, 2, 3, 44);
+    SHA256_EXP(3, 4, 5, 6, 7, 0, 1, 2, 45);
+    SHA256_EXP(2, 3, 4, 5, 6, 7, 0, 1, 46);
+    SHA256_EXP(1, 2, 3, 4, 5, 6, 7, 0, 47);
+    SHA256_EXP(0, 1, 2, 3, 4, 5, 6, 7, 48);
+    SHA256_EXP(7, 0, 1, 2, 3, 4, 5, 6, 49);
+    SHA256_EXP(6, 7, 0, 1, 2, 3, 4, 5, 50);
+    SHA256_EXP(5, 6, 7, 0, 1, 2, 3, 4, 51);
+    SHA256_EXP(4, 5, 6, 7, 0, 1, 2, 3, 52);
+    SHA256_EXP(3, 4, 5, 6, 7, 0, 1, 2, 53);
+    SHA256_EXP(2, 3, 4, 5, 6, 7, 0, 1, 54);
+    SHA256_EXP(1, 2, 3, 4, 5, 6, 7, 0, 55);
+    SHA256_EXP(0, 1, 2, 3, 4, 5, 6, 7, 56);
+    SHA256_EXP(7, 0, 1, 2, 3, 4, 5, 6, 57);
+    SHA256_EXP(6, 7, 0, 1, 2, 3, 4, 5, 58);
+    SHA256_EXP(5, 6, 7, 0, 1, 2, 3, 4, 59);
+    SHA256_EXP(4, 5, 6, 7, 0, 1, 2, 3, 60);
+    SHA256_EXP(3, 4, 5, 6, 7, 0, 1, 2, 61);
+    SHA256_EXP(2, 3, 4, 5, 6, 7, 0, 1, 62);
+    SHA256_EXP(1, 2, 3, 4, 5, 6, 7, 0, 63);
+
+    ctx->h[0] += wv[0];
+    ctx->h[1] += wv[1];
+    ctx->h[2] += wv[2];
+    ctx->h[3] += wv[3];
+    ctx->h[4] += wv[4];
+    ctx->h[5] += wv[5];
+    ctx->h[6] += wv[6];
+    ctx->h[7] += wv[7];
+#endif /* !UNROLL_LOOPS */
+  }
+}
+
+void avb_sha256_update(AvbSHA256Ctx* ctx, const uint8_t* data, uint32_t len) {
+  unsigned int block_nb;
+  unsigned int new_len, rem_len, tmp_len;
+  const uint8_t* shifted_data;
+
+  tmp_len = AVB_SHA256_BLOCK_SIZE - ctx->len;
+  rem_len = len < tmp_len ? len : tmp_len;
+
+  avb_memcpy(&ctx->block[ctx->len], data, rem_len);
+
+  if (ctx->len + len < AVB_SHA256_BLOCK_SIZE) {
+    ctx->len += len;
+    return;
+  }
+
+  new_len = len - rem_len;
+  block_nb = new_len / AVB_SHA256_BLOCK_SIZE;
+
+  shifted_data = data + rem_len;
+
+  SHA256_transform(ctx, ctx->block, 1);
+  SHA256_transform(ctx, shifted_data, block_nb);
+
+  rem_len = new_len % AVB_SHA256_BLOCK_SIZE;
+
+  avb_memcpy(ctx->block, &shifted_data[block_nb << 6], rem_len);
+
+  ctx->len = rem_len;
+  ctx->tot_len += (block_nb + 1) << 6;
+}
+
+uint8_t* avb_sha256_final(AvbSHA256Ctx* ctx) {
+  unsigned int block_nb;
+  unsigned int pm_len;
+  unsigned int len_b;
+#ifndef UNROLL_LOOPS
+  int i;
+#endif
+
+  block_nb =
+      (1 + ((AVB_SHA256_BLOCK_SIZE - 9) < (ctx->len % AVB_SHA256_BLOCK_SIZE)));
+
+  len_b = (ctx->tot_len + ctx->len) << 3;
+  pm_len = block_nb << 6;
+
+  avb_memset(ctx->block + ctx->len, 0, pm_len - ctx->len);
+  ctx->block[ctx->len] = 0x80;
+  UNPACK32(len_b, ctx->block + pm_len - 4);
+
+  SHA256_transform(ctx, ctx->block, block_nb);
+
+#ifndef UNROLL_LOOPS
+  for (i = 0; i < 8; i++) {
+    UNPACK32(ctx->h[i], &ctx->buf[i << 2]);
+  }
+#else
+  UNPACK32(ctx->h[0], &ctx->buf[0]);
+  UNPACK32(ctx->h[1], &ctx->buf[4]);
+  UNPACK32(ctx->h[2], &ctx->buf[8]);
+  UNPACK32(ctx->h[3], &ctx->buf[12]);
+  UNPACK32(ctx->h[4], &ctx->buf[16]);
+  UNPACK32(ctx->h[5], &ctx->buf[20]);
+  UNPACK32(ctx->h[6], &ctx->buf[24]);
+  UNPACK32(ctx->h[7], &ctx->buf[28]);
+#endif /* !UNROLL_LOOPS */
+
+  return ctx->buf;
+}
diff --git a/lib/libavb/avb_sha512.c b/lib/libavb/avb_sha512.c
new file mode 100644
index 0000000..6a1caa8
--- /dev/null
+++ b/lib/libavb/avb_sha512.c
@@ -0,0 +1,362 @@
+/*
+ * Copyright (C) 2005, 2007 Olivier Gay <olivier.gay@a3.epfl.ch>
+ * All rights reserved.
+ *
+ * FIPS 180-2 SHA-224/256/384/512 implementation
+ * Last update: 02/02/2007
+ * Issue date:  04/30/2005
+ *
+ * SPDX-License-Identifier:	BSD-3-Clause
+ */
+
+#include "avb/avb_sha.h"
+
+#define SHFR(x, n) (x >> n)
+#define ROTR(x, n) ((x >> n) | (x << ((sizeof(x) << 3) - n)))
+#define ROTL(x, n) ((x << n) | (x >> ((sizeof(x) << 3) - n)))
+#define CH(x, y, z) ((x & y) ^ (~x & z))
+#define MAJ(x, y, z) ((x & y) ^ (x & z) ^ (y & z))
+
+#define SHA512_F1(x) (ROTR(x, 28) ^ ROTR(x, 34) ^ ROTR(x, 39))
+#define SHA512_F2(x) (ROTR(x, 14) ^ ROTR(x, 18) ^ ROTR(x, 41))
+#define SHA512_F3(x) (ROTR(x, 1) ^ ROTR(x, 8) ^ SHFR(x, 7))
+#define SHA512_F4(x) (ROTR(x, 19) ^ ROTR(x, 61) ^ SHFR(x, 6))
+
+#define UNPACK32(x, str)                 \
+  {                                      \
+    *((str) + 3) = (uint8_t)((x));       \
+    *((str) + 2) = (uint8_t)((x) >> 8);  \
+    *((str) + 1) = (uint8_t)((x) >> 16); \
+    *((str) + 0) = (uint8_t)((x) >> 24); \
+  }
+
+#define UNPACK64(x, str)                         \
+  {                                              \
+    *((str) + 7) = (uint8_t)x;                   \
+    *((str) + 6) = (uint8_t)((uint64_t)x >> 8);  \
+    *((str) + 5) = (uint8_t)((uint64_t)x >> 16); \
+    *((str) + 4) = (uint8_t)((uint64_t)x >> 24); \
+    *((str) + 3) = (uint8_t)((uint64_t)x >> 32); \
+    *((str) + 2) = (uint8_t)((uint64_t)x >> 40); \
+    *((str) + 1) = (uint8_t)((uint64_t)x >> 48); \
+    *((str) + 0) = (uint8_t)((uint64_t)x >> 56); \
+  }
+
+#define PACK64(str, x)                                                        \
+  {                                                                           \
+    *(x) =                                                                    \
+        ((uint64_t) * ((str) + 7)) | ((uint64_t) * ((str) + 6) << 8) |        \
+        ((uint64_t) * ((str) + 5) << 16) | ((uint64_t) * ((str) + 4) << 24) | \
+        ((uint64_t) * ((str) + 3) << 32) | ((uint64_t) * ((str) + 2) << 40) | \
+        ((uint64_t) * ((str) + 1) << 48) | ((uint64_t) * ((str) + 0) << 56);  \
+  }
+
+/* Macros used for loops unrolling */
+
+#define SHA512_SCR(i) \
+  { w[i] = SHA512_F4(w[i - 2]) + w[i - 7] + SHA512_F3(w[i - 15]) + w[i - 16]; }
+
+#define SHA512_EXP(a, b, c, d, e, f, g, h, j)                               \
+  {                                                                         \
+    t1 = wv[h] + SHA512_F2(wv[e]) + CH(wv[e], wv[f], wv[g]) + sha512_k[j] + \
+         w[j];                                                              \
+    t2 = SHA512_F1(wv[a]) + MAJ(wv[a], wv[b], wv[c]);                       \
+    wv[d] += t1;                                                            \
+    wv[h] = t1 + t2;                                                        \
+  }
+
+static const uint64_t sha512_h0[8] = {0x6a09e667f3bcc908ULL,
+                                      0xbb67ae8584caa73bULL,
+                                      0x3c6ef372fe94f82bULL,
+                                      0xa54ff53a5f1d36f1ULL,
+                                      0x510e527fade682d1ULL,
+                                      0x9b05688c2b3e6c1fULL,
+                                      0x1f83d9abfb41bd6bULL,
+                                      0x5be0cd19137e2179ULL};
+
+static const uint64_t sha512_k[80] = {
+    0x428a2f98d728ae22ULL, 0x7137449123ef65cdULL, 0xb5c0fbcfec4d3b2fULL,
+    0xe9b5dba58189dbbcULL, 0x3956c25bf348b538ULL, 0x59f111f1b605d019ULL,
+    0x923f82a4af194f9bULL, 0xab1c5ed5da6d8118ULL, 0xd807aa98a3030242ULL,
+    0x12835b0145706fbeULL, 0x243185be4ee4b28cULL, 0x550c7dc3d5ffb4e2ULL,
+    0x72be5d74f27b896fULL, 0x80deb1fe3b1696b1ULL, 0x9bdc06a725c71235ULL,
+    0xc19bf174cf692694ULL, 0xe49b69c19ef14ad2ULL, 0xefbe4786384f25e3ULL,
+    0x0fc19dc68b8cd5b5ULL, 0x240ca1cc77ac9c65ULL, 0x2de92c6f592b0275ULL,
+    0x4a7484aa6ea6e483ULL, 0x5cb0a9dcbd41fbd4ULL, 0x76f988da831153b5ULL,
+    0x983e5152ee66dfabULL, 0xa831c66d2db43210ULL, 0xb00327c898fb213fULL,
+    0xbf597fc7beef0ee4ULL, 0xc6e00bf33da88fc2ULL, 0xd5a79147930aa725ULL,
+    0x06ca6351e003826fULL, 0x142929670a0e6e70ULL, 0x27b70a8546d22ffcULL,
+    0x2e1b21385c26c926ULL, 0x4d2c6dfc5ac42aedULL, 0x53380d139d95b3dfULL,
+    0x650a73548baf63deULL, 0x766a0abb3c77b2a8ULL, 0x81c2c92e47edaee6ULL,
+    0x92722c851482353bULL, 0xa2bfe8a14cf10364ULL, 0xa81a664bbc423001ULL,
+    0xc24b8b70d0f89791ULL, 0xc76c51a30654be30ULL, 0xd192e819d6ef5218ULL,
+    0xd69906245565a910ULL, 0xf40e35855771202aULL, 0x106aa07032bbd1b8ULL,
+    0x19a4c116b8d2d0c8ULL, 0x1e376c085141ab53ULL, 0x2748774cdf8eeb99ULL,
+    0x34b0bcb5e19b48a8ULL, 0x391c0cb3c5c95a63ULL, 0x4ed8aa4ae3418acbULL,
+    0x5b9cca4f7763e373ULL, 0x682e6ff3d6b2b8a3ULL, 0x748f82ee5defb2fcULL,
+    0x78a5636f43172f60ULL, 0x84c87814a1f0ab72ULL, 0x8cc702081a6439ecULL,
+    0x90befffa23631e28ULL, 0xa4506cebde82bde9ULL, 0xbef9a3f7b2c67915ULL,
+    0xc67178f2e372532bULL, 0xca273eceea26619cULL, 0xd186b8c721c0c207ULL,
+    0xeada7dd6cde0eb1eULL, 0xf57d4f7fee6ed178ULL, 0x06f067aa72176fbaULL,
+    0x0a637dc5a2c898a6ULL, 0x113f9804bef90daeULL, 0x1b710b35131c471bULL,
+    0x28db77f523047d84ULL, 0x32caab7b40c72493ULL, 0x3c9ebe0a15c9bebcULL,
+    0x431d67c49c100d4cULL, 0x4cc5d4becb3e42b6ULL, 0x597f299cfc657e2aULL,
+    0x5fcb6fab3ad6faecULL, 0x6c44198c4a475817ULL};
+
+/* SHA-512 implementation */
+
+void avb_sha512_init(AvbSHA512Ctx* ctx) {
+#ifdef UNROLL_LOOPS_SHA512
+  ctx->h[0] = sha512_h0[0];
+  ctx->h[1] = sha512_h0[1];
+  ctx->h[2] = sha512_h0[2];
+  ctx->h[3] = sha512_h0[3];
+  ctx->h[4] = sha512_h0[4];
+  ctx->h[5] = sha512_h0[5];
+  ctx->h[6] = sha512_h0[6];
+  ctx->h[7] = sha512_h0[7];
+#else
+  int i;
+
+  for (i = 0; i < 8; i++)
+    ctx->h[i] = sha512_h0[i];
+#endif /* UNROLL_LOOPS_SHA512 */
+
+  ctx->len = 0;
+  ctx->tot_len = 0;
+}
+
+static void SHA512_transform(AvbSHA512Ctx* ctx,
+                             const uint8_t* message,
+                             unsigned int block_nb) {
+  uint64_t w[80];
+  uint64_t wv[8];
+  uint64_t t1, t2;
+  const uint8_t* sub_block;
+  int i, j;
+
+  for (i = 0; i < (int)block_nb; i++) {
+    sub_block = message + (i << 7);
+
+#ifdef UNROLL_LOOPS_SHA512
+    PACK64(&sub_block[0], &w[0]);
+    PACK64(&sub_block[8], &w[1]);
+    PACK64(&sub_block[16], &w[2]);
+    PACK64(&sub_block[24], &w[3]);
+    PACK64(&sub_block[32], &w[4]);
+    PACK64(&sub_block[40], &w[5]);
+    PACK64(&sub_block[48], &w[6]);
+    PACK64(&sub_block[56], &w[7]);
+    PACK64(&sub_block[64], &w[8]);
+    PACK64(&sub_block[72], &w[9]);
+    PACK64(&sub_block[80], &w[10]);
+    PACK64(&sub_block[88], &w[11]);
+    PACK64(&sub_block[96], &w[12]);
+    PACK64(&sub_block[104], &w[13]);
+    PACK64(&sub_block[112], &w[14]);
+    PACK64(&sub_block[120], &w[15]);
+
+    SHA512_SCR(16);
+    SHA512_SCR(17);
+    SHA512_SCR(18);
+    SHA512_SCR(19);
+    SHA512_SCR(20);
+    SHA512_SCR(21);
+    SHA512_SCR(22);
+    SHA512_SCR(23);
+    SHA512_SCR(24);
+    SHA512_SCR(25);
+    SHA512_SCR(26);
+    SHA512_SCR(27);
+    SHA512_SCR(28);
+    SHA512_SCR(29);
+    SHA512_SCR(30);
+    SHA512_SCR(31);
+    SHA512_SCR(32);
+    SHA512_SCR(33);
+    SHA512_SCR(34);
+    SHA512_SCR(35);
+    SHA512_SCR(36);
+    SHA512_SCR(37);
+    SHA512_SCR(38);
+    SHA512_SCR(39);
+    SHA512_SCR(40);
+    SHA512_SCR(41);
+    SHA512_SCR(42);
+    SHA512_SCR(43);
+    SHA512_SCR(44);
+    SHA512_SCR(45);
+    SHA512_SCR(46);
+    SHA512_SCR(47);
+    SHA512_SCR(48);
+    SHA512_SCR(49);
+    SHA512_SCR(50);
+    SHA512_SCR(51);
+    SHA512_SCR(52);
+    SHA512_SCR(53);
+    SHA512_SCR(54);
+    SHA512_SCR(55);
+    SHA512_SCR(56);
+    SHA512_SCR(57);
+    SHA512_SCR(58);
+    SHA512_SCR(59);
+    SHA512_SCR(60);
+    SHA512_SCR(61);
+    SHA512_SCR(62);
+    SHA512_SCR(63);
+    SHA512_SCR(64);
+    SHA512_SCR(65);
+    SHA512_SCR(66);
+    SHA512_SCR(67);
+    SHA512_SCR(68);
+    SHA512_SCR(69);
+    SHA512_SCR(70);
+    SHA512_SCR(71);
+    SHA512_SCR(72);
+    SHA512_SCR(73);
+    SHA512_SCR(74);
+    SHA512_SCR(75);
+    SHA512_SCR(76);
+    SHA512_SCR(77);
+    SHA512_SCR(78);
+    SHA512_SCR(79);
+
+    wv[0] = ctx->h[0];
+    wv[1] = ctx->h[1];
+    wv[2] = ctx->h[2];
+    wv[3] = ctx->h[3];
+    wv[4] = ctx->h[4];
+    wv[5] = ctx->h[5];
+    wv[6] = ctx->h[6];
+    wv[7] = ctx->h[7];
+
+    j = 0;
+
+    do {
+      SHA512_EXP(0, 1, 2, 3, 4, 5, 6, 7, j);
+      j++;
+      SHA512_EXP(7, 0, 1, 2, 3, 4, 5, 6, j);
+      j++;
+      SHA512_EXP(6, 7, 0, 1, 2, 3, 4, 5, j);
+      j++;
+      SHA512_EXP(5, 6, 7, 0, 1, 2, 3, 4, j);
+      j++;
+      SHA512_EXP(4, 5, 6, 7, 0, 1, 2, 3, j);
+      j++;
+      SHA512_EXP(3, 4, 5, 6, 7, 0, 1, 2, j);
+      j++;
+      SHA512_EXP(2, 3, 4, 5, 6, 7, 0, 1, j);
+      j++;
+      SHA512_EXP(1, 2, 3, 4, 5, 6, 7, 0, j);
+      j++;
+    } while (j < 80);
+
+    ctx->h[0] += wv[0];
+    ctx->h[1] += wv[1];
+    ctx->h[2] += wv[2];
+    ctx->h[3] += wv[3];
+    ctx->h[4] += wv[4];
+    ctx->h[5] += wv[5];
+    ctx->h[6] += wv[6];
+    ctx->h[7] += wv[7];
+#else
+    for (j = 0; j < 16; j++) {
+      PACK64(&sub_block[j << 3], &w[j]);
+    }
+
+    for (j = 16; j < 80; j++) {
+      SHA512_SCR(j);
+    }
+
+    for (j = 0; j < 8; j++) {
+      wv[j] = ctx->h[j];
+    }
+
+    for (j = 0; j < 80; j++) {
+      t1 = wv[7] + SHA512_F2(wv[4]) + CH(wv[4], wv[5], wv[6]) + sha512_k[j] +
+           w[j];
+      t2 = SHA512_F1(wv[0]) + MAJ(wv[0], wv[1], wv[2]);
+      wv[7] = wv[6];
+      wv[6] = wv[5];
+      wv[5] = wv[4];
+      wv[4] = wv[3] + t1;
+      wv[3] = wv[2];
+      wv[2] = wv[1];
+      wv[1] = wv[0];
+      wv[0] = t1 + t2;
+    }
+
+    for (j = 0; j < 8; j++)
+      ctx->h[j] += wv[j];
+#endif /* UNROLL_LOOPS_SHA512 */
+  }
+}
+
+void avb_sha512_update(AvbSHA512Ctx* ctx, const uint8_t* data, uint32_t len) {
+  unsigned int block_nb;
+  unsigned int new_len, rem_len, tmp_len;
+  const uint8_t* shifted_data;
+
+  tmp_len = AVB_SHA512_BLOCK_SIZE - ctx->len;
+  rem_len = len < tmp_len ? len : tmp_len;
+
+  avb_memcpy(&ctx->block[ctx->len], data, rem_len);
+
+  if (ctx->len + len < AVB_SHA512_BLOCK_SIZE) {
+    ctx->len += len;
+    return;
+  }
+
+  new_len = len - rem_len;
+  block_nb = new_len / AVB_SHA512_BLOCK_SIZE;
+
+  shifted_data = data + rem_len;
+
+  SHA512_transform(ctx, ctx->block, 1);
+  SHA512_transform(ctx, shifted_data, block_nb);
+
+  rem_len = new_len % AVB_SHA512_BLOCK_SIZE;
+
+  avb_memcpy(ctx->block, &shifted_data[block_nb << 7], rem_len);
+
+  ctx->len = rem_len;
+  ctx->tot_len += (block_nb + 1) << 7;
+}
+
+uint8_t* avb_sha512_final(AvbSHA512Ctx* ctx) {
+  unsigned int block_nb;
+  unsigned int pm_len;
+  unsigned int len_b;
+
+#ifndef UNROLL_LOOPS_SHA512
+  int i;
+#endif
+
+  block_nb =
+      1 + ((AVB_SHA512_BLOCK_SIZE - 17) < (ctx->len % AVB_SHA512_BLOCK_SIZE));
+
+  len_b = (ctx->tot_len + ctx->len) << 3;
+  pm_len = block_nb << 7;
+
+  avb_memset(ctx->block + ctx->len, 0, pm_len - ctx->len);
+  ctx->block[ctx->len] = 0x80;
+  UNPACK32(len_b, ctx->block + pm_len - 4);
+
+  SHA512_transform(ctx, ctx->block, block_nb);
+
+#ifdef UNROLL_LOOPS_SHA512
+  UNPACK64(ctx->h[0], &ctx->buf[0]);
+  UNPACK64(ctx->h[1], &ctx->buf[8]);
+  UNPACK64(ctx->h[2], &ctx->buf[16]);
+  UNPACK64(ctx->h[3], &ctx->buf[24]);
+  UNPACK64(ctx->h[4], &ctx->buf[32]);
+  UNPACK64(ctx->h[5], &ctx->buf[40]);
+  UNPACK64(ctx->h[6], &ctx->buf[48]);
+  UNPACK64(ctx->h[7], &ctx->buf[56]);
+#else
+  for (i = 0; i < 8; i++)
+    UNPACK64(ctx->h[i], &ctx->buf[i << 3]);
+#endif /* UNROLL_LOOPS_SHA512 */
+
+  return ctx->buf;
+}
diff --git a/lib/libavb/avb_slot_verify.c b/lib/libavb/avb_slot_verify.c
new file mode 100644
index 0000000..17e73d6
--- /dev/null
+++ b/lib/libavb/avb_slot_verify.c
@@ -0,0 +1,1169 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * SPDX-License-Identifier:	MIT
+ */
+
+#include "avb/avb_slot_verify.h"
+#include "avb/avb_chain_partition_descriptor.h"
+#include "avb/avb_footer.h"
+#include "avb/avb_hash_descriptor.h"
+#include "avb/avb_kernel_cmdline_descriptor.h"
+#include "avb/avb_sha.h"
+#include "avb/avb_util.h"
+#include "avb/avb_vbmeta_image.h"
+#include "avb/avb_version.h"
+
+/* Maximum allow length (in bytes) of a partition name, including
+ * ab_suffix.
+ */
+#define PART_NAME_MAX_SIZE 32
+
+/* Maximum number of partitions that can be loaded with avb_slot_verify(). */
+#define MAX_NUMBER_OF_LOADED_PARTITIONS 32
+
+/* Maximum number of vbmeta images that can be loaded with avb_slot_verify(). */
+#define MAX_NUMBER_OF_VBMETA_IMAGES 32
+
+/* Maximum size of a vbmeta image - 64 KiB. */
+#define VBMETA_MAX_SIZE (64 * 1024)
+
+/* Helper function to see if we should continue with verification in
+ * allow_verification_error=true mode if something goes wrong. See the
+ * comments for the avb_slot_verify() function for more information.
+ */
+static inline bool result_should_continue(AvbSlotVerifyResult result) {
+  switch (result) {
+    case AVB_SLOT_VERIFY_RESULT_ERROR_OOM:
+    case AVB_SLOT_VERIFY_RESULT_ERROR_IO:
+    case AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA:
+    case AVB_SLOT_VERIFY_RESULT_ERROR_UNSUPPORTED_VERSION:
+      return false;
+
+    case AVB_SLOT_VERIFY_RESULT_OK:
+    case AVB_SLOT_VERIFY_RESULT_ERROR_VERIFICATION:
+    case AVB_SLOT_VERIFY_RESULT_ERROR_ROLLBACK_INDEX:
+    case AVB_SLOT_VERIFY_RESULT_ERROR_PUBLIC_KEY_REJECTED:
+      return true;
+  }
+
+  return false;
+}
+
+static AvbSlotVerifyResult load_and_verify_hash_partition(
+    AvbOps* ops,
+    const char* const* requested_partitions,
+    const char* ab_suffix,
+    bool allow_verification_error,
+    const AvbDescriptor* descriptor,
+    AvbSlotVerifyData* slot_data) {
+  AvbHashDescriptor hash_desc;
+  const uint8_t* desc_partition_name = NULL;
+  const uint8_t* desc_salt;
+  const uint8_t* desc_digest;
+  char part_name[PART_NAME_MAX_SIZE];
+  AvbSlotVerifyResult ret;
+  AvbIOResult io_ret;
+  uint8_t* image_buf = NULL;
+  size_t part_num_read;
+  uint8_t* digest;
+  size_t digest_len;
+  const char* found;
+
+  if (!avb_hash_descriptor_validate_and_byteswap(
+          (const AvbHashDescriptor*)descriptor, &hash_desc)) {
+    ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA;
+    goto out;
+  }
+
+  desc_partition_name =
+      ((const uint8_t*)descriptor) + sizeof(AvbHashDescriptor);
+  desc_salt = desc_partition_name + hash_desc.partition_name_len;
+  desc_digest = desc_salt + hash_desc.salt_len;
+
+  if (!avb_validate_utf8(desc_partition_name, hash_desc.partition_name_len)) {
+    avb_error("Partition name is not valid UTF-8.\n");
+    ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA;
+    goto out;
+  }
+
+  if (!avb_str_concat(part_name,
+                      sizeof part_name,
+                      (const char*)desc_partition_name,
+                      hash_desc.partition_name_len,
+                      ab_suffix,
+                      avb_strlen(ab_suffix))) {
+    avb_error("Partition name and suffix does not fit.\n");
+    ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA;
+    goto out;
+  }
+
+  image_buf = avb_malloc(hash_desc.image_size);
+  if (image_buf == NULL) {
+    ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
+    goto out;
+  }
+
+  io_ret = ops->read_from_partition(ops,
+                                    part_name,
+                                    0 /* offset */,
+                                    hash_desc.image_size,
+                                    image_buf,
+                                    &part_num_read);
+  if (io_ret == AVB_IO_RESULT_ERROR_OOM) {
+    ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
+    goto out;
+  } else if (io_ret != AVB_IO_RESULT_OK) {
+    avb_errorv(part_name, ": Error loading data from partition.\n", NULL);
+    ret = AVB_SLOT_VERIFY_RESULT_ERROR_IO;
+    goto out;
+  }
+  if (part_num_read != hash_desc.image_size) {
+    avb_errorv(part_name, ": Read fewer than requested bytes.\n", NULL);
+    ret = AVB_SLOT_VERIFY_RESULT_ERROR_IO;
+    goto out;
+  }
+
+  if (avb_strcmp((const char*)hash_desc.hash_algorithm, "sha256") == 0) {
+    AvbSHA256Ctx sha256_ctx;
+    avb_sha256_init(&sha256_ctx);
+    avb_sha256_update(&sha256_ctx, desc_salt, hash_desc.salt_len);
+    avb_sha256_update(&sha256_ctx, image_buf, hash_desc.image_size);
+    digest = avb_sha256_final(&sha256_ctx);
+    digest_len = AVB_SHA256_DIGEST_SIZE;
+  } else if (avb_strcmp((const char*)hash_desc.hash_algorithm, "sha512") == 0) {
+    AvbSHA512Ctx sha512_ctx;
+    avb_sha512_init(&sha512_ctx);
+    avb_sha512_update(&sha512_ctx, desc_salt, hash_desc.salt_len);
+    avb_sha512_update(&sha512_ctx, image_buf, hash_desc.image_size);
+    digest = avb_sha512_final(&sha512_ctx);
+    digest_len = AVB_SHA512_DIGEST_SIZE;
+  } else {
+    avb_errorv(part_name, ": Unsupported hash algorithm.\n", NULL);
+    ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA;
+    goto out;
+  }
+
+  if (digest_len != hash_desc.digest_len) {
+    avb_errorv(
+        part_name, ": Digest in descriptor not of expected size.\n", NULL);
+    ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA;
+    goto out;
+  }
+
+  if (avb_safe_memcmp(digest, desc_digest, digest_len) != 0) {
+    avb_errorv(part_name,
+               ": Hash of data does not match digest in descriptor.\n",
+               NULL);
+    ret = AVB_SLOT_VERIFY_RESULT_ERROR_VERIFICATION;
+    goto out;
+  }
+
+  ret = AVB_SLOT_VERIFY_RESULT_OK;
+
+out:
+
+  if (ret == AVB_SLOT_VERIFY_RESULT_OK || result_should_continue(ret)) {
+    /* If this is the requested partition, copy to slot_data. */
+    found = avb_strv_find_str(requested_partitions,
+                              (const char*)desc_partition_name,
+                              hash_desc.partition_name_len);
+    if (found != NULL) {
+      AvbPartitionData* loaded_partition;
+      if (slot_data->num_loaded_partitions == MAX_NUMBER_OF_LOADED_PARTITIONS) {
+        avb_errorv(part_name, ": Too many loaded partitions.\n", NULL);
+        ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
+        goto fail;
+      }
+      loaded_partition =
+          &slot_data->loaded_partitions[slot_data->num_loaded_partitions++];
+      loaded_partition->partition_name = avb_strdup(found);
+      loaded_partition->data_size = hash_desc.image_size;
+      loaded_partition->data = image_buf;
+      image_buf = NULL;
+    }
+  }
+
+fail:
+  if (image_buf != NULL) {
+    avb_free(image_buf);
+  }
+  return ret;
+}
+
+static AvbSlotVerifyResult load_and_verify_vbmeta(
+    AvbOps* ops,
+    const char* const* requested_partitions,
+    const char* ab_suffix,
+    bool allow_verification_error,
+    AvbVBMetaImageFlags toplevel_vbmeta_flags,
+    int rollback_index_location,
+    const char* partition_name,
+    size_t partition_name_len,
+    const uint8_t* expected_public_key,
+    size_t expected_public_key_length,
+    AvbSlotVerifyData* slot_data,
+    AvbAlgorithmType* out_algorithm_type) {
+  char full_partition_name[PART_NAME_MAX_SIZE];
+  AvbSlotVerifyResult ret;
+  AvbIOResult io_ret;
+  size_t vbmeta_offset;
+  size_t vbmeta_size;
+  uint8_t* vbmeta_buf = NULL;
+  size_t vbmeta_num_read;
+  AvbVBMetaVerifyResult vbmeta_ret;
+  const uint8_t* pk_data;
+  size_t pk_len;
+  AvbVBMetaImageHeader vbmeta_header;
+  uint64_t stored_rollback_index;
+  const AvbDescriptor** descriptors = NULL;
+  size_t num_descriptors;
+  size_t n;
+  bool is_main_vbmeta;
+  bool is_vbmeta_partition;
+  AvbVBMetaData* vbmeta_image_data = NULL;
+
+  ret = AVB_SLOT_VERIFY_RESULT_OK;
+
+  avb_assert(slot_data != NULL);
+
+  /* Since we allow top-level vbmeta in 'boot', use
+   * rollback_index_location to determine whether we're the main
+   * vbmeta struct.
+   */
+  is_main_vbmeta = (rollback_index_location == 0);
+  is_vbmeta_partition = (avb_strcmp(partition_name, "vbmeta") == 0);
+
+  if (!avb_validate_utf8((const uint8_t*)partition_name, partition_name_len)) {
+    avb_error("Partition name is not valid UTF-8.\n");
+    ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA;
+    goto out;
+  }
+
+  /* Construct full partition name. */
+  if (!avb_str_concat(full_partition_name,
+                      sizeof full_partition_name,
+                      partition_name,
+                      partition_name_len,
+                      ab_suffix,
+                      avb_strlen(ab_suffix))) {
+    avb_error("Partition name and suffix does not fit.\n");
+    ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA;
+    goto out;
+  }
+
+  avb_debugv("Loading vbmeta struct from partition '",
+             full_partition_name,
+             "'.\n",
+             NULL);
+
+  /* If we're loading from the main vbmeta partition, the vbmeta
+   * struct is in the beginning. Otherwise we have to locate it via a
+   * footer.
+   */
+  if (is_vbmeta_partition) {
+    vbmeta_offset = 0;
+    vbmeta_size = VBMETA_MAX_SIZE;
+  } else {
+    uint8_t footer_buf[AVB_FOOTER_SIZE];
+    size_t footer_num_read;
+    AvbFooter footer;
+
+    io_ret = ops->read_from_partition(ops,
+                                      full_partition_name,
+                                      -AVB_FOOTER_SIZE,
+                                      AVB_FOOTER_SIZE,
+                                      footer_buf,
+                                      &footer_num_read);
+    if (io_ret == AVB_IO_RESULT_ERROR_OOM) {
+      ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
+      goto out;
+    } else if (io_ret != AVB_IO_RESULT_OK) {
+      avb_errorv(full_partition_name, ": Error loading footer.\n", NULL);
+      ret = AVB_SLOT_VERIFY_RESULT_ERROR_IO;
+      goto out;
+    }
+    avb_assert(footer_num_read == AVB_FOOTER_SIZE);
+
+    if (!avb_footer_validate_and_byteswap((const AvbFooter*)footer_buf,
+                                          &footer)) {
+      avb_errorv(full_partition_name, ": Error validating footer.\n", NULL);
+      ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA;
+      goto out;
+    }
+
+    /* Basic footer sanity check since the data is untrusted. */
+    if (footer.vbmeta_size > VBMETA_MAX_SIZE) {
+      avb_errorv(
+          full_partition_name, ": Invalid vbmeta size in footer.\n", NULL);
+      ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA;
+      goto out;
+    }
+
+    vbmeta_offset = footer.vbmeta_offset;
+    vbmeta_size = footer.vbmeta_size;
+  }
+
+  vbmeta_buf = avb_malloc(vbmeta_size);
+  if (vbmeta_buf == NULL) {
+    ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
+    goto out;
+  }
+
+  io_ret = ops->read_from_partition(ops,
+                                    full_partition_name,
+                                    vbmeta_offset,
+                                    vbmeta_size,
+                                    vbmeta_buf,
+                                    &vbmeta_num_read);
+  if (io_ret == AVB_IO_RESULT_ERROR_OOM) {
+    ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
+    goto out;
+  } else if (io_ret != AVB_IO_RESULT_OK) {
+    /* If we're looking for 'vbmeta' but there is no such partition,
+     * go try to get it from the boot partition instead.
+     */
+    if (is_main_vbmeta && io_ret == AVB_IO_RESULT_ERROR_NO_SUCH_PARTITION &&
+        is_vbmeta_partition) {
+      avb_debugv(full_partition_name,
+                 ": No such partition. Trying 'boot' instead.\n",
+                 NULL);
+      ret = load_and_verify_vbmeta(ops,
+                                   requested_partitions,
+                                   ab_suffix,
+                                   allow_verification_error,
+                                   0 /* toplevel_vbmeta_flags */,
+                                   0 /* rollback_index_location */,
+                                   "boot",
+                                   avb_strlen("boot"),
+                                   NULL /* expected_public_key */,
+                                   0 /* expected_public_key_length */,
+                                   slot_data,
+                                   out_algorithm_type);
+      goto out;
+    } else {
+      avb_errorv(full_partition_name, ": Error loading vbmeta data.\n", NULL);
+      ret = AVB_SLOT_VERIFY_RESULT_ERROR_IO;
+      goto out;
+    }
+  }
+  avb_assert(vbmeta_num_read <= vbmeta_size);
+
+  /* Check if the image is properly signed and get the public key used
+   * to sign the image.
+   */
+  vbmeta_ret =
+      avb_vbmeta_image_verify(vbmeta_buf, vbmeta_num_read, &pk_data, &pk_len);
+  switch (vbmeta_ret) {
+    case AVB_VBMETA_VERIFY_RESULT_OK:
+      avb_assert(pk_data != NULL && pk_len > 0);
+      break;
+
+    case AVB_VBMETA_VERIFY_RESULT_OK_NOT_SIGNED:
+    case AVB_VBMETA_VERIFY_RESULT_HASH_MISMATCH:
+    case AVB_VBMETA_VERIFY_RESULT_SIGNATURE_MISMATCH:
+      ret = AVB_SLOT_VERIFY_RESULT_ERROR_VERIFICATION;
+      avb_errorv(full_partition_name,
+                 ": Error verifying vbmeta image: ",
+                 avb_vbmeta_verify_result_to_string(vbmeta_ret),
+                 "\n",
+                 NULL);
+      if (!allow_verification_error) {
+        goto out;
+      }
+      break;
+
+    case AVB_VBMETA_VERIFY_RESULT_INVALID_VBMETA_HEADER:
+      /* No way to continue this case. */
+      ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA;
+      avb_errorv(full_partition_name,
+                 ": Error verifying vbmeta image: invalid vbmeta header\n",
+                 NULL);
+      goto out;
+
+    case AVB_VBMETA_VERIFY_RESULT_UNSUPPORTED_VERSION:
+      /* No way to continue this case. */
+      ret = AVB_SLOT_VERIFY_RESULT_ERROR_UNSUPPORTED_VERSION;
+      avb_errorv(full_partition_name,
+                 ": Error verifying vbmeta image: unsupported AVB version\n",
+                 NULL);
+      goto out;
+  }
+
+  /* Byteswap the header. */
+  avb_vbmeta_image_header_to_host_byte_order((AvbVBMetaImageHeader*)vbmeta_buf,
+                                             &vbmeta_header);
+
+  /* If we're the toplevel, assign flags so they'll be passed down. */
+  if (is_main_vbmeta) {
+    toplevel_vbmeta_flags = (AvbVBMetaImageFlags)vbmeta_header.flags;
+  } else {
+    if (vbmeta_header.flags != 0) {
+      ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA;
+      avb_errorv(full_partition_name,
+                 ": chained vbmeta image has non-zero flags\n",
+                 NULL);
+      goto out;
+    }
+  }
+
+  /* Check if key used to make signature matches what is expected. */
+  if (pk_data != NULL) {
+    if (expected_public_key != NULL) {
+      avb_assert(!is_main_vbmeta);
+      if (expected_public_key_length != pk_len ||
+          avb_safe_memcmp(expected_public_key, pk_data, pk_len) != 0) {
+        avb_errorv(full_partition_name,
+                   ": Public key used to sign data does not match key in chain "
+                   "partition descriptor.\n",
+                   NULL);
+        ret = AVB_SLOT_VERIFY_RESULT_ERROR_PUBLIC_KEY_REJECTED;
+        if (!allow_verification_error) {
+          goto out;
+        }
+      }
+    } 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, 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;
+      } else if (io_ret != AVB_IO_RESULT_OK) {
+        avb_errorv(full_partition_name,
+                   ": Error while checking public key used to sign data.\n",
+                   NULL);
+        ret = AVB_SLOT_VERIFY_RESULT_ERROR_IO;
+        goto out;
+      }
+      if (!key_is_trusted) {
+        avb_errorv(full_partition_name,
+                   ": Public key used to sign data rejected.\n",
+                   NULL);
+        ret = AVB_SLOT_VERIFY_RESULT_ERROR_PUBLIC_KEY_REJECTED;
+        if (!allow_verification_error) {
+          goto out;
+        }
+      }
+    }
+  }
+
+  /* Check rollback index. */
+  io_ret = ops->read_rollback_index(
+      ops, rollback_index_location, &stored_rollback_index);
+  if (io_ret == AVB_IO_RESULT_ERROR_OOM) {
+    ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
+    goto out;
+  } else if (io_ret != AVB_IO_RESULT_OK) {
+    avb_errorv(full_partition_name,
+               ": Error getting rollback index for location.\n",
+               NULL);
+    ret = AVB_SLOT_VERIFY_RESULT_ERROR_IO;
+    goto out;
+  }
+  if (vbmeta_header.rollback_index < stored_rollback_index) {
+    avb_errorv(
+        full_partition_name,
+        ": Image rollback index is less than the stored rollback index.\n",
+        NULL);
+    ret = AVB_SLOT_VERIFY_RESULT_ERROR_ROLLBACK_INDEX;
+    if (!allow_verification_error) {
+      goto out;
+    }
+  }
+
+  /* Copy vbmeta to vbmeta_images before recursing. */
+  if (is_main_vbmeta) {
+    avb_assert(slot_data->num_vbmeta_images == 0);
+  } else {
+    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);
+    ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
+    goto out;
+  }
+  vbmeta_image_data = &slot_data->vbmeta_images[slot_data->num_vbmeta_images++];
+  vbmeta_image_data->partition_name = avb_strdup(partition_name);
+  vbmeta_image_data->vbmeta_data = vbmeta_buf;
+  /* Note that |vbmeta_buf| is actually |vbmeta_num_read| bytes long
+   * and this includes data past the end of the image. Pass the
+   * actual size of the vbmeta image. Also, no need to use
+   * avb_safe_add() since the header has already been verified.
+   */
+  vbmeta_image_data->vbmeta_size =
+      sizeof(AvbVBMetaImageHeader) +
+      vbmeta_header.authentication_data_block_size +
+      vbmeta_header.auxiliary_data_block_size;
+  vbmeta_image_data->verify_result = vbmeta_ret;
+
+  /* Now go through all descriptors and take the appropriate action:
+   *
+   * - hash descriptor: Load data from partition, calculate hash, and
+   *   checks that it matches what's in the hash descriptor.
+   *
+   * - hashtree descriptor: Do nothing since verification happens
+   *   on-the-fly from within the OS.
+   *
+   * - chained partition descriptor: Load the footer, load the vbmeta
+   *   image, verify vbmeta image (includes rollback checks, hash
+   *   checks, bail on chained partitions).
+   */
+  descriptors =
+      avb_descriptor_get_all(vbmeta_buf, vbmeta_num_read, &num_descriptors);
+  for (n = 0; n < num_descriptors; n++) {
+    AvbDescriptor desc;
+
+    if (!avb_descriptor_validate_and_byteswap(descriptors[n], &desc)) {
+      avb_errorv(full_partition_name, ": Descriptor is invalid.\n", NULL);
+      ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA;
+      goto out;
+    }
+
+    switch (desc.tag) {
+      case AVB_DESCRIPTOR_TAG_HASH: {
+        AvbSlotVerifyResult sub_ret;
+        sub_ret = load_and_verify_hash_partition(ops,
+                                                 requested_partitions,
+                                                 ab_suffix,
+                                                 allow_verification_error,
+                                                 descriptors[n],
+                                                 slot_data);
+        if (sub_ret != AVB_SLOT_VERIFY_RESULT_OK) {
+          ret = sub_ret;
+          if (!allow_verification_error || !result_should_continue(ret)) {
+            goto out;
+          }
+        }
+      } break;
+
+      case AVB_DESCRIPTOR_TAG_CHAIN_PARTITION: {
+        AvbSlotVerifyResult sub_ret;
+        AvbChainPartitionDescriptor chain_desc;
+        const uint8_t* chain_partition_name;
+        const uint8_t* chain_public_key;
+
+        /* Only allow CHAIN_PARTITION descriptors in the main vbmeta image. */
+        if (!is_main_vbmeta) {
+          avb_errorv(full_partition_name,
+                     ": Encountered chain descriptor not in main image.\n",
+                     NULL);
+          ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA;
+          goto out;
+        }
+
+        if (!avb_chain_partition_descriptor_validate_and_byteswap(
+                (AvbChainPartitionDescriptor*)descriptors[n], &chain_desc)) {
+          avb_errorv(full_partition_name,
+                     ": Chain partition descriptor is invalid.\n",
+                     NULL);
+          ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA;
+          goto out;
+        }
+
+        if (chain_desc.rollback_index_location == 0) {
+          avb_errorv(full_partition_name,
+                     ": Chain partition has invalid "
+                     "rollback_index_location field.\n",
+                     NULL);
+          ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA;
+          goto out;
+        }
+
+        chain_partition_name = ((const uint8_t*)descriptors[n]) +
+                               sizeof(AvbChainPartitionDescriptor);
+        chain_public_key = chain_partition_name + chain_desc.partition_name_len;
+
+        sub_ret = load_and_verify_vbmeta(ops,
+                                         requested_partitions,
+                                         ab_suffix,
+                                         allow_verification_error,
+                                         toplevel_vbmeta_flags,
+                                         chain_desc.rollback_index_location,
+                                         (const char*)chain_partition_name,
+                                         chain_desc.partition_name_len,
+                                         chain_public_key,
+                                         chain_desc.public_key_len,
+                                         slot_data,
+                                         NULL /* out_algorithm_type */);
+        if (sub_ret != AVB_SLOT_VERIFY_RESULT_OK) {
+          ret = sub_ret;
+          if (!result_should_continue(ret)) {
+            goto out;
+          }
+        }
+      } break;
+
+      case AVB_DESCRIPTOR_TAG_KERNEL_CMDLINE: {
+        const uint8_t* kernel_cmdline;
+        AvbKernelCmdlineDescriptor kernel_cmdline_desc;
+        bool apply_cmdline;
+
+        if (!avb_kernel_cmdline_descriptor_validate_and_byteswap(
+                (AvbKernelCmdlineDescriptor*)descriptors[n],
+                &kernel_cmdline_desc)) {
+          avb_errorv(full_partition_name,
+                     ": Kernel cmdline descriptor is invalid.\n",
+                     NULL);
+          ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA;
+          goto out;
+        }
+
+        kernel_cmdline = ((const uint8_t*)descriptors[n]) +
+                         sizeof(AvbKernelCmdlineDescriptor);
+
+        if (!avb_validate_utf8(kernel_cmdline,
+                               kernel_cmdline_desc.kernel_cmdline_length)) {
+          avb_errorv(full_partition_name,
+                     ": Kernel cmdline is not valid UTF-8.\n",
+                     NULL);
+          ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA;
+          goto out;
+        }
+
+        /* Compare the flags for top-level VBMeta struct with flags in
+         * the command-line descriptor so command-line snippets only
+         * intended for a certain mode (dm-verity enabled/disabled)
+         * are skipped if applicable.
+         */
+        apply_cmdline = true;
+        if (toplevel_vbmeta_flags & AVB_VBMETA_IMAGE_FLAGS_HASHTREE_DISABLED) {
+          if (kernel_cmdline_desc.flags &
+              AVB_KERNEL_CMDLINE_FLAGS_USE_ONLY_IF_HASHTREE_NOT_DISABLED) {
+            apply_cmdline = false;
+          }
+        } else {
+          if (kernel_cmdline_desc.flags &
+              AVB_KERNEL_CMDLINE_FLAGS_USE_ONLY_IF_HASHTREE_DISABLED) {
+            apply_cmdline = false;
+          }
+        }
+
+        if (apply_cmdline) {
+          if (slot_data->cmdline == NULL) {
+            slot_data->cmdline =
+                avb_calloc(kernel_cmdline_desc.kernel_cmdline_length + 1);
+            if (slot_data->cmdline == NULL) {
+              ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
+              goto out;
+            }
+            avb_memcpy(slot_data->cmdline,
+                       kernel_cmdline,
+                       kernel_cmdline_desc.kernel_cmdline_length);
+          } else {
+            /* new cmdline is: <existing_cmdline> + ' ' + <newcmdline> + '\0' */
+            size_t orig_size = avb_strlen(slot_data->cmdline);
+            size_t new_size =
+                orig_size + 1 + kernel_cmdline_desc.kernel_cmdline_length + 1;
+            char* new_cmdline = avb_calloc(new_size);
+            if (new_cmdline == NULL) {
+              ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
+              goto out;
+            }
+            avb_memcpy(new_cmdline, slot_data->cmdline, orig_size);
+            new_cmdline[orig_size] = ' ';
+            avb_memcpy(new_cmdline + orig_size + 1,
+                       kernel_cmdline,
+                       kernel_cmdline_desc.kernel_cmdline_length);
+            avb_free(slot_data->cmdline);
+            slot_data->cmdline = new_cmdline;
+          }
+        }
+      } break;
+
+      /* Explicit fall-through */
+      case AVB_DESCRIPTOR_TAG_PROPERTY:
+      case AVB_DESCRIPTOR_TAG_HASHTREE:
+        /* Do nothing. */
+        break;
+    }
+  }
+
+  if (rollback_index_location >= AVB_MAX_NUMBER_OF_ROLLBACK_INDEX_LOCATIONS) {
+    avb_errorv(
+        full_partition_name, ": Invalid rollback_index_location.\n", NULL);
+    ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA;
+    goto out;
+  }
+
+  slot_data->rollback_indexes[rollback_index_location] =
+      vbmeta_header.rollback_index;
+
+  if (out_algorithm_type != NULL) {
+    *out_algorithm_type = (AvbAlgorithmType)vbmeta_header.algorithm_type;
+  }
+
+out:
+  /* If |vbmeta_image_data| isn't NULL it means that it adopted
+   * |vbmeta_buf| so in that case don't free it here.
+   */
+  if (vbmeta_image_data == NULL) {
+    if (vbmeta_buf != NULL) {
+      avb_free(vbmeta_buf);
+    }
+  }
+  if (descriptors != NULL) {
+    avb_free(descriptors);
+  }
+  return ret;
+}
+
+#define NUM_GUIDS 3
+
+/* Substitutes all variables (e.g. $(ANDROID_SYSTEM_PARTUUID)) with
+ * values. Returns NULL on OOM, otherwise the cmdline with values
+ * replaced.
+ */
+static char* sub_cmdline(AvbOps* ops,
+                         const char* cmdline,
+                         const char* ab_suffix,
+                         bool using_boot_for_vbmeta) {
+  const char* part_name_str[NUM_GUIDS] = {"system", "boot", "vbmeta"};
+  const char* replace_str[NUM_GUIDS] = {"$(ANDROID_SYSTEM_PARTUUID)",
+                                        "$(ANDROID_BOOT_PARTUUID)",
+                                        "$(ANDROID_VBMETA_PARTUUID)"};
+  char* ret = NULL;
+  AvbIOResult io_ret;
+
+  /* Special-case for when the top-level vbmeta struct is in the boot
+   * partition.
+   */
+  if (using_boot_for_vbmeta) {
+    part_name_str[2] = "boot";
+  }
+
+  /* Replace unique partition GUIDs */
+  for (size_t n = 0; n < NUM_GUIDS; n++) {
+    char part_name[PART_NAME_MAX_SIZE];
+    char guid_buf[37];
+
+    if (!avb_str_concat(part_name,
+                        sizeof part_name,
+                        part_name_str[n],
+                        avb_strlen(part_name_str[n]),
+                        ab_suffix,
+                        avb_strlen(ab_suffix))) {
+      avb_error("Partition name and suffix does not fit.\n");
+      goto fail;
+    }
+
+    io_ret = ops->get_unique_guid_for_partition(
+        ops, part_name, guid_buf, sizeof guid_buf);
+    if (io_ret == AVB_IO_RESULT_ERROR_OOM) {
+      return NULL;
+    } else if (io_ret != AVB_IO_RESULT_OK) {
+      avb_error("Error getting unique GUID for partition.\n");
+      goto fail;
+    }
+
+    if (ret == NULL) {
+      ret = avb_replace(cmdline, replace_str[n], guid_buf);
+    } else {
+      char* new_ret = avb_replace(ret, replace_str[n], guid_buf);
+      avb_free(ret);
+      ret = new_ret;
+    }
+    if (ret == NULL) {
+      goto fail;
+    }
+  }
+
+  return ret;
+
+fail:
+  if (ret != NULL) {
+    avb_free(ret);
+  }
+  return NULL;
+}
+
+static int cmdline_append_option(AvbSlotVerifyData* slot_data,
+                                 const char* key,
+                                 const char* value) {
+  size_t offset, key_len, value_len;
+  char* new_cmdline;
+
+  key_len = avb_strlen(key);
+  value_len = avb_strlen(value);
+
+  offset = 0;
+  if (slot_data->cmdline != NULL) {
+    offset = avb_strlen(slot_data->cmdline);
+    if (offset > 0) {
+      offset += 1;
+    }
+  }
+
+  new_cmdline = avb_calloc(offset + key_len + value_len + 2);
+  if (new_cmdline == NULL) {
+    return 0;
+  }
+  if (offset > 0) {
+    avb_memcpy(new_cmdline, slot_data->cmdline, offset - 1);
+    new_cmdline[offset - 1] = ' ';
+  }
+  avb_memcpy(new_cmdline + offset, key, key_len);
+  new_cmdline[offset + key_len] = '=';
+  avb_memcpy(new_cmdline + offset + key_len + 1, value, value_len);
+  if (slot_data->cmdline != NULL) {
+    avb_free(slot_data->cmdline);
+  }
+  slot_data->cmdline = new_cmdline;
+
+  return 1;
+}
+
+#define AVB_MAX_DIGITS_UINT64 32
+
+/* Writes |value| to |digits| in base 10 followed by a NUL byte.
+ * Returns number of characters written excluding the NUL byte.
+ */
+static size_t uint64_to_base10(uint64_t value,
+                               char digits[AVB_MAX_DIGITS_UINT64]) {
+  char rev_digits[AVB_MAX_DIGITS_UINT64];
+  size_t n, num_digits;
+
+  for (num_digits = 0; num_digits < AVB_MAX_DIGITS_UINT64 - 1;) {
+    rev_digits[num_digits++] = (value % 10) + '0';
+    value /= 10;
+    if (value == 0) {
+      break;
+    }
+  }
+
+  for (n = 0; n < num_digits; n++) {
+    digits[n] = rev_digits[num_digits - 1 - n];
+  }
+  digits[n] = '\0';
+  return n;
+}
+
+static int cmdline_append_version(AvbSlotVerifyData* slot_data,
+                                  const char* key,
+                                  uint64_t major_version,
+                                  uint64_t minor_version) {
+  char major_digits[AVB_MAX_DIGITS_UINT64];
+  char minor_digits[AVB_MAX_DIGITS_UINT64];
+  char combined[AVB_MAX_DIGITS_UINT64 * 2 + 1];
+  size_t num_major_digits, num_minor_digits;
+
+  num_major_digits = uint64_to_base10(major_version, major_digits);
+  num_minor_digits = uint64_to_base10(minor_version, minor_digits);
+  avb_memcpy(combined, major_digits, num_major_digits);
+  combined[num_major_digits] = '.';
+  avb_memcpy(combined + num_major_digits + 1, minor_digits, num_minor_digits);
+  combined[num_major_digits + 1 + num_minor_digits] = '\0';
+
+  return cmdline_append_option(slot_data, key, combined);
+}
+
+static int cmdline_append_uint64_base10(AvbSlotVerifyData* slot_data,
+                                        const char* key,
+                                        uint64_t value) {
+  char digits[AVB_MAX_DIGITS_UINT64];
+  uint64_to_base10(value, digits);
+  return cmdline_append_option(slot_data, key, digits);
+}
+
+static int cmdline_append_hex(AvbSlotVerifyData* slot_data,
+                              const char* key,
+                              const uint8_t* data,
+                              size_t data_len) {
+  char hex_digits[17] = "0123456789abcdef";
+  char* hex_data;
+  int ret;
+  size_t n;
+
+  hex_data = avb_malloc(data_len * 2 + 1);
+  if (hex_data == NULL) {
+    return 0;
+  }
+
+  for (n = 0; n < data_len; n++) {
+    hex_data[n * 2] = hex_digits[data[n] >> 4];
+    hex_data[n * 2 + 1] = hex_digits[data[n] & 0x0f];
+  }
+  hex_data[n * 2] = '\0';
+
+  ret = cmdline_append_option(slot_data, key, hex_data);
+  avb_free(hex_data);
+  return ret;
+}
+
+AvbSlotVerifyResult avb_slot_verify(AvbOps* ops,
+                                    const char* const* requested_partitions,
+                                    const char* ab_suffix,
+                                    bool allow_verification_error,
+                                    AvbSlotVerifyData** out_data) {
+  AvbSlotVerifyResult ret;
+  AvbSlotVerifyData* slot_data = NULL;
+  AvbAlgorithmType algorithm_type = AVB_ALGORITHM_TYPE_NONE;
+  AvbIOResult io_ret;
+  bool using_boot_for_vbmeta = false;
+
+  if (out_data != NULL) {
+    *out_data = NULL;
+  }
+
+  slot_data = avb_calloc(sizeof(AvbSlotVerifyData));
+  if (slot_data == NULL) {
+    ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
+    goto fail;
+  }
+  slot_data->vbmeta_images =
+      avb_calloc(sizeof(AvbVBMetaData) * MAX_NUMBER_OF_VBMETA_IMAGES);
+  if (slot_data->vbmeta_images == NULL) {
+    ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
+    goto fail;
+  }
+  slot_data->loaded_partitions =
+      avb_calloc(sizeof(AvbPartitionData) * MAX_NUMBER_OF_LOADED_PARTITIONS);
+  if (slot_data->loaded_partitions == NULL) {
+    ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
+    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);
+  if (!allow_verification_error && ret != AVB_SLOT_VERIFY_RESULT_OK) {
+    goto fail;
+  }
+
+  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 things check out, mangle the kernel command-line as needed. */
+  if (result_should_continue(ret)) {
+    /* Fill in |ab_suffix| field. */
+    slot_data->ab_suffix = avb_strdup(ab_suffix);
+    if (slot_data->ab_suffix == NULL) {
+      ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
+      goto fail;
+    }
+
+    /* 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 fail;
+    }
+
+    /* Add androidboot.vbmeta.avb_version option. */
+    if (!cmdline_append_version(slot_data,
+                                "androidboot.vbmeta.avb_version",
+                                AVB_VERSION_MAJOR,
+                                AVB_VERSION_MINOR)) {
+      ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
+      goto fail;
+    }
+
+    /* Substitute $(ANDROID_SYSTEM_PARTUUID) and friends. */
+    if (slot_data->cmdline != NULL) {
+      char* new_cmdline;
+      new_cmdline = sub_cmdline(
+          ops, slot_data->cmdline, ab_suffix, using_boot_for_vbmeta);
+      if (new_cmdline == NULL) {
+        ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
+        goto fail;
+      }
+      avb_free(slot_data->cmdline);
+      slot_data->cmdline = new_cmdline;
+    }
+
+    /* Set androidboot.avb.device_state to "locked" or "unlocked". */
+    bool is_device_unlocked;
+    io_ret = ops->read_is_device_unlocked(ops, &is_device_unlocked);
+    if (io_ret == AVB_IO_RESULT_ERROR_OOM) {
+      ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
+      goto fail;
+    } else if (io_ret != AVB_IO_RESULT_OK) {
+      avb_error("Error getting device state.\n");
+      ret = AVB_SLOT_VERIFY_RESULT_ERROR_IO;
+      goto fail;
+    }
+    if (!cmdline_append_option(slot_data,
+                               "androidboot.vbmeta.device_state",
+                               is_device_unlocked ? "unlocked" : "locked")) {
+      ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
+      goto fail;
+    }
+
+    /* Set androidboot.vbmeta.{hash_alg, size, digest} - use same hash
+     * function as is used to sign vbmeta.
+     */
+    switch (algorithm_type) {
+      /* Explicit fallthrough. */
+      case AVB_ALGORITHM_TYPE_NONE:
+      case AVB_ALGORITHM_TYPE_SHA256_RSA2048:
+      case AVB_ALGORITHM_TYPE_SHA256_RSA4096:
+      case AVB_ALGORITHM_TYPE_SHA256_RSA8192: {
+        AvbSHA256Ctx ctx;
+        size_t n, total_size = 0;
+        avb_sha256_init(&ctx);
+        for (n = 0; n < slot_data->num_vbmeta_images; n++) {
+          avb_sha256_update(&ctx,
+                            slot_data->vbmeta_images[n].vbmeta_data,
+                            slot_data->vbmeta_images[n].vbmeta_size);
+          total_size += slot_data->vbmeta_images[n].vbmeta_size;
+        }
+        if (!cmdline_append_option(
+                slot_data, "androidboot.vbmeta.hash_alg", "sha256") ||
+            !cmdline_append_uint64_base10(
+                slot_data, "androidboot.vbmeta.size", total_size) ||
+            !cmdline_append_hex(slot_data,
+                                "androidboot.vbmeta.digest",
+                                avb_sha256_final(&ctx),
+                                AVB_SHA256_DIGEST_SIZE)) {
+          ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
+          goto fail;
+        }
+      } break;
+      /* Explicit fallthrough. */
+      case AVB_ALGORITHM_TYPE_SHA512_RSA2048:
+      case AVB_ALGORITHM_TYPE_SHA512_RSA4096:
+      case AVB_ALGORITHM_TYPE_SHA512_RSA8192: {
+        AvbSHA512Ctx ctx;
+        size_t n, total_size = 0;
+        avb_sha512_init(&ctx);
+        for (n = 0; n < slot_data->num_vbmeta_images; n++) {
+          avb_sha512_update(&ctx,
+                            slot_data->vbmeta_images[n].vbmeta_data,
+                            slot_data->vbmeta_images[n].vbmeta_size);
+          total_size += slot_data->vbmeta_images[n].vbmeta_size;
+        }
+        if (!cmdline_append_option(
+                slot_data, "androidboot.vbmeta.hash_alg", "sha512") ||
+            !cmdline_append_uint64_base10(
+                slot_data, "androidboot.vbmeta.size", total_size) ||
+            !cmdline_append_hex(slot_data,
+                                "androidboot.vbmeta.digest",
+                                avb_sha512_final(&ctx),
+                                AVB_SHA512_DIGEST_SIZE)) {
+          ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
+          goto fail;
+        }
+      } break;
+      case _AVB_ALGORITHM_NUM_TYPES:
+        avb_assert_not_reached();
+        break;
+    }
+
+    if (out_data != NULL) {
+      *out_data = slot_data;
+    } else {
+      avb_slot_verify_data_free(slot_data);
+    }
+  }
+
+  if (!allow_verification_error) {
+    avb_assert(ret == AVB_SLOT_VERIFY_RESULT_OK);
+  }
+
+  return ret;
+
+fail:
+  if (slot_data != NULL) {
+    avb_slot_verify_data_free(slot_data);
+  }
+  return ret;
+}
+
+void avb_slot_verify_data_free(AvbSlotVerifyData* data) {
+  if (data->ab_suffix != NULL) {
+    avb_free(data->ab_suffix);
+  }
+  if (data->cmdline != NULL) {
+    avb_free(data->cmdline);
+  }
+  if (data->vbmeta_images != NULL) {
+    size_t n;
+    for (n = 0; n < data->num_vbmeta_images; n++) {
+      AvbVBMetaData* vbmeta_image = &data->vbmeta_images[n];
+      if (vbmeta_image->partition_name != NULL) {
+        avb_free(vbmeta_image->partition_name);
+      }
+      if (vbmeta_image->vbmeta_data != NULL) {
+        avb_free(vbmeta_image->vbmeta_data);
+      }
+    }
+    avb_free(data->vbmeta_images);
+  }
+  if (data->loaded_partitions != NULL) {
+    size_t n;
+    for (n = 0; n < data->num_loaded_partitions; n++) {
+      AvbPartitionData* loaded_partition = &data->loaded_partitions[n];
+      if (loaded_partition->partition_name != NULL) {
+        avb_free(loaded_partition->partition_name);
+      }
+      if (loaded_partition->data != NULL) {
+        avb_free(loaded_partition->data);
+      }
+    }
+    avb_free(data->loaded_partitions);
+  }
+  avb_free(data);
+}
+
+const char* avb_slot_verify_result_to_string(AvbSlotVerifyResult result) {
+  const char* ret = NULL;
+
+  switch (result) {
+    case AVB_SLOT_VERIFY_RESULT_OK:
+      ret = "OK";
+      break;
+    case AVB_SLOT_VERIFY_RESULT_ERROR_OOM:
+      ret = "ERROR_OOM";
+      break;
+    case AVB_SLOT_VERIFY_RESULT_ERROR_IO:
+      ret = "ERROR_IO";
+      break;
+    case AVB_SLOT_VERIFY_RESULT_ERROR_VERIFICATION:
+      ret = "ERROR_VERIFICATION";
+      break;
+    case AVB_SLOT_VERIFY_RESULT_ERROR_ROLLBACK_INDEX:
+      ret = "ERROR_ROLLBACK_INDEX";
+      break;
+    case AVB_SLOT_VERIFY_RESULT_ERROR_PUBLIC_KEY_REJECTED:
+      ret = "ERROR_PUBLIC_KEY_REJECTED";
+      break;
+    case AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA:
+      ret = "ERROR_INVALID_METADATA";
+      break;
+    case AVB_SLOT_VERIFY_RESULT_ERROR_UNSUPPORTED_VERSION:
+      ret = "ERROR_UNSUPPORTED_VERSION";
+      break;
+      /* Do not add a 'default:' case here because of -Wswitch. */
+  }
+
+  if (ret == NULL) {
+    avb_error("Unknown AvbSlotVerifyResult value.\n");
+    ret = "(unknown)";
+  }
+
+  return ret;
+}
diff --git a/lib/libavb/avb_sysdeps_posix.c b/lib/libavb/avb_sysdeps_posix.c
new file mode 100644
index 0000000..3ede5c4
--- /dev/null
+++ b/lib/libavb/avb_sysdeps_posix.c
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * SPDX-License-Identifier:	MIT
+ */
+
+#include <stdarg.h>
+#include <stdlib.h>
+
+#include "avb/avb_sysdeps.h"
+
+int avb_memcmp(const void* src1, const void* src2, size_t n) {
+  return memcmp(src1, src2, n);
+}
+
+void* avb_memcpy(void* dest, const void* src, size_t n) {
+  return memcpy(dest, src, n);
+}
+
+void* avb_memset(void* dest, const int c, size_t n) {
+  return memset(dest, c, n);
+}
+
+int avb_strcmp(const char* s1, const char* s2) {
+  return strcmp(s1, s2);
+}
+
+size_t avb_strlen(const char* str) {
+  return strlen(str);
+}
+
+void avb_abort(void) {
+  hang();
+}
+
+void avb_print(const char* message) {
+  printf("%s", message);
+}
+
+void avb_printv(const char* message, ...) {
+  va_list ap;
+  const char* m;
+
+  va_start(ap, message);
+  for (m = message; m != NULL; m = va_arg(ap, const char*)) {
+    printf("%s", m);
+  }
+  va_end(ap);
+}
+
+void* avb_malloc_(size_t size) {
+  return malloc(size);
+}
+
+void avb_free(void* ptr) {
+  free(ptr);
+}
diff --git a/lib/libavb/avb_util.c b/lib/libavb/avb_util.c
new file mode 100644
index 0000000..8119ac0
--- /dev/null
+++ b/lib/libavb/avb_util.c
@@ -0,0 +1,385 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * SPDX-License-Identifier:	MIT
+ */
+
+#include "avb/avb_util.h"
+
+#include <stdarg.h>
+
+uint32_t avb_be32toh(uint32_t in) {
+  uint8_t* d = (uint8_t*)&in;
+  uint32_t ret;
+  ret = ((uint32_t)d[0]) << 24;
+  ret |= ((uint32_t)d[1]) << 16;
+  ret |= ((uint32_t)d[2]) << 8;
+  ret |= ((uint32_t)d[3]);
+  return ret;
+}
+
+uint64_t avb_be64toh(uint64_t in) {
+  uint8_t* d = (uint8_t*)&in;
+  uint64_t ret;
+  ret = ((uint64_t)d[0]) << 56;
+  ret |= ((uint64_t)d[1]) << 48;
+  ret |= ((uint64_t)d[2]) << 40;
+  ret |= ((uint64_t)d[3]) << 32;
+  ret |= ((uint64_t)d[4]) << 24;
+  ret |= ((uint64_t)d[5]) << 16;
+  ret |= ((uint64_t)d[6]) << 8;
+  ret |= ((uint64_t)d[7]);
+  return ret;
+}
+
+/* Converts a 32-bit unsigned integer from host to big-endian byte order. */
+uint32_t avb_htobe32(uint32_t in) {
+  union {
+    uint32_t word;
+    uint8_t bytes[4];
+  } ret;
+  ret.bytes[0] = (in >> 24) & 0xff;
+  ret.bytes[1] = (in >> 16) & 0xff;
+  ret.bytes[2] = (in >> 8) & 0xff;
+  ret.bytes[3] = in & 0xff;
+  return ret.word;
+}
+
+/* Converts a 64-bit unsigned integer from host to big-endian byte order. */
+uint64_t avb_htobe64(uint64_t in) {
+  union {
+    uint64_t word;
+    uint8_t bytes[8];
+  } ret;
+  ret.bytes[0] = (in >> 56) & 0xff;
+  ret.bytes[1] = (in >> 48) & 0xff;
+  ret.bytes[2] = (in >> 40) & 0xff;
+  ret.bytes[3] = (in >> 32) & 0xff;
+  ret.bytes[4] = (in >> 24) & 0xff;
+  ret.bytes[5] = (in >> 16) & 0xff;
+  ret.bytes[6] = (in >> 8) & 0xff;
+  ret.bytes[7] = in & 0xff;
+  return ret.word;
+}
+
+int avb_safe_memcmp(const void* s1, const void* s2, size_t n) {
+  const unsigned char* us1 = s1;
+  const unsigned char* us2 = s2;
+  int result = 0;
+
+  if (0 == n) {
+    return 0;
+  }
+
+  /*
+   * Code snippet without data-dependent branch due to Nate Lawson
+   * (nate at root.org) of Root Labs.
+   */
+  while (n--) {
+    result |= *us1++ ^ *us2++;
+  }
+
+  return result != 0;
+}
+
+bool avb_safe_add_to(uint64_t* value, uint64_t value_to_add) {
+  uint64_t original_value;
+
+  avb_assert(value != NULL);
+
+  original_value = *value;
+
+  *value += value_to_add;
+  if (*value < original_value) {
+    avb_error("Overflow when adding values.\n");
+    return false;
+  }
+
+  return true;
+}
+
+bool avb_safe_add(uint64_t* out_result, uint64_t a, uint64_t b) {
+  uint64_t dummy;
+  if (out_result == NULL) {
+    out_result = &dummy;
+  }
+  *out_result = a;
+  return avb_safe_add_to(out_result, b);
+}
+
+bool avb_validate_utf8(const uint8_t* data, size_t num_bytes) {
+  size_t n;
+  unsigned int num_cc;
+
+  for (n = 0, num_cc = 0; n < num_bytes; n++) {
+    uint8_t c = data[n];
+
+    if (num_cc > 0) {
+      if ((c & (0x80 | 0x40)) == 0x80) {
+        /* 10xx xxxx */
+      } else {
+        goto fail;
+      }
+      num_cc--;
+    } else {
+      if (c < 0x80) {
+        num_cc = 0;
+      } else if ((c & (0x80 | 0x40 | 0x20)) == (0x80 | 0x40)) {
+        /* 110x xxxx */
+        num_cc = 1;
+      } else if ((c & (0x80 | 0x40 | 0x20 | 0x10)) == (0x80 | 0x40 | 0x20)) {
+        /* 1110 xxxx */
+        num_cc = 2;
+      } else if ((c & (0x80 | 0x40 | 0x20 | 0x10 | 0x08)) ==
+                 (0x80 | 0x40 | 0x20 | 0x10)) {
+        /* 1111 0xxx */
+        num_cc = 3;
+      } else {
+        goto fail;
+      }
+    }
+  }
+
+  if (num_cc != 0) {
+    goto fail;
+  }
+
+  return true;
+
+fail:
+  return false;
+}
+
+bool avb_str_concat(char* buf,
+                    size_t buf_size,
+                    const char* str1,
+                    size_t str1_len,
+                    const char* str2,
+                    size_t str2_len) {
+  uint64_t combined_len;
+
+  if (!avb_safe_add(&combined_len, str1_len, str2_len)) {
+    avb_error("Overflow when adding string sizes.\n");
+    return false;
+  }
+
+  if (combined_len > buf_size - 1) {
+    avb_error("Insufficient buffer space.\n");
+    return false;
+  }
+
+  avb_memcpy(buf, str1, str1_len);
+  avb_memcpy(buf + str1_len, str2, str2_len);
+  buf[combined_len] = '\0';
+
+  return true;
+}
+
+void* avb_malloc(size_t size) {
+  void* ret = avb_malloc_(size);
+  if (ret == NULL) {
+    avb_error("Failed to allocate memory.\n");
+    return NULL;
+  }
+  return ret;
+}
+
+void* avb_calloc(size_t size) {
+  void* ret = avb_malloc(size);
+  if (ret == NULL) {
+    return NULL;
+  }
+
+  avb_memset(ret, '\0', size);
+  return ret;
+}
+
+char* avb_strdup(const char* str) {
+  size_t len = avb_strlen(str);
+  char* ret = avb_malloc(len + 1);
+  if (ret == NULL) {
+    return NULL;
+  }
+
+  avb_memcpy(ret, str, len);
+  ret[len] = '\0';
+
+  return ret;
+}
+
+const char* avb_strstr(const char* haystack, const char* needle) {
+  size_t n, m;
+
+  /* Look through |haystack| and check if the first character of
+   * |needle| matches. If so, check the rest of |needle|.
+   */
+  for (n = 0; haystack[n] != '\0'; n++) {
+    if (haystack[n] != needle[0]) {
+      continue;
+    }
+
+    for (m = 1;; m++) {
+      if (needle[m] == '\0') {
+        return haystack + n;
+      }
+
+      if (haystack[n + m] != needle[m]) {
+        break;
+      }
+    }
+  }
+
+  return NULL;
+}
+
+const char* avb_strv_find_str(const char* const* strings,
+                              const char* str,
+                              size_t str_size) {
+  size_t n;
+  for (n = 0; strings[n] != NULL; n++) {
+    if (avb_strlen(strings[n]) == str_size &&
+        avb_memcmp(strings[n], str, str_size) == 0) {
+      return strings[n];
+    }
+  }
+  return NULL;
+}
+
+char* avb_replace(const char* str, const char* search, const char* replace) {
+  char* ret = NULL;
+  size_t ret_len = 0;
+  size_t search_len, replace_len;
+  const char* str_after_last_replace;
+
+  search_len = avb_strlen(search);
+  replace_len = avb_strlen(replace);
+
+  str_after_last_replace = str;
+  while (*str != '\0') {
+    const char* s;
+    size_t num_before;
+    size_t num_new;
+
+    s = avb_strstr(str, search);
+    if (s == NULL) {
+      break;
+    }
+
+    num_before = s - str;
+
+    if (ret == NULL) {
+      num_new = num_before + replace_len + 1;
+      ret = avb_malloc(num_new);
+      if (ret == NULL) {
+        goto out;
+      }
+      avb_memcpy(ret, str, num_before);
+      avb_memcpy(ret + num_before, replace, replace_len);
+      ret[num_new - 1] = '\0';
+      ret_len = num_new - 1;
+    } else {
+      char* new_str;
+      num_new = ret_len + num_before + replace_len + 1;
+      new_str = avb_malloc(num_new);
+      if (ret == NULL) {
+        goto out;
+      }
+      avb_memcpy(new_str, ret, ret_len);
+      avb_memcpy(new_str + ret_len, str, num_before);
+      avb_memcpy(new_str + ret_len + num_before, replace, replace_len);
+      new_str[num_new - 1] = '\0';
+      avb_free(ret);
+      ret = new_str;
+      ret_len = num_new - 1;
+    }
+
+    str = s + search_len;
+    str_after_last_replace = str;
+  }
+
+  if (ret == NULL) {
+    ret = avb_strdup(str_after_last_replace);
+    if (ret == NULL) {
+      goto out;
+    }
+  } else {
+    size_t num_remaining = avb_strlen(str_after_last_replace);
+    size_t num_new = ret_len + num_remaining + 1;
+    char* new_str = avb_malloc(num_new);
+    if (ret == NULL) {
+      goto out;
+    }
+    avb_memcpy(new_str, ret, ret_len);
+    avb_memcpy(new_str + ret_len, str_after_last_replace, num_remaining);
+    new_str[num_new - 1] = '\0';
+    avb_free(ret);
+    ret = new_str;
+    ret_len = num_new - 1;
+  }
+
+out:
+  return ret;
+}
+
+/* We only support a limited amount of strings in avb_strdupv(). */
+#define AVB_STRDUPV_MAX_NUM_STRINGS 32
+
+char* avb_strdupv(const char* str, ...) {
+  va_list ap;
+  const char* strings[AVB_STRDUPV_MAX_NUM_STRINGS];
+  size_t lengths[AVB_STRDUPV_MAX_NUM_STRINGS];
+  size_t num_strings, n;
+  uint64_t total_length;
+  char *ret = NULL, *dest;
+
+  num_strings = 0;
+  total_length = 0;
+  va_start(ap, str);
+  do {
+    size_t str_len = avb_strlen(str);
+    strings[num_strings] = str;
+    lengths[num_strings] = str_len;
+    if (!avb_safe_add_to(&total_length, str_len)) {
+      avb_fatal("Overflow while determining total length.\n");
+      break;
+    }
+    num_strings++;
+    if (num_strings == AVB_STRDUPV_MAX_NUM_STRINGS) {
+      avb_fatal("Too many strings passed.\n");
+      break;
+    }
+    str = va_arg(ap, const char*);
+  } while (str != NULL);
+  va_end(ap);
+
+  ret = avb_malloc(total_length + 1);
+  if (ret == NULL) {
+    goto out;
+  }
+
+  dest = ret;
+  for (n = 0; n < num_strings; n++) {
+    avb_memcpy(dest, strings[n], lengths[n]);
+    dest += lengths[n];
+  }
+  *dest = '\0';
+  avb_assert(dest == ret + total_length);
+
+out:
+  return ret;
+}
+
+const char* avb_basename(const char* str) {
+  int64_t n;
+  size_t len;
+
+  len = avb_strlen(str);
+  if (len >= 2) {
+    for (n = len - 2; n >= 0; n--) {
+      if (str[n] == '/') {
+        return str + n + 1;
+      }
+    }
+  }
+  return str;
+}
diff --git a/lib/libavb/avb_vbmeta_image.c b/lib/libavb/avb_vbmeta_image.c
new file mode 100644
index 0000000..12bd3d6
--- /dev/null
+++ b/lib/libavb/avb_vbmeta_image.c
@@ -0,0 +1,290 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * SPDX-License-Identifier:	MIT
+ */
+
+#include "avb/avb_vbmeta_image.h"
+#include "avb/avb_crypto.h"
+#include "avb/avb_rsa.h"
+#include "avb/avb_sha.h"
+#include "avb/avb_util.h"
+#include "avb/avb_version.h"
+
+AvbVBMetaVerifyResult avb_vbmeta_image_verify(
+    const uint8_t* data,
+    size_t length,
+    const uint8_t** out_public_key_data,
+    size_t* out_public_key_length) {
+  AvbVBMetaVerifyResult ret;
+  AvbVBMetaImageHeader h;
+  uint8_t* computed_hash;
+  const AvbAlgorithmData* algorithm;
+  AvbSHA256Ctx sha256_ctx;
+  AvbSHA512Ctx sha512_ctx;
+  const uint8_t* header_block;
+  const uint8_t* authentication_block;
+  const uint8_t* auxiliary_block;
+  int verification_result;
+
+  ret = AVB_VBMETA_VERIFY_RESULT_INVALID_VBMETA_HEADER;
+
+  if (out_public_key_data != NULL) {
+    *out_public_key_data = NULL;
+  }
+  if (out_public_key_length != NULL) {
+    *out_public_key_length = 0;
+  }
+
+  /* Ensure magic is correct. */
+  if (avb_safe_memcmp(data, AVB_MAGIC, AVB_MAGIC_LEN) != 0) {
+    avb_error("Magic is incorrect.\n");
+    goto out;
+  }
+
+  /* Before we byteswap, ensure length is long enough. */
+  if (length < sizeof(AvbVBMetaImageHeader)) {
+    avb_error("Length is smaller than header.\n");
+    goto out;
+  }
+  avb_vbmeta_image_header_to_host_byte_order((const AvbVBMetaImageHeader*)data,
+                                             &h);
+
+  /* Ensure we don't attempt to access any fields if we do not meet
+   * the specified minimum version of libavb.
+   */
+  if ((h.required_libavb_version_major != AVB_VERSION_MAJOR) ||
+      (h.required_libavb_version_minor > AVB_VERSION_MINOR)) {
+    avb_error("Mismatch between image version and libavb version.\n");
+    ret = AVB_VBMETA_VERIFY_RESULT_UNSUPPORTED_VERSION;
+    goto out;
+  }
+
+  /* Ensure |release_string| ends with a NUL byte. */
+  if (h.release_string[AVB_RELEASE_STRING_SIZE - 1] != '\0') {
+    avb_error("Release string does not end with a NUL byte.\n");
+    goto out;
+  }
+
+  /* Ensure inner block sizes are multiple of 64. */
+  if ((h.authentication_data_block_size & 0x3f) != 0 ||
+      (h.auxiliary_data_block_size & 0x3f) != 0) {
+    avb_error("Block size is not a multiple of 64.\n");
+    goto out;
+  }
+
+  /* Ensure block sizes all add up to at most |length|. */
+  uint64_t block_total = sizeof(AvbVBMetaImageHeader);
+  if (!avb_safe_add_to(&block_total, h.authentication_data_block_size) ||
+      !avb_safe_add_to(&block_total, h.auxiliary_data_block_size)) {
+    avb_error("Overflow while computing size of boot image.\n");
+    goto out;
+  }
+  if (block_total > length) {
+    avb_error("Block sizes add up to more than given length.\n");
+    goto out;
+  }
+
+  uintptr_t data_ptr = (uintptr_t)data;
+  /* Ensure passed in memory doesn't wrap. */
+  if (!avb_safe_add(NULL, (uint64_t)data_ptr, length)) {
+    avb_error("Boot image location and length mismatch.\n");
+    goto out;
+  }
+
+  /* Ensure hash and signature are entirely in the Authentication data block. */
+  uint64_t hash_end;
+  if (!avb_safe_add(&hash_end, h.hash_offset, h.hash_size) ||
+      hash_end > h.authentication_data_block_size) {
+    avb_error("Hash is not entirely in its block.\n");
+    goto out;
+  }
+  uint64_t signature_end;
+  if (!avb_safe_add(&signature_end, h.signature_offset, h.signature_size) ||
+      signature_end > h.authentication_data_block_size) {
+    avb_error("Signature is not entirely in its block.\n");
+    goto out;
+  }
+
+  /* Ensure public key is entirely in the Auxiliary data block. */
+  uint64_t pubkey_end;
+  if (!avb_safe_add(&pubkey_end, h.public_key_offset, h.public_key_size) ||
+      pubkey_end > h.auxiliary_data_block_size) {
+    avb_error("Public key is not entirely in its block.\n");
+    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;
+    }
+  }
+
+  /* Bail early if there's no hash or signature. */
+  if (h.algorithm_type == AVB_ALGORITHM_TYPE_NONE) {
+    ret = AVB_VBMETA_VERIFY_RESULT_OK_NOT_SIGNED;
+    goto out;
+  }
+
+  /* Ensure algorithm field is supported. */
+  algorithm = avb_get_algorithm_data(h.algorithm_type);
+  if (!algorithm) {
+    avb_error("Invalid or unknown algorithm.\n");
+    goto out;
+  }
+
+  /* Bail if the embedded hash size doesn't match the chosen algorithm. */
+  if (h.hash_size != algorithm->hash_len) {
+    avb_error("Embedded hash has wrong size.\n");
+    goto out;
+  }
+
+  /* No overflow checks needed from here-on after since all block
+   * sizes and offsets have been verified above.
+   */
+
+  header_block = data;
+  authentication_block = header_block + sizeof(AvbVBMetaImageHeader);
+  auxiliary_block = authentication_block + h.authentication_data_block_size;
+
+  switch (h.algorithm_type) {
+    /* Explicit fall-through: */
+    case AVB_ALGORITHM_TYPE_SHA256_RSA2048:
+    case AVB_ALGORITHM_TYPE_SHA256_RSA4096:
+    case AVB_ALGORITHM_TYPE_SHA256_RSA8192:
+      avb_sha256_init(&sha256_ctx);
+      avb_sha256_update(
+          &sha256_ctx, header_block, sizeof(AvbVBMetaImageHeader));
+      avb_sha256_update(
+          &sha256_ctx, auxiliary_block, h.auxiliary_data_block_size);
+      computed_hash = avb_sha256_final(&sha256_ctx);
+      break;
+    /* Explicit fall-through: */
+    case AVB_ALGORITHM_TYPE_SHA512_RSA2048:
+    case AVB_ALGORITHM_TYPE_SHA512_RSA4096:
+    case AVB_ALGORITHM_TYPE_SHA512_RSA8192:
+      avb_sha512_init(&sha512_ctx);
+      avb_sha512_update(
+          &sha512_ctx, header_block, sizeof(AvbVBMetaImageHeader));
+      avb_sha512_update(
+          &sha512_ctx, auxiliary_block, h.auxiliary_data_block_size);
+      computed_hash = avb_sha512_final(&sha512_ctx);
+      break;
+    default:
+      avb_error("Unknown algorithm.\n");
+      goto out;
+  }
+
+  if (avb_safe_memcmp(authentication_block + h.hash_offset,
+                      computed_hash,
+                      h.hash_size) != 0) {
+    avb_error("Hash does not match!\n");
+    ret = AVB_VBMETA_VERIFY_RESULT_HASH_MISMATCH;
+    goto out;
+  }
+
+  verification_result =
+      avb_rsa_verify(auxiliary_block + h.public_key_offset,
+                     h.public_key_size,
+                     authentication_block + h.signature_offset,
+                     h.signature_size,
+                     authentication_block + h.hash_offset,
+                     h.hash_size,
+                     algorithm->padding,
+                     algorithm->padding_len);
+
+  if (verification_result == 0) {
+    ret = AVB_VBMETA_VERIFY_RESULT_SIGNATURE_MISMATCH;
+    goto out;
+  }
+
+  if (h.public_key_size > 0) {
+    if (out_public_key_data != NULL) {
+      *out_public_key_data = auxiliary_block + h.public_key_offset;
+    }
+    if (out_public_key_length != NULL) {
+      *out_public_key_length = h.public_key_size;
+    }
+  }
+
+  ret = AVB_VBMETA_VERIFY_RESULT_OK;
+
+out:
+  return ret;
+}
+
+void avb_vbmeta_image_header_to_host_byte_order(const AvbVBMetaImageHeader* src,
+                                                AvbVBMetaImageHeader* dest) {
+  avb_memcpy(dest, src, sizeof(AvbVBMetaImageHeader));
+
+  dest->required_libavb_version_major =
+      avb_be32toh(dest->required_libavb_version_major);
+  dest->required_libavb_version_minor =
+      avb_be32toh(dest->required_libavb_version_minor);
+
+  dest->authentication_data_block_size =
+      avb_be64toh(dest->authentication_data_block_size);
+  dest->auxiliary_data_block_size =
+      avb_be64toh(dest->auxiliary_data_block_size);
+
+  dest->algorithm_type = avb_be32toh(dest->algorithm_type);
+
+  dest->hash_offset = avb_be64toh(dest->hash_offset);
+  dest->hash_size = avb_be64toh(dest->hash_size);
+
+  dest->signature_offset = avb_be64toh(dest->signature_offset);
+  dest->signature_size = avb_be64toh(dest->signature_size);
+
+  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);
+
+  dest->rollback_index = avb_be64toh(dest->rollback_index);
+  dest->flags = avb_be32toh(dest->flags);
+}
+
+const char* avb_vbmeta_verify_result_to_string(AvbVBMetaVerifyResult result) {
+  const char* ret = NULL;
+
+  switch (result) {
+    case AVB_VBMETA_VERIFY_RESULT_OK:
+      ret = "OK";
+      break;
+    case AVB_VBMETA_VERIFY_RESULT_OK_NOT_SIGNED:
+      ret = "OK_NOT_SIGNED";
+      break;
+    case AVB_VBMETA_VERIFY_RESULT_INVALID_VBMETA_HEADER:
+      ret = "INVALID_VBMETA_HEADER";
+      break;
+    case AVB_VBMETA_VERIFY_RESULT_UNSUPPORTED_VERSION:
+      ret = "UNSUPPORTED_VERSION";
+      break;
+    case AVB_VBMETA_VERIFY_RESULT_HASH_MISMATCH:
+      ret = "HASH_MISMATCH";
+      break;
+    case AVB_VBMETA_VERIFY_RESULT_SIGNATURE_MISMATCH:
+      ret = "SIGNATURE_MISMATCH";
+      break;
+      /* Do not add a 'default:' case here because of -Wswitch. */
+  }
+
+  if (ret == NULL) {
+    avb_error("Unknown AvbVBMetaVerifyResult value.\n");
+    ret = "(unknown)";
+  }
+
+  return ret;
+}
diff --git a/lib/libavb/avb_version.c b/lib/libavb/avb_version.c
new file mode 100644
index 0000000..e07e0ed
--- /dev/null
+++ b/lib/libavb/avb_version.c
@@ -0,0 +1,16 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * SPDX-License-Identifier:	MIT
+ */
+
+#include "avb/avb_version.h"
+
+#define AVB_QUOTE(str) #str
+#define AVB_EXPAND_AND_QUOTE(str) AVB_QUOTE(str)
+
+/* Keep in sync with get_release_string() in avbtool. */
+const char* avb_version_string(void) {
+  return AVB_EXPAND_AND_QUOTE(AVB_VERSION_MAJOR) "." AVB_EXPAND_AND_QUOTE(
+      AVB_VERSION_MINOR) "." AVB_EXPAND_AND_QUOTE(AVB_VERSION_SUB);
+}
diff --git a/lib/libavb_ab/avb_ab_flow.c b/lib/libavb_ab/avb_ab_flow.c
new file mode 100644
index 0000000..7517003
--- /dev/null
+++ b/lib/libavb_ab/avb_ab_flow.c
@@ -0,0 +1,502 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * SPDX-License-Identifier:	MIT
+ */
+
+#include "avb/avb_ab_flow.h"
+
+uint32_t avb_crc32(const uint8_t* buf, size_t size) {
+  return crc32(0, buf, size);
+}
+
+bool avb_ab_data_verify_and_byteswap(const AvbABData* src, AvbABData* dest) {
+  /* Ensure magic is correct. */
+  if (avb_safe_memcmp(src->magic, AVB_AB_MAGIC, AVB_AB_MAGIC_LEN) != 0) {
+    avb_error("Magic is incorrect.\n");
+    return false;
+  }
+
+  avb_memcpy(dest, src, sizeof(AvbABData));
+  dest->crc32 = avb_be32toh(dest->crc32);
+
+  /* Ensure we don't attempt to access any fields if the major version
+   * is not supported.
+   */
+  if (dest->version_major > AVB_AB_MAJOR_VERSION) {
+    avb_error("No support for given major version.\n");
+    return false;
+  }
+
+  /* Bail if CRC32 doesn't match. */
+  if (dest->crc32 !=
+      avb_crc32((const uint8_t*)dest, sizeof(AvbABData) - sizeof(uint32_t))) {
+    avb_error("CRC32 does not match.\n");
+    return false;
+  }
+
+  return true;
+}
+
+void avb_ab_data_update_crc_and_byteswap(const AvbABData* src,
+                                         AvbABData* dest) {
+  avb_memcpy(dest, src, sizeof(AvbABData));
+  dest->crc32 = avb_htobe32(
+      avb_crc32((const uint8_t*)dest, sizeof(AvbABData) - sizeof(uint32_t)));
+}
+
+void avb_ab_data_init(AvbABData* data) {
+  avb_memset(data, '\0', sizeof(AvbABData));
+  avb_memcpy(data->magic, AVB_AB_MAGIC, AVB_AB_MAGIC_LEN);
+  data->version_major = AVB_AB_MAJOR_VERSION;
+  data->version_minor = AVB_AB_MINOR_VERSION;
+  data->slots[0].priority = AVB_AB_MAX_PRIORITY;
+  data->slots[0].tries_remaining = AVB_AB_MAX_TRIES_REMAINING;
+  data->slots[0].successful_boot = 0;
+  data->slots[1].priority = AVB_AB_MAX_PRIORITY - 1;
+  data->slots[1].tries_remaining = AVB_AB_MAX_TRIES_REMAINING;
+  data->slots[1].successful_boot = 0;
+}
+
+/* The AvbABData struct is stored 2048 bytes into the 'misc' partition
+ * following the 'struct bootloader_message' field. The struct is
+ * compatible with the guidelines in bootable/recovery/bootloader.h -
+ * e.g. it is stored in the |slot_suffix| field, starts with a
+ * NUL-byte, and is 32 bytes long.
+ */
+#define AB_METADATA_MISC_PARTITION_OFFSET 2048
+
+AvbIOResult avb_ab_data_read(AvbABOps* ab_ops, AvbABData* data) {
+  AvbOps* ops = ab_ops->ops;
+  AvbABData serialized;
+  AvbIOResult io_ret;
+  size_t num_bytes_read;
+
+  io_ret = ops->read_from_partition(ops,
+                                    "misc",
+                                    AB_METADATA_MISC_PARTITION_OFFSET,
+                                    sizeof(AvbABData),
+                                    &serialized,
+                                    &num_bytes_read);
+  if (io_ret == AVB_IO_RESULT_ERROR_OOM) {
+    return AVB_IO_RESULT_ERROR_OOM;
+  } else if (io_ret != AVB_IO_RESULT_OK ||
+             num_bytes_read != sizeof(AvbABData)) {
+    avb_error("Error reading A/B metadata.\n");
+    return AVB_IO_RESULT_ERROR_IO;
+  }
+
+  if (!avb_ab_data_verify_and_byteswap(&serialized, data)) {
+    avb_error(
+        "Error validating A/B metadata from disk. "
+        "Resetting and writing new A/B metadata to disk.\n");
+    avb_ab_data_init(data);
+    return avb_ab_data_write(ab_ops, data);
+  }
+
+  return AVB_IO_RESULT_OK;
+}
+
+AvbIOResult avb_ab_data_write(AvbABOps* ab_ops, const AvbABData* data) {
+  AvbOps* ops = ab_ops->ops;
+  AvbABData serialized;
+  AvbIOResult io_ret;
+
+  avb_ab_data_update_crc_and_byteswap(data, &serialized);
+  io_ret = ops->write_to_partition(ops,
+                                   "misc",
+                                   AB_METADATA_MISC_PARTITION_OFFSET,
+                                   sizeof(AvbABData),
+                                   &serialized);
+  if (io_ret == AVB_IO_RESULT_ERROR_OOM) {
+    return AVB_IO_RESULT_ERROR_OOM;
+  } else if (io_ret != AVB_IO_RESULT_OK) {
+    avb_error("Error writing A/B metadata.\n");
+    return AVB_IO_RESULT_ERROR_IO;
+  }
+  return AVB_IO_RESULT_OK;
+}
+
+static bool slot_is_bootable(AvbABSlotData* slot) {
+  return slot->priority > 0 &&
+         (slot->successful_boot || (slot->tries_remaining > 0));
+}
+
+static void slot_set_unbootable(AvbABSlotData* slot) {
+  slot->priority = 0;
+  slot->tries_remaining = 0;
+  slot->successful_boot = 0;
+}
+
+/* Ensure all unbootable and/or illegal states are marked as the
+ * canonical 'unbootable' state, e.g. priority=0, tries_remaining=0,
+ * and successful_boot=0.
+ */
+static void slot_normalize(AvbABSlotData* slot) {
+  if (slot->priority > 0) {
+    if (slot->tries_remaining == 0 && !slot->successful_boot) {
+      /* We've exhausted all tries -> unbootable. */
+      slot_set_unbootable(slot);
+    }
+    if (slot->tries_remaining > 0 && slot->successful_boot) {
+      /* Illegal state - avb_ab_mark_slot_successful() will clear
+       * tries_remaining when setting successful_boot.
+       */
+      slot_set_unbootable(slot);
+    }
+  } else {
+    slot_set_unbootable(slot);
+  }
+}
+
+static const char* slot_suffixes[2] = {"_a", "_b"};
+
+/* Helper function to load metadata - returns AVB_IO_RESULT_OK on
+ * success, error code otherwise.
+ */
+static AvbIOResult load_metadata(AvbABOps* ab_ops,
+                                 AvbABData* ab_data,
+                                 AvbABData* ab_data_orig) {
+  AvbIOResult io_ret;
+
+  io_ret = ab_ops->read_ab_metadata(ab_ops, ab_data);
+  if (io_ret != AVB_IO_RESULT_OK) {
+    avb_error("I/O error while loading A/B metadata.\n");
+    return io_ret;
+  }
+  *ab_data_orig = *ab_data;
+
+  /* Ensure data is normalized, e.g. illegal states will be marked as
+   * unbootable and all unbootable states are represented with
+   * (priority=0, tries_remaining=0, successful_boot=0).
+   */
+  slot_normalize(&ab_data->slots[0]);
+  slot_normalize(&ab_data->slots[1]);
+  return AVB_IO_RESULT_OK;
+}
+
+/* Writes A/B metadata to disk only if it has changed - returns
+ * AVB_IO_RESULT_OK on success, error code otherwise.
+ */
+static AvbIOResult save_metadata_if_changed(AvbABOps* ab_ops,
+                                            AvbABData* ab_data,
+                                            AvbABData* ab_data_orig) {
+  if (avb_safe_memcmp(ab_data, ab_data_orig, sizeof(AvbABData)) != 0) {
+    avb_debug("Writing A/B metadata to disk.\n");
+    return ab_ops->write_ab_metadata(ab_ops, ab_data);
+  }
+  return AVB_IO_RESULT_OK;
+}
+
+AvbABFlowResult avb_ab_flow(AvbABOps* ab_ops,
+                            const char* const* requested_partitions,
+                            bool allow_verification_error,
+                            AvbSlotVerifyData** out_data) {
+  AvbOps* ops = ab_ops->ops;
+  AvbSlotVerifyData* slot_data[2] = {NULL, NULL};
+  AvbSlotVerifyData* data = NULL;
+  AvbABFlowResult ret;
+  AvbABData ab_data, ab_data_orig;
+  size_t slot_index_to_boot, n;
+  AvbIOResult io_ret;
+  bool saw_and_allowed_verification_error = false;
+
+  io_ret = load_metadata(ab_ops, &ab_data, &ab_data_orig);
+  if (io_ret == AVB_IO_RESULT_ERROR_OOM) {
+    ret = AVB_AB_FLOW_RESULT_ERROR_OOM;
+    goto out;
+  } else if (io_ret != AVB_IO_RESULT_OK) {
+    ret = AVB_AB_FLOW_RESULT_ERROR_IO;
+    goto out;
+  }
+
+  /* Validate all bootable slots. */
+  for (n = 0; n < 2; n++) {
+    if (slot_is_bootable(&ab_data.slots[n])) {
+      AvbSlotVerifyResult verify_result;
+      bool set_slot_unbootable = false;
+
+      verify_result = avb_slot_verify(ops,
+                                      requested_partitions,
+                                      slot_suffixes[n],
+                                      allow_verification_error,
+                                      &slot_data[n]);
+      switch (verify_result) {
+        case AVB_SLOT_VERIFY_RESULT_ERROR_OOM:
+          ret = AVB_AB_FLOW_RESULT_ERROR_OOM;
+          goto out;
+
+        case AVB_SLOT_VERIFY_RESULT_ERROR_IO:
+          ret = AVB_AB_FLOW_RESULT_ERROR_IO;
+          goto out;
+
+        case AVB_SLOT_VERIFY_RESULT_OK:
+          break;
+
+        case AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA:
+        case AVB_SLOT_VERIFY_RESULT_ERROR_UNSUPPORTED_VERSION:
+          /* Even with |allow_verification_error| these mean game over. */
+          set_slot_unbootable = true;
+          break;
+
+        /* explicit fallthrough. */
+        case AVB_SLOT_VERIFY_RESULT_ERROR_VERIFICATION:
+        case AVB_SLOT_VERIFY_RESULT_ERROR_ROLLBACK_INDEX:
+        case AVB_SLOT_VERIFY_RESULT_ERROR_PUBLIC_KEY_REJECTED:
+          if (allow_verification_error) {
+            /* Do nothing since we allow this. */
+            avb_debugv("Allowing slot ",
+                       slot_suffixes[n],
+                       " which verified "
+                       "with result ",
+                       avb_slot_verify_result_to_string(verify_result),
+                       " because |allow_verification_error| is true.\n",
+                       NULL);
+            saw_and_allowed_verification_error = true;
+          } else {
+            set_slot_unbootable = true;
+          }
+          break;
+      }
+
+      if (set_slot_unbootable) {
+        avb_errorv("Error verifying slot ",
+                   slot_suffixes[n],
+                   " with result ",
+                   avb_slot_verify_result_to_string(verify_result),
+                   " - setting unbootable.\n",
+                   NULL);
+        slot_set_unbootable(&ab_data.slots[n]);
+      }
+    }
+  }
+
+  if (slot_is_bootable(&ab_data.slots[0]) &&
+      slot_is_bootable(&ab_data.slots[1])) {
+    if (ab_data.slots[1].priority > ab_data.slots[0].priority) {
+      slot_index_to_boot = 1;
+    } else {
+      slot_index_to_boot = 0;
+    }
+  } else if (slot_is_bootable(&ab_data.slots[0])) {
+    slot_index_to_boot = 0;
+  } else if (slot_is_bootable(&ab_data.slots[1])) {
+    slot_index_to_boot = 1;
+  } else {
+    /* No bootable slots! */
+    avb_error("No bootable slots found.\n");
+    ret = AVB_AB_FLOW_RESULT_ERROR_NO_BOOTABLE_SLOTS;
+    goto out;
+  }
+
+  /* Update stored rollback index such that the stored rollback index
+   * is the largest value supporting all currently bootable slots. Do
+   * this for every rollback index location.
+   */
+  for (n = 0; n < AVB_MAX_NUMBER_OF_ROLLBACK_INDEX_LOCATIONS; n++) {
+    uint64_t rollback_index_value = 0;
+
+    if (slot_data[0] != NULL && slot_data[1] != NULL) {
+      uint64_t a_rollback_index = slot_data[0]->rollback_indexes[n];
+      uint64_t b_rollback_index = slot_data[1]->rollback_indexes[n];
+      rollback_index_value =
+          (a_rollback_index < b_rollback_index ? a_rollback_index
+                                               : b_rollback_index);
+    } else if (slot_data[0] != NULL) {
+      rollback_index_value = slot_data[0]->rollback_indexes[n];
+    } else if (slot_data[1] != NULL) {
+      rollback_index_value = slot_data[1]->rollback_indexes[n];
+    }
+
+    if (rollback_index_value != 0) {
+      uint64_t current_rollback_index_value;
+      io_ret = ops->read_rollback_index(ops, n, &current_rollback_index_value);
+      if (io_ret == AVB_IO_RESULT_ERROR_OOM) {
+        ret = AVB_AB_FLOW_RESULT_ERROR_OOM;
+        goto out;
+      } else if (io_ret != AVB_IO_RESULT_OK) {
+        avb_error("Error getting rollback index for slot.\n");
+        ret = AVB_AB_FLOW_RESULT_ERROR_IO;
+        goto out;
+      }
+      if (current_rollback_index_value != rollback_index_value) {
+        io_ret = ops->write_rollback_index(ops, n, rollback_index_value);
+        if (io_ret == AVB_IO_RESULT_ERROR_OOM) {
+          ret = AVB_AB_FLOW_RESULT_ERROR_OOM;
+          goto out;
+        } else if (io_ret != AVB_IO_RESULT_OK) {
+          avb_error("Error setting stored rollback index.\n");
+          ret = AVB_AB_FLOW_RESULT_ERROR_IO;
+          goto out;
+        }
+      }
+    }
+  }
+
+  /* Finally, select this slot. */
+  avb_assert(slot_data[slot_index_to_boot] != NULL);
+  data = slot_data[slot_index_to_boot];
+  slot_data[slot_index_to_boot] = NULL;
+  if (saw_and_allowed_verification_error) {
+    avb_assert(allow_verification_error);
+    ret = AVB_AB_FLOW_RESULT_OK_WITH_VERIFICATION_ERROR;
+  } else {
+    ret = AVB_AB_FLOW_RESULT_OK;
+  }
+
+  /* ... and decrement tries remaining, if applicable. */
+  if (!ab_data.slots[slot_index_to_boot].successful_boot &&
+      ab_data.slots[slot_index_to_boot].tries_remaining > 0) {
+    ab_data.slots[slot_index_to_boot].tries_remaining -= 1;
+  }
+
+out:
+  io_ret = save_metadata_if_changed(ab_ops, &ab_data, &ab_data_orig);
+  if (io_ret != AVB_IO_RESULT_OK) {
+    if (io_ret == AVB_IO_RESULT_ERROR_OOM) {
+      ret = AVB_AB_FLOW_RESULT_ERROR_OOM;
+    } else {
+      ret = AVB_AB_FLOW_RESULT_ERROR_IO;
+    }
+    if (data != NULL) {
+      avb_slot_verify_data_free(data);
+      data = NULL;
+    }
+  }
+
+  for (n = 0; n < 2; n++) {
+    if (slot_data[n] != NULL) {
+      avb_slot_verify_data_free(slot_data[n]);
+    }
+  }
+
+  if (out_data != NULL) {
+    *out_data = data;
+  } else {
+    if (data != NULL) {
+      avb_slot_verify_data_free(data);
+    }
+  }
+
+  return ret;
+}
+
+AvbIOResult avb_ab_mark_slot_active(AvbABOps* ab_ops,
+                                    unsigned int slot_number) {
+  AvbABData ab_data, ab_data_orig;
+  unsigned int other_slot_number;
+  AvbIOResult ret;
+
+  avb_assert(slot_number < 2);
+
+  ret = load_metadata(ab_ops, &ab_data, &ab_data_orig);
+  if (ret != AVB_IO_RESULT_OK) {
+    goto out;
+  }
+
+  /* Make requested slot top priority, unsuccessful, and with max tries. */
+  ab_data.slots[slot_number].priority = AVB_AB_MAX_PRIORITY;
+  ab_data.slots[slot_number].tries_remaining = AVB_AB_MAX_TRIES_REMAINING;
+  ab_data.slots[slot_number].successful_boot = 0;
+
+  /* Ensure other slot doesn't have as high a priority. */
+  other_slot_number = 1 - slot_number;
+  if (ab_data.slots[other_slot_number].priority == AVB_AB_MAX_PRIORITY) {
+    ab_data.slots[other_slot_number].priority = AVB_AB_MAX_PRIORITY - 1;
+  }
+
+  ret = AVB_IO_RESULT_OK;
+
+out:
+  if (ret == AVB_IO_RESULT_OK) {
+    ret = save_metadata_if_changed(ab_ops, &ab_data, &ab_data_orig);
+  }
+  return ret;
+}
+
+AvbIOResult avb_ab_mark_slot_unbootable(AvbABOps* ab_ops,
+                                        unsigned int slot_number) {
+  AvbABData ab_data, ab_data_orig;
+  AvbIOResult ret;
+
+  avb_assert(slot_number < 2);
+
+  ret = load_metadata(ab_ops, &ab_data, &ab_data_orig);
+  if (ret != AVB_IO_RESULT_OK) {
+    goto out;
+  }
+
+  slot_set_unbootable(&ab_data.slots[slot_number]);
+
+  ret = AVB_IO_RESULT_OK;
+
+out:
+  if (ret == AVB_IO_RESULT_OK) {
+    ret = save_metadata_if_changed(ab_ops, &ab_data, &ab_data_orig);
+  }
+  return ret;
+}
+
+AvbIOResult avb_ab_mark_slot_successful(AvbABOps* ab_ops,
+                                        unsigned int slot_number) {
+  AvbABData ab_data, ab_data_orig;
+  AvbIOResult ret;
+
+  avb_assert(slot_number < 2);
+
+  ret = load_metadata(ab_ops, &ab_data, &ab_data_orig);
+  if (ret != AVB_IO_RESULT_OK) {
+    goto out;
+  }
+
+  if (!slot_is_bootable(&ab_data.slots[slot_number])) {
+    avb_error("Cannot mark unbootable slot as successful.\n");
+    ret = AVB_IO_RESULT_OK;
+    goto out;
+  }
+
+  ab_data.slots[slot_number].tries_remaining = 0;
+  ab_data.slots[slot_number].successful_boot = 1;
+
+  ret = AVB_IO_RESULT_OK;
+
+out:
+  if (ret == AVB_IO_RESULT_OK) {
+    ret = save_metadata_if_changed(ab_ops, &ab_data, &ab_data_orig);
+  }
+  return ret;
+}
+
+const char* avb_ab_flow_result_to_string(AvbABFlowResult result) {
+  const char* ret = NULL;
+
+  switch (result) {
+    case AVB_AB_FLOW_RESULT_OK:
+      ret = "OK";
+      break;
+
+    case AVB_AB_FLOW_RESULT_OK_WITH_VERIFICATION_ERROR:
+      ret = "OK_WITH_VERIFICATION_ERROR";
+      break;
+
+    case AVB_AB_FLOW_RESULT_ERROR_OOM:
+      ret = "ERROR_OOM";
+      break;
+
+    case AVB_AB_FLOW_RESULT_ERROR_IO:
+      ret = "ERROR_IO";
+      break;
+
+    case AVB_AB_FLOW_RESULT_ERROR_NO_BOOTABLE_SLOTS:
+      ret = "ERROR_NO_BOOTABLE_SLOTS";
+      break;
+      /* Do not add a 'default:' case here because of -Wswitch. */
+  }
+
+  if (ret == NULL) {
+    avb_error("Unknown AvbABFlowResult value.\n");
+    ret = "(unknown)";
+  }
+
+  return ret;
+}
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 30+ messages in thread

* [U-Boot] [PATCH 2/8] avb2.0: integrate avb 2.0 into the build system
  2018-04-25 13:17 [U-Boot] [PATCH 0/8] Initial integration of AVB2.0 Igor Opaniuk
  2018-04-25 13:17 ` [U-Boot] [PATCH 1/8] avb2.0: add Android Verified Boot 2.0 libraries Igor Opaniuk
@ 2018-04-25 13:17 ` Igor Opaniuk
  2018-04-25 13:18 ` [U-Boot] [PATCH 3/8] avb2.0: implement AVB ops Igor Opaniuk
                   ` (7 subsequent siblings)
  9 siblings, 0 replies; 30+ messages in thread
From: Igor Opaniuk @ 2018-04-25 13:17 UTC (permalink / raw)
  To: u-boot

Integrate libavb/libavb_ab into the build system. Introduce CONFIG_LIBAVB
and CONFIG_LIBAVB_AVB options for enabling build.

Signed-off-by: Igor Opaniuk <igor.opaniuk@linaro.org>
---
 lib/Kconfig            | 20 ++++++++++++++++++++
 lib/Makefile           |  2 ++
 lib/libavb/Makefile    | 15 +++++++++++++++
 lib/libavb_ab/Makefile |  9 +++++++++
 4 files changed, 46 insertions(+)
 create mode 100644 lib/libavb/Makefile
 create mode 100644 lib/libavb_ab/Makefile

diff --git a/lib/Kconfig b/lib/Kconfig
index 436b90f..0429e17 100644
--- a/lib/Kconfig
+++ b/lib/Kconfig
@@ -142,6 +142,26 @@ config TPM
 
 endmenu
 
+menu "Android Verified Boot"
+
+config LIBAVB
+	bool "Android Verified Boot 2.0 support"
+	depends on ANDROID_BOOT_IMAGE
+	help
+	  This enables support of Android Verified Boot 2.0 which can be used
+	  to assure the end user of the integrity of the software running on a
+	  device. Introduces such features as boot chain of trust, rollback
+	  protection etc.
+
+config LIBAVB_AB
+	bool "Android Verified Boot 2.0 A/B slot support"
+	depends on LIBAVB
+	help
+	  This enables support of Android Verified Boot for A/B slots, that
+	  are used in seamless system updates.
+
+endmenu
+
 menu "Hashing Support"
 
 config SHA1
diff --git a/lib/Makefile b/lib/Makefile
index 35da570..934f8a7 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -55,6 +55,8 @@ obj-$(CONFIG_$(SPL_)ZLIB) += zlib/
 obj-$(CONFIG_$(SPL_)GZIP) += gunzip.o
 obj-$(CONFIG_$(SPL_)LZO) += lzo/
 
+obj-$(CONFIG_LIBAVB) += libavb/
+obj-$(CONFIG_LIBAVB_AB) += libavb_ab/
 
 obj-$(CONFIG_$(SPL_TPL_)SAVEENV) += qsort.o
 obj-$(CONFIG_$(SPL_TPL_)OF_LIBFDT) += libfdt/
diff --git a/lib/libavb/Makefile b/lib/libavb/Makefile
new file mode 100644
index 0000000..0a06a26
--- /dev/null
+++ b/lib/libavb/Makefile
@@ -0,0 +1,15 @@
+#
+# (C) Copyright 2017 Linaro Limited
+#
+# SPDX-License-Identifier:	GPL-2.0+
+#
+
+obj-$(CONFIG_LIBAVB) += avb_chain_partition_descriptor.o avb_crypto.o
+obj-$(CONFIG_LIBAVB) += avb_footer.o avb_hashtree_descriptor.o
+obj-$(CONFIG_LIBAVB) += avb_property_descriptor.o avb_sha256.o
+obj-$(CONFIG_LIBAVB) += avb_slot_verify.o avb_util.o avb_version.o
+obj-$(CONFIG_LIBAVB) += avb_descriptor.o avb_hash_descriptor.o
+obj-$(CONFIG_LIBAVB) += avb_kernel_cmdline_descriptor.o avb_rsa.o avb_sha512.o
+obj-$(CONFIG_LIBAVB) += avb_sysdeps_posix.o avb_vbmeta_image.o
+
+ccflags-y = -DAVB_COMPILATION
diff --git a/lib/libavb_ab/Makefile b/lib/libavb_ab/Makefile
new file mode 100644
index 0000000..f4bd72e
--- /dev/null
+++ b/lib/libavb_ab/Makefile
@@ -0,0 +1,9 @@
+#
+# (C) Copyright 2017 Linaro Limited
+#
+# SPDX-License-Identifier:	GPL-2.0+
+#
+
+obj-$(CONFIG_LIBAVB_AB) += avb_ab_flow.o
+
+ccflags-y = -DAVB_COMPILATION
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 30+ messages in thread

* [U-Boot] [PATCH 3/8] avb2.0: implement AVB ops
  2018-04-25 13:17 [U-Boot] [PATCH 0/8] Initial integration of AVB2.0 Igor Opaniuk
  2018-04-25 13:17 ` [U-Boot] [PATCH 1/8] avb2.0: add Android Verified Boot 2.0 libraries Igor Opaniuk
  2018-04-25 13:17 ` [U-Boot] [PATCH 2/8] avb2.0: integrate avb 2.0 into the build system Igor Opaniuk
@ 2018-04-25 13:18 ` Igor Opaniuk
  2018-04-25 13:18 ` [U-Boot] [PATCH 4/8] cmd: avb2.0: avb command for performing verification Igor Opaniuk
                   ` (6 subsequent siblings)
  9 siblings, 0 replies; 30+ messages in thread
From: Igor Opaniuk @ 2018-04-25 13:18 UTC (permalink / raw)
  To: u-boot

Implement AVB ops on top of existing mmc subsystem API. Currently there
is a full implementation of such operations, defined by [1]
AVB2.0 specification:

.read_from_partition() - reads N bytes from a partition identified by
a name.
.write_to_partition() - Writes N bytes to a partition identified by a name.
.validate_vbmeta_public_key() - checks if the given public ‘vbmeta’
partition is trusted.
.get_unique_guid_for_partition() - Gets the GUID for a partition identified
by a string name.

As [1] specification recommends to use tamper-evident storage for storing
rollback indexes and device state (LOCKED/UNLOCKED),
currently are only stubs instead of full implementation for these ops:
.read_rollback_index() - Gets the rollback index for a given index location
.write_rollback_index() - Sets the rollback index to a given location
.read_is_device_unlocked() - Gets where the device is unlocked

[1] https://android.googlesource.com/platform/external/avb/+/master/README.md

Signed-off-by: Igor Opaniuk <igor.opaniuk@linaro.org>
---
 common/Makefile      |   2 +
 common/avb_verify.c  | 614 +++++++++++++++++++++++++++++++++++++++++++++++++++
 include/avb_verify.h |  80 +++++++
 3 files changed, 696 insertions(+)
 create mode 100644 common/avb_verify.c
 create mode 100644 include/avb_verify.h

diff --git a/common/Makefile b/common/Makefile
index 7011dad..7ae7ee1 100644
--- a/common/Makefile
+++ b/common/Makefile
@@ -136,3 +136,5 @@ obj-$(CONFIG_$(SPL_)LOG) += log.o
 obj-$(CONFIG_$(SPL_)LOG_CONSOLE) += log_console.o
 obj-y += s_record.o
 obj-y += xyzModem.o
+
+obj-$(CONFIG_LIBAVB_AB) += avb_verify.o
diff --git a/common/avb_verify.c b/common/avb_verify.c
new file mode 100644
index 0000000..b3d1229
--- /dev/null
+++ b/common/avb_verify.c
@@ -0,0 +1,614 @@
+/*
+ * (C) Copyright 2018, Linaro Limited
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <avb_verify.h>
+#include <fastboot.h>
+#include <image.h>
+#include <malloc.h>
+#include <part.h>
+
+const unsigned char avb_root_pub[1032] = {
+	0x0, 0x0, 0x10, 0x0, 0x55, 0xd9, 0x4, 0xad, 0xd8, 0x4,
+	0xaf, 0xe3, 0xd3, 0x84, 0x6c, 0x7e, 0xd, 0x89, 0x3d, 0xc2,
+	0x8c, 0xd3, 0x12, 0x55, 0xe9, 0x62, 0xc9, 0xf1, 0xf, 0x5e,
+	0xcc, 0x16, 0x72, 0xab, 0x44, 0x7c, 0x2c, 0x65, 0x4a, 0x94,
+	0xb5, 0x16, 0x2b, 0x0, 0xbb, 0x6, 0xef, 0x13, 0x7, 0x53,
+	0x4c, 0xf9, 0x64, 0xb9, 0x28, 0x7a, 0x1b, 0x84, 0x98, 0x88,
+	0xd8, 0x67, 0xa4, 0x23, 0xf9, 0xa7, 0x4b, 0xdc, 0x4a, 0xf,
+	0xf7, 0x3a, 0x18, 0xae, 0x54, 0xa8, 0x15, 0xfe, 0xb0, 0xad,
+	0xac, 0x35, 0xda, 0x3b, 0xad, 0x27, 0xbc, 0xaf, 0xe8, 0xd3,
+	0x2f, 0x37, 0x34, 0xd6, 0x51, 0x2b, 0x6c, 0x5a, 0x27, 0xd7,
+	0x96, 0x6, 0xaf, 0x6b, 0xb8, 0x80, 0xca, 0xfa, 0x30, 0xb4,
+	0xb1, 0x85, 0xb3, 0x4d, 0xaa, 0xaa, 0xc3, 0x16, 0x34, 0x1a,
+	0xb8, 0xe7, 0xc7, 0xfa, 0xf9, 0x9, 0x77, 0xab, 0x97, 0x93,
+	0xeb, 0x44, 0xae, 0xcf, 0x20, 0xbc, 0xf0, 0x80, 0x11, 0xdb,
+	0x23, 0xc, 0x47, 0x71, 0xb9, 0x6d, 0xd6, 0x7b, 0x60, 0x47,
+	0x87, 0x16, 0x56, 0x93, 0xb7, 0xc2, 0x2a, 0x9a, 0xb0, 0x4c,
+	0x1, 0xc, 0x30, 0xd8, 0x93, 0x87, 0xf0, 0xed, 0x6e, 0x8b,
+	0xbe, 0x30, 0x5b, 0xf6, 0xa6, 0xaf, 0xdd, 0x80, 0x7c, 0x45,
+	0x5e, 0x8f, 0x91, 0x93, 0x5e, 0x44, 0xfe, 0xb8, 0x82, 0x7,
+	0xee, 0x79, 0xca, 0xbf, 0x31, 0x73, 0x62, 0x58, 0xe3, 0xcd,
+	0xc4, 0xbc, 0xc2, 0x11, 0x1d, 0xa1, 0x4a, 0xbf, 0xfe, 0x27,
+	0x7d, 0xa1, 0xf6, 0x35, 0xa3, 0x5e, 0xca, 0xdc, 0x57, 0x2f,
+	0x3e, 0xf0, 0xc9, 0x5d, 0x86, 0x6a, 0xf8, 0xaf, 0x66, 0xa7,
+	0xed, 0xcd, 0xb8, 0xed, 0xa1, 0x5f, 0xba, 0x9b, 0x85, 0x1a,
+	0xd5, 0x9, 0xae, 0x94, 0x4e, 0x3b, 0xcf, 0xcb, 0x5c, 0xc9,
+	0x79, 0x80, 0xf7, 0xcc, 0xa6, 0x4a, 0xa8, 0x6a, 0xd8, 0xd3,
+	0x31, 0x11, 0xf9, 0xf6, 0x2, 0x63, 0x2a, 0x1a, 0x2d, 0xd1,
+	0x1a, 0x66, 0x1b, 0x16, 0x41, 0xbd, 0xbd, 0xf7, 0x4d, 0xc0,
+	0x4a, 0xe5, 0x27, 0x49, 0x5f, 0x7f, 0x58, 0xe3, 0x27, 0x2d,
+	0xe5, 0xc9, 0x66, 0xe, 0x52, 0x38, 0x16, 0x38, 0xfb, 0x16,
+	0xeb, 0x53, 0x3f, 0xe6, 0xfd, 0xe9, 0xa2, 0x5e, 0x25, 0x59,
+	0xd8, 0x79, 0x45, 0xff, 0x3, 0x4c, 0x26, 0xa2, 0x0, 0x5a,
+	0x8e, 0xc2, 0x51, 0xa1, 0x15, 0xf9, 0x7b, 0xf4, 0x5c, 0x81,
+	0x9b, 0x18, 0x47, 0x35, 0xd8, 0x2d, 0x5, 0xe9, 0xad, 0xf,
+	0x35, 0x74, 0x15, 0xa3, 0x8e, 0x8b, 0xcc, 0x27, 0xda, 0x7c,
+	0x5d, 0xe4, 0xfa, 0x4, 0xd3, 0x5, 0xb, 0xba, 0x3a, 0xb2,
+	0x49, 0x45, 0x2f, 0x47, 0xc7, 0xd, 0x41, 0x3f, 0x97, 0x80,
+	0x4d, 0x3f, 0xc1, 0xb5, 0xbb, 0x70, 0x5f, 0xa7, 0x37, 0xaf,
+	0x48, 0x22, 0x12, 0x45, 0x2e, 0xf5, 0xf, 0x87, 0x92, 0xe2,
+	0x84, 0x1, 0xf9, 0x12, 0xf, 0x14, 0x15, 0x24, 0xce, 0x89,
+	0x99, 0xee, 0xb9, 0xc4, 0x17, 0x70, 0x70, 0x15, 0xea, 0xbe,
+	0xc6, 0x6c, 0x1f, 0x62, 0xb3, 0xf4, 0x2d, 0x16, 0x87, 0xfb,
+	0x56, 0x1e, 0x45, 0xab, 0xae, 0x32, 0xe4, 0x5e, 0x91, 0xed,
+	0x53, 0x66, 0x5e, 0xbd, 0xed, 0xad, 0xe6, 0x12, 0x39, 0xd,
+	0x83, 0xc9, 0xe8, 0x6b, 0x6c, 0x2d, 0xa5, 0xee, 0xc4, 0x5a,
+	0x66, 0xae, 0x8c, 0x97, 0xd7, 0xd, 0x6c, 0x49, 0xc7, 0xf5,
+	0xc4, 0x92, 0x31, 0x8b, 0x9, 0xee, 0x33, 0xda, 0xa9, 0x37,
+	0xb6, 0x49, 0x18, 0xf8, 0xe, 0x60, 0x45, 0xc8, 0x33, 0x91,
+	0xef, 0x20, 0x57, 0x10, 0xbe, 0x78, 0x2d, 0x83, 0x26, 0xd6,
+	0xca, 0x61, 0xf9, 0x2f, 0xe0, 0xbf, 0x5, 0x30, 0x52, 0x5a,
+	0x12, 0x1c, 0x0, 0xa7, 0x5d, 0xcc, 0x7c, 0x2e, 0xc5, 0x95,
+	0x8b, 0xa3, 0x3b, 0xf0, 0x43, 0x2e, 0x5e, 0xdd, 0x0, 0xdb,
+	0xd, 0xb3, 0x37, 0x99, 0xa9, 0xcd, 0x9c, 0xb7, 0x43, 0xf7,
+	0x35, 0x44, 0x21, 0xc2, 0x82, 0x71, 0xab, 0x8d, 0xaa, 0xb4,
+	0x41, 0x11, 0xec, 0x1e, 0x8d, 0xfc, 0x14, 0x82, 0x92, 0x4e,
+	0x83, 0x6a, 0xa, 0x6b, 0x35, 0x5e, 0x5d, 0xe9, 0x5c, 0xcc,
+	0x8c, 0xde, 0x39, 0xd1, 0x4a, 0x5b, 0x5f, 0x63, 0xa9, 0x64,
+	0xe0, 0xa, 0xcb, 0xb, 0xb8, 0x5a, 0x7c, 0xc3, 0xb, 0xe6,
+	0xbe, 0xfe, 0x8b, 0xf, 0x7d, 0x34, 0x8e, 0x2, 0x66, 0x74,
+	0x1, 0x6c, 0xca, 0x76, 0xac, 0x7c, 0x67, 0x8, 0x2f, 0x3f,
+	0x1a, 0xa6, 0x2c, 0x60, 0xb3, 0xff, 0xda, 0x8d, 0xb8, 0x12,
+	0xc, 0x0, 0x7f, 0xcc, 0x50, 0xa1, 0x5c, 0x64, 0xa1, 0xe2,
+	0x5f, 0x32, 0x65, 0xc9, 0x9c, 0xbe, 0xd6, 0xa, 0x13, 0x87,
+	0x3c, 0x2a, 0x45, 0x47, 0xc, 0xca, 0x42, 0x82, 0xfa, 0x89,
+	0x65, 0xe7, 0x89, 0xb4, 0x8f, 0xf7, 0x1e, 0xe6, 0x23, 0xa5,
+	0xd0, 0x59, 0x37, 0x79, 0x92, 0xd7, 0xce, 0x3d, 0xfd, 0xe3,
+	0xa1, 0xb, 0xcf, 0x6c, 0x85, 0xa0, 0x65, 0xf3, 0x5c, 0xc6,
+	0x4a, 0x63, 0x5f, 0x6e, 0x3a, 0x3a, 0x2a, 0x8b, 0x6a, 0xb6,
+	0x2f, 0xbb, 0xf8, 0xb2, 0x4b, 0x62, 0xbc, 0x1a, 0x91, 0x25,
+	0x66, 0xe3, 0x69, 0xca, 0x60, 0x49, 0xb, 0xf6, 0x8a, 0xbe,
+	0x3e, 0x76, 0x53, 0xc2, 0x7a, 0xa8, 0x4, 0x17, 0x75, 0xf1,
+	0xf3, 0x3, 0x62, 0x1b, 0x85, 0xb2, 0xb0, 0xef, 0x80, 0x15,
+	0xb6, 0xd4, 0x4e, 0xdf, 0x71, 0xac, 0xdb, 0x2a, 0x4, 0xd4,
+	0xb4, 0x21, 0xba, 0x65, 0x56, 0x57, 0xe8, 0xfa, 0x84, 0xa2,
+	0x7d, 0x13, 0xe, 0xaf, 0xd7, 0x9a, 0x58, 0x2a, 0xa3, 0x81,
+	0x84, 0x8d, 0x9, 0xa0, 0x6a, 0xc1, 0xbb, 0xd9, 0xf5, 0x86,
+	0xac, 0xbd, 0x75, 0x61, 0x9, 0xe6, 0x8c, 0x3d, 0x77, 0xb2,
+	0xed, 0x30, 0x20, 0xe4, 0x0, 0x1d, 0x97, 0xe8, 0xbf, 0xc7,
+	0x0, 0x1b, 0x21, 0xb1, 0x16, 0xe7, 0x41, 0x67, 0x2e, 0xec,
+	0x38, 0xbc, 0xe5, 0x1b, 0xb4, 0x6, 0x23, 0x31, 0x71, 0x1c,
+	0x49, 0xcd, 0x76, 0x4a, 0x76, 0x36, 0x8d, 0xa3, 0x89, 0x8b,
+	0x4a, 0x7a, 0xf4, 0x87, 0xc8, 0x15, 0xf, 0x37, 0x39, 0xf6,
+	0x6d, 0x80, 0x19, 0xef, 0x5c, 0xa8, 0x66, 0xce, 0x1b, 0x16,
+	0x79, 0x21, 0xdf, 0xd7, 0x31, 0x30, 0xc4, 0x21, 0xdd, 0x34,
+	0x5b, 0xd2, 0x1a, 0x2b, 0x3e, 0x5d, 0xf7, 0xea, 0xca, 0x5,
+	0x8e, 0xb7, 0xcb, 0x49, 0x2e, 0xa0, 0xe3, 0xf4, 0xa7, 0x48,
+	0x19, 0x10, 0x9c, 0x4, 0xa7, 0xf4, 0x28, 0x74, 0xc8, 0x6f,
+	0x63, 0x20, 0x2b, 0x46, 0x24, 0x26, 0x19, 0x1d, 0xd1, 0x2c,
+	0x31, 0x6d, 0x5a, 0x29, 0xa2, 0x6, 0xa6, 0xb2, 0x41, 0xcc,
+	0xa, 0x27, 0x96, 0x9, 0x96, 0xac, 0x47, 0x65, 0x78, 0x68,
+	0x51, 0x98, 0xd6, 0xd8, 0xa6, 0x2d, 0xa0, 0xcf, 0xec, 0xe2,
+	0x74, 0xf2, 0x82, 0xe3, 0x97, 0xd9, 0x7e, 0xd4, 0xf8, 0xb,
+	0x70, 0x43, 0x3d, 0xb1, 0x7b, 0x97, 0x80, 0xd6, 0xcb, 0xd7,
+	0x19, 0xbc, 0x63, 0xb, 0xfd, 0x4d, 0x88, 0xfe, 0x67, 0xac,
+	0xb8, 0xcc, 0x50, 0xb7, 0x68, 0xb3, 0x5b, 0xd6, 0x1e, 0x25,
+	0xfc, 0x5f, 0x3c, 0x8d, 0xb1, 0x33, 0x7c, 0xb3, 0x49, 0x1,
+	0x3f, 0x71, 0x55, 0xe, 0x51, 0xba, 0x61, 0x26, 0xfa, 0xea,
+	0xe5, 0xb5, 0xe8, 0xaa, 0xcf, 0xcd, 0x96, 0x9f, 0xd6, 0xc1,
+	0x5f, 0x53, 0x91, 0xad, 0x5, 0xde, 0x20, 0xe7, 0x51, 0xda,
+	0x5b, 0x95, 0x67, 0xed, 0xf4, 0xee, 0x42, 0x65, 0x70, 0x13,
+	0xb, 0x70, 0x14, 0x1c, 0xc9, 0xe0, 0x19, 0xca, 0x5f, 0xf5,
+	0x1d, 0x70, 0x4b, 0x6c, 0x6, 0x74, 0xec, 0xb5, 0x2e, 0x77,
+	0xe1, 0x74, 0xa1, 0xa3, 0x99, 0xa0, 0x85, 0x9e, 0xf1, 0xac,
+	0xd8, 0x7e,
+};
+
+/**
+ * ============================================================================
+ * IO(mmc) auxiliary functions
+ * ============================================================================
+ */
+static unsigned long mmc_read_and_flush(struct mmc_part *part,
+					lbaint_t start,
+					lbaint_t sectors,
+					void *buffer)
+{
+	unsigned long blks;
+	void *tmp_buf;
+	size_t buf_size;
+	bool unaligned = is_buf_unaligned(buffer);
+
+	if (start < part->info.start) {
+		printf("%s: partition start out of bounds\n", __func__);
+		return 0;
+	}
+	if ((start + sectors) > (part->info.start + part->info.size)) {
+		sectors = part->info.start + part->info.size - start;
+		printf("%s: read sector aligned to partition bounds (%ld)\n",
+		       __func__, sectors);
+	}
+
+	/*
+	 * Reading fails on unaligned buffers, so we have to
+	 * use aligned temporary buffer and then copy to destination
+	 */
+
+	if (unaligned) {
+		printf("Handling unaligned read buffer..\n");
+		tmp_buf = get_sector_buf();
+		buf_size = get_sector_buf_size();
+		if (sectors > buf_size / part->info.blksz)
+			sectors = buf_size / part->info.blksz;
+	} else {
+		tmp_buf = buffer;
+	}
+
+	blks = part->mmc->block_dev.block_read(part->mmc_blk,
+				start, sectors, tmp_buf);
+	/* flush cache after read */
+	flush_cache((ulong)tmp_buf, sectors * part->info.blksz);
+
+	if (unaligned)
+		memcpy(buffer, tmp_buf, sectors * part->info.blksz);
+
+	return blks;
+}
+
+static unsigned long mmc_write(struct mmc_part *part, lbaint_t start,
+			       lbaint_t sectors, void *buffer)
+{
+	void *tmp_buf;
+	size_t buf_size;
+	bool unaligned = is_buf_unaligned(buffer);
+
+	if (start < part->info.start) {
+		printf("%s: partition start out of bounds\n", __func__);
+		return 0;
+	}
+	if ((start + sectors) > (part->info.start + part->info.size)) {
+		sectors = part->info.start + part->info.size - start;
+		printf("%s: sector aligned to partition bounds (%ld)\n",
+		       __func__, sectors);
+	}
+	if (unaligned) {
+		tmp_buf = get_sector_buf();
+		buf_size = get_sector_buf_size();
+		printf("Handling unaligned wrire buffer..\n");
+		if (sectors > buf_size / part->info.blksz)
+			sectors = buf_size / part->info.blksz;
+
+		memcpy(tmp_buf, buffer, sectors * part->info.blksz);
+	} else {
+		tmp_buf = buffer;
+	}
+
+	return part->mmc->block_dev.block_write(part->mmc_blk,
+				start, sectors, tmp_buf);
+}
+
+static struct mmc_part *get_partition(AvbOps *ops, const char *partition)
+{
+	int ret;
+	u8 dev_num;
+	int part_num = 0;
+	struct mmc_part *part;
+	struct blk_desc *mmc_blk;
+
+	part = malloc(sizeof(struct mmc_part));
+	if (!part)
+		return NULL;
+
+	dev_num = get_boot_device(ops);
+	part->mmc = find_mmc_device(dev_num);
+	if (!part->mmc) {
+		printf("No MMC device at slot %x\n", dev_num);
+		return NULL;
+	}
+
+	if (mmc_init(part->mmc)) {
+		printf("MMC initialization failed\n");
+		return NULL;
+	}
+
+	ret = mmc_switch_part(part->mmc, part_num);
+	if (ret)
+		return NULL;
+
+	mmc_blk = mmc_get_blk_desc(part->mmc);
+	if (!mmc_blk) {
+		printf("Error - failed to obtain block descriptor\n");
+		return NULL;
+	}
+
+	ret = part_get_info_by_name(mmc_blk, partition, &part->info);
+	if (!ret) {
+		printf("Can't find partition '%s'\n", partition);
+		return NULL;
+	}
+
+	part->dev_num = dev_num;
+	part->mmc_blk = mmc_blk;
+
+	return part;
+}
+
+static AvbIOResult mmc_byte_io(AvbOps *ops,
+			       const char *partition,
+			       s64 offset,
+			       size_t num_bytes,
+			       void *buffer,
+			       size_t *out_num_read,
+			       enum mmc_io_type io_type)
+{
+	ulong ret;
+	struct mmc_part *part;
+	u64 start_offset, start_sector, sectors, residue;
+	u8 *tmp_buf;
+	size_t io_cnt = 0;
+
+	if (!partition || !buffer || io_type > IO_WRITE)
+		return AVB_IO_RESULT_ERROR_IO;
+
+	part = get_partition(ops, partition);
+	if (!part)
+		return AVB_IO_RESULT_ERROR_NO_SUCH_PARTITION;
+
+	start_offset = calc_offset(part, offset);
+	while (num_bytes) {
+		start_sector = start_offset / part->info.blksz;
+		sectors = num_bytes / part->info.blksz;
+		/* handle non block-aligned reads */
+		if (start_offset % part->info.blksz ||
+		    num_bytes < part->info.blksz) {
+			tmp_buf = get_sector_buf();
+			if (start_offset % part->info.blksz) {
+				residue = part->info.blksz -
+					(start_offset % part->info.blksz);
+				if (residue > num_bytes)
+					residue = num_bytes;
+			} else {
+				residue = num_bytes;
+			}
+
+			if (io_type == IO_READ) {
+				ret = mmc_read_and_flush(part,
+							 part->info.start +
+							 start_sector,
+							 1, tmp_buf);
+
+				if (ret != 1) {
+					printf("%s: read error (%ld, %lld)\n",
+					       __func__, ret, start_sector);
+					return AVB_IO_RESULT_ERROR_IO;
+				}
+				/*
+				 * if this is not aligned at sector start,
+				 * we have to adjust the tmp buffer
+				 */
+				tmp_buf += (start_offset % part->info.blksz);
+				memcpy(buffer, (void *)tmp_buf, residue);
+			} else {
+				ret = mmc_read_and_flush(part,
+							 part->info.start +
+							 start_sector,
+							 1, tmp_buf);
+
+				if (ret != 1) {
+					printf("%s: read error (%ld, %lld)\n",
+					       __func__, ret, start_sector);
+					return AVB_IO_RESULT_ERROR_IO;
+				}
+				memcpy((void *)tmp_buf +
+					start_offset % part->info.blksz,
+					buffer, residue);
+
+				ret = mmc_write(part, part->info.start +
+						start_sector, 1, tmp_buf);
+				if (ret != 1) {
+					printf("%s: write error (%ld, %lld)\n",
+					       __func__, ret, start_sector);
+					return AVB_IO_RESULT_ERROR_IO;
+				}
+			}
+
+			io_cnt += residue;
+			buffer += residue;
+			start_offset += residue;
+			num_bytes -= residue;
+			continue;
+		}
+
+		if (sectors) {
+			if (io_type == IO_READ) {
+				ret = mmc_read_and_flush(part,
+							 part->info.start +
+							 start_sector,
+							 sectors, buffer);
+			} else {
+				ret = mmc_write(part,
+						part->info.start +
+						start_sector,
+						sectors, buffer);
+			}
+
+			if (!ret) {
+				printf("%s: sector read error\n", __func__);
+				return AVB_IO_RESULT_ERROR_IO;
+			}
+
+			io_cnt += ret * part->info.blksz;
+			buffer += ret * part->info.blksz;
+			start_offset += ret * part->info.blksz;
+			num_bytes -= ret * part->info.blksz;
+		}
+	}
+
+	/* Set counter for read operation */
+	if (io_type == IO_READ && out_num_read)
+		*out_num_read = io_cnt;
+
+	return AVB_IO_RESULT_OK;
+}
+
+/**
+ * ============================================================================
+ * AVB 2.0 operations
+ * ============================================================================
+ */
+
+/**
+ * read_from_partition() - reads @num_bytes from  @offset from partition
+ * identified by a string name
+ *
+ * @ops: contains AVB ops handlers
+ * @partition_name: partition name, NUL-terminated UTF-8 string
+ * @offset: offset from the beginning of partition
+ * @num_bytes: amount of bytes to read
+ * @buffer: destination buffer to store data
+ * @out_num_read:
+ *
+ * @return:
+ *      AVB_IO_RESULT_OK, if partition was found and read operation succeed
+ *      AVB_IO_RESULT_ERROR_IO, if i/o error occurred from the underlying i/o
+ *            subsystem
+ *      AVB_IO_RESULT_ERROR_NO_SUCH_PARTITION, if there is no partition with
+ *      the given name
+ */
+static AvbIOResult read_from_partition(AvbOps *ops,
+				       const char *partition_name,
+				       s64 offset_from_partition,
+				       size_t num_bytes,
+				       void *buffer,
+				       size_t *out_num_read)
+{
+	return mmc_byte_io(ops, partition_name, offset_from_partition,
+			   num_bytes, buffer, out_num_read, IO_READ);
+}
+
+/**
+ * write_to_partition() - writes N bytes to a partition identified by a string
+ * name
+ *
+ * @ops: AvbOps, contains AVB ops handlers
+ * @partition_name: partition name
+ * @offset_from_partition: offset from the beginning of partition
+ * @num_bytes: amount of bytes to write
+ * @buf: data to write
+ * @out_num_read:
+ *
+ * @return:
+ *      AVB_IO_RESULT_OK, if partition was found and read operation succeed
+ *      AVB_IO_RESULT_ERROR_IO, if input/output error occurred
+ *      AVB_IO_RESULT_ERROR_NO_SUCH_PARTITION, if partition, specified in
+ *            @partition_name was not found
+ */
+static AvbIOResult write_to_partition(AvbOps *ops,
+				      const char *partition_name,
+				      s64 offset_from_partition,
+				      size_t num_bytes,
+				      const void *buffer)
+{
+	return mmc_byte_io(ops, partition_name, offset_from_partition,
+			   num_bytes, (void *)buffer, NULL, IO_WRITE);
+}
+
+/**
+ * validate_vmbeta_public_key() - checks if the given public key used to sign
+ * the vbmeta partition is trusted
+ *
+ * @ops: AvbOps, contains AVB ops handlers
+ * @public_key_data: public key for verifying vbmeta partition signature
+ * @public_key_length: length of public key
+ * @public_key_metadata:
+ * @public_key_metadata_length:
+ * @out_key_is_trusted:
+ *
+ * @return:
+ *      AVB_IO_RESULT_OK, if partition was found and read operation succeed
+ */
+static AvbIOResult validate_vbmeta_public_key(AvbOps *ops,
+					      const u8 *public_key_data,
+					      size_t public_key_length,
+					      const u8
+					      *public_key_metadata,
+					      size_t
+					      public_key_metadata_length,
+					      bool *out_key_is_trusted)
+{
+	if (!public_key_length || !public_key_data || !out_key_is_trusted)
+		return AVB_IO_RESULT_ERROR_IO;
+
+	*out_key_is_trusted = false;
+	if (public_key_length != sizeof(avb_root_pub))
+		return AVB_IO_RESULT_ERROR_IO;
+
+	if (memcmp(avb_root_pub, public_key_data, public_key_length) == 0)
+		*out_key_is_trusted = true;
+
+	return AVB_IO_RESULT_OK;
+}
+
+/**
+ * read_rollback_index() - gets the rollback index corresponding to the
+ * location of given by @out_rollback_index.
+ *
+ * @ops: contains AvbOps handlers
+ * @rollback_index_slot:
+ * @out_rollback_index: used to write a retrieved rollback index.
+ *
+ * @return
+ *       AVB_IO_RESULT_OK, if the roolback index was retrieved
+ */
+static AvbIOResult read_rollback_index(AvbOps *ops,
+				       size_t rollback_index_slot,
+				       u64 *out_rollback_index)
+{
+	/* For now we always return 0 as the stored rollback index. */
+	printf("TODO: implement %s.\n", __func__);
+
+	if (out_rollback_index)
+		*out_rollback_index = 0;
+
+	return AVB_IO_RESULT_OK;
+}
+
+/**
+ * write_rollback_index() - sets the rollback index corresponding to the
+ * location of given by @out_rollback_index.
+ *
+ * @ops: contains AvbOps handlers
+ * @rollback_index_slot:
+ * @rollback_index: rollback index to write.
+ *
+ * @return
+ *       AVB_IO_RESULT_OK, if the roolback index was retrieved
+ */
+static AvbIOResult write_rollback_index(AvbOps *ops,
+					size_t rollback_index_slot,
+					u64 rollback_index)
+{
+	/* For now this is a no-op. */
+	printf("TODO: implement %s.\n", __func__);
+
+	return AVB_IO_RESULT_OK;
+}
+
+/**
+ * read_is_device_unlocked() - gets whether the device is unlocked
+ *
+ * @ops: contains AVB ops handlers
+ * @out_is_unlocked: device unlock state is stored here, true if unlocked,
+ *       false otherwise
+ *
+ * @return:
+ *       AVB_IO_RESULT_OK: state is retrieved successfully
+ *       AVB_IO_RESULT_ERROR_IO: an error occurred
+ */
+static AvbIOResult read_is_device_unlocked(AvbOps *ops, bool *out_is_unlocked)
+{
+	/* For now we always return that the device is unlocked. */
+
+	printf("TODO: implement %s.\n", __func__);
+
+	*out_is_unlocked = true;
+
+	return AVB_IO_RESULT_OK;
+}
+
+/**
+ * get_unique_guid_for_partition() - gets the GUID for a partition identified
+ * by a string name
+ *
+ * @ops: contains AVB ops handlers
+ * @partition: partition name (NUL-terminated UTF-8 string)
+ * @guid_buf: buf, used to copy in GUID string. Example of value:
+ *      527c1c6d-6361-4593-8842-3c78fcd39219
+ * @guid_buf_size: @guid_buf buffer size
+ *
+ * @return:
+ *      AVB_IO_RESULT_OK, on success (GUID found)
+ *      AVB_IO_RESULT_ERROR_IO, if incorrect buffer size (@guid_buf_size) was
+ *             provided
+ *      AVB_IO_RESULT_ERROR_NO_SUCH_PARTITION, if partition was not found
+ */
+static AvbIOResult get_unique_guid_for_partition(AvbOps *ops,
+						 const char *partition,
+						 char *guid_buf,
+						 size_t guid_buf_size)
+{
+	struct mmc_part *part;
+	size_t uuid_size;
+
+	part = get_partition(ops, partition);
+	if (!part)
+		return AVB_IO_RESULT_ERROR_NO_SUCH_PARTITION;
+
+	uuid_size = sizeof(part->info.uuid);
+	if (uuid_size > guid_buf_size)
+		return AVB_IO_RESULT_ERROR_IO;
+
+	memcpy(guid_buf, part->info.uuid, uuid_size);
+	guid_buf[uuid_size - 1] = 0;
+
+	return AVB_IO_RESULT_OK;
+}
+
+/**
+ * ============================================================================
+ * AVB2.0 AvbOps alloc/initialisation/free
+ * ============================================================================
+ */
+AvbOps *avb_ops_alloc(int boot_device)
+{
+	struct AvbOpsData *ops_data;
+
+	ops_data = avb_calloc(sizeof(struct AvbOpsData));
+	if (!ops_data)
+		return NULL;
+
+	ops_data->ops.user_data = ops_data;
+
+	ops_data->ops.ab_ops = &ops_data->ab_ops;
+	ops_data->ops.read_from_partition = read_from_partition;
+	ops_data->ops.write_to_partition = write_to_partition;
+	ops_data->ops.validate_vbmeta_public_key = validate_vbmeta_public_key;
+	ops_data->ops.read_rollback_index = read_rollback_index;
+	ops_data->ops.write_rollback_index = write_rollback_index;
+	ops_data->ops.read_is_device_unlocked = read_is_device_unlocked;
+	ops_data->ops.get_unique_guid_for_partition =
+		get_unique_guid_for_partition;
+
+	ops_data->ab_ops.ops = &ops_data->ops;
+	ops_data->ab_ops.read_ab_metadata = avb_ab_data_read;
+	ops_data->ab_ops.write_ab_metadata = avb_ab_data_write;
+	ops_data->mmc_dev = boot_device;
+
+	return &ops_data->ops;
+}
+
+void avb_ops_free(AvbOps *ops)
+{
+	struct AvbOpsData *ops_data;
+
+	if (ops)
+		return;
+
+	ops_data = ops->user_data;
+
+	if (ops_data)
+		avb_free(ops_data);
+}
diff --git a/include/avb_verify.h b/include/avb_verify.h
new file mode 100644
index 0000000..fb7ab23
--- /dev/null
+++ b/include/avb_verify.h
@@ -0,0 +1,80 @@
+
+/*
+ * (C) Copyright 2018, Linaro Limited
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#ifndef	_AVB_VERIFY_H
+#define _AVB_VERIFY_H
+
+#include <avb/libavb_ab.h>
+#include <mmc.h>
+
+#define ALLOWED_BUF_ALIGN	8
+
+struct AvbOpsData {
+	struct AvbOps ops;
+	struct AvbABOps ab_ops;
+	int mmc_dev;
+};
+
+struct mmc_part {
+	int dev_num;
+	struct mmc *mmc;
+	struct blk_desc *mmc_blk;
+	disk_partition_t info;
+};
+
+enum mmc_io_type {
+	IO_READ,
+	IO_WRITE
+};
+
+AvbOps *avb_ops_alloc(int boot_device);
+void avb_ops_free(AvbOps *ops);
+
+/**
+ * ============================================================================
+ * I/O helper inline functions
+ * ============================================================================
+ */
+static inline uint64_t calc_offset(struct mmc_part *part, int64_t offset)
+{
+	u64 part_size = part->info.size * part->info.blksz;
+
+	if (offset < 0)
+		return part_size + offset;
+
+	return offset;
+}
+
+static inline size_t get_sector_buf_size(void)
+{
+	return (size_t)CONFIG_FASTBOOT_BUF_SIZE;
+}
+
+static inline void *get_sector_buf(void)
+{
+	return (void *)CONFIG_FASTBOOT_BUF_ADDR;
+}
+
+static inline bool is_buf_unaligned(void *buffer)
+{
+	return (bool)((uintptr_t)buffer % ALLOWED_BUF_ALIGN);
+}
+
+static inline int get_boot_device(AvbOps *ops)
+{
+	struct AvbOpsData *data;
+
+	if (ops) {
+		data = ops->user_data;
+		if (data)
+			return data->mmc_dev;
+	}
+
+	return -1;
+}
+
+#endif /* _AVB_VERIFY_H */
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 30+ messages in thread

* [U-Boot] [PATCH 4/8] cmd: avb2.0: avb command for performing verification
  2018-04-25 13:17 [U-Boot] [PATCH 0/8] Initial integration of AVB2.0 Igor Opaniuk
                   ` (2 preceding siblings ...)
  2018-04-25 13:18 ` [U-Boot] [PATCH 3/8] avb2.0: implement AVB ops Igor Opaniuk
@ 2018-04-25 13:18 ` Igor Opaniuk
  2018-05-02 18:52   ` Sam Protsenko
  2018-05-03  2:31   ` Simon Glass
  2018-04-25 13:18 ` [U-Boot] [PATCH 5/8] avb2.0: add boot states and dm-verity support Igor Opaniuk
                   ` (5 subsequent siblings)
  9 siblings, 2 replies; 30+ messages in thread
From: Igor Opaniuk @ 2018-04-25 13:18 UTC (permalink / raw)
  To: u-boot

Enable a "avb" command to execute Android Verified
Boot 2.0 operations. It includes such subcommands:
  avb init - initialize avb2 subsystem
  avb read_rb - read rollback index
  avb write_rb - write rollback index
  avb is_unlocked - check device lock state
  avb get_uuid - read and print uuid of a partition
  avb read_part - read data from partition
  avb read_part_hex - read data from partition and output to stdout
  avb write_part - write data to partition
  avb verify - run full verification chain

Signed-off-by: Igor Opaniuk <igor.opaniuk@linaro.org>
---
 cmd/Kconfig  |  15 +++
 cmd/Makefile |   3 +
 cmd/avb.c    | 351 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 369 insertions(+)
 create mode 100644 cmd/avb.c

diff --git a/cmd/Kconfig b/cmd/Kconfig
index bc1d2f3..96695ff 100644
--- a/cmd/Kconfig
+++ b/cmd/Kconfig
@@ -1675,6 +1675,21 @@ config CMD_TRACE
 	  for analsys (e.g. using bootchart). See doc/README.trace for full
 	  details.
 
+config CMD_AVB
+	bool "avb - Android Verified Boot 2.0 operations"
+	depends on LIBAVB_AB
+	help
+	  Enables a "avb" command to perform verification of partitions using
+	  Android Verified Boot 2.0 functionality. It includes such subcommands:
+	    avb init - initialize avb2 subsystem
+	    avb read_rb - read rollback index
+	    avb write_rb - write rollback index
+	    avb is_unlocked - check device lock state
+	    avb get_uuid - read and print uuid of a partition
+	    avb read_part - read data from partition
+	    avb read_part_hex - read data from partition and output to stdout
+	    avb write_part - write data to partition
+	    avb verify - run full verification chain
 endmenu
 
 config CMD_UBI
diff --git a/cmd/Makefile b/cmd/Makefile
index c4269ac..bbf6c2a 100644
--- a/cmd/Makefile
+++ b/cmd/Makefile
@@ -151,6 +151,9 @@ obj-$(CONFIG_CMD_REGULATOR) += regulator.o
 
 obj-$(CONFIG_CMD_BLOB) += blob.o
 
+# Android Verified Boot 2.0
+obj-$(CONFIG_CMD_AVB) += avb.o
+
 obj-$(CONFIG_X86) += x86/
 endif # !CONFIG_SPL_BUILD
 
diff --git a/cmd/avb.c b/cmd/avb.c
new file mode 100644
index 0000000..d040906
--- /dev/null
+++ b/cmd/avb.c
@@ -0,0 +1,351 @@
+
+/*
+ * (C) Copyright 2018, Linaro Limited
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <avb_verify.h>
+#include <command.h>
+#include <image.h>
+#include <malloc.h>
+#include <mmc.h>
+
+#define AVB_BOOTARGS	"avb_bootargs"
+static struct AvbOps *avb_ops;
+
+static const char * const requested_partitions[] = {"boot",
+					     "system",
+					     "vendor",
+					     NULL};
+
+int do_avb_init(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+	unsigned long mmc_dev;
+
+	if (argc != 2)
+		return CMD_RET_USAGE;
+
+	mmc_dev = simple_strtoul(argv[1], NULL, 16);
+
+	if (avb_ops)
+		avb_ops_free(avb_ops);
+
+	avb_ops = avb_ops_alloc(mmc_dev);
+	if (avb_ops)
+		return CMD_RET_SUCCESS;
+
+	return CMD_RET_FAILURE;
+}
+
+int do_avb_read_part(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+	const char *part;
+	s64 offset;
+	size_t bytes, bytes_read = 0;
+	void *buffer;
+
+	if (!avb_ops) {
+		printf("AVB 2.0 is not initialized, please run 'avb init'\n");
+		return CMD_RET_USAGE;
+	}
+
+	if (argc != 5)
+		return CMD_RET_USAGE;
+
+	part = argv[1];
+	offset = simple_strtoul(argv[2], NULL, 16);
+	bytes = simple_strtoul(argv[3], NULL, 16);
+	buffer = (void *)simple_strtoul(argv[4], NULL, 16);
+
+	if (avb_ops->read_from_partition(avb_ops, part, offset, bytes,
+					 buffer, &bytes_read) ==
+					 AVB_IO_RESULT_OK) {
+		printf("Read %zu bytes\n", bytes_read);
+		return CMD_RET_SUCCESS;
+	}
+
+	return CMD_RET_FAILURE;
+}
+
+int do_avb_read_part_hex(cmd_tbl_t *cmdtp, int flag, int argc,
+			 char *const argv[])
+{
+	const char *part;
+	s64 offset;
+	size_t bytes, bytes_read = 0;
+	char *buffer;
+
+	if (!avb_ops) {
+		printf("AVB 2.0 is not initialized, please run 'avb init'\n");
+		return CMD_RET_USAGE;
+	}
+
+	if (argc != 4)
+		return CMD_RET_USAGE;
+
+	part = argv[1];
+	offset = simple_strtoul(argv[2], NULL, 16);
+	bytes = simple_strtoul(argv[3], NULL, 16);
+
+	buffer = malloc(bytes);
+	if (!buffer) {
+		printf("Failed to tlb_allocate buffer for data\n");
+		return CMD_RET_FAILURE;
+	}
+	memset(buffer, 0, bytes);
+
+	if (avb_ops->read_from_partition(avb_ops, part, offset, bytes, buffer,
+					 &bytes_read) == AVB_IO_RESULT_OK) {
+		printf("Requested %zu, read %zu bytes\n", bytes, bytes_read);
+		printf("Data: ");
+		for (int i = 0; i < bytes_read; i++)
+			printf("%02X", buffer[i]);
+
+		printf("\n");
+
+		free(buffer);
+		return CMD_RET_SUCCESS;
+	}
+
+	free(buffer);
+	return CMD_RET_FAILURE;
+}
+
+int do_avb_write_part(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+	const char *part;
+	s64 offset;
+	size_t bytes;
+	void *buffer;
+
+	if (!avb_ops) {
+		printf("AVB 2.0 is not initialized, run 'avb init' first\n");
+		return CMD_RET_FAILURE;
+	}
+
+	if (argc != 5)
+		return CMD_RET_USAGE;
+
+	part = argv[1];
+	offset = simple_strtoul(argv[2], NULL, 16);
+	bytes = simple_strtoul(argv[3], NULL, 16);
+	buffer = (void *)simple_strtoul(argv[4], NULL, 16);
+
+	if (avb_ops->write_to_partition(avb_ops, part, offset, bytes, buffer) ==
+	    AVB_IO_RESULT_OK) {
+		printf("Wrote %zu bytes\n", bytes);
+		return CMD_RET_SUCCESS;
+	}
+
+	return CMD_RET_FAILURE;
+}
+
+int do_avb_read_rb(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+	size_t index;
+	u64 rb_idx;
+
+	if (!avb_ops) {
+		printf("AVB 2.0 is not initialized, run 'avb init' first\n");
+		return CMD_RET_FAILURE;
+	}
+
+	if (argc != 2)
+		return CMD_RET_USAGE;
+
+	index = (size_t)simple_strtoul(argv[1], NULL, 16);
+
+	if (avb_ops->read_rollback_index(avb_ops, index, &rb_idx) ==
+	    AVB_IO_RESULT_OK) {
+		printf("Rollback index: %llu\n", rb_idx);
+		return CMD_RET_SUCCESS;
+	}
+	return CMD_RET_FAILURE;
+}
+
+int do_avb_write_rb(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+	size_t index;
+	u64 rb_idx;
+
+	if (!avb_ops) {
+		printf("AVB 2.0 is not initialized, run 'avb init' first\n");
+		return CMD_RET_FAILURE;
+	}
+
+	if (argc != 3)
+		return CMD_RET_USAGE;
+
+	index = (size_t)simple_strtoul(argv[1], NULL, 16);
+	rb_idx = simple_strtoul(argv[2], NULL, 16);
+
+	if (avb_ops->write_rollback_index(avb_ops, index, rb_idx) ==
+	    AVB_IO_RESULT_OK)
+		return CMD_RET_SUCCESS;
+
+	return CMD_RET_FAILURE;
+}
+
+int do_avb_get_uuid(cmd_tbl_t *cmdtp, int flag,
+		    int argc, char * const argv[])
+{
+	const char *part;
+	char buffer[UUID_STR_LEN + 1];
+
+	if (!avb_ops) {
+		printf("AVB 2.0 is not initialized, run 'avb init' first\n");
+		return CMD_RET_FAILURE;
+	}
+
+	if (argc != 2)
+		return CMD_RET_USAGE;
+
+	part = argv[1];
+
+	if (avb_ops->get_unique_guid_for_partition(avb_ops, part, buffer,
+						   UUID_STR_LEN + 1) ==
+						   AVB_IO_RESULT_OK) {
+		printf("'%s' UUID: %s\n", part, buffer);
+		return CMD_RET_SUCCESS;
+	}
+
+	return CMD_RET_FAILURE;
+}
+
+int do_avb_verify_part(cmd_tbl_t *cmdtp, int flag,
+		       int argc, char *const argv[])
+{
+	AvbSlotVerifyResult slot_result;
+	AvbSlotVerifyData *out_data;
+
+	bool unlocked = false;
+	int res = CMD_RET_FAILURE;
+
+	if (!avb_ops) {
+		printf("AVB 2.0 is not initialized, run 'avb init' first\n");
+		return CMD_RET_FAILURE;
+	}
+
+	if (argc != 1)
+		return CMD_RET_USAGE;
+
+	printf("## Android Verified Boot 2.0 version %s\n",
+	       avb_version_string());
+
+	if (avb_ops->read_is_device_unlocked(avb_ops, &unlocked) !=
+	    AVB_IO_RESULT_OK) {
+		printf("Can't determine device lock state.\n");
+		return CMD_RET_FAILURE;
+	}
+
+	slot_result = avb_slot_verify(avb_ops, requested_partitions,
+				      "", unlocked, &out_data);
+	switch (slot_result) {
+	case AVB_SLOT_VERIFY_RESULT_OK:
+		printf("Verification passed successfully\n");
+
+		/* export additional bootargs to AVB_BOOTARGS env var */
+		env_set(AVB_BOOTARGS, out_data->cmdline);
+
+		res = CMD_RET_SUCCESS;
+		break;
+	case AVB_SLOT_VERIFY_RESULT_ERROR_VERIFICATION:
+		printf("Verification failed\n");
+		break;
+	case AVB_SLOT_VERIFY_RESULT_ERROR_IO:
+		printf("I/O error occurred during verification\n");
+		break;
+	case AVB_SLOT_VERIFY_RESULT_ERROR_OOM:
+		printf("OOM error occurred during verification\n");
+		break;
+	case AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA:
+		printf("Corrupted dm-verity metadata detected\n");
+		break;
+	case AVB_SLOT_VERIFY_RESULT_ERROR_UNSUPPORTED_VERSION:
+		printf("Unsupported version avbtool was used\n");
+		break;
+	case AVB_SLOT_VERIFY_RESULT_ERROR_ROLLBACK_INDEX:
+		printf("Checking rollback index failed\n");
+		break;
+	case AVB_SLOT_VERIFY_RESULT_ERROR_PUBLIC_KEY_REJECTED:
+		printf("Public key was rejected\n");
+		break;
+	default:
+		printf("Unknown error occurred\n");
+	}
+
+	return res;
+}
+
+int do_avb_is_unlocked(cmd_tbl_t *cmdtp, int flag,
+		       int argc, char * const argv[])
+{
+	bool unlock;
+
+	if (!avb_ops) {
+		printf("AVB not initialized, run 'avb init' first\n");
+		return CMD_RET_FAILURE;
+	}
+
+	if (argc != 1) {
+		printf("--%s(-1)\n", __func__);
+		return CMD_RET_USAGE;
+	}
+
+	if (avb_ops->read_is_device_unlocked(avb_ops, &unlock) ==
+	    AVB_IO_RESULT_OK) {
+		printf("Unlocked = %d\n", unlock);
+		return CMD_RET_SUCCESS;
+	}
+
+	return CMD_RET_FAILURE;
+}
+
+static cmd_tbl_t cmd_avb[] = {
+	U_BOOT_CMD_MKENT(init, 2, 0, do_avb_init, "", ""),
+	U_BOOT_CMD_MKENT(read_rb, 2, 0, do_avb_read_rb, "", ""),
+	U_BOOT_CMD_MKENT(write_rb, 3, 0, do_avb_write_rb, "", ""),
+	U_BOOT_CMD_MKENT(is_unlocked, 1, 0, do_avb_is_unlocked, "", ""),
+	U_BOOT_CMD_MKENT(get_uuid, 2, 0, do_avb_get_uuid, "", ""),
+	U_BOOT_CMD_MKENT(read_part, 5, 0, do_avb_read_part, "", ""),
+	U_BOOT_CMD_MKENT(read_part_hex, 4, 0, do_avb_read_part_hex, "", ""),
+	U_BOOT_CMD_MKENT(write_part, 5, 0, do_avb_write_part, "", ""),
+	U_BOOT_CMD_MKENT(verify, 1, 0, do_avb_verify_part, "", ""),
+};
+
+static int do_avb(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+	cmd_tbl_t *cp;
+
+	cp = find_cmd_tbl(argv[1], cmd_avb, ARRAY_SIZE(cmd_avb));
+
+	argc--;
+	argv++;
+
+	if (!cp || argc > cp->maxargs)
+		return CMD_RET_USAGE;
+
+	if (flag == CMD_FLAG_REPEAT)
+		return CMD_RET_FAILURE;
+
+	return cp->cmd(cmdtp, flag, argc, argv);
+}
+
+U_BOOT_CMD(
+	avb, 29, 0, do_avb,
+	"Provides commands for testing Android Verified Boot 2.0 functionality",
+	"init <dev> - initialize avb2 for <dev>\n"
+	"avb read_rb <num> - read rollback index at location <num>\n"
+	"avb write_rb <num> <rb> - write rollback index <rb> to <num>\n"
+	"avb is_unlocked - returns unlock status of the device\n"
+	"avb get_uuid <partname> - read and print uuid of partition <part>\n"
+	"avb read_part <partname> <offset> <num> <addr> - read <num> bytes from\n"
+	"    partition <partname> to buffer <addr>\n"
+	"avb read_part_hex <partname> <offset> <num> - read <num> bytes from\n"
+	"    partition <partname> and print to stdout\n"
+	"avb write_part <partname> <offset> <num> <addr> - write <num> bytes to\n"
+	"    <partname> by <offset> using data from <addr>\n"
+	"avb verify - run verification process using hash data\n"
+	"    from vbmeta structure\n"
+	);
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 30+ messages in thread

* [U-Boot] [PATCH 5/8] avb2.0: add boot states and dm-verity support
  2018-04-25 13:17 [U-Boot] [PATCH 0/8] Initial integration of AVB2.0 Igor Opaniuk
                   ` (3 preceding siblings ...)
  2018-04-25 13:18 ` [U-Boot] [PATCH 4/8] cmd: avb2.0: avb command for performing verification Igor Opaniuk
@ 2018-04-25 13:18 ` Igor Opaniuk
  2018-05-02 18:59   ` Sam Protsenko
  2018-04-25 13:18 ` [U-Boot] [PATCH 6/8] am57xx_hs: avb2.0: add support of AVB 2.0 Igor Opaniuk
                   ` (4 subsequent siblings)
  9 siblings, 1 reply; 30+ messages in thread
From: Igor Opaniuk @ 2018-04-25 13:18 UTC (permalink / raw)
  To: u-boot

1. Add initial support of boot states mode (red, green, yellow)
2. Add functions for enforcing dm-verity configurations

Signed-off-by: Igor Opaniuk <igor.opaniuk@linaro.org>
---
 cmd/avb.c            |  17 ++++++-
 common/avb_verify.c  | 140 +++++++++++++++++++++++++++++++++++++++++++++++++--
 include/avb_verify.h |  19 ++++++-
 3 files changed, 171 insertions(+), 5 deletions(-)

diff --git a/cmd/avb.c b/cmd/avb.c
index d040906..2c15b47 100644
--- a/cmd/avb.c
+++ b/cmd/avb.c
@@ -218,6 +218,8 @@ int do_avb_verify_part(cmd_tbl_t *cmdtp, int flag,
 {
 	AvbSlotVerifyResult slot_result;
 	AvbSlotVerifyData *out_data;
+	char *cmdline;
+	char *extra_args;
 
 	bool unlocked = false;
 	int res = CMD_RET_FAILURE;
@@ -243,10 +245,23 @@ int do_avb_verify_part(cmd_tbl_t *cmdtp, int flag,
 				      "", unlocked, &out_data);
 	switch (slot_result) {
 	case AVB_SLOT_VERIFY_RESULT_OK:
+		/* Until we don't have support of changing unlock states, we
+		 * assume that we are by default in locked state.
+		 * So in this case we can boot only when verification is
+		 * successful; we also supply in cmdline GREEN boot state
+		 */
 		printf("Verification passed successfully\n");
 
 		/* export additional bootargs to AVB_BOOTARGS env var */
-		env_set(AVB_BOOTARGS, out_data->cmdline);
+
+		extra_args = avb_set_state(avb_ops, AVB_GREEN);
+		if (extra_args)
+			cmdline = append_cmd_line(out_data->cmdline,
+						  extra_args);
+		else
+			cmdline = out_data->cmdline;
+
+		env_set(AVB_BOOTARGS, cmdline);
 
 		res = CMD_RET_SUCCESS;
 		break;
diff --git a/common/avb_verify.c b/common/avb_verify.c
index b3d1229..df5e407 100644
--- a/common/avb_verify.c
+++ b/common/avb_verify.c
@@ -119,6 +119,140 @@ const unsigned char avb_root_pub[1032] = {
 
 /**
  * ============================================================================
+ * Boot states support (GREEN, YELLOW, ORANGE, RED) and dm_verity
+ * ============================================================================
+ */
+char *avb_set_state(AvbOps *ops, enum avb_boot_state boot_state)
+{
+	struct AvbOpsData *data;
+	char *cmdline = NULL;
+
+	if (!ops)
+		return NULL;
+
+	data = (struct AvbOpsData *)ops->user_data;
+	if (!data)
+		return NULL;
+
+	data->boot_state = boot_state;
+	switch (boot_state) {
+	case AVB_GREEN:
+		cmdline = "androidboot.verifiedbootstate=green";
+		break;
+	case AVB_YELLOW:
+		cmdline = "androidboot.verifiedbootstate=yellow";
+		break;
+	case AVB_ORANGE:
+		cmdline = "androidboot.verifiedbootstate=orange";
+	case AVB_RED:
+		break;
+	}
+
+	return cmdline;
+}
+
+char *append_cmd_line(char *cmdline_orig, char *cmdline_new)
+{
+	char *cmd_line;
+
+	if (!cmdline_new)
+		return cmdline_orig;
+
+	if (cmdline_orig)
+		cmd_line = cmdline_orig;
+	else
+		cmd_line = " ";
+
+	cmd_line = avb_strdupv(cmd_line, " ", cmdline_new, NULL);
+
+	return cmd_line;
+}
+
+static int avb_find_dm_args(char **args, char *str)
+{
+	int i = 0;
+
+	if (!str)
+		return -1;
+
+	do {
+		if ((!args[i]) || (i >= AVB_MAX_ARGS))
+			return -1;
+
+		if (strstr(args[i], str))
+			return i;
+
+		i++;
+	} while (1);
+}
+
+static char *avb_set_enforce_option(const char *cmdline, const char *option)
+{
+	char *cmdarg[AVB_MAX_ARGS];
+	char *newargs = NULL;
+	int i = 0;
+	int total_args;
+
+	memset(cmdarg, 0, sizeof(cmdarg));
+	cmdarg[i++] = strtok((char *)cmdline, " ");
+
+	do {
+		cmdarg[i] = strtok(NULL, " ");
+		if (!cmdarg[i])
+			break;
+
+		if (++i >= AVB_MAX_ARGS) {
+			printf("%s: Can't handle more then %d args\n",
+			       __func__, i);
+			return NULL;
+		}
+	} while (true);
+
+	total_args = i;
+	i = avb_find_dm_args(&cmdarg[0], VERITY_TABLE_OPT_LOGGING);
+	if (i >= 0) {
+		cmdarg[i] = (char *)option;
+	} else {
+		i = avb_find_dm_args(&cmdarg[0], VERITY_TABLE_OPT_RESTART);
+		if (i < 0) {
+			printf("%s: No verity options found\n", __func__);
+			return NULL;
+		}
+
+		cmdarg[i] = (char *)option;
+	}
+
+	for (i = 0; i <= total_args; i++)
+		newargs = append_cmd_line(newargs, cmdarg[i]);
+
+	return newargs;
+}
+
+char *avb_set_ignore_corruption(const char *cmdline)
+{
+	char *newargs = NULL;
+
+	newargs = avb_set_enforce_option(cmdline, VERITY_TABLE_OPT_LOGGING);
+	if (newargs)
+		newargs = append_cmd_line(newargs,
+					  "androidboot.veritymode=eio");
+
+	return newargs;
+}
+
+char *avb_set_enforce_verity(const char *cmdline)
+{
+	char *newargs;
+
+	newargs = avb_set_enforce_option(cmdline, VERITY_TABLE_OPT_RESTART);
+	if (newargs)
+		newargs = append_cmd_line(newargs,
+					  "androidboot.veritymode=enforcing");
+	return newargs;
+}
+
+/**
+ * ============================================================================
  * IO(mmc) auxiliary functions
  * ============================================================================
  */
@@ -478,7 +612,7 @@ static AvbIOResult read_rollback_index(AvbOps *ops,
 				       u64 *out_rollback_index)
 {
 	/* For now we always return 0 as the stored rollback index. */
-	printf("TODO: implement %s.\n", __func__);
+	printf("%s not supported yet\n", __func__);
 
 	if (out_rollback_index)
 		*out_rollback_index = 0;
@@ -502,7 +636,7 @@ static AvbIOResult write_rollback_index(AvbOps *ops,
 					u64 rollback_index)
 {
 	/* For now this is a no-op. */
-	printf("TODO: implement %s.\n", __func__);
+	printf("%s not supported yet\n", __func__);
 
 	return AVB_IO_RESULT_OK;
 }
@@ -522,7 +656,7 @@ static AvbIOResult read_is_device_unlocked(AvbOps *ops, bool *out_is_unlocked)
 {
 	/* For now we always return that the device is unlocked. */
 
-	printf("TODO: implement %s.\n", __func__);
+	printf("%s not supported yet\n", __func__);
 
 	*out_is_unlocked = true;
 
diff --git a/include/avb_verify.h b/include/avb_verify.h
index fb7ab23..9363ca5 100644
--- a/include/avb_verify.h
+++ b/include/avb_verify.h
@@ -11,12 +11,23 @@
 #include <avb/libavb_ab.h>
 #include <mmc.h>
 
-#define ALLOWED_BUF_ALIGN	8
+#define AVB_MAX_ARGS			1024
+#define VERITY_TABLE_OPT_RESTART	"restart_on_corruption"
+#define VERITY_TABLE_OPT_LOGGING	"ignore_corruption"
+#define ALLOWED_BUF_ALIGN		8
+
+enum avb_boot_state {
+	AVB_GREEN,
+	AVB_YELLOW,
+	AVB_ORANGE,
+	AVB_RED,
+};
 
 struct AvbOpsData {
 	struct AvbOps ops;
 	struct AvbABOps ab_ops;
 	int mmc_dev;
+	enum avb_boot_state boot_state;
 };
 
 struct mmc_part {
@@ -34,6 +45,12 @@ enum mmc_io_type {
 AvbOps *avb_ops_alloc(int boot_device);
 void avb_ops_free(AvbOps *ops);
 
+char *avb_set_state(AvbOps *ops, enum avb_boot_state boot_state);
+char *avb_set_enforce_verity(const char *cmdline);
+char *avb_set_ignore_corruption(const char *cmdline);
+
+char *append_cmd_line(char *cmdline_orig, char *cmdline_new);
+
 /**
  * ============================================================================
  * I/O helper inline functions
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 30+ messages in thread

* [U-Boot] [PATCH 6/8] am57xx_hs: avb2.0: add support of AVB 2.0
  2018-04-25 13:17 [U-Boot] [PATCH 0/8] Initial integration of AVB2.0 Igor Opaniuk
                   ` (4 preceding siblings ...)
  2018-04-25 13:18 ` [U-Boot] [PATCH 5/8] avb2.0: add boot states and dm-verity support Igor Opaniuk
@ 2018-04-25 13:18 ` Igor Opaniuk
  2018-05-02 19:06   ` Sam Protsenko
  2018-04-25 13:18 ` [U-Boot] [PATCH 7/8] test/py: avb2.0: add tests for avb commands Igor Opaniuk
                   ` (3 subsequent siblings)
  9 siblings, 1 reply; 30+ messages in thread
From: Igor Opaniuk @ 2018-04-25 13:18 UTC (permalink / raw)
  To: u-boot

1. Add vbmeta partition info to android partition layout for am57xx SoC
2. Add support of AVB 2.0 (including avb subset of commands) for am57xx HS

Signed-off-by: Igor Opaniuk <igor.opaniuk@linaro.org>
---
 configs/am57xx_hs_evm_defconfig |  3 +++
 include/configs/am57xx_evm.h    | 11 +++++++++++
 include/environment/ti/boot.h   | 15 +++++++++++++++
 3 files changed, 29 insertions(+)

diff --git a/configs/am57xx_hs_evm_defconfig b/configs/am57xx_hs_evm_defconfig
index ca9742f..226537a 100644
--- a/configs/am57xx_hs_evm_defconfig
+++ b/configs/am57xx_hs_evm_defconfig
@@ -81,3 +81,6 @@ CONFIG_USB_GADGET=y
 CONFIG_USB_GADGET_MANUFACTURER="Texas Instruments"
 CONFIG_USB_GADGET_VENDOR_NUM=0x0451
 CONFIG_USB_GADGET_PRODUCT_NUM=0xd022
+# CONFIG_LIBAVB is not set
+# CONFIG_LIBAVB_AB is not set
+# CONFIG_CMD_AVB is not set
diff --git a/include/configs/am57xx_evm.h b/include/configs/am57xx_evm.h
index d1f73f7..020eec1 100644
--- a/include/configs/am57xx_evm.h
+++ b/include/configs/am57xx_evm.h
@@ -38,6 +38,16 @@
 
 #define CONFIG_SYS_OMAP_ABE_SYSCK
 
+#define str(a)				#a
+#define VBMETA_PART_SIZE		(64 * 1024)
+
+#if defined(CONFIG_LIBAVB)
+#define VBMETA_PART \
+	"name=vbmeta,size=" str(VBMETA_PART_SIZE) ",uuid=${uuid_gpt_vbmeta};"
+#else
+#define VBMETA_PART			""
+#endif
+
 /* Define the default GPT table for eMMC */
 #define PARTS_DEFAULT \
 	/* Linux partitions */ \
@@ -61,6 +71,7 @@
 	"name=cache,size=256M,uuid=${uuid_gpt_cache};" \
 	"name=ipu1,size=1M,uuid=${uuid_gpt_ipu1};" \
 	"name=ipu2,size=1M,uuid=${uuid_gpt_ipu2};" \
+	VBMETA_PART \
 	"name=userdata,size=-,uuid=${uuid_gpt_userdata}"
 
 #define DFUARGS \
diff --git a/include/environment/ti/boot.h b/include/environment/ti/boot.h
index 24b7783..a8336ae 100644
--- a/include/environment/ti/boot.h
+++ b/include/environment/ti/boot.h
@@ -18,6 +18,19 @@
 #define PARTS_DEFAULT
 #endif
 
+#if defined(CONFIG_CMD_AVB)
+#define AVB_VERIFY_CHECK "if run avb_verify; then " \
+				"echo AVB verification OK.;" \
+				"set bootargs $bootargs $avb_bootargs;" \
+			"else " \
+				"echo AVB verification failed.;" \
+			"exit; fi;"
+#define AVB_VERIFY_CMD "avb_verify=avb init 1; avb verify;\0"
+#else
+#define AVB_VERIFY_CHECK ""
+#define AVB_VERIFY_CMD ""
+#endif
+
 #define DEFAULT_COMMON_BOOT_TI_ARGS \
 	"console=" CONSOLEDEV ",115200n8\0" \
 	"fdtfile=undefined\0" \
@@ -26,6 +39,7 @@
 	"bootfile=zImage\0" \
 	"usbtty=cdc_acm\0" \
 	"vram=16M\0" \
+	AVB_VERIFY_CMD \
 	"partitions=" PARTS_DEFAULT "\0" \
 	"optargs=\0" \
 	"dofastboot=0\0" \
@@ -43,6 +57,7 @@
 		"setenv machid fe6; " \
 		"mmc dev $mmcdev; " \
 		"mmc rescan; " \
+		AVB_VERIFY_CHECK \
 		"part start mmc ${mmcdev} environment fdt_start; " \
 		"part size mmc ${mmcdev} environment fdt_size; " \
 		"part start mmc ${mmcdev} boot boot_start; " \
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 30+ messages in thread

* [U-Boot] [PATCH 7/8] test/py: avb2.0: add tests for avb commands
  2018-04-25 13:17 [U-Boot] [PATCH 0/8] Initial integration of AVB2.0 Igor Opaniuk
                   ` (5 preceding siblings ...)
  2018-04-25 13:18 ` [U-Boot] [PATCH 6/8] am57xx_hs: avb2.0: add support of AVB 2.0 Igor Opaniuk
@ 2018-04-25 13:18 ` Igor Opaniuk
  2018-04-25 13:18 ` [U-Boot] [PATCH 8/8] doc: avb2.0: add README about AVB2.0 integration Igor Opaniuk
                   ` (2 subsequent siblings)
  9 siblings, 0 replies; 30+ messages in thread
From: Igor Opaniuk @ 2018-04-25 13:18 UTC (permalink / raw)
  To: u-boot

1. Run AVB 2.0 full verification chain, avb verify
2. Check if 'avb get_uuid' works, compare results with
'part list mmc 1' output
3. Test `avb read` commands, which reads N bytes from a partition
identified by a name

Signed-off-by: Igor Opaniuk <igor.opaniuk@linaro.org>
---
 test/py/tests/test_avb.py | 111 ++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 111 insertions(+)
 create mode 100644 test/py/tests/test_avb.py

diff --git a/test/py/tests/test_avb.py b/test/py/tests/test_avb.py
new file mode 100644
index 0000000..770bdde
--- /dev/null
+++ b/test/py/tests/test_avb.py
@@ -0,0 +1,111 @@
+# Copyright (c) 2018, Linaro Limited
+#
+# SPDX-License-Identifier:  GPL-2.0+
+#
+# Android Verified Boot 2.0 Test
+
+"""
+This tests Android Verified Boot 2.0 support in U-boot:
+
+For additional details about how to build proper vbmeta partition
+check doc/README.avb2
+
+For configuration verification:
+- Corrupt boot partition and check for failure
+- Corrupt vbmeta partition and check for failure
+"""
+
+import pytest
+import u_boot_utils as util
+
+# defauld mmc id
+mmc_dev = 1
+temp_addr = 0x90000000
+temp_addr2 = 0x90002000
+
+def test_avb_verify(u_boot_console):
+    """Run AVB 2.0 boot verification chain with avb subset of commands
+    """
+
+    success_str = "Verification passed successfully"
+
+    response = u_boot_console.run_command('avb init %s' %str(mmc_dev))
+    assert response == ''
+    response = u_boot_console.run_command('avb verify')
+    assert response.find(success_str)
+
+
+def test_avb_mmc_uuid(u_boot_console):
+    """Check if 'avb get_uuid' works, compare results with
+    'part list mmc 1' output
+    """
+
+    response = u_boot_console.run_command('avb init %s' % str(mmc_dev))
+    assert response == ''
+
+    response = u_boot_console.run_command('mmc rescan; mmc dev %s' %
+                                          str(mmc_dev))
+    assert response.find('is current device')
+
+    part_lines = u_boot_console.run_command('mmc part').splitlines()
+    part_list = {}
+    cur_partname = ""
+
+    for line in part_lines:
+        if "\"" in line:
+            start_pt = line.find("\"")
+            end_pt = line.find("\"", start_pt + 1)
+            cur_partname = line[start_pt + 1: end_pt]
+
+        if "guid:" in line:
+            guid_to_check = line.split("guid:\t")
+            part_list[cur_partname] = guid_to_check[1]
+
+    # lets check all guids with avb get_guid
+    for part, guid in part_list.iteritems():
+        avb_guid_resp = u_boot_console.run_command('avb get_uuid %s' % part)
+        assert guid == avb_guid_resp.split("UUID: ")[1]
+
+
+def test_avb_read_rb(u_boot_console):
+    """Test reading rollback indexes
+    """
+
+    response = u_boot_console.run_command('avb init %s' % str(mmc_dev))
+    assert response == ''
+
+    response = u_boot_console.run_command('avb read_rb 1')
+
+
+def test_avb_is_unlocked(u_boot_console):
+    """Test if device is in the unlocked state
+    """
+
+    response = u_boot_console.run_command('avb init %s' % str(mmc_dev))
+    assert response == ''
+
+    response = u_boot_console.run_command('avb is_unlocked')
+
+
+def test_avb_mmc_read(u_boot_console):
+    """Test mmc read operation
+    """
+
+    response = u_boot_console.run_command('mmc rescan; mmc dev %s 0' %
+                                          str(mmc_dev))
+    assert response.find('is current device')
+
+    response = u_boot_console.run_command('mmc read 0x%x 0x100 0x1' % temp_addr)
+    assert response.find('read: OK')
+
+    response = u_boot_console.run_command('avb init %s' % str(mmc_dev))
+    assert response == ''
+
+    response = u_boot_console.run_command('avb read_part xloader 0 100 0x%x' %
+                                           temp_addr2)
+    assert response.find('Read 512 bytes')
+
+    # Now lets compare two buffers
+    response = u_boot_console.run_command('cmp 0x%x 0x%x 40' %
+                                          (temp_addr, temp_addr2))
+    assert response.find('64 word')
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 30+ messages in thread

* [U-Boot] [PATCH 8/8] doc: avb2.0: add README about AVB2.0 integration
  2018-04-25 13:17 [U-Boot] [PATCH 0/8] Initial integration of AVB2.0 Igor Opaniuk
                   ` (6 preceding siblings ...)
  2018-04-25 13:18 ` [U-Boot] [PATCH 7/8] test/py: avb2.0: add tests for avb commands Igor Opaniuk
@ 2018-04-25 13:18 ` Igor Opaniuk
  2018-05-02 19:12   ` Sam Protsenko
  2018-04-26  3:05 ` [U-Boot] [PATCH 0/8] Initial integration of AVB2.0 Kever Yang
  2018-05-06 11:31 ` Eugeniu Rosca
  9 siblings, 1 reply; 30+ messages in thread
From: Igor Opaniuk @ 2018-04-25 13:18 UTC (permalink / raw)
  To: u-boot

Contains:
1. Overview of Android Verified Boot 2.0
2. Description of avb subset of commands
3. Examples of errors when boot/vendor/system/vbmeta partitions
are tampered
4. Examples of enabling AVB2.0 on your setup

Signed-off-by: Igor Opaniuk <igor.opaniuk@linaro.org>
---
 doc/README.avb2 | 100 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 100 insertions(+)
 create mode 100644 doc/README.avb2

diff --git a/doc/README.avb2 b/doc/README.avb2
new file mode 100644
index 0000000..40db7c5
--- /dev/null
+++ b/doc/README.avb2
@@ -0,0 +1,100 @@
+Android Verified Boot 2.0
+
+This file contains information about the current support of Android Verified
+Boot 2.0 in U-boot
+
+1. OVERVIEW
+---------------------------------
+Verified Boot establishes a chain of trust from the bootloader to system images
+* Provides integrity checking for:
+  - Android Boot image: Linux kernel + ramdisk. RAW hashing of the whole
+    partition is done and the hash is compared with the one stored in
+    the VBMeta image
+  - system/vendor partitions: verifying root hash of dm-verity hashtrees.
+* Provides capabilities for rollback protection.
+
+Integrity of the bootloader (U-boot BLOB and environment) is out of scope.
+
+For additional details check:
+https://android.googlesource.com/platform/external/avb/+/master/README.md
+
+
+2. AVB 2.0 U-BOOT SHELL COMMANDS
+-----------------------------------
+Provides CLI interface to invoke AVB 2.0 verification + misc. commands for
+different testing purposes:
+
+avb init <dev> - initialize avb 2.0 for <dev>
+avb verify - run verification process using hash data from vbmeta structure
+avb read_rb <num> - read rollback index at location <num>
+avb write_rb <num> <rb> - write rollback index <rb> to <num>
+avb is_unlocked - returns unlock status of the device
+avb get_uuid <partname> - read and print uuid of partition <partname>
+avb read_part <partname> <offset> <num> <addr> - read <num> bytes from
+partition <partname> to buffer <addr>
+avb write_part <partname> <offset> <num> <addr> - write <num> bytes to
+<partname> by <offset> using data from <addr>
+
+
+3. PARTITIONS TAMPERING (EXAMPLE)
+-----------------------------------
+Boot or system/vendor (dm-verity metadata section) is tampered:
+=> avb init 1
+=> avb verify
+avb_slot_verify.c:175: ERROR: boot: Hash of data does not match digest in
+descriptor.
+Slot verification result: ERROR_IO
+
+Vbmeta partition is tampered:
+=> avb init 1
+=> avb verify
+avb_vbmeta_image.c:206: ERROR: Hash does not match!
+avb_slot_verify.c:388: ERROR: vbmeta: Error verifying vbmeta image:
+HASH_MISMATCH
+Slot verification result: ERROR_IO
+
+
+4. ENABLE ON YOUR BOARD
+-----------------------------------
+The following options must be enabled:
+CONFIG_LIBAVB=y
+CONFIG_LIBAVB_AB=y
+CONFIG_CMD_AVB=y
+
+
+Then add `avb verify` invocation to your android boot sequence of commands,
+e.g.:
+
+=> avb_verify=avb init $mmcdev; avb verify;
+=> if run avb_verify; then                       \
+        echo AVB verification OK. Continue boot; \
+        set bootargs $bootargs $avb_bootargs;    \
+   else                                          \
+        echo AVB verification failed;            \
+        exit;                                    \
+   fi;                                           \
+
+=> emmc_android_boot=                                   \
+       echo Trying to boot Android from eMMC ...;       \
+       ...                                              \
+       run avb_verify;                                  \
+       mmc read ${fdtaddr} ${fdt_start} ${fdt_size};    \
+       mmc read ${loadaddr} ${boot_start} ${boot_size}; \
+       bootm $loadaddr $loadaddr $fdtaddr;              \
+
+
+To switch on automatic generation of vbmeta partition in AOSP build, add these
+lines to device configuration mk file:
+
+BOARD_AVB_ENABLE := true
+BOARD_AVB_ALGORITHM := SHA512_RSA4096
+BOARD_BOOTIMAGE_PARTITION_SIZE := <boot partition size>
+
+After flashing U-boot don't forget to update environment and write new
+partition table:
+=> env default -f -a
+=> setenv partitions $partitions_android
+=> env save
+=> fas 1
+
+$ fastboot oem format
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 30+ messages in thread

* [U-Boot] [PATCH 0/8] Initial integration of AVB2.0
  2018-04-25 13:17 [U-Boot] [PATCH 0/8] Initial integration of AVB2.0 Igor Opaniuk
                   ` (7 preceding siblings ...)
  2018-04-25 13:18 ` [U-Boot] [PATCH 8/8] doc: avb2.0: add README about AVB2.0 integration Igor Opaniuk
@ 2018-04-26  3:05 ` Kever Yang
  2018-04-26 13:00   ` Igor Opaniuk
  2018-04-26 18:35   ` Alex Deymo
  2018-05-06 11:31 ` Eugeniu Rosca
  9 siblings, 2 replies; 30+ messages in thread
From: Kever Yang @ 2018-04-26  3:05 UTC (permalink / raw)
  To: u-boot

Hi Igor,

    It's great to see the patch set to support AVB2.0, the upstream
libavb(from aosp) combine the AVB with A/B which I think should be
two separate feature, are you going to split them?

    BTW, do you have plan to update boot_android cmd to support avb?
the command is too weak for use now.
And any plan to add opptee_client/smcc to talk to OPTEE/ATF?

Thanks,
- Kever
On 04/25/2018 09:17 PM, Igor Opaniuk wrote:
> This series of patches introduces support of Android Verified Boot 2.0,
> which provides integrity checking of Android partitions on MMC.
>
> It integrates libavb/libavb_ab into the U-boot, provides implementation of
> AvbOps, subset of `avb` commands to run verification chain (and for debugging
> purposes), and it enables AVB2.0 verification on AM57xx HS SoC by default. 
>
> Currently, there is still no support for verification of A/B boot slots 
> and no rollback protection (for storing rollback indexes 
> there are plans to use eMMC RPMB)
>
> Libavb/libavb_ab will be deviated from AOSP upstream in the future,
> that's why minimal amount of changes were introduced into the lib sources, 
> so checkpatch may fail.
>
> For additional details check [1] AVB 2.0 README and doc/README.avb2, which
> is a part of this patchset.
>
> [1] https://android.googlesource.com/platform/external/avb/+/master/README.md
>
> Igor Opaniuk (8):
>   avb2.0: add Android Verified Boot 2.0 libraries
>   avb2.0: integrate avb 2.0 into the build system
>   avb2.0: implement AVB ops
>   cmd: avb2.0: avb command for performing verification
>   avb2.0: add boot states and dm-verity support
>   am57xx_hs: avb2.0: add support of AVB 2.0
>   test/py: avb2.0: add tests for avb commands
>   doc: avb2.0: add README about AVB2.0 integration
>
>  cmd/Kconfig                                  |   15 +
>  cmd/Makefile                                 |    3 +
>  cmd/avb.c                                    |  366 ++++++++
>  common/Makefile                              |    2 +
>  common/avb_verify.c                          |  748 ++++++++++++++++
>  configs/am57xx_hs_evm_defconfig              |    3 +
>  doc/README.avb2                              |  100 +++
>  include/avb/avb_ab_flow.h                    |  235 ++++++
>  include/avb/avb_ab_ops.h                     |   61 ++
>  include/avb/avb_chain_partition_descriptor.h |   54 ++
>  include/avb/avb_crypto.h                     |  147 ++++
>  include/avb/avb_descriptor.h                 |  113 +++
>  include/avb/avb_footer.h                     |   68 ++
>  include/avb/avb_hash_descriptor.h            |   55 ++
>  include/avb/avb_hashtree_descriptor.h        |   65 ++
>  include/avb/avb_kernel_cmdline_descriptor.h  |   63 ++
>  include/avb/avb_ops.h                        |  196 +++++
>  include/avb/avb_property_descriptor.h        |   89 ++
>  include/avb/avb_rsa.h                        |   55 ++
>  include/avb/avb_sha.h                        |   72 ++
>  include/avb/avb_slot_verify.h                |  239 ++++++
>  include/avb/avb_sysdeps.h                    |   97 +++
>  include/avb/avb_util.h                       |  259 ++++++
>  include/avb/avb_vbmeta_image.h               |  272 ++++++
>  include/avb/avb_version.h                    |   45 +
>  include/avb/libavb.h                         |   32 +
>  include/avb/libavb_ab.h                      |   22 +
>  include/avb_verify.h                         |   97 +++
>  include/configs/am57xx_evm.h                 |   11 +
>  include/environment/ti/boot.h                |   15 +
>  lib/Kconfig                                  |   20 +
>  lib/Makefile                                 |    2 +
>  lib/libavb/Makefile                          |   15 +
>  lib/libavb/avb_chain_partition_descriptor.c  |   46 +
>  lib/libavb/avb_crypto.c                      |  355 ++++++++
>  lib/libavb/avb_descriptor.c                  |  142 ++++
>  lib/libavb/avb_footer.c                      |   36 +
>  lib/libavb/avb_hash_descriptor.c             |   43 +
>  lib/libavb/avb_hashtree_descriptor.c         |   51 ++
>  lib/libavb/avb_kernel_cmdline_descriptor.c   |   40 +
>  lib/libavb/avb_property_descriptor.c         |  167 ++++
>  lib/libavb/avb_rsa.c                         |  277 ++++++
>  lib/libavb/avb_sha256.c                      |  364 ++++++++
>  lib/libavb/avb_sha512.c                      |  362 ++++++++
>  lib/libavb/avb_slot_verify.c                 | 1169 ++++++++++++++++++++++++++
>  lib/libavb/avb_sysdeps_posix.c               |   57 ++
>  lib/libavb/avb_util.c                        |  385 +++++++++
>  lib/libavb/avb_vbmeta_image.c                |  290 +++++++
>  lib/libavb/avb_version.c                     |   16 +
>  lib/libavb_ab/Makefile                       |    9 +
>  lib/libavb_ab/avb_ab_flow.c                  |  502 +++++++++++
>  test/py/tests/test_avb.py                    |  111 +++
>  52 files changed, 8058 insertions(+)
>  create mode 100644 cmd/avb.c
>  create mode 100644 common/avb_verify.c
>  create mode 100644 doc/README.avb2
>  create mode 100644 include/avb/avb_ab_flow.h
>  create mode 100644 include/avb/avb_ab_ops.h
>  create mode 100644 include/avb/avb_chain_partition_descriptor.h
>  create mode 100644 include/avb/avb_crypto.h
>  create mode 100644 include/avb/avb_descriptor.h
>  create mode 100644 include/avb/avb_footer.h
>  create mode 100644 include/avb/avb_hash_descriptor.h
>  create mode 100644 include/avb/avb_hashtree_descriptor.h
>  create mode 100644 include/avb/avb_kernel_cmdline_descriptor.h
>  create mode 100644 include/avb/avb_ops.h
>  create mode 100644 include/avb/avb_property_descriptor.h
>  create mode 100644 include/avb/avb_rsa.h
>  create mode 100644 include/avb/avb_sha.h
>  create mode 100644 include/avb/avb_slot_verify.h
>  create mode 100644 include/avb/avb_sysdeps.h
>  create mode 100644 include/avb/avb_util.h
>  create mode 100644 include/avb/avb_vbmeta_image.h
>  create mode 100644 include/avb/avb_version.h
>  create mode 100644 include/avb/libavb.h
>  create mode 100644 include/avb/libavb_ab.h
>  create mode 100644 include/avb_verify.h
>  create mode 100644 lib/libavb/Makefile
>  create mode 100644 lib/libavb/avb_chain_partition_descriptor.c
>  create mode 100644 lib/libavb/avb_crypto.c
>  create mode 100644 lib/libavb/avb_descriptor.c
>  create mode 100644 lib/libavb/avb_footer.c
>  create mode 100644 lib/libavb/avb_hash_descriptor.c
>  create mode 100644 lib/libavb/avb_hashtree_descriptor.c
>  create mode 100644 lib/libavb/avb_kernel_cmdline_descriptor.c
>  create mode 100644 lib/libavb/avb_property_descriptor.c
>  create mode 100644 lib/libavb/avb_rsa.c
>  create mode 100644 lib/libavb/avb_sha256.c
>  create mode 100644 lib/libavb/avb_sha512.c
>  create mode 100644 lib/libavb/avb_slot_verify.c
>  create mode 100644 lib/libavb/avb_sysdeps_posix.c
>  create mode 100644 lib/libavb/avb_util.c
>  create mode 100644 lib/libavb/avb_vbmeta_image.c
>  create mode 100644 lib/libavb/avb_version.c
>  create mode 100644 lib/libavb_ab/Makefile
>  create mode 100644 lib/libavb_ab/avb_ab_flow.c
>  create mode 100644 test/py/tests/test_avb.py
>

^ permalink raw reply	[flat|nested] 30+ messages in thread

* [U-Boot] [PATCH 0/8] Initial integration of AVB2.0
  2018-04-26  3:05 ` [U-Boot] [PATCH 0/8] Initial integration of AVB2.0 Kever Yang
@ 2018-04-26 13:00   ` Igor Opaniuk
  2018-04-26 18:35   ` Alex Deymo
  1 sibling, 0 replies; 30+ messages in thread
From: Igor Opaniuk @ 2018-04-26 13:00 UTC (permalink / raw)
  To: u-boot

On 26 April 2018 at 06:05, Kever Yang <kever.yang@rock-chips.com> wrote:
> Hi Igor,
>
>     It's great to see the patch set to support AVB2.0, the upstream
> libavb(from aosp) combine the AVB with A/B which I think should be
> two separate feature, are you going to split them?

Hi Kever,

Right, support of verification of A/B slots is going to be in a
separate patch-set.

>     BTW, do you have plan to update boot_android cmd to support avb?
> the command is too weak for use now.
> And any plan to add opptee_client/smcc to talk to OPTEE/ATF?

Did you mean boot_android cmd from this patch
https://lists.denx.de/pipermail/u-boot/2017-April/285867.html,
that was never up-streamed? I guess the main suggestion was to extend
existing bootm (by adding detection and parsing of Android boot images)
instead of introducing brand new command for booting Android.

As currently major amount of boards use sequence of mmc/bootm
commands for this purposes and bootm obviously is supposed to boot
something from RAM, I assumed that it would be wrong to invoke avb
verification from bootm itself. Because of this reason I've introduced
avb set of commands for explicitly triggering the verification process.
You can check the example how AVB2.0 is enabled on AM57xx HS
(check "am57xx_hs: avb2.0: add support of AVB 2.0" patch).

The only one prerequisite is that U-boot env itself should be also a part
of chain of trust  (so it can't be tampered and "avb verify" removed)

Best regards,
Igor

>
> Thanks,
> - Kever
> On 04/25/2018 09:17 PM, Igor Opaniuk wrote:
>> This series of patches introduces support of Android Verified Boot 2.0,
>> which provides integrity checking of Android partitions on MMC.
>>
>> It integrates libavb/libavb_ab into the U-boot, provides implementation of
>> AvbOps, subset of `avb` commands to run verification chain (and for debugging
>> purposes), and it enables AVB2.0 verification on AM57xx HS SoC by default.
>>
>> Currently, there is still no support for verification of A/B boot slots
>> and no rollback protection (for storing rollback indexes
>> there are plans to use eMMC RPMB)
>>
>> Libavb/libavb_ab will be deviated from AOSP upstream in the future,
>> that's why minimal amount of changes were introduced into the lib sources,
>> so checkpatch may fail.
>>
>> For additional details check [1] AVB 2.0 README and doc/README.avb2, which
>> is a part of this patchset.
>>
>> [1] https://android.googlesource.com/platform/external/avb/+/master/README.md
>>
>> Igor Opaniuk (8):
>>   avb2.0: add Android Verified Boot 2.0 libraries
>>   avb2.0: integrate avb 2.0 into the build system
>>   avb2.0: implement AVB ops
>>   cmd: avb2.0: avb command for performing verification
>>   avb2.0: add boot states and dm-verity support
>>   am57xx_hs: avb2.0: add support of AVB 2.0
>>   test/py: avb2.0: add tests for avb commands
>>   doc: avb2.0: add README about AVB2.0 integration
>>
>>  cmd/Kconfig                                  |   15 +
>>  cmd/Makefile                                 |    3 +
>>  cmd/avb.c                                    |  366 ++++++++
>>  common/Makefile                              |    2 +
>>  common/avb_verify.c                          |  748 ++++++++++++++++
>>  configs/am57xx_hs_evm_defconfig              |    3 +
>>  doc/README.avb2                              |  100 +++
>>  include/avb/avb_ab_flow.h                    |  235 ++++++
>>  include/avb/avb_ab_ops.h                     |   61 ++
>>  include/avb/avb_chain_partition_descriptor.h |   54 ++
>>  include/avb/avb_crypto.h                     |  147 ++++
>>  include/avb/avb_descriptor.h                 |  113 +++
>>  include/avb/avb_footer.h                     |   68 ++
>>  include/avb/avb_hash_descriptor.h            |   55 ++
>>  include/avb/avb_hashtree_descriptor.h        |   65 ++
>>  include/avb/avb_kernel_cmdline_descriptor.h  |   63 ++
>>  include/avb/avb_ops.h                        |  196 +++++
>>  include/avb/avb_property_descriptor.h        |   89 ++
>>  include/avb/avb_rsa.h                        |   55 ++
>>  include/avb/avb_sha.h                        |   72 ++
>>  include/avb/avb_slot_verify.h                |  239 ++++++
>>  include/avb/avb_sysdeps.h                    |   97 +++
>>  include/avb/avb_util.h                       |  259 ++++++
>>  include/avb/avb_vbmeta_image.h               |  272 ++++++
>>  include/avb/avb_version.h                    |   45 +
>>  include/avb/libavb.h                         |   32 +
>>  include/avb/libavb_ab.h                      |   22 +
>>  include/avb_verify.h                         |   97 +++
>>  include/configs/am57xx_evm.h                 |   11 +
>>  include/environment/ti/boot.h                |   15 +
>>  lib/Kconfig                                  |   20 +
>>  lib/Makefile                                 |    2 +
>>  lib/libavb/Makefile                          |   15 +
>>  lib/libavb/avb_chain_partition_descriptor.c  |   46 +
>>  lib/libavb/avb_crypto.c                      |  355 ++++++++
>>  lib/libavb/avb_descriptor.c                  |  142 ++++
>>  lib/libavb/avb_footer.c                      |   36 +
>>  lib/libavb/avb_hash_descriptor.c             |   43 +
>>  lib/libavb/avb_hashtree_descriptor.c         |   51 ++
>>  lib/libavb/avb_kernel_cmdline_descriptor.c   |   40 +
>>  lib/libavb/avb_property_descriptor.c         |  167 ++++
>>  lib/libavb/avb_rsa.c                         |  277 ++++++
>>  lib/libavb/avb_sha256.c                      |  364 ++++++++
>>  lib/libavb/avb_sha512.c                      |  362 ++++++++
>>  lib/libavb/avb_slot_verify.c                 | 1169 ++++++++++++++++++++++++++
>>  lib/libavb/avb_sysdeps_posix.c               |   57 ++
>>  lib/libavb/avb_util.c                        |  385 +++++++++
>>  lib/libavb/avb_vbmeta_image.c                |  290 +++++++
>>  lib/libavb/avb_version.c                     |   16 +
>>  lib/libavb_ab/Makefile                       |    9 +
>>  lib/libavb_ab/avb_ab_flow.c                  |  502 +++++++++++
>>  test/py/tests/test_avb.py                    |  111 +++
>>  52 files changed, 8058 insertions(+)
>>  create mode 100644 cmd/avb.c
>>  create mode 100644 common/avb_verify.c
>>  create mode 100644 doc/README.avb2
>>  create mode 100644 include/avb/avb_ab_flow.h
>>  create mode 100644 include/avb/avb_ab_ops.h
>>  create mode 100644 include/avb/avb_chain_partition_descriptor.h
>>  create mode 100644 include/avb/avb_crypto.h
>>  create mode 100644 include/avb/avb_descriptor.h
>>  create mode 100644 include/avb/avb_footer.h
>>  create mode 100644 include/avb/avb_hash_descriptor.h
>>  create mode 100644 include/avb/avb_hashtree_descriptor.h
>>  create mode 100644 include/avb/avb_kernel_cmdline_descriptor.h
>>  create mode 100644 include/avb/avb_ops.h
>>  create mode 100644 include/avb/avb_property_descriptor.h
>>  create mode 100644 include/avb/avb_rsa.h
>>  create mode 100644 include/avb/avb_sha.h
>>  create mode 100644 include/avb/avb_slot_verify.h
>>  create mode 100644 include/avb/avb_sysdeps.h
>>  create mode 100644 include/avb/avb_util.h
>>  create mode 100644 include/avb/avb_vbmeta_image.h
>>  create mode 100644 include/avb/avb_version.h
>>  create mode 100644 include/avb/libavb.h
>>  create mode 100644 include/avb/libavb_ab.h
>>  create mode 100644 include/avb_verify.h
>>  create mode 100644 lib/libavb/Makefile
>>  create mode 100644 lib/libavb/avb_chain_partition_descriptor.c
>>  create mode 100644 lib/libavb/avb_crypto.c
>>  create mode 100644 lib/libavb/avb_descriptor.c
>>  create mode 100644 lib/libavb/avb_footer.c
>>  create mode 100644 lib/libavb/avb_hash_descriptor.c
>>  create mode 100644 lib/libavb/avb_hashtree_descriptor.c
>>  create mode 100644 lib/libavb/avb_kernel_cmdline_descriptor.c
>>  create mode 100644 lib/libavb/avb_property_descriptor.c
>>  create mode 100644 lib/libavb/avb_rsa.c
>>  create mode 100644 lib/libavb/avb_sha256.c
>>  create mode 100644 lib/libavb/avb_sha512.c
>>  create mode 100644 lib/libavb/avb_slot_verify.c
>>  create mode 100644 lib/libavb/avb_sysdeps_posix.c
>>  create mode 100644 lib/libavb/avb_util.c
>>  create mode 100644 lib/libavb/avb_vbmeta_image.c
>>  create mode 100644 lib/libavb/avb_version.c
>>  create mode 100644 lib/libavb_ab/Makefile
>>  create mode 100644 lib/libavb_ab/avb_ab_flow.c
>>  create mode 100644 test/py/tests/test_avb.py
>>
>
>

^ permalink raw reply	[flat|nested] 30+ messages in thread

* [U-Boot] [PATCH 0/8] Initial integration of AVB2.0
  2018-04-26  3:05 ` [U-Boot] [PATCH 0/8] Initial integration of AVB2.0 Kever Yang
  2018-04-26 13:00   ` Igor Opaniuk
@ 2018-04-26 18:35   ` Alex Deymo
  2018-04-27  9:53     ` Igor Opaniuk
  1 sibling, 1 reply; 30+ messages in thread
From: Alex Deymo @ 2018-04-26 18:35 UTC (permalink / raw)
  To: u-boot

Hi Kever,
  libavb and libavb_ab are different things, and we split them for a
reason. Adding libavb is great, but you don't need to add libavb_ab as an
A/B implementation. The boot_android command referenced by Igor doesn't use
that as an A/B implementation, but uses the structs already defined in
the Boot Control Block (BCB) and the android bootloader flow. I would
recommend to include the libavb only.

Igor,
What changes did you need to do to libavb to import it to U-Boot? The idea
with libavb is that it should be easy to integrate into your bootloader
without changes; and therefore easy to update and integrate new patches
when we release new versions of libavb. We would like to avoid diverting
from it to reduce the maintenance cost.

Best regards,
Alex


Le jeu. 26 avr. 2018 à 05:05, Kever Yang <kever.yang@rock-chips.com> a
écrit :

> Hi Igor,
>
>     It's great to see the patch set to support AVB2.0, the upstream
> libavb(from aosp) combine the AVB with A/B which I think should be
> two separate feature, are you going to split them?
>
>     BTW, do you have plan to update boot_android cmd to support avb?
> the command is too weak for use now.
> And any plan to add opptee_client/smcc to talk to OPTEE/ATF?
>
> Thanks,
> - Kever
> On 04/25/2018 09:17 PM, Igor Opaniuk wrote:
> > This series of patches introduces support of Android Verified Boot 2.0,
> > which provides integrity checking of Android partitions on MMC.
> >
> > It integrates libavb/libavb_ab into the U-boot, provides implementation
> of
> > AvbOps, subset of `avb` commands to run verification chain (and for
> debugging
> > purposes), and it enables AVB2.0 verification on AM57xx HS SoC by
> default.
> >
> > Currently, there is still no support for verification of A/B boot slots
> > and no rollback protection (for storing rollback indexes
> > there are plans to use eMMC RPMB)
> >
> > Libavb/libavb_ab will be deviated from AOSP upstream in the future,
> > that's why minimal amount of changes were introduced into the lib
> sources,
> > so checkpatch may fail.
> >
> > For additional details check [1] AVB 2.0 README and doc/README.avb2,
> which
> > is a part of this patchset.
> >
> > [1]
> https://android.googlesource.com/platform/external/avb/+/master/README.md
> >
> > Igor Opaniuk (8):
> >   avb2.0: add Android Verified Boot 2.0 libraries
> >   avb2.0: integrate avb 2.0 into the build system
> >   avb2.0: implement AVB ops
> >   cmd: avb2.0: avb command for performing verification
> >   avb2.0: add boot states and dm-verity support
> >   am57xx_hs: avb2.0: add support of AVB 2.0
> >   test/py: avb2.0: add tests for avb commands
> >   doc: avb2.0: add README about AVB2.0 integration
> >
> >  cmd/Kconfig                                  |   15 +
> >  cmd/Makefile                                 |    3 +
> >  cmd/avb.c                                    |  366 ++++++++
> >  common/Makefile                              |    2 +
> >  common/avb_verify.c                          |  748 ++++++++++++++++
> >  configs/am57xx_hs_evm_defconfig              |    3 +
> >  doc/README.avb2                              |  100 +++
> >  include/avb/avb_ab_flow.h                    |  235 ++++++
> >  include/avb/avb_ab_ops.h                     |   61 ++
> >  include/avb/avb_chain_partition_descriptor.h |   54 ++
> >  include/avb/avb_crypto.h                     |  147 ++++
> >  include/avb/avb_descriptor.h                 |  113 +++
> >  include/avb/avb_footer.h                     |   68 ++
> >  include/avb/avb_hash_descriptor.h            |   55 ++
> >  include/avb/avb_hashtree_descriptor.h        |   65 ++
> >  include/avb/avb_kernel_cmdline_descriptor.h  |   63 ++
> >  include/avb/avb_ops.h                        |  196 +++++
> >  include/avb/avb_property_descriptor.h        |   89 ++
> >  include/avb/avb_rsa.h                        |   55 ++
> >  include/avb/avb_sha.h                        |   72 ++
> >  include/avb/avb_slot_verify.h                |  239 ++++++
> >  include/avb/avb_sysdeps.h                    |   97 +++
> >  include/avb/avb_util.h                       |  259 ++++++
> >  include/avb/avb_vbmeta_image.h               |  272 ++++++
> >  include/avb/avb_version.h                    |   45 +
> >  include/avb/libavb.h                         |   32 +
> >  include/avb/libavb_ab.h                      |   22 +
> >  include/avb_verify.h                         |   97 +++
> >  include/configs/am57xx_evm.h                 |   11 +
> >  include/environment/ti/boot.h                |   15 +
> >  lib/Kconfig                                  |   20 +
> >  lib/Makefile                                 |    2 +
> >  lib/libavb/Makefile                          |   15 +
> >  lib/libavb/avb_chain_partition_descriptor.c  |   46 +
> >  lib/libavb/avb_crypto.c                      |  355 ++++++++
> >  lib/libavb/avb_descriptor.c                  |  142 ++++
> >  lib/libavb/avb_footer.c                      |   36 +
> >  lib/libavb/avb_hash_descriptor.c             |   43 +
> >  lib/libavb/avb_hashtree_descriptor.c         |   51 ++
> >  lib/libavb/avb_kernel_cmdline_descriptor.c   |   40 +
> >  lib/libavb/avb_property_descriptor.c         |  167 ++++
> >  lib/libavb/avb_rsa.c                         |  277 ++++++
> >  lib/libavb/avb_sha256.c                      |  364 ++++++++
> >  lib/libavb/avb_sha512.c                      |  362 ++++++++
> >  lib/libavb/avb_slot_verify.c                 | 1169
> ++++++++++++++++++++++++++
> >  lib/libavb/avb_sysdeps_posix.c               |   57 ++
> >  lib/libavb/avb_util.c                        |  385 +++++++++
> >  lib/libavb/avb_vbmeta_image.c                |  290 +++++++
> >  lib/libavb/avb_version.c                     |   16 +
> >  lib/libavb_ab/Makefile                       |    9 +
> >  lib/libavb_ab/avb_ab_flow.c                  |  502 +++++++++++
> >  test/py/tests/test_avb.py                    |  111 +++
> >  52 files changed, 8058 insertions(+)
> >  create mode 100644 cmd/avb.c
> >  create mode 100644 common/avb_verify.c
> >  create mode 100644 doc/README.avb2
> >  create mode 100644 include/avb/avb_ab_flow.h
> >  create mode 100644 include/avb/avb_ab_ops.h
> >  create mode 100644 include/avb/avb_chain_partition_descriptor.h
> >  create mode 100644 include/avb/avb_crypto.h
> >  create mode 100644 include/avb/avb_descriptor.h
> >  create mode 100644 include/avb/avb_footer.h
> >  create mode 100644 include/avb/avb_hash_descriptor.h
> >  create mode 100644 include/avb/avb_hashtree_descriptor.h
> >  create mode 100644 include/avb/avb_kernel_cmdline_descriptor.h
> >  create mode 100644 include/avb/avb_ops.h
> >  create mode 100644 include/avb/avb_property_descriptor.h
> >  create mode 100644 include/avb/avb_rsa.h
> >  create mode 100644 include/avb/avb_sha.h
> >  create mode 100644 include/avb/avb_slot_verify.h
> >  create mode 100644 include/avb/avb_sysdeps.h
> >  create mode 100644 include/avb/avb_util.h
> >  create mode 100644 include/avb/avb_vbmeta_image.h
> >  create mode 100644 include/avb/avb_version.h
> >  create mode 100644 include/avb/libavb.h
> >  create mode 100644 include/avb/libavb_ab.h
> >  create mode 100644 include/avb_verify.h
> >  create mode 100644 lib/libavb/Makefile
> >  create mode 100644 lib/libavb/avb_chain_partition_descriptor.c
> >  create mode 100644 lib/libavb/avb_crypto.c
> >  create mode 100644 lib/libavb/avb_descriptor.c
> >  create mode 100644 lib/libavb/avb_footer.c
> >  create mode 100644 lib/libavb/avb_hash_descriptor.c
> >  create mode 100644 lib/libavb/avb_hashtree_descriptor.c
> >  create mode 100644 lib/libavb/avb_kernel_cmdline_descriptor.c
> >  create mode 100644 lib/libavb/avb_property_descriptor.c
> >  create mode 100644 lib/libavb/avb_rsa.c
> >  create mode 100644 lib/libavb/avb_sha256.c
> >  create mode 100644 lib/libavb/avb_sha512.c
> >  create mode 100644 lib/libavb/avb_slot_verify.c
> >  create mode 100644 lib/libavb/avb_sysdeps_posix.c
> >  create mode 100644 lib/libavb/avb_util.c
> >  create mode 100644 lib/libavb/avb_vbmeta_image.c
> >  create mode 100644 lib/libavb/avb_version.c
> >  create mode 100644 lib/libavb_ab/Makefile
> >  create mode 100644 lib/libavb_ab/avb_ab_flow.c
> >  create mode 100644 test/py/tests/test_avb.py
> >
>
>
> _______________________________________________
> U-Boot mailing list
> U-Boot at lists.denx.de
> https://lists.denx.de/listinfo/u-boot
>

^ permalink raw reply	[flat|nested] 30+ messages in thread

* [U-Boot] [PATCH 0/8] Initial integration of AVB2.0
  2018-04-26 18:35   ` Alex Deymo
@ 2018-04-27  9:53     ` Igor Opaniuk
  2018-04-30 10:47       ` Alex Deymo
  0 siblings, 1 reply; 30+ messages in thread
From: Igor Opaniuk @ 2018-04-27  9:53 UTC (permalink / raw)
  To: u-boot

Hi Alex,

I've replaced licence texts in source file headers to SPDX short
identifiers (suggestion from Tom Rini).
As far as I know that was the only one major change I introduced to
libavb/libavb_ab.
I also did remove crc32() implementation and used existing in U-boot
because of licence ambiguity,
frankly I wasn't sure if it was GPL-2.0 compatible (
https://android.googlesource.com/platform/external/avb/+/master/libavb/avb_crc32.c).

Regarding libavb_ab, I guess I can exclude it for now, as there is no
any functionality implemented for A/B
slots support in this patch-set. And, btw, I've noticed the note in
the latest README.md for AVB2.0
on googlesource "This code is DEPRECATED and you must define
AVB_AB_I_UNDERSTAND_LIBAVB_AB_IS_DEPRECATED  to use it. The code will
be removed Jun 1 2018.".
Does it mean that a/b stuff will be included in libavb instead of
seperate libavb_av lib?

Thanks!

Regards,
Igor

On 26 April 2018 at 19:35, Alex Deymo <deymo+@google.com> wrote:
> Hi Kever,
>   libavb and libavb_ab are different things, and we split them for a reason.
> Adding libavb is great, but you don't need to add libavb_ab as an A/B
> implementation. The boot_android command referenced by Igor doesn't use that
> as an A/B implementation, but uses the structs already defined in the Boot
> Control Block (BCB) and the android bootloader flow. I would recommend to
> include the libavb only.
>
> Igor,
> What changes did you need to do to libavb to import it to U-Boot? The idea
> with libavb is that it should be easy to integrate into your bootloader
> without changes; and therefore easy to update and integrate new patches when
> we release new versions of libavb. We would like to avoid diverting from it
> to reduce the maintenance cost.
>
> Best regards,
> Alex
>
>
> Le jeu. 26 avr. 2018 à 05:05, Kever Yang <kever.yang@rock-chips.com> a écrit
> :
>>
>> Hi Igor,
>>
>>     It's great to see the patch set to support AVB2.0, the upstream
>> libavb(from aosp) combine the AVB with A/B which I think should be
>> two separate feature, are you going to split them?
>>
>>     BTW, do you have plan to update boot_android cmd to support avb?
>> the command is too weak for use now.
>> And any plan to add opptee_client/smcc to talk to OPTEE/ATF?
>>
>> Thanks,
>> - Kever
>> On 04/25/2018 09:17 PM, Igor Opaniuk wrote:
>> > This series of patches introduces support of Android Verified Boot 2.0,
>> > which provides integrity checking of Android partitions on MMC.
>> >
>> > It integrates libavb/libavb_ab into the U-boot, provides implementation
>> > of
>> > AvbOps, subset of `avb` commands to run verification chain (and for
>> > debugging
>> > purposes), and it enables AVB2.0 verification on AM57xx HS SoC by
>> > default.
>> >
>> > Currently, there is still no support for verification of A/B boot slots
>> > and no rollback protection (for storing rollback indexes
>> > there are plans to use eMMC RPMB)
>> >
>> > Libavb/libavb_ab will be deviated from AOSP upstream in the future,
>> > that's why minimal amount of changes were introduced into the lib
>> > sources,
>> > so checkpatch may fail.
>> >
>> > For additional details check [1] AVB 2.0 README and doc/README.avb2,
>> > which
>> > is a part of this patchset.
>> >
>> > [1]
>> > https://android.googlesource.com/platform/external/avb/+/master/README.md
>> >
>> > Igor Opaniuk (8):
>> >   avb2.0: add Android Verified Boot 2.0 libraries
>> >   avb2.0: integrate avb 2.0 into the build system
>> >   avb2.0: implement AVB ops
>> >   cmd: avb2.0: avb command for performing verification
>> >   avb2.0: add boot states and dm-verity support
>> >   am57xx_hs: avb2.0: add support of AVB 2.0
>> >   test/py: avb2.0: add tests for avb commands
>> >   doc: avb2.0: add README about AVB2.0 integration
>> >
>> >  cmd/Kconfig                                  |   15 +
>> >  cmd/Makefile                                 |    3 +
>> >  cmd/avb.c                                    |  366 ++++++++
>> >  common/Makefile                              |    2 +
>> >  common/avb_verify.c                          |  748 ++++++++++++++++
>> >  configs/am57xx_hs_evm_defconfig              |    3 +
>> >  doc/README.avb2                              |  100 +++
>> >  include/avb/avb_ab_flow.h                    |  235 ++++++
>> >  include/avb/avb_ab_ops.h                     |   61 ++
>> >  include/avb/avb_chain_partition_descriptor.h |   54 ++
>> >  include/avb/avb_crypto.h                     |  147 ++++
>> >  include/avb/avb_descriptor.h                 |  113 +++
>> >  include/avb/avb_footer.h                     |   68 ++
>> >  include/avb/avb_hash_descriptor.h            |   55 ++
>> >  include/avb/avb_hashtree_descriptor.h        |   65 ++
>> >  include/avb/avb_kernel_cmdline_descriptor.h  |   63 ++
>> >  include/avb/avb_ops.h                        |  196 +++++
>> >  include/avb/avb_property_descriptor.h        |   89 ++
>> >  include/avb/avb_rsa.h                        |   55 ++
>> >  include/avb/avb_sha.h                        |   72 ++
>> >  include/avb/avb_slot_verify.h                |  239 ++++++
>> >  include/avb/avb_sysdeps.h                    |   97 +++
>> >  include/avb/avb_util.h                       |  259 ++++++
>> >  include/avb/avb_vbmeta_image.h               |  272 ++++++
>> >  include/avb/avb_version.h                    |   45 +
>> >  include/avb/libavb.h                         |   32 +
>> >  include/avb/libavb_ab.h                      |   22 +
>> >  include/avb_verify.h                         |   97 +++
>> >  include/configs/am57xx_evm.h                 |   11 +
>> >  include/environment/ti/boot.h                |   15 +
>> >  lib/Kconfig                                  |   20 +
>> >  lib/Makefile                                 |    2 +
>> >  lib/libavb/Makefile                          |   15 +
>> >  lib/libavb/avb_chain_partition_descriptor.c  |   46 +
>> >  lib/libavb/avb_crypto.c                      |  355 ++++++++
>> >  lib/libavb/avb_descriptor.c                  |  142 ++++
>> >  lib/libavb/avb_footer.c                      |   36 +
>> >  lib/libavb/avb_hash_descriptor.c             |   43 +
>> >  lib/libavb/avb_hashtree_descriptor.c         |   51 ++
>> >  lib/libavb/avb_kernel_cmdline_descriptor.c   |   40 +
>> >  lib/libavb/avb_property_descriptor.c         |  167 ++++
>> >  lib/libavb/avb_rsa.c                         |  277 ++++++
>> >  lib/libavb/avb_sha256.c                      |  364 ++++++++
>> >  lib/libavb/avb_sha512.c                      |  362 ++++++++
>> >  lib/libavb/avb_slot_verify.c                 | 1169
>> > ++++++++++++++++++++++++++
>> >  lib/libavb/avb_sysdeps_posix.c               |   57 ++
>> >  lib/libavb/avb_util.c                        |  385 +++++++++
>> >  lib/libavb/avb_vbmeta_image.c                |  290 +++++++
>> >  lib/libavb/avb_version.c                     |   16 +
>> >  lib/libavb_ab/Makefile                       |    9 +
>> >  lib/libavb_ab/avb_ab_flow.c                  |  502 +++++++++++
>> >  test/py/tests/test_avb.py                    |  111 +++
>> >  52 files changed, 8058 insertions(+)
>> >  create mode 100644 cmd/avb.c
>> >  create mode 100644 common/avb_verify.c
>> >  create mode 100644 doc/README.avb2
>> >  create mode 100644 include/avb/avb_ab_flow.h
>> >  create mode 100644 include/avb/avb_ab_ops.h
>> >  create mode 100644 include/avb/avb_chain_partition_descriptor.h
>> >  create mode 100644 include/avb/avb_crypto.h
>> >  create mode 100644 include/avb/avb_descriptor.h
>> >  create mode 100644 include/avb/avb_footer.h
>> >  create mode 100644 include/avb/avb_hash_descriptor.h
>> >  create mode 100644 include/avb/avb_hashtree_descriptor.h
>> >  create mode 100644 include/avb/avb_kernel_cmdline_descriptor.h
>> >  create mode 100644 include/avb/avb_ops.h
>> >  create mode 100644 include/avb/avb_property_descriptor.h
>> >  create mode 100644 include/avb/avb_rsa.h
>> >  create mode 100644 include/avb/avb_sha.h
>> >  create mode 100644 include/avb/avb_slot_verify.h
>> >  create mode 100644 include/avb/avb_sysdeps.h
>> >  create mode 100644 include/avb/avb_util.h
>> >  create mode 100644 include/avb/avb_vbmeta_image.h
>> >  create mode 100644 include/avb/avb_version.h
>> >  create mode 100644 include/avb/libavb.h
>> >  create mode 100644 include/avb/libavb_ab.h
>> >  create mode 100644 include/avb_verify.h
>> >  create mode 100644 lib/libavb/Makefile
>> >  create mode 100644 lib/libavb/avb_chain_partition_descriptor.c
>> >  create mode 100644 lib/libavb/avb_crypto.c
>> >  create mode 100644 lib/libavb/avb_descriptor.c
>> >  create mode 100644 lib/libavb/avb_footer.c
>> >  create mode 100644 lib/libavb/avb_hash_descriptor.c
>> >  create mode 100644 lib/libavb/avb_hashtree_descriptor.c
>> >  create mode 100644 lib/libavb/avb_kernel_cmdline_descriptor.c
>> >  create mode 100644 lib/libavb/avb_property_descriptor.c
>> >  create mode 100644 lib/libavb/avb_rsa.c
>> >  create mode 100644 lib/libavb/avb_sha256.c
>> >  create mode 100644 lib/libavb/avb_sha512.c
>> >  create mode 100644 lib/libavb/avb_slot_verify.c
>> >  create mode 100644 lib/libavb/avb_sysdeps_posix.c
>> >  create mode 100644 lib/libavb/avb_util.c
>> >  create mode 100644 lib/libavb/avb_vbmeta_image.c
>> >  create mode 100644 lib/libavb/avb_version.c
>> >  create mode 100644 lib/libavb_ab/Makefile
>> >  create mode 100644 lib/libavb_ab/avb_ab_flow.c
>> >  create mode 100644 test/py/tests/test_avb.py
>> >
>>
>>
>> _______________________________________________
>> U-Boot mailing list
>> U-Boot at lists.denx.de
>> https://lists.denx.de/listinfo/u-boot



-- 
Regards,
Igor Opaniuk

^ permalink raw reply	[flat|nested] 30+ messages in thread

* [U-Boot] [PATCH 0/8] Initial integration of AVB2.0
  2018-04-27  9:53     ` Igor Opaniuk
@ 2018-04-30 10:47       ` Alex Deymo
  0 siblings, 0 replies; 30+ messages in thread
From: Alex Deymo @ 2018-04-30 10:47 UTC (permalink / raw)
  To: u-boot

Hi Igor,

The "libavb_ab" is an implementation of A/B flow, which you could use, but
you are not required to use in your A/B bootloader to make an Android
device. This ended up not being used in general, for different reasons. The
integration of the A/B error modes into an existing device depended on
other factors about your device, and it is closer to the rest of the
bootloader than it is to libavb. You can read more details about the
reasons here: https://android.googlesource.com/platform/external/avb/+/
37f5946d0e1159273eff61dd8041377fedbf55a9

Anyway, once you have selected a slot to boot from (using your own A/B
logic) or if your device has only one slot, the verification process is
done by libavb. There's the feedback loop from libavb to your A/B logic to
tell you that the slot is certainly broken, but it isn't the only feedback
your A/B logic is supposed to get. If the slot boots past libavb but the
kernel crashes and reboots later on after a broken update, the counters in
the bootloader's A/B logic shold also figure out that the slot is broken;
but there's no A/B flow logic in libavb itself. libavb is just about
verifying your boot end-to-end handling all the different ways you can sign
these images.

There's an extension to libavb, which is used in Android Things
(libavb_atx). That one is useful to include if you expect to boot Android
Things images (in Android Things you have multiple different products using
the exact same hardware SoM, which are not interchangeable).

Anyway, thanks for doing this. I think maybe a quick shell script to update
libavb (automate the changes/renames you did) would be good, but I don't
think is needed now.

Regards,
Alex.

2018-04-27 11:53 GMT+02:00 Igor Opaniuk <igor.opaniuk@linaro.org>:

> Hi Alex,
>
> I've replaced licence texts in source file headers to SPDX short
> identifiers (suggestion from Tom Rini).
> As far as I know that was the only one major change I introduced to
> libavb/libavb_ab.
> I also did remove crc32() implementation and used existing in U-boot
> because of licence ambiguity,
> frankly I wasn't sure if it was GPL-2.0 compatible (
> https://android.googlesource.com/platform/external/avb/+/mas
> ter/libavb/avb_crc32.c).
>
> Regarding libavb_ab, I guess I can exclude it for now, as there is no
> any functionality implemented for A/B
> slots support in this patch-set. And, btw, I've noticed the note in
> the latest README.md for AVB2.0
> on googlesource "This code is DEPRECATED and you must define
> AVB_AB_I_UNDERSTAND_LIBAVB_AB_IS_DEPRECATED  to use it. The code will
> be removed Jun 1 2018.".
> Does it mean that a/b stuff will be included in libavb instead of
> seperate libavb_av lib?
>
> Thanks!
>
> Regards,
> Igor

^ permalink raw reply	[flat|nested] 30+ messages in thread

* [U-Boot] [PATCH 4/8] cmd: avb2.0: avb command for performing verification
  2018-04-25 13:18 ` [U-Boot] [PATCH 4/8] cmd: avb2.0: avb command for performing verification Igor Opaniuk
@ 2018-05-02 18:52   ` Sam Protsenko
  2018-05-03  2:31   ` Simon Glass
  1 sibling, 0 replies; 30+ messages in thread
From: Sam Protsenko @ 2018-05-02 18:52 UTC (permalink / raw)
  To: u-boot

On 25 April 2018 at 16:18, Igor Opaniuk <igor.opaniuk@linaro.org> wrote:
> Enable a "avb" command to execute Android Verified
> Boot 2.0 operations. It includes such subcommands:
>   avb init - initialize avb2 subsystem
>   avb read_rb - read rollback index
>   avb write_rb - write rollback index
>   avb is_unlocked - check device lock state
>   avb get_uuid - read and print uuid of a partition
>   avb read_part - read data from partition
>   avb read_part_hex - read data from partition and output to stdout
>   avb write_part - write data to partition
>   avb verify - run full verification chain
>
> Signed-off-by: Igor Opaniuk <igor.opaniuk@linaro.org>
> ---
>  cmd/Kconfig  |  15 +++
>  cmd/Makefile |   3 +
>  cmd/avb.c    | 351 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
>  3 files changed, 369 insertions(+)
>  create mode 100644 cmd/avb.c
>
> diff --git a/cmd/Kconfig b/cmd/Kconfig
> index bc1d2f3..96695ff 100644
> --- a/cmd/Kconfig
> +++ b/cmd/Kconfig
> @@ -1675,6 +1675,21 @@ config CMD_TRACE
>           for analsys (e.g. using bootchart). See doc/README.trace for full
>           details.
>
> +config CMD_AVB
> +       bool "avb - Android Verified Boot 2.0 operations"
> +       depends on LIBAVB_AB
> +       help
> +         Enables a "avb" command to perform verification of partitions using
> +         Android Verified Boot 2.0 functionality. It includes such subcommands:
> +           avb init - initialize avb2 subsystem
> +           avb read_rb - read rollback index
> +           avb write_rb - write rollback index
> +           avb is_unlocked - check device lock state
> +           avb get_uuid - read and print uuid of a partition
> +           avb read_part - read data from partition
> +           avb read_part_hex - read data from partition and output to stdout
> +           avb write_part - write data to partition
> +           avb verify - run full verification chain
>  endmenu
>
>  config CMD_UBI
> diff --git a/cmd/Makefile b/cmd/Makefile
> index c4269ac..bbf6c2a 100644
> --- a/cmd/Makefile
> +++ b/cmd/Makefile
> @@ -151,6 +151,9 @@ obj-$(CONFIG_CMD_REGULATOR) += regulator.o
>
>  obj-$(CONFIG_CMD_BLOB) += blob.o
>
> +# Android Verified Boot 2.0
> +obj-$(CONFIG_CMD_AVB) += avb.o
> +
>  obj-$(CONFIG_X86) += x86/
>  endif # !CONFIG_SPL_BUILD
>
> diff --git a/cmd/avb.c b/cmd/avb.c
> new file mode 100644
> index 0000000..d040906
> --- /dev/null
> +++ b/cmd/avb.c
> @@ -0,0 +1,351 @@
> +
> +/*
> + * (C) Copyright 2018, Linaro Limited
> + *
> + * SPDX-License-Identifier:    GPL-2.0+
> + */
> +
> +#include <avb_verify.h>
> +#include <command.h>
> +#include <image.h>
> +#include <malloc.h>
> +#include <mmc.h>
> +
> +#define AVB_BOOTARGS   "avb_bootargs"
> +static struct AvbOps *avb_ops;
> +
> +static const char * const requested_partitions[] = {"boot",
> +                                            "system",
> +                                            "vendor",
> +                                            NULL};
> +
> +int do_avb_init(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
> +{
> +       unsigned long mmc_dev;
> +
> +       if (argc != 2)
> +               return CMD_RET_USAGE;
> +
> +       mmc_dev = simple_strtoul(argv[1], NULL, 16);
> +
> +       if (avb_ops)
> +               avb_ops_free(avb_ops);
> +
> +       avb_ops = avb_ops_alloc(mmc_dev);
> +       if (avb_ops)
> +               return CMD_RET_SUCCESS;
> +
> +       return CMD_RET_FAILURE;
> +}
> +
> +int do_avb_read_part(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
> +{
> +       const char *part;
> +       s64 offset;
> +       size_t bytes, bytes_read = 0;
> +       void *buffer;
> +
> +       if (!avb_ops) {
> +               printf("AVB 2.0 is not initialized, please run 'avb init'\n");
> +               return CMD_RET_USAGE;
> +       }
> +
> +       if (argc != 5)
> +               return CMD_RET_USAGE;
> +
> +       part = argv[1];
> +       offset = simple_strtoul(argv[2], NULL, 16);
> +       bytes = simple_strtoul(argv[3], NULL, 16);
> +       buffer = (void *)simple_strtoul(argv[4], NULL, 16);

+ Simon Glass

AFAIU, to make it possible to run this command on "sandbox", you
should use map_sysmem() and friends.

> +
> +       if (avb_ops->read_from_partition(avb_ops, part, offset, bytes,
> +                                        buffer, &bytes_read) ==
> +                                        AVB_IO_RESULT_OK) {
> +               printf("Read %zu bytes\n", bytes_read);
> +               return CMD_RET_SUCCESS;
> +       }
> +
> +       return CMD_RET_FAILURE;
> +}
> +
> +int do_avb_read_part_hex(cmd_tbl_t *cmdtp, int flag, int argc,
> +                        char *const argv[])
> +{
> +       const char *part;
> +       s64 offset;
> +       size_t bytes, bytes_read = 0;
> +       char *buffer;
> +
> +       if (!avb_ops) {
> +               printf("AVB 2.0 is not initialized, please run 'avb init'\n");
> +               return CMD_RET_USAGE;
> +       }
> +
> +       if (argc != 4)
> +               return CMD_RET_USAGE;
> +
> +       part = argv[1];
> +       offset = simple_strtoul(argv[2], NULL, 16);
> +       bytes = simple_strtoul(argv[3], NULL, 16);
> +
> +       buffer = malloc(bytes);
> +       if (!buffer) {
> +               printf("Failed to tlb_allocate buffer for data\n");
> +               return CMD_RET_FAILURE;
> +       }
> +       memset(buffer, 0, bytes);
> +
> +       if (avb_ops->read_from_partition(avb_ops, part, offset, bytes, buffer,
> +                                        &bytes_read) == AVB_IO_RESULT_OK) {
> +               printf("Requested %zu, read %zu bytes\n", bytes, bytes_read);
> +               printf("Data: ");
> +               for (int i = 0; i < bytes_read; i++)
> +                       printf("%02X", buffer[i]);
> +
> +               printf("\n");
> +
> +               free(buffer);
> +               return CMD_RET_SUCCESS;
> +       }
> +
> +       free(buffer);
> +       return CMD_RET_FAILURE;
> +}
> +
> +int do_avb_write_part(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
> +{
> +       const char *part;
> +       s64 offset;
> +       size_t bytes;
> +       void *buffer;
> +
> +       if (!avb_ops) {
> +               printf("AVB 2.0 is not initialized, run 'avb init' first\n");
> +               return CMD_RET_FAILURE;
> +       }
> +
> +       if (argc != 5)
> +               return CMD_RET_USAGE;
> +
> +       part = argv[1];
> +       offset = simple_strtoul(argv[2], NULL, 16);
> +       bytes = simple_strtoul(argv[3], NULL, 16);
> +       buffer = (void *)simple_strtoul(argv[4], NULL, 16);
> +
> +       if (avb_ops->write_to_partition(avb_ops, part, offset, bytes, buffer) ==
> +           AVB_IO_RESULT_OK) {
> +               printf("Wrote %zu bytes\n", bytes);
> +               return CMD_RET_SUCCESS;
> +       }
> +
> +       return CMD_RET_FAILURE;
> +}
> +
> +int do_avb_read_rb(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
> +{
> +       size_t index;
> +       u64 rb_idx;
> +
> +       if (!avb_ops) {
> +               printf("AVB 2.0 is not initialized, run 'avb init' first\n");
> +               return CMD_RET_FAILURE;
> +       }
> +
> +       if (argc != 2)
> +               return CMD_RET_USAGE;
> +
> +       index = (size_t)simple_strtoul(argv[1], NULL, 16);
> +
> +       if (avb_ops->read_rollback_index(avb_ops, index, &rb_idx) ==
> +           AVB_IO_RESULT_OK) {
> +               printf("Rollback index: %llu\n", rb_idx);
> +               return CMD_RET_SUCCESS;
> +       }
> +       return CMD_RET_FAILURE;
> +}
> +
> +int do_avb_write_rb(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
> +{
> +       size_t index;
> +       u64 rb_idx;
> +
> +       if (!avb_ops) {
> +               printf("AVB 2.0 is not initialized, run 'avb init' first\n");
> +               return CMD_RET_FAILURE;
> +       }
> +
> +       if (argc != 3)
> +               return CMD_RET_USAGE;
> +
> +       index = (size_t)simple_strtoul(argv[1], NULL, 16);
> +       rb_idx = simple_strtoul(argv[2], NULL, 16);
> +
> +       if (avb_ops->write_rollback_index(avb_ops, index, rb_idx) ==
> +           AVB_IO_RESULT_OK)
> +               return CMD_RET_SUCCESS;
> +
> +       return CMD_RET_FAILURE;
> +}
> +
> +int do_avb_get_uuid(cmd_tbl_t *cmdtp, int flag,
> +                   int argc, char * const argv[])
> +{
> +       const char *part;
> +       char buffer[UUID_STR_LEN + 1];
> +
> +       if (!avb_ops) {
> +               printf("AVB 2.0 is not initialized, run 'avb init' first\n");
> +               return CMD_RET_FAILURE;
> +       }
> +
> +       if (argc != 2)
> +               return CMD_RET_USAGE;
> +
> +       part = argv[1];
> +
> +       if (avb_ops->get_unique_guid_for_partition(avb_ops, part, buffer,
> +                                                  UUID_STR_LEN + 1) ==
> +                                                  AVB_IO_RESULT_OK) {
> +               printf("'%s' UUID: %s\n", part, buffer);
> +               return CMD_RET_SUCCESS;
> +       }
> +
> +       return CMD_RET_FAILURE;
> +}
> +
> +int do_avb_verify_part(cmd_tbl_t *cmdtp, int flag,
> +                      int argc, char *const argv[])
> +{
> +       AvbSlotVerifyResult slot_result;
> +       AvbSlotVerifyData *out_data;
> +
> +       bool unlocked = false;
> +       int res = CMD_RET_FAILURE;
> +
> +       if (!avb_ops) {
> +               printf("AVB 2.0 is not initialized, run 'avb init' first\n");
> +               return CMD_RET_FAILURE;
> +       }
> +
> +       if (argc != 1)
> +               return CMD_RET_USAGE;
> +
> +       printf("## Android Verified Boot 2.0 version %s\n",
> +              avb_version_string());
> +
> +       if (avb_ops->read_is_device_unlocked(avb_ops, &unlocked) !=
> +           AVB_IO_RESULT_OK) {
> +               printf("Can't determine device lock state.\n");
> +               return CMD_RET_FAILURE;
> +       }
> +
> +       slot_result = avb_slot_verify(avb_ops, requested_partitions,
> +                                     "", unlocked, &out_data);
> +       switch (slot_result) {
> +       case AVB_SLOT_VERIFY_RESULT_OK:
> +               printf("Verification passed successfully\n");
> +
> +               /* export additional bootargs to AVB_BOOTARGS env var */
> +               env_set(AVB_BOOTARGS, out_data->cmdline);
> +
> +               res = CMD_RET_SUCCESS;
> +               break;
> +       case AVB_SLOT_VERIFY_RESULT_ERROR_VERIFICATION:
> +               printf("Verification failed\n");
> +               break;
> +       case AVB_SLOT_VERIFY_RESULT_ERROR_IO:
> +               printf("I/O error occurred during verification\n");
> +               break;
> +       case AVB_SLOT_VERIFY_RESULT_ERROR_OOM:
> +               printf("OOM error occurred during verification\n");
> +               break;
> +       case AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA:
> +               printf("Corrupted dm-verity metadata detected\n");
> +               break;
> +       case AVB_SLOT_VERIFY_RESULT_ERROR_UNSUPPORTED_VERSION:
> +               printf("Unsupported version avbtool was used\n");
> +               break;
> +       case AVB_SLOT_VERIFY_RESULT_ERROR_ROLLBACK_INDEX:
> +               printf("Checking rollback index failed\n");
> +               break;
> +       case AVB_SLOT_VERIFY_RESULT_ERROR_PUBLIC_KEY_REJECTED:
> +               printf("Public key was rejected\n");
> +               break;
> +       default:
> +               printf("Unknown error occurred\n");
> +       }
> +
> +       return res;
> +}
> +
> +int do_avb_is_unlocked(cmd_tbl_t *cmdtp, int flag,
> +                      int argc, char * const argv[])
> +{
> +       bool unlock;
> +
> +       if (!avb_ops) {
> +               printf("AVB not initialized, run 'avb init' first\n");
> +               return CMD_RET_FAILURE;
> +       }
> +
> +       if (argc != 1) {
> +               printf("--%s(-1)\n", __func__);
> +               return CMD_RET_USAGE;
> +       }
> +
> +       if (avb_ops->read_is_device_unlocked(avb_ops, &unlock) ==
> +           AVB_IO_RESULT_OK) {
> +               printf("Unlocked = %d\n", unlock);
> +               return CMD_RET_SUCCESS;
> +       }
> +
> +       return CMD_RET_FAILURE;
> +}
> +
> +static cmd_tbl_t cmd_avb[] = {
> +       U_BOOT_CMD_MKENT(init, 2, 0, do_avb_init, "", ""),
> +       U_BOOT_CMD_MKENT(read_rb, 2, 0, do_avb_read_rb, "", ""),
> +       U_BOOT_CMD_MKENT(write_rb, 3, 0, do_avb_write_rb, "", ""),
> +       U_BOOT_CMD_MKENT(is_unlocked, 1, 0, do_avb_is_unlocked, "", ""),
> +       U_BOOT_CMD_MKENT(get_uuid, 2, 0, do_avb_get_uuid, "", ""),
> +       U_BOOT_CMD_MKENT(read_part, 5, 0, do_avb_read_part, "", ""),
> +       U_BOOT_CMD_MKENT(read_part_hex, 4, 0, do_avb_read_part_hex, "", ""),
> +       U_BOOT_CMD_MKENT(write_part, 5, 0, do_avb_write_part, "", ""),
> +       U_BOOT_CMD_MKENT(verify, 1, 0, do_avb_verify_part, "", ""),
> +};
> +
> +static int do_avb(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
> +{
> +       cmd_tbl_t *cp;
> +
> +       cp = find_cmd_tbl(argv[1], cmd_avb, ARRAY_SIZE(cmd_avb));
> +
> +       argc--;
> +       argv++;
> +
> +       if (!cp || argc > cp->maxargs)
> +               return CMD_RET_USAGE;
> +
> +       if (flag == CMD_FLAG_REPEAT)
> +               return CMD_RET_FAILURE;
> +
> +       return cp->cmd(cmdtp, flag, argc, argv);
> +}
> +
> +U_BOOT_CMD(
> +       avb, 29, 0, do_avb,
> +       "Provides commands for testing Android Verified Boot 2.0 functionality",
> +       "init <dev> - initialize avb2 for <dev>\n"
> +       "avb read_rb <num> - read rollback index at location <num>\n"
> +       "avb write_rb <num> <rb> - write rollback index <rb> to <num>\n"
> +       "avb is_unlocked - returns unlock status of the device\n"
> +       "avb get_uuid <partname> - read and print uuid of partition <part>\n"
> +       "avb read_part <partname> <offset> <num> <addr> - read <num> bytes from\n"
> +       "    partition <partname> to buffer <addr>\n"
> +       "avb read_part_hex <partname> <offset> <num> - read <num> bytes from\n"
> +       "    partition <partname> and print to stdout\n"
> +       "avb write_part <partname> <offset> <num> <addr> - write <num> bytes to\n"
> +       "    <partname> by <offset> using data from <addr>\n"
> +       "avb verify - run verification process using hash data\n"
> +       "    from vbmeta structure\n"
> +       );
> --
> 2.7.4
>

^ permalink raw reply	[flat|nested] 30+ messages in thread

* [U-Boot] [PATCH 5/8] avb2.0: add boot states and dm-verity support
  2018-04-25 13:18 ` [U-Boot] [PATCH 5/8] avb2.0: add boot states and dm-verity support Igor Opaniuk
@ 2018-05-02 18:59   ` Sam Protsenko
  0 siblings, 0 replies; 30+ messages in thread
From: Sam Protsenko @ 2018-05-02 18:59 UTC (permalink / raw)
  To: u-boot

On 25 April 2018 at 16:18, Igor Opaniuk <igor.opaniuk@linaro.org> wrote:
> 1. Add initial support of boot states mode (red, green, yellow)
> 2. Add functions for enforcing dm-verity configurations
>
> Signed-off-by: Igor Opaniuk <igor.opaniuk@linaro.org>
> ---
>  cmd/avb.c            |  17 ++++++-
>  common/avb_verify.c  | 140 +++++++++++++++++++++++++++++++++++++++++++++++++--
>  include/avb_verify.h |  19 ++++++-
>  3 files changed, 171 insertions(+), 5 deletions(-)
>
> diff --git a/cmd/avb.c b/cmd/avb.c
> index d040906..2c15b47 100644
> --- a/cmd/avb.c
> +++ b/cmd/avb.c
> @@ -218,6 +218,8 @@ int do_avb_verify_part(cmd_tbl_t *cmdtp, int flag,
>  {
>         AvbSlotVerifyResult slot_result;
>         AvbSlotVerifyData *out_data;
> +       char *cmdline;
> +       char *extra_args;
>
>         bool unlocked = false;
>         int res = CMD_RET_FAILURE;
> @@ -243,10 +245,23 @@ int do_avb_verify_part(cmd_tbl_t *cmdtp, int flag,
>                                       "", unlocked, &out_data);
>         switch (slot_result) {
>         case AVB_SLOT_VERIFY_RESULT_OK:
> +               /* Until we don't have support of changing unlock states, we
> +                * assume that we are by default in locked state.
> +                * So in this case we can boot only when verification is
> +                * successful; we also supply in cmdline GREEN boot state
> +                */
>                 printf("Verification passed successfully\n");
>
>                 /* export additional bootargs to AVB_BOOTARGS env var */
> -               env_set(AVB_BOOTARGS, out_data->cmdline);
> +
> +               extra_args = avb_set_state(avb_ops, AVB_GREEN);
> +               if (extra_args)
> +                       cmdline = append_cmd_line(out_data->cmdline,
> +                                                 extra_args);
> +               else
> +                       cmdline = out_data->cmdline;
> +
> +               env_set(AVB_BOOTARGS, cmdline);
>
>                 res = CMD_RET_SUCCESS;
>                 break;
> diff --git a/common/avb_verify.c b/common/avb_verify.c
> index b3d1229..df5e407 100644
> --- a/common/avb_verify.c
> +++ b/common/avb_verify.c
> @@ -119,6 +119,140 @@ const unsigned char avb_root_pub[1032] = {
>
>  /**
>   * ============================================================================
> + * Boot states support (GREEN, YELLOW, ORANGE, RED) and dm_verity
> + * ============================================================================
> + */
> +char *avb_set_state(AvbOps *ops, enum avb_boot_state boot_state)
> +{
> +       struct AvbOpsData *data;
> +       char *cmdline = NULL;
> +
> +       if (!ops)
> +               return NULL;
> +
> +       data = (struct AvbOpsData *)ops->user_data;
> +       if (!data)
> +               return NULL;
> +
> +       data->boot_state = boot_state;
> +       switch (boot_state) {
> +       case AVB_GREEN:
> +               cmdline = "androidboot.verifiedbootstate=green";
> +               break;
> +       case AVB_YELLOW:
> +               cmdline = "androidboot.verifiedbootstate=yellow";
> +               break;
> +       case AVB_ORANGE:
> +               cmdline = "androidboot.verifiedbootstate=orange";
> +       case AVB_RED:
> +               break;
> +       }
> +
> +       return cmdline;
> +}
> +
> +char *append_cmd_line(char *cmdline_orig, char *cmdline_new)
> +{
> +       char *cmd_line;
> +
> +       if (!cmdline_new)
> +               return cmdline_orig;
> +
> +       if (cmdline_orig)
> +               cmd_line = cmdline_orig;
> +       else
> +               cmd_line = " ";
> +
> +       cmd_line = avb_strdupv(cmd_line, " ", cmdline_new, NULL);
> +
> +       return cmd_line;
> +}
> +
> +static int avb_find_dm_args(char **args, char *str)
> +{
> +       int i = 0;
> +
> +       if (!str)
> +               return -1;
> +
> +       do {
> +               if ((!args[i]) || (i >= AVB_MAX_ARGS))

Conditions probably should be swapped, to avoid "index out of bounds" error.

> +                       return -1;
> +
> +               if (strstr(args[i], str))
> +                       return i;
> +
> +               i++;
> +       } while (1);
> +}

Just a suggestion: wouldn't it be better to use "for" instead of
"do/while" here? Like this:

       for (i = 0; i < AVB_MAX_ARGS, args[i]; ++i) {
               if (strstr(args[i], str))
                       return i;
       }

       return -1;

> +
> +static char *avb_set_enforce_option(const char *cmdline, const char *option)
> +{
> +       char *cmdarg[AVB_MAX_ARGS];
> +       char *newargs = NULL;
> +       int i = 0;
> +       int total_args;
> +
> +       memset(cmdarg, 0, sizeof(cmdarg));
> +       cmdarg[i++] = strtok((char *)cmdline, " ");
> +
> +       do {
> +               cmdarg[i] = strtok(NULL, " ");
> +               if (!cmdarg[i])
> +                       break;
> +
> +               if (++i >= AVB_MAX_ARGS) {
> +                       printf("%s: Can't handle more then %d args\n",
> +                              __func__, i);
> +                       return NULL;
> +               }
> +       } while (true);
> +
> +       total_args = i;
> +       i = avb_find_dm_args(&cmdarg[0], VERITY_TABLE_OPT_LOGGING);
> +       if (i >= 0) {
> +               cmdarg[i] = (char *)option;
> +       } else {
> +               i = avb_find_dm_args(&cmdarg[0], VERITY_TABLE_OPT_RESTART);
> +               if (i < 0) {
> +                       printf("%s: No verity options found\n", __func__);
> +                       return NULL;
> +               }
> +
> +               cmdarg[i] = (char *)option;
> +       }
> +
> +       for (i = 0; i <= total_args; i++)
> +               newargs = append_cmd_line(newargs, cmdarg[i]);
> +
> +       return newargs;
> +}
> +
> +char *avb_set_ignore_corruption(const char *cmdline)
> +{
> +       char *newargs = NULL;
> +
> +       newargs = avb_set_enforce_option(cmdline, VERITY_TABLE_OPT_LOGGING);
> +       if (newargs)
> +               newargs = append_cmd_line(newargs,
> +                                         "androidboot.veritymode=eio");
> +
> +       return newargs;
> +}
> +
> +char *avb_set_enforce_verity(const char *cmdline)
> +{
> +       char *newargs;
> +
> +       newargs = avb_set_enforce_option(cmdline, VERITY_TABLE_OPT_RESTART);
> +       if (newargs)
> +               newargs = append_cmd_line(newargs,
> +                                         "androidboot.veritymode=enforcing");
> +       return newargs;
> +}
> +
> +/**
> + * ============================================================================
>   * IO(mmc) auxiliary functions
>   * ============================================================================
>   */
> @@ -478,7 +612,7 @@ static AvbIOResult read_rollback_index(AvbOps *ops,
>                                        u64 *out_rollback_index)
>  {
>         /* For now we always return 0 as the stored rollback index. */
> -       printf("TODO: implement %s.\n", __func__);
> +       printf("%s not supported yet\n", __func__);
>
>         if (out_rollback_index)
>                 *out_rollback_index = 0;
> @@ -502,7 +636,7 @@ static AvbIOResult write_rollback_index(AvbOps *ops,
>                                         u64 rollback_index)
>  {
>         /* For now this is a no-op. */
> -       printf("TODO: implement %s.\n", __func__);
> +       printf("%s not supported yet\n", __func__);
>
>         return AVB_IO_RESULT_OK;
>  }
> @@ -522,7 +656,7 @@ static AvbIOResult read_is_device_unlocked(AvbOps *ops, bool *out_is_unlocked)
>  {
>         /* For now we always return that the device is unlocked. */
>
> -       printf("TODO: implement %s.\n", __func__);
> +       printf("%s not supported yet\n", __func__);
>
>         *out_is_unlocked = true;
>
> diff --git a/include/avb_verify.h b/include/avb_verify.h
> index fb7ab23..9363ca5 100644
> --- a/include/avb_verify.h
> +++ b/include/avb_verify.h
> @@ -11,12 +11,23 @@
>  #include <avb/libavb_ab.h>
>  #include <mmc.h>
>
> -#define ALLOWED_BUF_ALIGN      8
> +#define AVB_MAX_ARGS                   1024
> +#define VERITY_TABLE_OPT_RESTART       "restart_on_corruption"
> +#define VERITY_TABLE_OPT_LOGGING       "ignore_corruption"
> +#define ALLOWED_BUF_ALIGN              8
> +
> +enum avb_boot_state {
> +       AVB_GREEN,
> +       AVB_YELLOW,
> +       AVB_ORANGE,
> +       AVB_RED,
> +};
>
>  struct AvbOpsData {
>         struct AvbOps ops;
>         struct AvbABOps ab_ops;
>         int mmc_dev;
> +       enum avb_boot_state boot_state;
>  };
>
>  struct mmc_part {
> @@ -34,6 +45,12 @@ enum mmc_io_type {
>  AvbOps *avb_ops_alloc(int boot_device);
>  void avb_ops_free(AvbOps *ops);
>
> +char *avb_set_state(AvbOps *ops, enum avb_boot_state boot_state);
> +char *avb_set_enforce_verity(const char *cmdline);
> +char *avb_set_ignore_corruption(const char *cmdline);
> +
> +char *append_cmd_line(char *cmdline_orig, char *cmdline_new);
> +
>  /**
>   * ============================================================================
>   * I/O helper inline functions
> --
> 2.7.4
>

^ permalink raw reply	[flat|nested] 30+ messages in thread

* [U-Boot] [PATCH 6/8] am57xx_hs: avb2.0: add support of AVB 2.0
  2018-04-25 13:18 ` [U-Boot] [PATCH 6/8] am57xx_hs: avb2.0: add support of AVB 2.0 Igor Opaniuk
@ 2018-05-02 19:06   ` Sam Protsenko
  0 siblings, 0 replies; 30+ messages in thread
From: Sam Protsenko @ 2018-05-02 19:06 UTC (permalink / raw)
  To: u-boot

On 25 April 2018 at 16:18, Igor Opaniuk <igor.opaniuk@linaro.org> wrote:
> 1. Add vbmeta partition info to android partition layout for am57xx SoC
> 2. Add support of AVB 2.0 (including avb subset of commands) for am57xx HS
>
> Signed-off-by: Igor Opaniuk <igor.opaniuk@linaro.org>
> ---
>  configs/am57xx_hs_evm_defconfig |  3 +++
>  include/configs/am57xx_evm.h    | 11 +++++++++++
>  include/environment/ti/boot.h   | 15 +++++++++++++++
>  3 files changed, 29 insertions(+)
>
> diff --git a/configs/am57xx_hs_evm_defconfig b/configs/am57xx_hs_evm_defconfig
> index ca9742f..226537a 100644
> --- a/configs/am57xx_hs_evm_defconfig
> +++ b/configs/am57xx_hs_evm_defconfig
> @@ -81,3 +81,6 @@ CONFIG_USB_GADGET=y
>  CONFIG_USB_GADGET_MANUFACTURER="Texas Instruments"
>  CONFIG_USB_GADGET_VENDOR_NUM=0x0451
>  CONFIG_USB_GADGET_PRODUCT_NUM=0xd022
> +# CONFIG_LIBAVB is not set
> +# CONFIG_LIBAVB_AB is not set
> +# CONFIG_CMD_AVB is not set

Maybe it would be better to put "default n" to corresponding options
in Kconfig? So that we only need to enable those when needed, instead
of disabling in all not related configs. Because otherwise we risk to
have not needed feature enabled in all boards. But "buildman" should
show you that, if you run it for all "arm" boards.

> diff --git a/include/configs/am57xx_evm.h b/include/configs/am57xx_evm.h
> index d1f73f7..020eec1 100644
> --- a/include/configs/am57xx_evm.h
> +++ b/include/configs/am57xx_evm.h
> @@ -38,6 +38,16 @@
>
>  #define CONFIG_SYS_OMAP_ABE_SYSCK
>
> +#define str(a)                         #a

Consider using __stringify_1() or just __stringify() for this.

> +#define VBMETA_PART_SIZE               (64 * 1024)
> +
> +#if defined(CONFIG_LIBAVB)
> +#define VBMETA_PART \
> +       "name=vbmeta,size=" str(VBMETA_PART_SIZE) ",uuid=${uuid_gpt_vbmeta};"
> +#else
> +#define VBMETA_PART                    ""
> +#endif
> +
>  /* Define the default GPT table for eMMC */
>  #define PARTS_DEFAULT \
>         /* Linux partitions */ \
> @@ -61,6 +71,7 @@
>         "name=cache,size=256M,uuid=${uuid_gpt_cache};" \
>         "name=ipu1,size=1M,uuid=${uuid_gpt_ipu1};" \
>         "name=ipu2,size=1M,uuid=${uuid_gpt_ipu2};" \
> +       VBMETA_PART \
>         "name=userdata,size=-,uuid=${uuid_gpt_userdata}"
>
>  #define DFUARGS \
> diff --git a/include/environment/ti/boot.h b/include/environment/ti/boot.h
> index 24b7783..a8336ae 100644
> --- a/include/environment/ti/boot.h
> +++ b/include/environment/ti/boot.h
> @@ -18,6 +18,19 @@
>  #define PARTS_DEFAULT
>  #endif
>
> +#if defined(CONFIG_CMD_AVB)
> +#define AVB_VERIFY_CHECK "if run avb_verify; then " \
> +                               "echo AVB verification OK.;" \
> +                               "set bootargs $bootargs $avb_bootargs;" \
> +                       "else " \
> +                               "echo AVB verification failed.;" \
> +                       "exit; fi;"
> +#define AVB_VERIFY_CMD "avb_verify=avb init 1; avb verify;\0"
> +#else
> +#define AVB_VERIFY_CHECK ""
> +#define AVB_VERIFY_CMD ""
> +#endif
> +
>  #define DEFAULT_COMMON_BOOT_TI_ARGS \
>         "console=" CONSOLEDEV ",115200n8\0" \
>         "fdtfile=undefined\0" \
> @@ -26,6 +39,7 @@
>         "bootfile=zImage\0" \
>         "usbtty=cdc_acm\0" \
>         "vram=16M\0" \
> +       AVB_VERIFY_CMD \
>         "partitions=" PARTS_DEFAULT "\0" \
>         "optargs=\0" \
>         "dofastboot=0\0" \
> @@ -43,6 +57,7 @@
>                 "setenv machid fe6; " \
>                 "mmc dev $mmcdev; " \
>                 "mmc rescan; " \
> +               AVB_VERIFY_CHECK \
>                 "part start mmc ${mmcdev} environment fdt_start; " \
>                 "part size mmc ${mmcdev} environment fdt_size; " \
>                 "part start mmc ${mmcdev} boot boot_start; " \
> --
> 2.7.4
>

^ permalink raw reply	[flat|nested] 30+ messages in thread

* [U-Boot] [PATCH 8/8] doc: avb2.0: add README about AVB2.0 integration
  2018-04-25 13:18 ` [U-Boot] [PATCH 8/8] doc: avb2.0: add README about AVB2.0 integration Igor Opaniuk
@ 2018-05-02 19:12   ` Sam Protsenko
  2018-05-16  9:20     ` Igor Opaniuk
  0 siblings, 1 reply; 30+ messages in thread
From: Sam Protsenko @ 2018-05-02 19:12 UTC (permalink / raw)
  To: u-boot

On 25 April 2018 at 16:18, Igor Opaniuk <igor.opaniuk@linaro.org> wrote:
> Contains:
> 1. Overview of Android Verified Boot 2.0
> 2. Description of avb subset of commands
> 3. Examples of errors when boot/vendor/system/vbmeta partitions
> are tampered
> 4. Examples of enabling AVB2.0 on your setup
>
> Signed-off-by: Igor Opaniuk <igor.opaniuk@linaro.org>
> ---
>  doc/README.avb2 | 100 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 100 insertions(+)
>  create mode 100644 doc/README.avb2
>
> diff --git a/doc/README.avb2 b/doc/README.avb2
> new file mode 100644
> index 0000000..40db7c5
> --- /dev/null
> +++ b/doc/README.avb2
> @@ -0,0 +1,100 @@
> +Android Verified Boot 2.0
> +
> +This file contains information about the current support of Android Verified
> +Boot 2.0 in U-boot
> +
> +1. OVERVIEW
> +---------------------------------
> +Verified Boot establishes a chain of trust from the bootloader to system images
> +* Provides integrity checking for:
> +  - Android Boot image: Linux kernel + ramdisk. RAW hashing of the whole
> +    partition is done and the hash is compared with the one stored in
> +    the VBMeta image
> +  - system/vendor partitions: verifying root hash of dm-verity hashtrees.
> +* Provides capabilities for rollback protection.
> +
> +Integrity of the bootloader (U-boot BLOB and environment) is out of scope.
> +
> +For additional details check:
> +https://android.googlesource.com/platform/external/avb/+/master/README.md
> +
> +
> +2. AVB 2.0 U-BOOT SHELL COMMANDS
> +-----------------------------------
> +Provides CLI interface to invoke AVB 2.0 verification + misc. commands for
> +different testing purposes:
> +
> +avb init <dev> - initialize avb 2.0 for <dev>
> +avb verify - run verification process using hash data from vbmeta structure
> +avb read_rb <num> - read rollback index at location <num>
> +avb write_rb <num> <rb> - write rollback index <rb> to <num>
> +avb is_unlocked - returns unlock status of the device
> +avb get_uuid <partname> - read and print uuid of partition <partname>
> +avb read_part <partname> <offset> <num> <addr> - read <num> bytes from
> +partition <partname> to buffer <addr>
> +avb write_part <partname> <offset> <num> <addr> - write <num> bytes to
> +<partname> by <offset> using data from <addr>
> +
> +
> +3. PARTITIONS TAMPERING (EXAMPLE)
> +-----------------------------------
> +Boot or system/vendor (dm-verity metadata section) is tampered:
> +=> avb init 1
> +=> avb verify
> +avb_slot_verify.c:175: ERROR: boot: Hash of data does not match digest in
> +descriptor.
> +Slot verification result: ERROR_IO
> +
> +Vbmeta partition is tampered:
> +=> avb init 1
> +=> avb verify
> +avb_vbmeta_image.c:206: ERROR: Hash does not match!
> +avb_slot_verify.c:388: ERROR: vbmeta: Error verifying vbmeta image:
> +HASH_MISMATCH
> +Slot verification result: ERROR_IO
> +
> +
> +4. ENABLE ON YOUR BOARD
> +-----------------------------------
> +The following options must be enabled:
> +CONFIG_LIBAVB=y
> +CONFIG_LIBAVB_AB=y
> +CONFIG_CMD_AVB=y
> +
> +
> +Then add `avb verify` invocation to your android boot sequence of commands,
> +e.g.:
> +
> +=> avb_verify=avb init $mmcdev; avb verify;
> +=> if run avb_verify; then                       \
> +        echo AVB verification OK. Continue boot; \
> +        set bootargs $bootargs $avb_bootargs;    \
> +   else                                          \
> +        echo AVB verification failed;            \
> +        exit;                                    \
> +   fi;                                           \
> +
> +=> emmc_android_boot=                                   \
> +       echo Trying to boot Android from eMMC ...;       \
> +       ...                                              \
> +       run avb_verify;                                  \
> +       mmc read ${fdtaddr} ${fdt_start} ${fdt_size};    \
> +       mmc read ${loadaddr} ${boot_start} ${boot_size}; \
> +       bootm $loadaddr $loadaddr $fdtaddr;              \
> +
> +
> +To switch on automatic generation of vbmeta partition in AOSP build, add these
> +lines to device configuration mk file:
> +
> +BOARD_AVB_ENABLE := true
> +BOARD_AVB_ALGORITHM := SHA512_RSA4096
> +BOARD_BOOTIMAGE_PARTITION_SIZE := <boot partition size>
> +
> +After flashing U-boot don't forget to update environment and write new
> +partition table:
> +=> env default -f -a
> +=> setenv partitions $partitions_android
> +=> env save
> +=> fas 1
> +
> +$ fastboot oem format

FYI, those commands can be shrank down to a single command:

    => gpt write mmc 1 $partitions_android

because that's exactly what "fastboot oem format" is doing. This way
you can avoid using fastboot, and thus having it as a dependency. But
your way is better w.r.t. user experience (i.e. if environment is
already set, user can just run host command, and avoid tinkering with
U-Boot shell at all). Please choose which one is better depending on
targeting use-case.

> --
> 2.7.4
>

^ permalink raw reply	[flat|nested] 30+ messages in thread

* [U-Boot] [PATCH 4/8] cmd: avb2.0: avb command for performing verification
  2018-04-25 13:18 ` [U-Boot] [PATCH 4/8] cmd: avb2.0: avb command for performing verification Igor Opaniuk
  2018-05-02 18:52   ` Sam Protsenko
@ 2018-05-03  2:31   ` Simon Glass
  2018-05-15 15:44     ` Igor Opaniuk
  1 sibling, 1 reply; 30+ messages in thread
From: Simon Glass @ 2018-05-03  2:31 UTC (permalink / raw)
  To: u-boot

Hi Igor,

On 25 April 2018 at 07:18, Igor Opaniuk <igor.opaniuk@linaro.org> wrote:
> Enable a "avb" command to execute Android Verified
> Boot 2.0 operations. It includes such subcommands:
>   avb init - initialize avb2 subsystem
>   avb read_rb - read rollback index
>   avb write_rb - write rollback index
>   avb is_unlocked - check device lock state
>   avb get_uuid - read and print uuid of a partition
>   avb read_part - read data from partition
>   avb read_part_hex - read data from partition and output to stdout
>   avb write_part - write data to partition
>   avb verify - run full verification chain
>
> Signed-off-by: Igor Opaniuk <igor.opaniuk@linaro.org>
> ---
>  cmd/Kconfig  |  15 +++
>  cmd/Makefile |   3 +
>  cmd/avb.c    | 351 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
>  3 files changed, 369 insertions(+)
>  create mode 100644 cmd/avb.c
>
> diff --git a/cmd/Kconfig b/cmd/Kconfig
> index bc1d2f3..96695ff 100644
> --- a/cmd/Kconfig
> +++ b/cmd/Kconfig
> @@ -1675,6 +1675,21 @@ config CMD_TRACE
>           for analsys (e.g. using bootchart). See doc/README.trace for full
>           details.
>
> +config CMD_AVB
> +       bool "avb - Android Verified Boot 2.0 operations"
> +       depends on LIBAVB_AB
> +       help
> +         Enables a "avb" command to perform verification of partitions using
> +         Android Verified Boot 2.0 functionality. It includes such subcommands:
> +           avb init - initialize avb2 subsystem
> +           avb read_rb - read rollback index
> +           avb write_rb - write rollback index
> +           avb is_unlocked - check device lock state
> +           avb get_uuid - read and print uuid of a partition
> +           avb read_part - read data from partition
> +           avb read_part_hex - read data from partition and output to stdout
> +           avb write_part - write data to partition
> +           avb verify - run full verification chain
>  endmenu
>
>  config CMD_UBI
> diff --git a/cmd/Makefile b/cmd/Makefile
> index c4269ac..bbf6c2a 100644
> --- a/cmd/Makefile
> +++ b/cmd/Makefile
> @@ -151,6 +151,9 @@ obj-$(CONFIG_CMD_REGULATOR) += regulator.o
>
>  obj-$(CONFIG_CMD_BLOB) += blob.o
>
> +# Android Verified Boot 2.0
> +obj-$(CONFIG_CMD_AVB) += avb.o
> +
>  obj-$(CONFIG_X86) += x86/
>  endif # !CONFIG_SPL_BUILD
>
> diff --git a/cmd/avb.c b/cmd/avb.c
> new file mode 100644
> index 0000000..d040906
> --- /dev/null
> +++ b/cmd/avb.c
> @@ -0,0 +1,351 @@
> +
> +/*
> + * (C) Copyright 2018, Linaro Limited
> + *
> + * SPDX-License-Identifier:    GPL-2.0+
> + */
> +
> +#include <avb_verify.h>
> +#include <command.h>
> +#include <image.h>
> +#include <malloc.h>
> +#include <mmc.h>
> +
> +#define AVB_BOOTARGS   "avb_bootargs"
> +static struct AvbOps *avb_ops;
> +
> +static const char * const requested_partitions[] = {"boot",
> +                                            "system",
> +                                            "vendor",
> +                                            NULL};
> +
> +int do_avb_init(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
> +{
> +       unsigned long mmc_dev;
> +
> +       if (argc != 2)
> +               return CMD_RET_USAGE;
> +
> +       mmc_dev = simple_strtoul(argv[1], NULL, 16);
> +
> +       if (avb_ops)
> +               avb_ops_free(avb_ops);
> +
> +       avb_ops = avb_ops_alloc(mmc_dev);
> +       if (avb_ops)
> +               return CMD_RET_SUCCESS;
> +
> +       return CMD_RET_FAILURE;
> +}
> +
> +int do_avb_read_part(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
> +{
> +       const char *part;
> +       s64 offset;
> +       size_t bytes, bytes_read = 0;
> +       void *buffer;
> +
> +       if (!avb_ops) {
> +               printf("AVB 2.0 is not initialized, please run 'avb init'\n");
> +               return CMD_RET_USAGE;
> +       }
> +
> +       if (argc != 5)
> +               return CMD_RET_USAGE;
> +
> +       part = argv[1];
> +       offset = simple_strtoul(argv[2], NULL, 16);
> +       bytes = simple_strtoul(argv[3], NULL, 16);
> +       buffer = (void *)simple_strtoul(argv[4], NULL, 16);
> +
> +       if (avb_ops->read_from_partition(avb_ops, part, offset, bytes,
> +                                        buffer, &bytes_read) ==
> +                                        AVB_IO_RESULT_OK) {

Please can you make sure this uses driver model, and put wrappers for
these function calls in the uclass?

Regards,
Simon

^ permalink raw reply	[flat|nested] 30+ messages in thread

* [U-Boot] [PATCH 0/8] Initial integration of AVB2.0
  2018-04-25 13:17 [U-Boot] [PATCH 0/8] Initial integration of AVB2.0 Igor Opaniuk
                   ` (8 preceding siblings ...)
  2018-04-26  3:05 ` [U-Boot] [PATCH 0/8] Initial integration of AVB2.0 Kever Yang
@ 2018-05-06 11:31 ` Eugeniu Rosca
  2018-05-15 15:31   ` Eugeniu Rosca
  9 siblings, 1 reply; 30+ messages in thread
From: Eugeniu Rosca @ 2018-05-06 11:31 UTC (permalink / raw)
  To: u-boot

Hello Igor, Alex, Kever,

Having these patches in mainline would be great, as this would reduce
the delta between our own and community U-boot trees. After having a
quick look at this series, I have some questions/review findings.

These patches appear to be slightly older than what is available in [1].

More precisely, ignoring:
- change of license
- drop of avb_crc32.c
- updates in avb_sysdeps_posix.c
- 's^#include "^#include "avb/^'

The version of libavb imported in this patch series seems to match
commit b60834f7a4a8 ("uefi: Set both androidboot.slot and
androidboot.slot_suffix.") from [1].

FYI, there are 12 more non-merge commits in the avb repository [2]. Is
there a strong reason not to include them?

I am not an expert in AVB, but IMHO, as suggested by Alex, we shouldn't
assume that the in-tree libavb will diverge from the vanilla one. IMHO
a cleaner workflow would be to contribute any bugfixes to the original
repository and update the U-boot libavb from time to time, similar
to how it's done, as example, for dtc in kernel [3]. Or maybe you see
some obstacles to achieve this in practice?

Assuming that:
1) libavb will undergo regular updates from its original repository.
2) most of libavb headers are not designed to be included from
   non-libavb code, throwing below:
#error "Never include this file directly, include libavb.h instead."

I wonder if it would be possible to keep the internal libavb headers in
lib/libavb (similar to how it's done by NXP in [4]), since this would
allow not rewriting the original include paths for such headers in every
*.c file and hence minimize the delta between in-tree vs out-of-tree
code, as well as potentially speed up the update process (and/or
simplify any update script which will take care of it, as also
mentioned by Alex).

My final question is what's your opinion about the NXP-specific libavb
wrapper implementation found at `lib/avb/fsl/` in [5]/[6] which seems
to rely on libavb and libavb_ab. Do you see it as a good model to be
followed by other platforms (both from point of view of contents and
placement in the tree)? I am asking because we are in the middle
of some decision-making for similar/alternative implementation on a
different SoC, so your feedback will be extremely helpful and greatly
appreciated.

Thank you!

Best regards,
Eugeniu.

[1] https://android.googlesource.com/platform/external/avb/+/master

[2] Postt-b60834f7a4a8 libavb commits in [1]
$> git log --oneline --no-merges b60834f7a4a8..avb_upstream/master -- libavb
30dd8e5a1757 libavb: Add new routine to calculate a digest of all vbmeta images.
fd0ba0d49101 Implement support for on-device persistent digests.
97740e537ad1 Split kernel cmdline code in separate file.
fcadbf1d1a71 Support (boot) partition preloading.
061e33b39e27 Add avb_div_by_10() sysdep operation.
36e5c43f58d2 Fix incorrect variable names in avb_replace
fc2531374e30 Fix AvbAlgorithmType type-limits error
047ecf7d2361 libavb: Avoid conflict with system-provided crc32 symbol.
0922bf8970fd Make it possible to disable verification.
01ca9962bd0d libavb: Only load and verify hash partition if requested.
8221811c5da1 libavb: Allow specifying dm-verity error handling.
27a291fcc194 libavb: Load entire partition if |allow_verification_error| is true.

[3] The way in-tree kernel DTC is aligned to upsteam:
$> git log --oneline --no-merges -i --grep "update.*upstream" -- scripts/dtc
9130ba884640 scripts/dtc: Update to upstream version v1.4.6-9-gaadd0b65c987
e45fe7f788dd scripts/dtc: Update to upstream version v1.4.5-6-gc1e55a5513e9
4201d057ea91 scripts/dtc: Update to upstream version v1.4.5-3-gb1a60033c110
89d123106a97 scripts/dtc: Update to upstream version v1.4.4-8-g756ffc4f52f6

[4] http://git.freescale.com/git/cgit.cgi/imx/uboot-imx.git/commit/?h=60e14a6a07c5
[5] http://git.freescale.com/git/cgit.cgi/imx/uboot-imx.git/tree/lib/avb/fsl?h=imx_v2015.04_brillo
[6] http://git.freescale.com/git/cgit.cgi/imx/uboot-imx.git/tree/lib/avb/fsl?h=imx_v2017.03_4.9.11_1.0.0_ga

^ permalink raw reply	[flat|nested] 30+ messages in thread

* [U-Boot] [PATCH 0/8] Initial integration of AVB2.0
  2018-05-06 11:31 ` Eugeniu Rosca
@ 2018-05-15 15:31   ` Eugeniu Rosca
  2018-05-15 16:58     ` Igor Opaniuk
  0 siblings, 1 reply; 30+ messages in thread
From: Eugeniu Rosca @ 2018-05-15 15:31 UTC (permalink / raw)
  To: u-boot

On Sun, May 06, 2018 at 01:31:18PM +0200, Eugeniu Rosca wrote:
> Hello Igor, Alex, Kever,
> 
> I wonder if it would be possible to keep the internal libavb headers in
> lib/libavb (similar to how it's done by NXP in [4]), since this would
> allow not rewriting the original include paths for such headers in every
> *.c file and hence minimize the delta between in-tree vs out-of-tree
> code, as well as potentially speed up the update process (and/or
> simplify any update script which will take care of it, as also
> mentioned by Alex).
> 
> [4] http://git.freescale.com/git/cgit.cgi/imx/uboot-imx.git/commit/?h=60e14a6a07c5

Here is what I mean.
Three lzma headers are exposed to internal users/consumers:

$ git grep '"../../lib/'
---<-snip->---
include/lzma/LzmaDec.h:#include "../../lib/lzma/LzmaDec.h"
include/lzma/LzmaTools.h:#include "../../lib/lzma/LzmaTools.h"
include/lzma/LzmaTypes.h:#include "../../lib/lzma/Types.h"
---<-snip->---

A few places where lzma headers are used:

$ git grep 'include <lzma/Lzma'
cmd/lzmadec.c:#include <lzma/LzmaTools.h>
common/bootm.c:#include <lzma/LzmaTypes.h>
common/bootm.c:#include <lzma/LzmaDec.h>
common/bootm.c:#include <lzma/LzmaTools.h>
lib/lzma/LzmaTools.h:#include <lzma/LzmaTypes.h>
test/compression.c:#include <lzma/LzmaTypes.h>
test/compression.c:#include <lzma/LzmaDec.h>
test/compression.c:#include <lzma/LzmaTools.h>

For libavb this would translate to:

$ cat include/avb/libavb.h
---<-snip->---
#include "../../lib/libavb/avb_chain_partition_descriptor.h"
#include "../../lib/libavb/avb_crypto.h"
#include "../../lib/libavb/avb_descriptor.h"
#include "../../lib/libavb/avb_footer.h"
#include "../../lib/libavb/avb_hash_descriptor.h"
---<-snip->---

And with that, various consumers (mainly libavb_avb?) would do:
#include <avb/libavb.h>

As said, this would make integration of new libavb versions much easier.
Would appreciate your thoughts.

Best regards,
Eugeniu.

^ permalink raw reply	[flat|nested] 30+ messages in thread

* [U-Boot] [PATCH 4/8] cmd: avb2.0: avb command for performing verification
  2018-05-03  2:31   ` Simon Glass
@ 2018-05-15 15:44     ` Igor Opaniuk
  2018-05-15 16:26       ` Simon Glass
  0 siblings, 1 reply; 30+ messages in thread
From: Igor Opaniuk @ 2018-05-15 15:44 UTC (permalink / raw)
  To: u-boot

Hi Simon,

I've dug into DriverModel documentation and even created a PoC for
existing avb commands. The problem is that (maybe I missed out some
key concepts) I'm still
not sure if it makes sense to follow it driver mode in the context of
AVB 2.0 feature and
what kind of extra devices can be used within the same uclass in this case?
Could you please explain in detail.
Thanks

Hi Sam,
Thanks, will fix!


On 3 May 2018 at 05:31, Simon Glass <sjg@chromium.org> wrote:
> Hi Igor,
>
> On 25 April 2018 at 07:18, Igor Opaniuk <igor.opaniuk@linaro.org> wrote:
>> Enable a "avb" command to execute Android Verified
>> Boot 2.0 operations. It includes such subcommands:
>>   avb init - initialize avb2 subsystem
>>   avb read_rb - read rollback index
>>   avb write_rb - write rollback index
>>   avb is_unlocked - check device lock state
>>   avb get_uuid - read and print uuid of a partition
>>   avb read_part - read data from partition
>>   avb read_part_hex - read data from partition and output to stdout
>>   avb write_part - write data to partition
>>   avb verify - run full verification chain
>>
>> Signed-off-by: Igor Opaniuk <igor.opaniuk@linaro.org>
>> ---
>>  cmd/Kconfig  |  15 +++
>>  cmd/Makefile |   3 +
>>  cmd/avb.c    | 351 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
>>  3 files changed, 369 insertions(+)
>>  create mode 100644 cmd/avb.c
>>
>> diff --git a/cmd/Kconfig b/cmd/Kconfig
>> index bc1d2f3..96695ff 100644
>> --- a/cmd/Kconfig
>> +++ b/cmd/Kconfig
>> @@ -1675,6 +1675,21 @@ config CMD_TRACE
>>           for analsys (e.g. using bootchart). See doc/README.trace for full
>>           details.
>>
>> +config CMD_AVB
>> +       bool "avb - Android Verified Boot 2.0 operations"
>> +       depends on LIBAVB_AB
>> +       help
>> +         Enables a "avb" command to perform verification of partitions using
>> +         Android Verified Boot 2.0 functionality. It includes such subcommands:
>> +           avb init - initialize avb2 subsystem
>> +           avb read_rb - read rollback index
>> +           avb write_rb - write rollback index
>> +           avb is_unlocked - check device lock state
>> +           avb get_uuid - read and print uuid of a partition
>> +           avb read_part - read data from partition
>> +           avb read_part_hex - read data from partition and output to stdout
>> +           avb write_part - write data to partition
>> +           avb verify - run full verification chain
>>  endmenu
>>
>>  config CMD_UBI
>> diff --git a/cmd/Makefile b/cmd/Makefile
>> index c4269ac..bbf6c2a 100644
>> --- a/cmd/Makefile
>> +++ b/cmd/Makefile
>> @@ -151,6 +151,9 @@ obj-$(CONFIG_CMD_REGULATOR) += regulator.o
>>
>>  obj-$(CONFIG_CMD_BLOB) += blob.o
>>
>> +# Android Verified Boot 2.0
>> +obj-$(CONFIG_CMD_AVB) += avb.o
>> +
>>  obj-$(CONFIG_X86) += x86/
>>  endif # !CONFIG_SPL_BUILD
>>
>> diff --git a/cmd/avb.c b/cmd/avb.c
>> new file mode 100644
>> index 0000000..d040906
>> --- /dev/null
>> +++ b/cmd/avb.c
>> @@ -0,0 +1,351 @@
>> +
>> +/*
>> + * (C) Copyright 2018, Linaro Limited
>> + *
>> + * SPDX-License-Identifier:    GPL-2.0+
>> + */
>> +
>> +#include <avb_verify.h>
>> +#include <command.h>
>> +#include <image.h>
>> +#include <malloc.h>
>> +#include <mmc.h>
>> +
>> +#define AVB_BOOTARGS   "avb_bootargs"
>> +static struct AvbOps *avb_ops;
>> +
>> +static const char * const requested_partitions[] = {"boot",
>> +                                            "system",
>> +                                            "vendor",
>> +                                            NULL};
>> +
>> +int do_avb_init(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
>> +{
>> +       unsigned long mmc_dev;
>> +
>> +       if (argc != 2)
>> +               return CMD_RET_USAGE;
>> +
>> +       mmc_dev = simple_strtoul(argv[1], NULL, 16);
>> +
>> +       if (avb_ops)
>> +               avb_ops_free(avb_ops);
>> +
>> +       avb_ops = avb_ops_alloc(mmc_dev);
>> +       if (avb_ops)
>> +               return CMD_RET_SUCCESS;
>> +
>> +       return CMD_RET_FAILURE;
>> +}
>> +
>> +int do_avb_read_part(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
>> +{
>> +       const char *part;
>> +       s64 offset;
>> +       size_t bytes, bytes_read = 0;
>> +       void *buffer;
>> +
>> +       if (!avb_ops) {
>> +               printf("AVB 2.0 is not initialized, please run 'avb init'\n");
>> +               return CMD_RET_USAGE;
>> +       }
>> +
>> +       if (argc != 5)
>> +               return CMD_RET_USAGE;
>> +
>> +       part = argv[1];
>> +       offset = simple_strtoul(argv[2], NULL, 16);
>> +       bytes = simple_strtoul(argv[3], NULL, 16);
>> +       buffer = (void *)simple_strtoul(argv[4], NULL, 16);
>> +
>> +       if (avb_ops->read_from_partition(avb_ops, part, offset, bytes,
>> +                                        buffer, &bytes_read) ==
>> +                                        AVB_IO_RESULT_OK) {
>
> Please can you make sure this uses driver model, and put wrappers for
> these function calls in the uclass?
>
> Regards,
> Simon



-- 
Regards,
Igor Opaniuk

^ permalink raw reply	[flat|nested] 30+ messages in thread

* [U-Boot] [PATCH 4/8] cmd: avb2.0: avb command for performing verification
  2018-05-15 15:44     ` Igor Opaniuk
@ 2018-05-15 16:26       ` Simon Glass
  2018-05-15 17:31         ` Igor Opaniuk
  0 siblings, 1 reply; 30+ messages in thread
From: Simon Glass @ 2018-05-15 16:26 UTC (permalink / raw)
  To: u-boot

Hi Igor,

On 16 May 2018 at 01:44, Igor Opaniuk <igor.opaniuk@linaro.org> wrote:
> Hi Simon,
>
> I've dug into DriverModel documentation and even created a PoC for
> existing avb commands. The problem is that (maybe I missed out some
> key concepts) I'm still
> not sure if it makes sense to follow it driver mode in the context of
> AVB 2.0 feature and
> what kind of extra devices can be used within the same uclass in this case?
> Could you please explain in detail.
> Thanks

avb_ops_alloc() is allocating a struct and then assigning operations
to its members.

This is what driver model is designed to do. It handles the
allocations and the operations become part of the uclass interface.

At present it looks like you only have one driver. I'm not sure if it
would make sense to have a second one.

As a counter example see cros_ec uclass, which does things
differently. It models the EC interface (I2C, SPI, LPC) using DM, with
just a single impl on top.

Also can you please drop the CamelCase in the patches? We don't use
that in U-Boot.

>
> Hi Sam,
> Thanks, will fix!
>
>
> On 3 May 2018 at 05:31, Simon Glass <sjg@chromium.org> wrote:
>> Hi Igor,
>>
>> On 25 April 2018 at 07:18, Igor Opaniuk <igor.opaniuk@linaro.org> wrote:
>>> Enable a "avb" command to execute Android Verified
>>> Boot 2.0 operations. It includes such subcommands:
>>>   avb init - initialize avb2 subsystem
>>>   avb read_rb - read rollback index
>>>   avb write_rb - write rollback index
>>>   avb is_unlocked - check device lock state
>>>   avb get_uuid - read and print uuid of a partition
>>>   avb read_part - read data from partition
>>>   avb read_part_hex - read data from partition and output to stdout
>>>   avb write_part - write data to partition
>>>   avb verify - run full verification chain
>>>
>>> Signed-off-by: Igor Opaniuk <igor.opaniuk@linaro.org>
>>> ---
>>>  cmd/Kconfig  |  15 +++
>>>  cmd/Makefile |   3 +
>>>  cmd/avb.c    | 351 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
>>>  3 files changed, 369 insertions(+)
>>>  create mode 100644 cmd/avb.c
>>>
>>> diff --git a/cmd/Kconfig b/cmd/Kconfig
>>> index bc1d2f3..96695ff 100644
>>> --- a/cmd/Kconfig
>>> +++ b/cmd/Kconfig
>>> @@ -1675,6 +1675,21 @@ config CMD_TRACE
>>>           for analsys (e.g. using bootchart). See doc/README.trace for full
>>>           details.
>>>
>>> +config CMD_AVB
>>> +       bool "avb - Android Verified Boot 2.0 operations"
>>> +       depends on LIBAVB_AB
>>> +       help
>>> +         Enables a "avb" command to perform verification of partitions using
>>> +         Android Verified Boot 2.0 functionality. It includes such subcommands:
>>> +           avb init - initialize avb2 subsystem
>>> +           avb read_rb - read rollback index
>>> +           avb write_rb - write rollback index
>>> +           avb is_unlocked - check device lock state
>>> +           avb get_uuid - read and print uuid of a partition
>>> +           avb read_part - read data from partition
>>> +           avb read_part_hex - read data from partition and output to stdout
>>> +           avb write_part - write data to partition
>>> +           avb verify - run full verification chain
>>>  endmenu
>>>
>>>  config CMD_UBI
>>> diff --git a/cmd/Makefile b/cmd/Makefile
>>> index c4269ac..bbf6c2a 100644
>>> --- a/cmd/Makefile
>>> +++ b/cmd/Makefile
>>> @@ -151,6 +151,9 @@ obj-$(CONFIG_CMD_REGULATOR) += regulator.o
>>>
>>>  obj-$(CONFIG_CMD_BLOB) += blob.o
>>>
>>> +# Android Verified Boot 2.0
>>> +obj-$(CONFIG_CMD_AVB) += avb.o
>>> +
>>>  obj-$(CONFIG_X86) += x86/
>>>  endif # !CONFIG_SPL_BUILD
>>>
>>> diff --git a/cmd/avb.c b/cmd/avb.c
>>> new file mode 100644
>>> index 0000000..d040906
>>> --- /dev/null
>>> +++ b/cmd/avb.c
>>> @@ -0,0 +1,351 @@
>>> +
>>> +/*
>>> + * (C) Copyright 2018, Linaro Limited
>>> + *
>>> + * SPDX-License-Identifier:    GPL-2.0+
>>> + */
>>> +
>>> +#include <avb_verify.h>
>>> +#include <command.h>
>>> +#include <image.h>
>>> +#include <malloc.h>
>>> +#include <mmc.h>
>>> +
>>> +#define AVB_BOOTARGS   "avb_bootargs"
>>> +static struct AvbOps *avb_ops;
>>> +
>>> +static const char * const requested_partitions[] = {"boot",
>>> +                                            "system",
>>> +                                            "vendor",
>>> +                                            NULL};
>>> +
>>> +int do_avb_init(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
>>> +{
>>> +       unsigned long mmc_dev;
>>> +
>>> +       if (argc != 2)
>>> +               return CMD_RET_USAGE;
>>> +
>>> +       mmc_dev = simple_strtoul(argv[1], NULL, 16);
>>> +
>>> +       if (avb_ops)
>>> +               avb_ops_free(avb_ops);
>>> +
>>> +       avb_ops = avb_ops_alloc(mmc_dev);
>>> +       if (avb_ops)
>>> +               return CMD_RET_SUCCESS;
>>> +
>>> +       return CMD_RET_FAILURE;
>>> +}
>>> +
>>> +int do_avb_read_part(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
>>> +{
>>> +       const char *part;
>>> +       s64 offset;
>>> +       size_t bytes, bytes_read = 0;
>>> +       void *buffer;
>>> +
>>> +       if (!avb_ops) {
>>> +               printf("AVB 2.0 is not initialized, please run 'avb init'\n");
>>> +               return CMD_RET_USAGE;
>>> +       }
>>> +
>>> +       if (argc != 5)
>>> +               return CMD_RET_USAGE;
>>> +
>>> +       part = argv[1];
>>> +       offset = simple_strtoul(argv[2], NULL, 16);
>>> +       bytes = simple_strtoul(argv[3], NULL, 16);
>>> +       buffer = (void *)simple_strtoul(argv[4], NULL, 16);
>>> +
>>> +       if (avb_ops->read_from_partition(avb_ops, part, offset, bytes,
>>> +                                        buffer, &bytes_read) ==
>>> +                                        AVB_IO_RESULT_OK) {
>>
>> Please can you make sure this uses driver model, and put wrappers for
>> these function calls in the uclass?

Regards,
Simon

^ permalink raw reply	[flat|nested] 30+ messages in thread

* [U-Boot] [PATCH 0/8] Initial integration of AVB2.0
  2018-05-15 15:31   ` Eugeniu Rosca
@ 2018-05-15 16:58     ` Igor Opaniuk
  2018-05-15 17:10       ` Eugeniu Rosca
  0 siblings, 1 reply; 30+ messages in thread
From: Igor Opaniuk @ 2018-05-15 16:58 UTC (permalink / raw)
  To: u-boot

Hi Eugeniu,

You're totally right regarding avb internal headers, they all
should remain in lib/libavb.
v2 patchset (planning to send it by the end of this week) will
include these changes you're talking about (+ will include libavb
updates from [1]).

> My final question is what's your opinion about the NXP-specific libavb
> wrapper implementation found at `lib/avb/fsl/` in [5]/[6] which seems
> to rely on libavb and libavb_ab. Do you see it as a good model to be
> followed by other platforms (both from point of view of contents and
> placement in the tree)? I am asking because we are in the middle
> of some decision-making for similar/alternative implementation on a
> different SoC, so your feedback will be extremely helpful and greatly
> appreciated.

I've taken a quick look at patches from [2], and noticed a few issues (IMHO):
1) It includes custom implementation of RPMB operations, although
generic RPMB functionality already exists in the U-boot mainline
(check drivers/mmc/rpmb.c)
2) It introduces a brand-new "boota" command for booting Android,
although existing bootm does already support Android boot image
parsing and booting.
3) It doesn't have any dm-verify enforcement policies in case
if the bootloader is in the "locked" state (at least, I didn't manage
to grep it)
4) There are a bunch of platform-specific code introduced to
fastboot driver, and it's used as a base for working with GPT
in avb ops (sounds strange, but this is what I see here), although
mainline U-boot does have API for this purposes.

Obviously, the root cause of all these issues is a big divergence
from the U-boot mainline codebase.

Thanks!

Regards,
Igor

[1] https://android.googlesource.com/platform/external/avb/+/master
[2] http://git.freescale.com/git/cgit.cgi/imx/uboot-imx.git/tree/lib/avb/fsl?h=imx_v2017.03_4.9.11_1.0.0_ga

On 15 May 2018 at 18:31, Eugeniu Rosca <erosca@de.adit-jv.com> wrote:
> On Sun, May 06, 2018 at 01:31:18PM +0200, Eugeniu Rosca wrote:
>> Hello Igor, Alex, Kever,
>>
>> I wonder if it would be possible to keep the internal libavb headers in
>> lib/libavb (similar to how it's done by NXP in [4]), since this would
>> allow not rewriting the original include paths for such headers in every
>> *.c file and hence minimize the delta between in-tree vs out-of-tree
>> code, as well as potentially speed up the update process (and/or
>> simplify any update script which will take care of it, as also
>> mentioned by Alex).
>>
>> [4] http://git.freescale.com/git/cgit.cgi/imx/uboot-imx.git/commit/?h=60e14a6a07c5
>
> Here is what I mean.
> Three lzma headers are exposed to internal users/consumers:
>
> $ git grep '"../../lib/'
> ---<-snip->---
> include/lzma/LzmaDec.h:#include "../../lib/lzma/LzmaDec.h"
> include/lzma/LzmaTools.h:#include "../../lib/lzma/LzmaTools.h"
> include/lzma/LzmaTypes.h:#include "../../lib/lzma/Types.h"
> ---<-snip->---
>
> A few places where lzma headers are used:
>
> $ git grep 'include <lzma/Lzma'
> cmd/lzmadec.c:#include <lzma/LzmaTools.h>
> common/bootm.c:#include <lzma/LzmaTypes.h>
> common/bootm.c:#include <lzma/LzmaDec.h>
> common/bootm.c:#include <lzma/LzmaTools.h>
> lib/lzma/LzmaTools.h:#include <lzma/LzmaTypes.h>
> test/compression.c:#include <lzma/LzmaTypes.h>
> test/compression.c:#include <lzma/LzmaDec.h>
> test/compression.c:#include <lzma/LzmaTools.h>
>
> For libavb this would translate to:
>
> $ cat include/avb/libavb.h
> ---<-snip->---
> #include "../../lib/libavb/avb_chain_partition_descriptor.h"
> #include "../../lib/libavb/avb_crypto.h"
> #include "../../lib/libavb/avb_descriptor.h"
> #include "../../lib/libavb/avb_footer.h"
> #include "../../lib/libavb/avb_hash_descriptor.h"
> ---<-snip->---
>
> And with that, various consumers (mainly libavb_avb?) would do:
> #include <avb/libavb.h>
>
> As said, this would make integration of new libavb versions much easier.
> Would appreciate your thoughts.
>
> Best regards,
> Eugeniu.



-- 
Regards,
Igor Opaniuk

^ permalink raw reply	[flat|nested] 30+ messages in thread

* [U-Boot] [PATCH 0/8] Initial integration of AVB2.0
  2018-05-15 16:58     ` Igor Opaniuk
@ 2018-05-15 17:10       ` Eugeniu Rosca
  0 siblings, 0 replies; 30+ messages in thread
From: Eugeniu Rosca @ 2018-05-15 17:10 UTC (permalink / raw)
  To: u-boot

Hi Igor,

On Tue, May 15, 2018 at 07:58:51PM +0300, Igor Opaniuk wrote:
> Hi Eugeniu,
> 
> You're totally right regarding avb internal headers, they all
> should remain in lib/libavb.
> v2 patchset (planning to send it by the end of this week) will
> include these changes you're talking about (+ will include libavb
> updates from [1]).

Good to hear that!

> 
> I've taken a quick look at patches from [2], and noticed a few issues (IMHO):
> 1) It includes custom implementation of RPMB operations, although
> generic RPMB functionality already exists in the U-boot mainline
> (check drivers/mmc/rpmb.c)
> 2) It introduces a brand-new "boota" command for booting Android,
> although existing bootm does already support Android boot image
> parsing and booting.
> 3) It doesn't have any dm-verify enforcement policies in case
> if the bootloader is in the "locked" state (at least, I didn't manage
> to grep it)
> 4) There are a bunch of platform-specific code introduced to
> fastboot driver, and it's used as a base for working with GPT
> in avb ops (sounds strange, but this is what I see here), although
> mainline U-boot does have API for this purposes.

Thanks for the detailed reply. I am looking forward for a cleaner and
better partitioned porting of libavb/libavb_ab to the main tree. Your
effort is very appreciated!

> Regards,
> Igor
> 
> [1] https://android.googlesource.com/platform/external/avb/+/master
> [2] http://git.freescale.com/git/cgit.cgi/imx/uboot-imx.git/tree/lib/avb/fsl?h=imx_v2017.03_4.9.11_1.0.0_ga

Best regards,
Eugeniu.

^ permalink raw reply	[flat|nested] 30+ messages in thread

* [U-Boot] [PATCH 4/8] cmd: avb2.0: avb command for performing verification
  2018-05-15 16:26       ` Simon Glass
@ 2018-05-15 17:31         ` Igor Opaniuk
  2018-05-15 18:28           ` Simon Glass
  0 siblings, 1 reply; 30+ messages in thread
From: Igor Opaniuk @ 2018-05-15 17:31 UTC (permalink / raw)
  To: u-boot

On 15 May 2018 at 19:26, Simon Glass <sjg@chromium.org> wrote:
> Hi Igor,
>
> On 16 May 2018 at 01:44, Igor Opaniuk <igor.opaniuk@linaro.org> wrote:
>> Hi Simon,
>>
>> I've dug into DriverModel documentation and even created a PoC for
>> existing avb commands. The problem is that (maybe I missed out some
>> key concepts) I'm still
>> not sure if it makes sense to follow it driver mode in the context of
>> AVB 2.0 feature and
>> what kind of extra devices can be used within the same uclass in this case?
>> Could you please explain in detail.
>> Thanks
>
> avb_ops_alloc() is allocating a struct and then assigning operations
> to its members.
>
> This is what driver model is designed to do. It handles the
> allocations and the operations become part of the uclass interface.
>
> At present it looks like you only have one driver. I'm not sure if it
> would make sense to have a second one.
>
> As a counter example see cros_ec uclass, which does things
> differently. It models the EC interface (I2C, SPI, LPC) using DM, with
> just a single impl on top.

Right, I do understand what DriverModel is and why it should
be used in the case of real-device drivers. But regarding Android Verified
Boot 2.0 feature, which introduces verification capabilities
and leverages only device-independent APIs,
I see no reason why it should be used here.
Could you please check [1] and confirm that this set of commands should
really follow this model.

> Also can you please drop the CamelCase in the patches? We don't use
> that in U-Boot.

Frankly, I don't like it also, bit all CamelCase instances in
the code relate to libavb/libavb_ab library ([2]), which is planned to be
deviated from AOSP upstream in the future.
That's why a decision was made to not introduce any changes to simplify this
process, as Google intensively introduces new changes to it.
(I've left a notice in the cover letter that checkpatch
will fail on the commit, which introduces libavb; also, there is the ongoing
discussion there regarding why libavb/libavb_ab should be
kept as it's. Please join us, if you don't mind).

Thanks!

Best regards,
Igor

[1] https://android.googlesource.com/platform/external/avb/+/master/README.md
[2] https://android.googlesource.com/platform/external/avb/
>>
>> Hi Sam,
>> Thanks, will fix!
>>
>>
>> On 3 May 2018 at 05:31, Simon Glass <sjg@chromium.org> wrote:
>>> Hi Igor,
>>>
>>> On 25 April 2018 at 07:18, Igor Opaniuk <igor.opaniuk@linaro.org> wrote:
>>>> Enable a "avb" command to execute Android Verified
>>>> Boot 2.0 operations. It includes such subcommands:
>>>>   avb init - initialize avb2 subsystem
>>>>   avb read_rb - read rollback index
>>>>   avb write_rb - write rollback index
>>>>   avb is_unlocked - check device lock state
>>>>   avb get_uuid - read and print uuid of a partition
>>>>   avb read_part - read data from partition
>>>>   avb read_part_hex - read data from partition and output to stdout
>>>>   avb write_part - write data to partition
>>>>   avb verify - run full verification chain
>>>>
>>>> Signed-off-by: Igor Opaniuk <igor.opaniuk@linaro.org>
>>>> ---
>>>>  cmd/Kconfig  |  15 +++
>>>>  cmd/Makefile |   3 +
>>>>  cmd/avb.c    | 351 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
>>>>  3 files changed, 369 insertions(+)
>>>>  create mode 100644 cmd/avb.c
>>>>
>>>> diff --git a/cmd/Kconfig b/cmd/Kconfig
>>>> index bc1d2f3..96695ff 100644
>>>> --- a/cmd/Kconfig
>>>> +++ b/cmd/Kconfig
>>>> @@ -1675,6 +1675,21 @@ config CMD_TRACE
>>>>           for analsys (e.g. using bootchart). See doc/README.trace for full
>>>>           details.
>>>>
>>>> +config CMD_AVB
>>>> +       bool "avb - Android Verified Boot 2.0 operations"
>>>> +       depends on LIBAVB_AB
>>>> +       help
>>>> +         Enables a "avb" command to perform verification of partitions using
>>>> +         Android Verified Boot 2.0 functionality. It includes such subcommands:
>>>> +           avb init - initialize avb2 subsystem
>>>> +           avb read_rb - read rollback index
>>>> +           avb write_rb - write rollback index
>>>> +           avb is_unlocked - check device lock state
>>>> +           avb get_uuid - read and print uuid of a partition
>>>> +           avb read_part - read data from partition
>>>> +           avb read_part_hex - read data from partition and output to stdout
>>>> +           avb write_part - write data to partition
>>>> +           avb verify - run full verification chain
>>>>  endmenu
>>>>
>>>>  config CMD_UBI
>>>> diff --git a/cmd/Makefile b/cmd/Makefile
>>>> index c4269ac..bbf6c2a 100644
>>>> --- a/cmd/Makefile
>>>> +++ b/cmd/Makefile
>>>> @@ -151,6 +151,9 @@ obj-$(CONFIG_CMD_REGULATOR) += regulator.o
>>>>
>>>>  obj-$(CONFIG_CMD_BLOB) += blob.o
>>>>
>>>> +# Android Verified Boot 2.0
>>>> +obj-$(CONFIG_CMD_AVB) += avb.o
>>>> +
>>>>  obj-$(CONFIG_X86) += x86/
>>>>  endif # !CONFIG_SPL_BUILD
>>>>
>>>> diff --git a/cmd/avb.c b/cmd/avb.c
>>>> new file mode 100644
>>>> index 0000000..d040906
>>>> --- /dev/null
>>>> +++ b/cmd/avb.c
>>>> @@ -0,0 +1,351 @@
>>>> +
>>>> +/*
>>>> + * (C) Copyright 2018, Linaro Limited
>>>> + *
>>>> + * SPDX-License-Identifier:    GPL-2.0+
>>>> + */
>>>> +
>>>> +#include <avb_verify.h>
>>>> +#include <command.h>
>>>> +#include <image.h>
>>>> +#include <malloc.h>
>>>> +#include <mmc.h>
>>>> +
>>>> +#define AVB_BOOTARGS   "avb_bootargs"
>>>> +static struct AvbOps *avb_ops;
>>>> +
>>>> +static const char * const requested_partitions[] = {"boot",
>>>> +                                            "system",
>>>> +                                            "vendor",
>>>> +                                            NULL};
>>>> +
>>>> +int do_avb_init(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
>>>> +{
>>>> +       unsigned long mmc_dev;
>>>> +
>>>> +       if (argc != 2)
>>>> +               return CMD_RET_USAGE;
>>>> +
>>>> +       mmc_dev = simple_strtoul(argv[1], NULL, 16);
>>>> +
>>>> +       if (avb_ops)
>>>> +               avb_ops_free(avb_ops);
>>>> +
>>>> +       avb_ops = avb_ops_alloc(mmc_dev);
>>>> +       if (avb_ops)
>>>> +               return CMD_RET_SUCCESS;
>>>> +
>>>> +       return CMD_RET_FAILURE;
>>>> +}
>>>> +
>>>> +int do_avb_read_part(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
>>>> +{
>>>> +       const char *part;
>>>> +       s64 offset;
>>>> +       size_t bytes, bytes_read = 0;
>>>> +       void *buffer;
>>>> +
>>>> +       if (!avb_ops) {
>>>> +               printf("AVB 2.0 is not initialized, please run 'avb init'\n");
>>>> +               return CMD_RET_USAGE;
>>>> +       }
>>>> +
>>>> +       if (argc != 5)
>>>> +               return CMD_RET_USAGE;
>>>> +
>>>> +       part = argv[1];
>>>> +       offset = simple_strtoul(argv[2], NULL, 16);
>>>> +       bytes = simple_strtoul(argv[3], NULL, 16);
>>>> +       buffer = (void *)simple_strtoul(argv[4], NULL, 16);
>>>> +
>>>> +       if (avb_ops->read_from_partition(avb_ops, part, offset, bytes,
>>>> +                                        buffer, &bytes_read) ==
>>>> +                                        AVB_IO_RESULT_OK) {
>>>
>>> Please can you make sure this uses driver model, and put wrappers for
>>> these function calls in the uclass?
>
> Regards,
> Simon



-- 
Regards,
Igor Opaniuk

^ permalink raw reply	[flat|nested] 30+ messages in thread

* [U-Boot] [PATCH 4/8] cmd: avb2.0: avb command for performing verification
  2018-05-15 17:31         ` Igor Opaniuk
@ 2018-05-15 18:28           ` Simon Glass
  2018-05-16  8:20             ` Igor Opaniuk
  0 siblings, 1 reply; 30+ messages in thread
From: Simon Glass @ 2018-05-15 18:28 UTC (permalink / raw)
  To: u-boot

(Tom can you please comment on the CamelCase question?)

Hi Igor,

On 15 May 2018 at 11:31, Igor Opaniuk <igor.opaniuk@linaro.org> wrote:
> On 15 May 2018 at 19:26, Simon Glass <sjg@chromium.org> wrote:
>> Hi Igor,
>>
>> On 16 May 2018 at 01:44, Igor Opaniuk <igor.opaniuk@linaro.org> wrote:
>>> Hi Simon,
>>>
>>> I've dug into DriverModel documentation and even created a PoC for
>>> existing avb commands. The problem is that (maybe I missed out some
>>> key concepts) I'm still
>>> not sure if it makes sense to follow it driver mode in the context of
>>> AVB 2.0 feature and
>>> what kind of extra devices can be used within the same uclass in this case?
>>> Could you please explain in detail.
>>> Thanks
>>
>> avb_ops_alloc() is allocating a struct and then assigning operations
>> to its members.
>>
>> This is what driver model is designed to do. It handles the
>> allocations and the operations become part of the uclass interface.
>>
>> At present it looks like you only have one driver. I'm not sure if it
>> would make sense to have a second one.
>>
>> As a counter example see cros_ec uclass, which does things
>> differently. It models the EC interface (I2C, SPI, LPC) using DM, with
>> just a single impl on top.
>
> Right, I do understand what DriverModel is and why it should
> be used in the case of real-device drivers. But regarding Android Verified
> Boot 2.0 feature, which introduces verification capabilities
> and leverages only device-independent APIs,
> I see no reason why it should be used here.
> Could you please check [1] and confirm that this set of commands should
> really follow this model.

If there is no need for operations and indirection through function
pointers, why not just call the functions directly?

I do think (as the code is currently structured) that DM makes sense,
even though I understand that you are not creating a device. Perhaps
Tom might have thoughts on this though?

>
>> Also can you please drop the CamelCase in the patches? We don't use
>> that in U-Boot.
>
> Frankly, I don't like it also, bit all CamelCase instances in
> the code relate to libavb/libavb_ab library ([2]), which is planned to be
> deviated from AOSP upstream in the future.
> That's why a decision was made to not introduce any changes to simplify this
> process, as Google intensively introduces new changes to it.

Tom, what do you think? It's not how things usually work, but perhaps
there is precedent for this?

> (I've left a notice in the cover letter that checkpatch
> will fail on the commit, which introduces libavb; also, there is the ongoing
> discussion there regarding why libavb/libavb_ab should be
> kept as it's. Please join us, if you don't mind).

I do see the cover letter thread but could not find the camel case
discussion. Can you please point me to it?

>
> Thanks!
>
> Best regards,
> Igor
>
> [1] https://android.googlesource.com/platform/external/avb/+/master/README.md
> [2] https://android.googlesource.com/platform/external/avb/
>>>

[..]

Regards,
Simon

^ permalink raw reply	[flat|nested] 30+ messages in thread

* [U-Boot] [PATCH 4/8] cmd: avb2.0: avb command for performing verification
  2018-05-15 18:28           ` Simon Glass
@ 2018-05-16  8:20             ` Igor Opaniuk
  2018-05-16 15:40               ` Simon Glass
  0 siblings, 1 reply; 30+ messages in thread
From: Igor Opaniuk @ 2018-05-16  8:20 UTC (permalink / raw)
  To: u-boot

Hi Simon,

> If there is no need for operations and indirection through function
> pointers, why not just call the functions directly?

This is the way how libavb is integrated into bootloader. libavb interfaces with
the bootloader through the supplied AvbOps struct. This includes operations to
read and write data from partitions, read and write rollback indexes, check
if the public key used to make a signature should be accepted, and so on.
This is what Google AVB 2.0 specification says.
For additional details please check [1].

In this particular patch, all avb commands, except the main "avb
verify", are used
to debug these particular callback implementations
(can be used when enabling this feature on new platform etc.).
The reason I use indirection through function pointers is that they
are not supposed
to be public, and are not intended to be used somehow directly, only by libavb
(check [2] how libavb is using it)

>> (I've left a notice in the cover letter that checkpatch
>> will fail on the commit, which introduces libavb; also, there is the ongoing
>> discussion there regarding why libavb/libavb_ab should be
>> kept as it's. Please join us, if you don't mind).
>
> I do see the cover letter thread but could not find the camel case
> discussion. Can you please point me to it?

There is no any particular discussion about CamelCase, but a few general
statements why I should avoid introducing any changes in
libavb/libavb_ab libraries.
Regarding our particular case, AvbSlotVerifyResult and AvbSlotVerifyData types
(I guess you're talking about these CamelCase instances) are defined inside
libavb library, so obviously I can't simply replace it with something, that
conforms to the Linux kernel coding style

Thanks

[1] https://android.googlesource.com/platform/external/avb/+/master/README.md#system-dependencies
[2] https://android.googlesource.com/platform/external/avb/+/master/libavb/avb_cmdline.c#71

On 15 May 2018 at 21:28, Simon Glass <sjg@chromium.org> wrote:
> (Tom can you please comment on the CamelCase question?)
>
> Hi Igor,
>
> On 15 May 2018 at 11:31, Igor Opaniuk <igor.opaniuk@linaro.org> wrote:
>> On 15 May 2018 at 19:26, Simon Glass <sjg@chromium.org> wrote:
>>> Hi Igor,
>>>
>>> On 16 May 2018 at 01:44, Igor Opaniuk <igor.opaniuk@linaro.org> wrote:
>>>> Hi Simon,
>>>>
>>>> I've dug into DriverModel documentation and even created a PoC for
>>>> existing avb commands. The problem is that (maybe I missed out some
>>>> key concepts) I'm still
>>>> not sure if it makes sense to follow it driver mode in the context of
>>>> AVB 2.0 feature and
>>>> what kind of extra devices can be used within the same uclass in this case?
>>>> Could you please explain in detail.
>>>> Thanks
>>>
>>> avb_ops_alloc() is allocating a struct and then assigning operations
>>> to its members.
>>>
>>> This is what driver model is designed to do. It handles the
>>> allocations and the operations become part of the uclass interface.
>>>
>>> At present it looks like you only have one driver. I'm not sure if it
>>> would make sense to have a second one.
>>>
>>> As a counter example see cros_ec uclass, which does things
>>> differently. It models the EC interface (I2C, SPI, LPC) using DM, with
>>> just a single impl on top.
>>
>> Right, I do understand what DriverModel is and why it should
>> be used in the case of real-device drivers. But regarding Android Verified
>> Boot 2.0 feature, which introduces verification capabilities
>> and leverages only device-independent APIs,
>> I see no reason why it should be used here.
>> Could you please check [1] and confirm that this set of commands should
>> really follow this model.
>
> If there is no need for operations and indirection through function
> pointers, why not just call the functions directly?
>
> I do think (as the code is currently structured) that DM makes sense,
> even though I understand that you are not creating a device. Perhaps
> Tom might have thoughts on this though?
>
>>
>>> Also can you please drop the CamelCase in the patches? We don't use
>>> that in U-Boot.
>>
>> Frankly, I don't like it also, bit all CamelCase instances in
>> the code relate to libavb/libavb_ab library ([2]), which is planned to be
>> deviated from AOSP upstream in the future.
>> That's why a decision was made to not introduce any changes to simplify this
>> process, as Google intensively introduces new changes to it.
>
> Tom, what do you think? It's not how things usually work, but perhaps
> there is precedent for this?
>
>> (I've left a notice in the cover letter that checkpatch
>> will fail on the commit, which introduces libavb; also, there is the ongoing
>> discussion there regarding why libavb/libavb_ab should be
>> kept as it's. Please join us, if you don't mind).
>
> I do see the cover letter thread but could not find the camel case
> discussion. Can you please point me to it?
>
>>
>> Thanks!
>>
>> Best regards,
>> Igor
>>
>> [1] https://android.googlesource.com/platform/external/avb/+/master/README.md
>> [2] https://android.googlesource.com/platform/external/avb/
>>>>
>
> [..]
>
> Regards,
> Simon



-- 
Regards,
Igor Opaniuk

^ permalink raw reply	[flat|nested] 30+ messages in thread

* [U-Boot] [PATCH 8/8] doc: avb2.0: add README about AVB2.0 integration
  2018-05-02 19:12   ` Sam Protsenko
@ 2018-05-16  9:20     ` Igor Opaniuk
  0 siblings, 0 replies; 30+ messages in thread
From: Igor Opaniuk @ 2018-05-16  9:20 UTC (permalink / raw)
  To: u-boot

Hi Sam,

Thanks, will include this notice in the v2 patchset

Regards,
Igor

On 2 May 2018 at 22:12, Sam Protsenko <semen.protsenko@linaro.org> wrote:
> On 25 April 2018 at 16:18, Igor Opaniuk <igor.opaniuk@linaro.org> wrote:
>> Contains:
>> 1. Overview of Android Verified Boot 2.0
>> 2. Description of avb subset of commands
>> 3. Examples of errors when boot/vendor/system/vbmeta partitions
>> are tampered
>> 4. Examples of enabling AVB2.0 on your setup
>>
>> Signed-off-by: Igor Opaniuk <igor.opaniuk@linaro.org>
>> ---
>>  doc/README.avb2 | 100 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
>>  1 file changed, 100 insertions(+)
>>  create mode 100644 doc/README.avb2
>>
>> diff --git a/doc/README.avb2 b/doc/README.avb2
>> new file mode 100644
>> index 0000000..40db7c5
>> --- /dev/null
>> +++ b/doc/README.avb2
>> @@ -0,0 +1,100 @@
>> +Android Verified Boot 2.0
>> +
>> +This file contains information about the current support of Android Verified
>> +Boot 2.0 in U-boot
>> +
>> +1. OVERVIEW
>> +---------------------------------
>> +Verified Boot establishes a chain of trust from the bootloader to system images
>> +* Provides integrity checking for:
>> +  - Android Boot image: Linux kernel + ramdisk. RAW hashing of the whole
>> +    partition is done and the hash is compared with the one stored in
>> +    the VBMeta image
>> +  - system/vendor partitions: verifying root hash of dm-verity hashtrees.
>> +* Provides capabilities for rollback protection.
>> +
>> +Integrity of the bootloader (U-boot BLOB and environment) is out of scope.
>> +
>> +For additional details check:
>> +https://android.googlesource.com/platform/external/avb/+/master/README.md
>> +
>> +
>> +2. AVB 2.0 U-BOOT SHELL COMMANDS
>> +-----------------------------------
>> +Provides CLI interface to invoke AVB 2.0 verification + misc. commands for
>> +different testing purposes:
>> +
>> +avb init <dev> - initialize avb 2.0 for <dev>
>> +avb verify - run verification process using hash data from vbmeta structure
>> +avb read_rb <num> - read rollback index at location <num>
>> +avb write_rb <num> <rb> - write rollback index <rb> to <num>
>> +avb is_unlocked - returns unlock status of the device
>> +avb get_uuid <partname> - read and print uuid of partition <partname>
>> +avb read_part <partname> <offset> <num> <addr> - read <num> bytes from
>> +partition <partname> to buffer <addr>
>> +avb write_part <partname> <offset> <num> <addr> - write <num> bytes to
>> +<partname> by <offset> using data from <addr>
>> +
>> +
>> +3. PARTITIONS TAMPERING (EXAMPLE)
>> +-----------------------------------
>> +Boot or system/vendor (dm-verity metadata section) is tampered:
>> +=> avb init 1
>> +=> avb verify
>> +avb_slot_verify.c:175: ERROR: boot: Hash of data does not match digest in
>> +descriptor.
>> +Slot verification result: ERROR_IO
>> +
>> +Vbmeta partition is tampered:
>> +=> avb init 1
>> +=> avb verify
>> +avb_vbmeta_image.c:206: ERROR: Hash does not match!
>> +avb_slot_verify.c:388: ERROR: vbmeta: Error verifying vbmeta image:
>> +HASH_MISMATCH
>> +Slot verification result: ERROR_IO
>> +
>> +
>> +4. ENABLE ON YOUR BOARD
>> +-----------------------------------
>> +The following options must be enabled:
>> +CONFIG_LIBAVB=y
>> +CONFIG_LIBAVB_AB=y
>> +CONFIG_CMD_AVB=y
>> +
>> +
>> +Then add `avb verify` invocation to your android boot sequence of commands,
>> +e.g.:
>> +
>> +=> avb_verify=avb init $mmcdev; avb verify;
>> +=> if run avb_verify; then                       \
>> +        echo AVB verification OK. Continue boot; \
>> +        set bootargs $bootargs $avb_bootargs;    \
>> +   else                                          \
>> +        echo AVB verification failed;            \
>> +        exit;                                    \
>> +   fi;                                           \
>> +
>> +=> emmc_android_boot=                                   \
>> +       echo Trying to boot Android from eMMC ...;       \
>> +       ...                                              \
>> +       run avb_verify;                                  \
>> +       mmc read ${fdtaddr} ${fdt_start} ${fdt_size};    \
>> +       mmc read ${loadaddr} ${boot_start} ${boot_size}; \
>> +       bootm $loadaddr $loadaddr $fdtaddr;              \
>> +
>> +
>> +To switch on automatic generation of vbmeta partition in AOSP build, add these
>> +lines to device configuration mk file:
>> +
>> +BOARD_AVB_ENABLE := true
>> +BOARD_AVB_ALGORITHM := SHA512_RSA4096
>> +BOARD_BOOTIMAGE_PARTITION_SIZE := <boot partition size>
>> +
>> +After flashing U-boot don't forget to update environment and write new
>> +partition table:
>> +=> env default -f -a
>> +=> setenv partitions $partitions_android
>> +=> env save
>> +=> fas 1
>> +
>> +$ fastboot oem format
>
> FYI, those commands can be shrank down to a single command:
>
>     => gpt write mmc 1 $partitions_android
>
> because that's exactly what "fastboot oem format" is doing. This way
> you can avoid using fastboot, and thus having it as a dependency. But
> your way is better w.r.t. user experience (i.e. if environment is
> already set, user can just run host command, and avoid tinkering with
> U-Boot shell at all). Please choose which one is better depending on
> targeting use-case.
>
>> --
>> 2.7.4
>>



-- 
Regards,
Igor Opaniuk

^ permalink raw reply	[flat|nested] 30+ messages in thread

* [U-Boot] [PATCH 4/8] cmd: avb2.0: avb command for performing verification
  2018-05-16  8:20             ` Igor Opaniuk
@ 2018-05-16 15:40               ` Simon Glass
  0 siblings, 0 replies; 30+ messages in thread
From: Simon Glass @ 2018-05-16 15:40 UTC (permalink / raw)
  To: u-boot

Hi Igor,

On 16 May 2018 at 02:20, Igor Opaniuk <igor.opaniuk@linaro.org> wrote:
> Hi Simon,
>
>> If there is no need for operations and indirection through function
>> pointers, why not just call the functions directly?
>
> This is the way how libavb is integrated into bootloader. libavb interfaces with
> the bootloader through the supplied AvbOps struct. This includes operations to
> read and write data from partitions, read and write rollback indexes, check
> if the public key used to make a signature should be accepted, and so on.
> This is what Google AVB 2.0 specification says.
> For additional details please check [1].
>
> In this particular patch, all avb commands, except the main "avb
> verify", are used
> to debug these particular callback implementations
> (can be used when enabling this feature on new platform etc.).
> The reason I use indirection through function pointers is that they
> are not supposed
> to be public, and are not intended to be used somehow directly, only by libavb
> (check [2] how libavb is using it)
>
>>> (I've left a notice in the cover letter that checkpatch
>>> will fail on the commit, which introduces libavb; also, there is the ongoing
>>> discussion there regarding why libavb/libavb_ab should be
>>> kept as it's. Please join us, if you don't mind).
>>
>> I do see the cover letter thread but could not find the camel case
>> discussion. Can you please point me to it?
>
> There is no any particular discussion about CamelCase, but a few general
> statements why I should avoid introducing any changes in
> libavb/libavb_ab libraries.
> Regarding our particular case, AvbSlotVerifyResult and AvbSlotVerifyData types
> (I guess you're talking about these CamelCase instances) are defined inside
> libavb library, so obviously I can't simply replace it with something, that
> conforms to the Linux kernel coding style

Maybe I've lost track of the patches, but I thought you were
implementing this library in U-Boot and thus can call things whatever
you like?

We have had a similar thing with EFI, but in that case there was no
reference code to use, so it was easier to just rename things to
kernel style.

In this case it seems that you want to be able to easily merge changes
back and forth between U-Boot's copy of the library and the upstream
one.

I think we have to balance that desire against the impact of having
non-conforming code in the U-Boot code base. So far we have tended to
adjust the code to fit kernel style in these situations.

Anyway I think this is Tom's call and I'm happy with whatever he decides.

[..]

Regards,
Simon

^ permalink raw reply	[flat|nested] 30+ messages in thread

end of thread, other threads:[~2018-05-16 15:40 UTC | newest]

Thread overview: 30+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-04-25 13:17 [U-Boot] [PATCH 0/8] Initial integration of AVB2.0 Igor Opaniuk
2018-04-25 13:17 ` [U-Boot] [PATCH 1/8] avb2.0: add Android Verified Boot 2.0 libraries Igor Opaniuk
2018-04-25 13:17 ` [U-Boot] [PATCH 2/8] avb2.0: integrate avb 2.0 into the build system Igor Opaniuk
2018-04-25 13:18 ` [U-Boot] [PATCH 3/8] avb2.0: implement AVB ops Igor Opaniuk
2018-04-25 13:18 ` [U-Boot] [PATCH 4/8] cmd: avb2.0: avb command for performing verification Igor Opaniuk
2018-05-02 18:52   ` Sam Protsenko
2018-05-03  2:31   ` Simon Glass
2018-05-15 15:44     ` Igor Opaniuk
2018-05-15 16:26       ` Simon Glass
2018-05-15 17:31         ` Igor Opaniuk
2018-05-15 18:28           ` Simon Glass
2018-05-16  8:20             ` Igor Opaniuk
2018-05-16 15:40               ` Simon Glass
2018-04-25 13:18 ` [U-Boot] [PATCH 5/8] avb2.0: add boot states and dm-verity support Igor Opaniuk
2018-05-02 18:59   ` Sam Protsenko
2018-04-25 13:18 ` [U-Boot] [PATCH 6/8] am57xx_hs: avb2.0: add support of AVB 2.0 Igor Opaniuk
2018-05-02 19:06   ` Sam Protsenko
2018-04-25 13:18 ` [U-Boot] [PATCH 7/8] test/py: avb2.0: add tests for avb commands Igor Opaniuk
2018-04-25 13:18 ` [U-Boot] [PATCH 8/8] doc: avb2.0: add README about AVB2.0 integration Igor Opaniuk
2018-05-02 19:12   ` Sam Protsenko
2018-05-16  9:20     ` Igor Opaniuk
2018-04-26  3:05 ` [U-Boot] [PATCH 0/8] Initial integration of AVB2.0 Kever Yang
2018-04-26 13:00   ` Igor Opaniuk
2018-04-26 18:35   ` Alex Deymo
2018-04-27  9:53     ` Igor Opaniuk
2018-04-30 10:47       ` Alex Deymo
2018-05-06 11:31 ` Eugeniu Rosca
2018-05-15 15:31   ` Eugeniu Rosca
2018-05-15 16:58     ` Igor Opaniuk
2018-05-15 17:10       ` Eugeniu Rosca

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.