summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorMatthew Shyu <matthew.shyu@amlogic.com>2018-05-03 13:34:42 +0800
committerDongjin Kim <tobetter@gmail.com>2018-11-08 14:57:22 +0900
commitcabb2cd3ff71b2824c8432d66d7b09d4ed558a42 (patch)
treede0ea3b87c9bc2031ae0d6168921d369384f187c /lib
parent342bf68eab3161727fd3ec522e4b1f1a84a6ed06 (diff)
downloadu-boot-odroid-c1-cabb2cd3ff71b2824c8432d66d7b09d4ed558a42.tar.gz
boot: avb: Enable AVB2 [4/6]
PD#164745 Problem: Need to implement AVB2 on Android P Solution: 1. Integrate libavb 2. Use test key by default 3. Use rpmb if CONFIG_AML_ANTIROLLBACK Verify: Enable CONFIG_AVB2 and CONFIG_AML_ANTIROLLBACK Program u-boot.bin, dtb.img, vbmeta.img, boot.img, system.img, vendor.img During bootm, it should shown avb_slot_verify.c:524: DEBUG: Loading vbmeta struct from partition 'vbmeta'. Verified using testkey avb_slot_verify.c:286: DEBUG: boot: Loading entire partition. avb_slot_verify.c:286: DEBUG: recovery: Loading entire partition. avb_slot_verify.c:286: DEBUG: dtb: Loading entire partition. In Android console, $ mount It should shown /dev/block/dm-0 on /system type ext4 /dev/block/dm-1 on /vendor type ext4 Change-Id: I827311728e9eb819e21ee66baf2d1e28f1531fb1 Signed-off-by: Matthew Shyu<matthew.shyu@amlogic.com>
Diffstat (limited to 'lib')
-rw-r--r--lib/Makefile2
-rw-r--r--lib/libavb/Makefile20
-rw-r--r--lib/libavb/avb_chain_partition_descriptor.c64
-rw-r--r--lib/libavb/avb_cmdline.c447
-rw-r--r--lib/libavb/avb_cmdline.h90
-rw-r--r--lib/libavb/avb_crc32.c114
-rw-r--r--lib/libavb/avb_crypto.c372
-rw-r--r--lib/libavb/avb_descriptor.c160
-rw-r--r--lib/libavb/avb_footer.c54
-rw-r--r--lib/libavb/avb_hash_descriptor.c62
-rw-r--r--lib/libavb/avb_hashtree_descriptor.c70
-rw-r--r--lib/libavb/avb_kernel_cmdline_descriptor.c58
-rw-r--r--lib/libavb/avb_property_descriptor.c185
-rw-r--r--lib/libavb/avb_rsa.c299
-rw-r--r--lib/libavb/avb_rsa.h73
-rw-r--r--lib/libavb/avb_sha.h90
-rw-r--r--lib/libavb/avb_sha256.c390
-rw-r--r--lib/libavb/avb_sha512.c388
-rw-r--r--lib/libavb/avb_slot_verify.c1346
-rw-r--r--lib/libavb/avb_sysdeps_posix.c85
-rw-r--r--lib/libavb/avb_util.c430
-rw-r--r--lib/libavb/avb_vbmeta_image.c308
-rw-r--r--lib/libavb/avb_version.c34
-rw-r--r--lib/libavb/testkey.c52
24 files changed, 5193 insertions, 0 deletions
diff --git a/lib/Makefile b/lib/Makefile
index 46e7c14ece..b181b723a6 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -72,5 +72,7 @@ obj-$(CONFIG_CMD_GPT) += uuid.o
obj-y += vsprintf.o
#obj-$(CONFIG_LIB_RAND) += rand.o
+obj-$(CONFIG_AVB2) += libavb/
+
obj-y += rand.o
subdir-ccflags-$(CONFIG_CC_OPTIMIZE_LIBS_FOR_SPEED) += -O2
diff --git a/lib/libavb/Makefile b/lib/libavb/Makefile
new file mode 100644
index 0000000000..7168a78998
--- /dev/null
+++ b/lib/libavb/Makefile
@@ -0,0 +1,20 @@
+obj-y += avb_chain_partition_descriptor.o
+obj-y += avb_cmdline.o
+obj-y += avb_crc32.o
+obj-y += avb_crypto.o
+obj-y += avb_descriptor.o
+obj-y += avb_footer.o
+obj-y += avb_hash_descriptor.o
+obj-y += avb_hashtree_descriptor.o
+obj-y += avb_kernel_cmdline_descriptor.o
+obj-y += avb_property_descriptor.o
+obj-y += avb_rsa.o
+obj-y += avb_sha256.o
+obj-y += avb_sha512.o
+obj-y += avb_slot_verify.o
+obj-y += avb_sysdeps_posix.o
+obj-y += avb_util.o
+obj-y += avb_vbmeta_image.o
+obj-y += avb_version.o
+obj-y += testkey.o
+ccflags-y += -DAVB_COMPILATION -DAVB_ENABLE_DEBUG
diff --git a/lib/libavb/avb_chain_partition_descriptor.c b/lib/libavb/avb_chain_partition_descriptor.c
new file mode 100644
index 0000000000..4bdfcdc25d
--- /dev/null
+++ b/lib/libavb/avb_chain_partition_descriptor.c
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <libavb/avb_chain_partition_descriptor.h>
+#include <libavb/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_cmdline.c b/lib/libavb/avb_cmdline.c
new file mode 100644
index 0000000000..5eb5578499
--- /dev/null
+++ b/lib/libavb/avb_cmdline.c
@@ -0,0 +1,447 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "avb_cmdline.h"
+#include "avb_sha.h"
+#include <libavb/avb_util.h>
+#include <libavb/avb_version.h>
+
+#define NUM_GUIDS 3
+
+/* Substitutes all variables (e.g. $(ANDROID_SYSTEM_PARTUUID)) with
+ * values. Returns NULL on OOM, otherwise the cmdline with values
+ * replaced.
+ */
+char* avb_sub_cmdline(AvbOps* ops,
+ const char* cmdline,
+ const char* ab_suffix,
+ bool using_boot_for_vbmeta,
+ const AvbCmdlineSubstList* additional_substitutions) {
+ 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;
+ size_t n;
+
+ /* 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 (n = 0; n < NUM_GUIDS; n++) {
+ char part_name[AVB_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) {
+ goto fail;
+ } 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;
+ }
+ }
+
+ avb_assert(ret != NULL);
+
+ /* Replace any additional substitutions. */
+ if (additional_substitutions != NULL) {
+ for (n = 0; n < additional_substitutions->size; ++n) {
+ char* new_ret = avb_replace(ret,
+ additional_substitutions->tokens[n],
+ additional_substitutions->values[n]);
+ 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++] = avb_div_by_10(&value) + '0';
+ 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) {
+ int ret;
+ char* hex_data = avb_bin2hex(data, data_len);
+ if (hex_data == NULL) {
+ return 0;
+ }
+ ret = cmdline_append_option(slot_data, key, hex_data);
+ avb_free(hex_data);
+ return ret;
+}
+
+AvbSlotVerifyResult avb_append_options(
+ AvbOps* ops,
+ AvbSlotVerifyData* slot_data,
+ AvbVBMetaImageHeader* toplevel_vbmeta,
+ AvbAlgorithmType algorithm_type,
+ AvbHashtreeErrorMode hashtree_error_mode) {
+ AvbSlotVerifyResult ret;
+ const char* verity_mode = "invalid";
+ bool is_device_unlocked;
+ AvbIOResult io_ret;
+ char vbmeta_partition[256];
+
+ snprintf(vbmeta_partition, sizeof(vbmeta_partition) - strlen("dev/block/"), "/dev/block/%s",
+ slot_data->vbmeta_images->partition_name);
+ /* Add androidboot.vbmeta.device option. */
+ if (!cmdline_append_option(slot_data,
+ "androidboot.vbmeta.device",
+ vbmeta_partition)) {
+ ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
+ goto out;
+ }
+
+ /* 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 out;
+ }
+
+ /* Set androidboot.avb.device_state to "locked" or "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 out;
+ } else if (io_ret != AVB_IO_RESULT_OK) {
+ avb_error("Error getting device state.\n");
+ ret = AVB_SLOT_VERIFY_RESULT_ERROR_IO;
+ goto out;
+ }
+ if (!cmdline_append_option(slot_data,
+ "androidboot.vbmeta.device_state",
+ is_device_unlocked ? "unlocked" : "locked")) {
+ ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
+ goto out;
+ }
+
+ /* 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 out;
+ }
+ } 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 out;
+ }
+ } break;
+ case _AVB_ALGORITHM_NUM_TYPES:
+ avb_assert_not_reached();
+ break;
+ }
+
+ /* Set androidboot.veritymode and androidboot.vbmeta.invalidate_on_error */
+ if (toplevel_vbmeta->flags & AVB_VBMETA_IMAGE_FLAGS_HASHTREE_DISABLED) {
+ verity_mode = "disabled";
+ } else {
+ const char* dm_verity_mode = "invalid";
+ char* new_ret;
+
+ switch (hashtree_error_mode) {
+ case AVB_HASHTREE_ERROR_MODE_RESTART_AND_INVALIDATE:
+ if (!cmdline_append_option(
+ slot_data, "androidboot.vbmeta.invalidate_on_error", "yes")) {
+ ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
+ goto out;
+ }
+ verity_mode = "enforcing";
+ dm_verity_mode = "restart_on_corruption";
+ break;
+ case AVB_HASHTREE_ERROR_MODE_RESTART:
+ verity_mode = "enforcing";
+ dm_verity_mode = "restart_on_corruption";
+ break;
+ case AVB_HASHTREE_ERROR_MODE_EIO:
+ verity_mode = "eio";
+ /* For now there's no option to specify the EIO mode. So
+ * just use 'ignore_zero_blocks' since that's already set
+ * and dm-verity-target.c supports specifying this multiple
+ * times.
+ */
+ dm_verity_mode = "ignore_zero_blocks";
+ break;
+ case AVB_HASHTREE_ERROR_MODE_LOGGING:
+ verity_mode = "logging";
+ dm_verity_mode = "ignore_corruption";
+ break;
+ }
+ new_ret = avb_replace(
+ slot_data->cmdline, "$(ANDROID_VERITY_MODE)", dm_verity_mode);
+ avb_free(slot_data->cmdline);
+ slot_data->cmdline = new_ret;
+ if (slot_data->cmdline == NULL) {
+ ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
+ goto out;
+ }
+ }
+ if (!cmdline_append_option(
+ slot_data, "androidboot.veritymode", verity_mode)) {
+ ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
+ goto out;
+ }
+
+ ret = AVB_SLOT_VERIFY_RESULT_OK;
+
+out:
+
+ return ret;
+}
+
+AvbCmdlineSubstList* avb_new_cmdline_subst_list() {
+ return (AvbCmdlineSubstList*)avb_calloc(sizeof(AvbCmdlineSubstList));
+}
+
+void avb_free_cmdline_subst_list(AvbCmdlineSubstList* cmdline_subst) {
+ size_t i;
+ for (i = 0; i < cmdline_subst->size; ++i) {
+ avb_free(cmdline_subst->tokens[i]);
+ avb_free(cmdline_subst->values[i]);
+ }
+ cmdline_subst->size = 0;
+ avb_free(cmdline_subst);
+}
+
+AvbSlotVerifyResult avb_add_root_digest_substitution(
+ const char* part_name,
+ const uint8_t* digest,
+ size_t digest_size,
+ AvbCmdlineSubstList* out_cmdline_subst) {
+ const char* kDigestSubPrefix = "$(AVB_";
+ const char* kDigestSubSuffix = "_ROOT_DIGEST)";
+ size_t part_name_len = avb_strlen(part_name);
+ size_t list_index = out_cmdline_subst->size;
+
+ avb_assert(part_name_len < AVB_PART_NAME_MAX_SIZE);
+ avb_assert(digest_size <= AVB_SHA512_DIGEST_SIZE);
+ if (part_name_len >= AVB_PART_NAME_MAX_SIZE ||
+ digest_size > AVB_SHA512_DIGEST_SIZE) {
+ return AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA;
+ }
+
+ if (out_cmdline_subst->size >= AVB_MAX_NUM_CMDLINE_SUBST) {
+ /* The list is full. Currently dynamic growth of this list is not supported.
+ */
+ return AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA;
+ }
+
+ /* Construct the token to replace in the command line based on the partition
+ * name. For partition 'foo', this will be '$(AVB_FOO_ROOT_DIGEST)'.
+ */
+ out_cmdline_subst->tokens[list_index] =
+ avb_strdupv(kDigestSubPrefix, part_name, kDigestSubSuffix, NULL);
+ if (out_cmdline_subst->tokens[list_index] == NULL) {
+ goto fail;
+ }
+ avb_uppercase(out_cmdline_subst->tokens[list_index]);
+
+ /* The digest value is hex encoded when inserted in the command line. */
+ out_cmdline_subst->values[list_index] = avb_bin2hex(digest, digest_size);
+ if (out_cmdline_subst->values[list_index] == NULL) {
+ goto fail;
+ }
+
+ out_cmdline_subst->size++;
+ return AVB_SLOT_VERIFY_RESULT_OK;
+
+fail:
+ if (out_cmdline_subst->tokens[list_index]) {
+ avb_free(out_cmdline_subst->tokens[list_index]);
+ }
+ if (out_cmdline_subst->values[list_index]) {
+ avb_free(out_cmdline_subst->values[list_index]);
+ }
+ return AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
+}
diff --git a/lib/libavb/avb_cmdline.h b/lib/libavb/avb_cmdline.h
new file mode 100644
index 0000000000..01620960f5
--- /dev/null
+++ b/lib/libavb/avb_cmdline.h
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#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_CMDLINE_H_
+#define AVB_CMDLINE_H_
+
+#include <libavb/avb_ops.h>
+#include <libavb/avb_slot_verify.h>
+
+/* Maximum allow length (in bytes) of a partition name, including
+ * ab_suffix.
+ */
+#define AVB_PART_NAME_MAX_SIZE 32
+
+#define AVB_MAX_NUM_CMDLINE_SUBST 10
+
+/* Holds information about command-line substitutions. */
+typedef struct AvbCmdlineSubstList {
+ size_t size;
+ char* tokens[AVB_MAX_NUM_CMDLINE_SUBST];
+ char* values[AVB_MAX_NUM_CMDLINE_SUBST];
+} AvbCmdlineSubstList;
+
+/* Substitutes all variables (e.g. $(ANDROID_SYSTEM_PARTUUID)) with
+ * values. Returns NULL on OOM, otherwise the cmdline with values
+ * replaced.
+ */
+char* avb_sub_cmdline(AvbOps* ops,
+ const char* cmdline,
+ const char* ab_suffix,
+ bool using_boot_for_vbmeta,
+ const AvbCmdlineSubstList* additional_substitutions);
+
+AvbSlotVerifyResult avb_append_options(
+ AvbOps* ops,
+ AvbSlotVerifyData* slot_data,
+ AvbVBMetaImageHeader* toplevel_vbmeta,
+ AvbAlgorithmType algorithm_type,
+ AvbHashtreeErrorMode hashtree_error_mode);
+
+/* Allocates and initializes a new command line substitution list. Free with
+ * |avb_free_cmdline_subst_list|.
+ */
+AvbCmdlineSubstList* avb_new_cmdline_subst_list(void);
+
+/* Use this instead of |avb_free| to deallocate a AvbCmdlineSubstList. */
+void avb_free_cmdline_subst_list(AvbCmdlineSubstList* cmdline_subst);
+
+/* Adds a hashtree root digest to be substituted in $(AVB_*_ROOT_DIGEST)
+ * variables. The partition name differentiates the variable. For example, if
+ * |part_name| is "foo" then $(AVB_FOO_ROOT_DIGEST) will be substituted with the
+ * hex encoding of the digest. The substitution will be added to
+ * |out_cmdline_subst|. Returns AVB_SLOT_VERIFY_RESULT_OK on success.
+ */
+AvbSlotVerifyResult avb_add_root_digest_substitution(
+ const char* part_name,
+ const uint8_t* digest,
+ size_t digest_size,
+ AvbCmdlineSubstList* out_cmdline_subst);
+
+#endif
diff --git a/lib/libavb/avb_crc32.c b/lib/libavb/avb_crc32.c
new file mode 100644
index 0000000000..868ffe4210
--- /dev/null
+++ b/lib/libavb/avb_crc32.c
@@ -0,0 +1,114 @@
+/*-
+ * COPYRIGHT (C) 1986 Gary S. Brown. You may use this program, or
+ * code or tables extracted from it, as desired without restriction.
+ */
+
+/*
+ * First, the polynomial itself and its table of feedback terms. The
+ * polynomial is
+ * X^32+X^26+X^23+X^22+X^16+X^12+X^11+X^10+X^8+X^7+X^5+X^4+X^2+X^1+X^0
+ *
+ * Note that we take it "backwards" and put the highest-order term in
+ * the lowest-order bit. The X^32 term is "implied"; the LSB is the
+ * X^31 term, etc. The X^0 term (usually shown as "+1") results in
+ * the MSB being 1
+ *
+ * Note that the usual hardware shift register implementation, which
+ * is what we're using (we're merely optimizing it by doing eight-bit
+ * chunks at a time) shifts bits into the lowest-order term. In our
+ * implementation, that means shifting towards the right. Why do we
+ * do it this way? Because the calculated CRC must be transmitted in
+ * order from highest-order term to lowest-order term. UARTs transmit
+ * characters in order from LSB to MSB. By storing the CRC this way
+ * we hand it to the UART in the order low-byte to high-byte; the UART
+ * sends each low-bit to hight-bit; and the result is transmission bit
+ * by bit from highest- to lowest-order term without requiring any bit
+ * shuffling on our part. Reception works similarly
+ *
+ * The feedback terms table consists of 256, 32-bit entries. Notes
+ *
+ * The table can be generated at runtime if desired; code to do so
+ * is shown later. It might not be obvious, but the feedback
+ * terms simply represent the results of eight shift/xor opera
+ * tions for all combinations of data and CRC register values
+ *
+ * The values must be right-shifted by eight bits by the "updcrc
+ * logic; the shift must be unsigned (bring in zeroes). On some
+ * hardware you could probably optimize the shift in assembler by
+ * using byte-swap instructions
+ * polynomial $edb88320
+ *
+ *
+ * CRC32 code derived from work by Gary S. Brown.
+ */
+
+#include <libavb/avb_sysdeps.h>
+#include <libavb/avb_util.h>
+
+/* Code taken from FreeBSD 8 */
+
+static uint32_t iavb_crc32_tab[] = {
+ 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f,
+ 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
+ 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2,
+ 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
+ 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,
+ 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
+ 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c,
+ 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
+ 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423,
+ 0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
+ 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106,
+ 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
+ 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d,
+ 0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
+ 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
+ 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
+ 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7,
+ 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
+ 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa,
+ 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
+ 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81,
+ 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
+ 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84,
+ 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
+ 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,
+ 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
+ 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e,
+ 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
+ 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55,
+ 0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
+ 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28,
+ 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
+ 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f,
+ 0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
+ 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
+ 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
+ 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69,
+ 0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
+ 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc,
+ 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
+ 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693,
+ 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
+ 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d};
+
+/*
+ * A function that calculates the CRC-32 based on the table above is
+ * given below for documentation purposes. An equivalent implementation
+ * of this function that's actually used in the kernel can be found
+ * in sys/libkern.h, where it can be inlined.
+ */
+
+static uint32_t iavb_crc32(uint32_t crc_in, const uint8_t* buf, int size) {
+ const uint8_t* p = buf;
+ uint32_t crc;
+
+ crc = crc_in ^ ~0U;
+ while (size--)
+ crc = iavb_crc32_tab[(crc ^ *p++) & 0xFF] ^ (crc >> 8);
+ return crc ^ ~0U;
+}
+
+uint32_t avb_crc32(const uint8_t* buf, size_t size) {
+ return iavb_crc32(0, buf, size);
+}
diff --git a/lib/libavb/avb_crypto.c b/lib/libavb/avb_crypto.c
new file mode 100644
index 0000000000..0133d42d3d
--- /dev/null
+++ b/lib/libavb/avb_crypto.c
@@ -0,0 +1,372 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <libavb/avb_crypto.h>
+#include "avb_rsa.h"
+#include "avb_sha.h"
+#include <libavb/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 ((size_t)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 0000000000..081a900bd7
--- /dev/null
+++ b/lib/libavb/avb_descriptor.c
@@ -0,0 +1,160 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <libavb/avb_descriptor.h>
+#include <libavb/avb_util.h>
+#include <libavb/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 0000000000..592ef19730
--- /dev/null
+++ b/lib/libavb/avb_footer.c
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <libavb/avb_footer.h>
+#include <libavb/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 0000000000..61c9888ee4
--- /dev/null
+++ b/lib/libavb/avb_hash_descriptor.c
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <libavb/avb_hash_descriptor.h>
+#include <libavb/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);
+ dest->flags = avb_be32toh(dest->flags);
+
+ /* 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 0000000000..793beaf370
--- /dev/null
+++ b/lib/libavb/avb_hashtree_descriptor.c
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <libavb/avb_hashtree_descriptor.h>
+#include <libavb/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);
+ dest->flags = avb_be32toh(dest->flags);
+
+ /* 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 0000000000..c3b8110c62
--- /dev/null
+++ b/lib/libavb/avb_kernel_cmdline_descriptor.c
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <libavb/avb_kernel_cmdline_descriptor.h>
+#include <libavb/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 0000000000..4c5764d8bc
--- /dev/null
+++ b/lib/libavb/avb_property_descriptor.c
@@ -0,0 +1,185 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <libavb/avb_property_descriptor.h>
+#include <libavb/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 0000000000..9b36871302
--- /dev/null
+++ b/lib/libavb/avb_rsa.c
@@ -0,0 +1,299 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+/* 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.
+ */
+
+/* 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_rsa.h"
+#include "avb_sha.h"
+#include <libavb/avb_util.h>
+#include <libavb/avb_vbmeta_image.h>
+
+typedef struct IAvbKey {
+ 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) */
+} IAvbKey;
+
+static IAvbKey* iavb_parse_key_data(const uint8_t* data, size_t length) {
+ AvbRSAPublicKeyHeader h;
+ IAvbKey* 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 = (IAvbKey*)(avb_malloc(sizeof(IAvbKey) + 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(IAvbKey) 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;
+}
+
+static void iavb_free_parsed_key(IAvbKey* key) {
+ avb_free(key);
+}
+
+/* a[] -= mod */
+static void subM(const IAvbKey* 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 IAvbKey* 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 IAvbKey* 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 IAvbKey* 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 IAvbKey* 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 at 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;
+ IAvbKey* parsed_key = NULL;
+ bool success = false;
+
+ if (key == NULL || sig == NULL || hash == NULL || padding == NULL) {
+ avb_error("Invalid input.\n");
+ goto out;
+ }
+
+ parsed_key = iavb_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) {
+ iavb_free_parsed_key(parsed_key);
+ }
+ if (buf != NULL) {
+ avb_free(buf);
+ }
+ return success;
+}
diff --git a/lib/libavb/avb_rsa.h b/lib/libavb/avb_rsa.h
new file mode 100644
index 0000000000..95f187fb50
--- /dev/null
+++ b/lib/libavb/avb_rsa.h
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+/* 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 <libavb/avb_crypto.h>
+#include <libavb/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/lib/libavb/avb_sha.h b/lib/libavb/avb_sha.h
new file mode 100644
index 0000000000..8f1b1dc27c
--- /dev/null
+++ b/lib/libavb/avb_sha.h
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#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 <libavb/avb_crypto.h>
+#include <libavb/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/lib/libavb/avb_sha256.c b/lib/libavb/avb_sha256.c
new file mode 100644
index 0000000000..cdd143a93f
--- /dev/null
+++ b/lib/libavb/avb_sha256.c
@@ -0,0 +1,390 @@
+/* SHA-256 and SHA-512 implementation based on code by Oliver Gay
+ * <olivier.gay@a3.epfl.ch> under a BSD-style license. See below.
+ */
+
+/*
+ * FIPS 180-2 SHA-224/256/384/512 implementation
+ * Last update: 02/02/2007
+ * Issue date: 04/30/2005
+ *
+ * Copyright (C) 2005, 2007 Olivier Gay <olivier.gay@a3.epfl.ch>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the project nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "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 0000000000..8df63193c9
--- /dev/null
+++ b/lib/libavb/avb_sha512.c
@@ -0,0 +1,388 @@
+/* SHA-256 and SHA-512 implementation based on code by Oliver Gay
+ * <olivier.gay@a3.epfl.ch> under a BSD-style license. See below.
+ */
+
+/*
+ * FIPS 180-2 SHA-224/256/384/512 implementation
+ * Last update: 02/02/2007
+ * Issue date: 04/30/2005
+ *
+ * Copyright (C) 2005, 2007 Olivier Gay <olivier.gay@a3.epfl.ch>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the project nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "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 0000000000..1e91dda92b
--- /dev/null
+++ b/lib/libavb/avb_slot_verify.c
@@ -0,0 +1,1346 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <libavb/avb_slot_verify.h>
+#include <libavb/avb_chain_partition_descriptor.h>
+#include "avb_cmdline.h"
+#include <libavb/avb_footer.h>
+#include <libavb/avb_hash_descriptor.h>
+#include <libavb/avb_hashtree_descriptor.h>
+#include <libavb/avb_kernel_cmdline_descriptor.h>
+#include "avb_sha.h"
+#include <libavb/avb_util.h>
+#include <libavb/avb_vbmeta_image.h>
+#include <libavb/avb_version.h>
+
+/* 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:
+ case AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_ARGUMENT:
+ 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_full_partition(AvbOps* ops,
+ const char* part_name,
+ uint64_t image_size,
+ uint8_t** out_image_buf,
+ bool* out_image_preloaded) {
+ size_t part_num_read;
+ AvbIOResult io_ret;
+
+ /* Make sure that we do not overwrite existing data. */
+ avb_assert(*out_image_buf == NULL);
+ avb_assert(!*out_image_preloaded);
+
+ /* We are going to implicitly cast image_size from uint64_t to size_t in the
+ * following code, so we need to make sure that the cast is safe. */
+ if (image_size != (size_t)(image_size)) {
+ avb_errorv(part_name, ": Partition size too large to load.\n", NULL);
+ return AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA;
+ }
+
+ /* Try use a preloaded one. */
+ if (ops->get_preloaded_partition != NULL) {
+ io_ret = ops->get_preloaded_partition(
+ ops, part_name, image_size, out_image_buf, &part_num_read);
+ if (io_ret == AVB_IO_RESULT_ERROR_OOM) {
+ return AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
+ } else if (io_ret != AVB_IO_RESULT_OK) {
+ avb_errorv(part_name, ": Error loading data from partition.\n", NULL);
+ return AVB_SLOT_VERIFY_RESULT_ERROR_IO;
+ }
+
+ if (*out_image_buf != NULL) {
+ if (part_num_read != image_size) {
+ avb_errorv(part_name, ": Read incorrect number of bytes.\n", NULL);
+ return AVB_SLOT_VERIFY_RESULT_ERROR_IO;
+ }
+ *out_image_preloaded = true;
+ }
+ }
+
+ /* Allocate and copy the partition. */
+ if (!*out_image_preloaded) {
+ *out_image_buf = avb_malloc(image_size);
+ if (*out_image_buf == NULL) {
+ return AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
+ }
+
+ io_ret = ops->read_from_partition(ops,
+ part_name,
+ 0 /* offset */,
+ image_size,
+ *out_image_buf,
+ &part_num_read);
+ if (io_ret == AVB_IO_RESULT_ERROR_OOM) {
+ return AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
+ } else if (io_ret != AVB_IO_RESULT_OK) {
+ avb_errorv(part_name, ": Error loading data from partition.\n", NULL);
+ return AVB_SLOT_VERIFY_RESULT_ERROR_IO;
+ }
+ if (part_num_read != image_size) {
+ avb_errorv(part_name, ": Read incorrect number of bytes.\n", NULL);
+ return AVB_SLOT_VERIFY_RESULT_ERROR_IO;
+ }
+ }
+
+ return AVB_SLOT_VERIFY_RESULT_OK;
+}
+
+static AvbSlotVerifyResult read_persistent_digest(AvbOps* ops,
+ const char* part_name,
+ size_t expected_digest_size,
+ uint8_t* out_digest) {
+ char* persistent_value_name = NULL;
+ AvbIOResult io_ret = AVB_IO_RESULT_OK;
+ size_t stored_digest_size = 0;
+
+ if (ops->read_persistent_value == NULL) {
+ avb_errorv(part_name, ": Persistent values are not implemented.\n", NULL);
+ return AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA;
+ }
+ persistent_value_name =
+ avb_strdupv(AVB_NPV_PERSISTENT_DIGEST_PREFIX, part_name, NULL);
+ if (persistent_value_name == NULL) {
+ return AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
+ }
+ io_ret = ops->read_persistent_value(ops,
+ persistent_value_name,
+ expected_digest_size,
+ out_digest,
+ &stored_digest_size);
+ avb_free(persistent_value_name);
+ if (io_ret == AVB_IO_RESULT_ERROR_OOM) {
+ return AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
+ } else if (io_ret == AVB_IO_RESULT_ERROR_NO_SUCH_VALUE) {
+ avb_errorv(part_name, ": Persistent digest does not exist.\n", NULL);
+ return AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA;
+ } else if (io_ret == AVB_IO_RESULT_ERROR_INVALID_VALUE_SIZE ||
+ io_ret == AVB_IO_RESULT_ERROR_INSUFFICIENT_SPACE ||
+ expected_digest_size != stored_digest_size) {
+ avb_errorv(
+ part_name, ": Persistent digest is not of expected size.\n", NULL);
+ return AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA;
+ } else if (io_ret != AVB_IO_RESULT_OK) {
+ avb_errorv(part_name, ": Error reading persistent digest.\n", NULL);
+ return AVB_SLOT_VERIFY_RESULT_ERROR_IO;
+ }
+ return AVB_SLOT_VERIFY_RESULT_OK;
+}
+
+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[AVB_PART_NAME_MAX_SIZE];
+ AvbSlotVerifyResult ret;
+ AvbIOResult io_ret;
+ uint8_t* image_buf = NULL;
+ bool image_preloaded = false;
+ uint8_t* digest;
+ size_t digest_len;
+ const char* found;
+ uint64_t image_size;
+ size_t expected_digest_len = 0;
+ uint8_t expected_digest_buf[AVB_SHA512_DIGEST_SIZE];
+ const uint8_t* expected_digest = NULL;
+
+ 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;
+ }
+
+ /* Don't bother loading or validating unless the partition was
+ * requested in the first place.
+ */
+ found = avb_strv_find_str(requested_partitions,
+ (const char*)desc_partition_name,
+ hash_desc.partition_name_len);
+ if (found == NULL) {
+ ret = AVB_SLOT_VERIFY_RESULT_OK;
+ goto out;
+ }
+
+ if ((hash_desc.flags & AVB_HASH_DESCRIPTOR_FLAGS_DO_NOT_USE_AB) != 0) {
+ /* No ab_suffix, just copy the partition name as is. */
+ if (hash_desc.partition_name_len >= AVB_PART_NAME_MAX_SIZE) {
+ avb_error("Partition name does not fit.\n");
+ ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA;
+ goto out;
+ }
+ avb_memcpy(part_name, desc_partition_name, hash_desc.partition_name_len);
+ part_name[hash_desc.partition_name_len] = '\0';
+ } else if (hash_desc.digest_len == 0 && avb_strlen(ab_suffix) != 0) {
+ /* No ab_suffix allowed for partitions without a digest in the descriptor
+ * because these partitions hold data unique to this device and are not
+ * updated using an A/B scheme.
+ */
+ avb_error("Cannot use A/B with a persistent digest.\n");
+ ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA;
+ goto out;
+ } else {
+ /* Add ab_suffix to the partition name. */
+ 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;
+ }
+ }
+
+ /* If we're allowing verification errors then hash_desc.image_size
+ * may no longer match what's in the partition... so in this case
+ * just load the entire partition.
+ *
+ * For example, this can happen if a developer does 'fastboot flash
+ * boot /path/to/new/and/bigger/boot.img'. We want this to work
+ * since it's such a common workflow.
+ */
+ image_size = hash_desc.image_size;
+ if (allow_verification_error) {
+ if (ops->get_size_of_partition == NULL) {
+ avb_errorv(part_name,
+ ": The get_size_of_partition() operation is "
+ "not implemented so we may not load the entire partition. "
+ "Please implement.",
+ NULL);
+ } else {
+ io_ret = ops->get_size_of_partition(ops, part_name, &image_size);
+ 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 determining partition size.\n", NULL);
+ ret = AVB_SLOT_VERIFY_RESULT_ERROR_IO;
+ goto out;
+ }
+ avb_debugv(part_name, ": Loading entire partition.\n", NULL);
+ }
+ }
+
+ ret = load_full_partition(
+ ops, part_name, image_size, &image_buf, &image_preloaded);
+ if (ret != AVB_SLOT_VERIFY_RESULT_OK) {
+ 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 (hash_desc.digest_len == 0) {
+ // Expect a match to a persistent digest.
+ avb_debugv(part_name, ": No digest, using persistent digest.\n", NULL);
+ expected_digest_len = digest_len;
+ expected_digest = expected_digest_buf;
+ avb_assert(expected_digest_len <= sizeof(expected_digest_buf));
+ ret =
+ read_persistent_digest(ops, part_name, digest_len, expected_digest_buf);
+ if (ret != AVB_SLOT_VERIFY_RESULT_OK) {
+ goto out;
+ }
+ } else {
+ // Expect a match to the digest in the descriptor.
+ expected_digest_len = hash_desc.digest_len;
+ expected_digest = desc_digest;
+ }
+
+ if (digest_len != expected_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, expected_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 it worked and something was loaded, copy to slot_data. */
+ if ((ret == AVB_SLOT_VERIFY_RESULT_OK || result_should_continue(ret)) &&
+ image_buf != 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 = image_size;
+ loaded_partition->data = image_buf;
+ loaded_partition->preloaded = image_preloaded;
+ image_buf = NULL;
+ }
+
+fail:
+ if (image_buf != NULL && !image_preloaded) {
+ avb_free(image_buf);
+ }
+ return ret;
+}
+
+static AvbSlotVerifyResult load_requested_partitions(
+ AvbOps* ops,
+ const char* const* requested_partitions,
+ const char* ab_suffix,
+ AvbSlotVerifyData* slot_data) {
+ AvbSlotVerifyResult ret;
+ uint8_t* image_buf = NULL;
+ bool image_preloaded = false;
+ size_t n;
+
+ if (ops->get_size_of_partition == NULL) {
+ avb_error("get_size_of_partition() not implemented.\n");
+ ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_ARGUMENT;
+ goto out;
+ }
+
+ for (n = 0; requested_partitions[n] != NULL; n++) {
+ char part_name[AVB_PART_NAME_MAX_SIZE];
+ AvbIOResult io_ret;
+ uint64_t image_size;
+ AvbPartitionData* loaded_partition;
+
+ if (!avb_str_concat(part_name,
+ sizeof part_name,
+ requested_partitions[n],
+ avb_strlen(requested_partitions[n]),
+ 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;
+ }
+
+ io_ret = ops->get_size_of_partition(ops, part_name, &image_size);
+ 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 determining partition size.\n", NULL);
+ ret = AVB_SLOT_VERIFY_RESULT_ERROR_IO;
+ goto out;
+ }
+ avb_debugv(part_name, ": Loading entire partition.\n", NULL);
+
+ ret = load_full_partition(
+ ops, part_name, image_size, &image_buf, &image_preloaded);
+ if (ret != AVB_SLOT_VERIFY_RESULT_OK) {
+ goto out;
+ }
+
+ /* Move to slot_data. */
+ 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 out;
+ }
+ loaded_partition =
+ &slot_data->loaded_partitions[slot_data->num_loaded_partitions++];
+ loaded_partition->partition_name = avb_strdup(requested_partitions[n]);
+ if (loaded_partition->partition_name == NULL) {
+ ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
+ goto out;
+ }
+ loaded_partition->data_size = image_size;
+ loaded_partition->data = image_buf; /* Transferring the owner. */
+ loaded_partition->preloaded = image_preloaded;
+ image_buf = NULL;
+ image_preloaded = false;
+ }
+
+ ret = AVB_SLOT_VERIFY_RESULT_OK;
+
+out:
+ /* Free the current buffer if any. */
+ if (image_buf != NULL && !image_preloaded) {
+ avb_free(image_buf);
+ }
+ /* Buffers that are already saved in slot_data will be handled by the caller
+ * even on failure. */
+ 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,
+ AvbCmdlineSubstList* out_additional_cmdline_subst) {
+ char full_partition_name[AVB_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,
+ out_additional_cmdline_subst);
+ 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;
+
+ /* If verification has been disabled by setting a bit in the image,
+ * we're done... except that we need to load the entirety of the
+ * requested partitions.
+ */
+ if (vbmeta_header.flags & AVB_VBMETA_IMAGE_FLAGS_VERIFICATION_DISABLED) {
+ AvbSlotVerifyResult sub_ret;
+ avb_debugv(
+ full_partition_name, ": VERIFICATION_DISABLED bit is set.\n", NULL);
+ /* If load_requested_partitions() fail it is always a fatal
+ * failure (e.g. ERROR_INVALID_ARGUMENT, ERROR_OOM, etc.) rather
+ * than recoverable (e.g. one where result_should_continue()
+ * returns true) and we want to convey that error.
+ */
+ sub_ret = load_requested_partitions(
+ ops, requested_partitions, ab_suffix, slot_data);
+ if (sub_ret != AVB_SLOT_VERIFY_RESULT_OK) {
+ ret = sub_ret;
+ }
+ goto out;
+ }
+
+ /* 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. (Unless the descriptor uses a
+ * persistent digest, in which case we need to find it).
+ *
+ * - 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 */
+ NULL /* out_additional_cmdline_subst */);
+ 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;
+
+ case AVB_DESCRIPTOR_TAG_HASHTREE: {
+ AvbHashtreeDescriptor hashtree_desc;
+
+ if (!avb_hashtree_descriptor_validate_and_byteswap(
+ (AvbHashtreeDescriptor*)descriptors[n], &hashtree_desc)) {
+ avb_errorv(
+ full_partition_name, ": Hashtree descriptor is invalid.\n", NULL);
+ ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA;
+ goto out;
+ }
+
+ /* We only need to continue when there is no digest in the descriptor.
+ * This is because the only processing here is to find the digest and
+ * make it available on the kernel command line.
+ */
+ if (hashtree_desc.root_digest_len == 0) {
+ char part_name[AVB_PART_NAME_MAX_SIZE];
+ size_t digest_len = 0;
+ uint8_t digest_buf[AVB_SHA512_DIGEST_SIZE];
+ const uint8_t* desc_partition_name =
+ ((const uint8_t*)descriptors[n]) + sizeof(AvbHashtreeDescriptor);
+
+ if (!avb_validate_utf8(desc_partition_name,
+ hashtree_desc.partition_name_len)) {
+ avb_error("Partition name is not valid UTF-8.\n");
+ ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA;
+ goto out;
+ }
+
+ /* No ab_suffix for partitions without a digest in the descriptor
+ * because these partitions hold data unique to this device and are
+ * not updated using an A/B scheme.
+ */
+ if ((hashtree_desc.flags &
+ AVB_HASHTREE_DESCRIPTOR_FLAGS_DO_NOT_USE_AB) == 0 &&
+ avb_strlen(ab_suffix) != 0) {
+ avb_error("Cannot use A/B with a persistent root digest.\n");
+ ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA;
+ goto out;
+ }
+ if (hashtree_desc.partition_name_len >= AVB_PART_NAME_MAX_SIZE) {
+ avb_error("Partition name does not fit.\n");
+ ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA;
+ goto out;
+ }
+ avb_memcpy(
+ part_name, desc_partition_name, hashtree_desc.partition_name_len);
+ part_name[hashtree_desc.partition_name_len] = '\0';
+
+ /* Determine the expected digest size from the hash algorithm. */
+ if (avb_strcmp((const char*)hashtree_desc.hash_algorithm, "sha1") ==
+ 0) {
+ digest_len = AVB_SHA1_DIGEST_SIZE;
+ } else if (avb_strcmp((const char*)hashtree_desc.hash_algorithm,
+ "sha256") == 0) {
+ digest_len = AVB_SHA256_DIGEST_SIZE;
+ } else if (avb_strcmp((const char*)hashtree_desc.hash_algorithm,
+ "sha512") == 0) {
+ 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;
+ }
+
+ ret = read_persistent_digest(ops, part_name, digest_len, digest_buf);
+ if (ret != AVB_SLOT_VERIFY_RESULT_OK) {
+ goto out;
+ }
+
+ if (out_additional_cmdline_subst) {
+ ret =
+ avb_add_root_digest_substitution(part_name,
+ digest_buf,
+ digest_len,
+ out_additional_cmdline_subst);
+ if (ret != AVB_SLOT_VERIFY_RESULT_OK) {
+ goto out;
+ }
+ }
+ }
+ } break;
+
+ case AVB_DESCRIPTOR_TAG_PROPERTY:
+ /* 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;
+}
+
+AvbSlotVerifyResult avb_slot_verify(AvbOps* ops,
+ const char* const* requested_partitions,
+ const char* ab_suffix,
+ AvbSlotVerifyFlags flags,
+ AvbHashtreeErrorMode hashtree_error_mode,
+ AvbSlotVerifyData** out_data) {
+ AvbSlotVerifyResult ret;
+ AvbSlotVerifyData* slot_data = NULL;
+ AvbAlgorithmType algorithm_type = AVB_ALGORITHM_TYPE_NONE;
+ bool using_boot_for_vbmeta = false;
+ AvbVBMetaImageHeader toplevel_vbmeta;
+ bool allow_verification_error =
+ (flags & AVB_SLOT_VERIFY_FLAGS_ALLOW_VERIFICATION_ERROR);
+ AvbCmdlineSubstList* additional_cmdline_subst = NULL;
+
+ /* Fail early if we're missing the AvbOps needed for slot verification.
+ *
+ * For now, handle get_size_of_partition() not being implemented. In
+ * a later release we may change that.
+ */
+ avb_assert(ops->read_is_device_unlocked != NULL);
+ avb_assert(ops->read_from_partition != NULL);
+ avb_assert(ops->validate_vbmeta_public_key != NULL);
+ avb_assert(ops->read_rollback_index != NULL);
+ avb_assert(ops->get_unique_guid_for_partition != NULL);
+
+ if (out_data != NULL) {
+ *out_data = NULL;
+ }
+
+ /* Allowing dm-verity errors defeats the purpose of verified boot so
+ * only allow this if set up to allow verification errors
+ * (e.g. typically only UNLOCKED mode).
+ */
+ if (hashtree_error_mode == AVB_HASHTREE_ERROR_MODE_LOGGING &&
+ !allow_verification_error) {
+ ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_ARGUMENT;
+ goto fail;
+ }
+
+ 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;
+ }
+
+ additional_cmdline_subst = avb_new_cmdline_subst_list();
+ if (additional_cmdline_subst == 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,
+ additional_cmdline_subst);
+ if (!allow_verification_error && ret != AVB_SLOT_VERIFY_RESULT_OK) {
+ goto fail;
+ }
+
+ /* If things check out, mangle the kernel command-line as needed. */
+ if (result_should_continue(ret)) {
+ if (avb_strcmp(slot_data->vbmeta_images[0].partition_name, "vbmeta") != 0) {
+ avb_assert(
+ avb_strcmp(slot_data->vbmeta_images[0].partition_name, "boot") == 0);
+ using_boot_for_vbmeta = true;
+ }
+
+ /* Byteswap top-level vbmeta header since we'll need it below. */
+ avb_vbmeta_image_header_to_host_byte_order(
+ (const AvbVBMetaImageHeader*)slot_data->vbmeta_images[0].vbmeta_data,
+ &toplevel_vbmeta);
+
+ /* 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;
+ }
+
+ /* If verification is disabled, we are done ... we specifically
+ * don't want to add any androidboot.* options since verification
+ * is disabled.
+ */
+ if (toplevel_vbmeta.flags & AVB_VBMETA_IMAGE_FLAGS_VERIFICATION_DISABLED) {
+ /* Since verification is disabled we didn't process any
+ * descriptors and thus there's no cmdline... so set root= such
+ * that the system partition is mounted.
+ */
+ avb_assert(slot_data->cmdline == NULL);
+ slot_data->cmdline =
+ avb_strdup("root=PARTUUID=$(ANDROID_SYSTEM_PARTUUID)");
+ if (slot_data->cmdline == NULL) {
+ ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
+ goto fail;
+ }
+ } else {
+ /* Add options - any failure in avb_append_options() is either an
+ * I/O or OOM error.
+ */
+ AvbSlotVerifyResult sub_ret = avb_append_options(ops,
+ slot_data,
+ &toplevel_vbmeta,
+ algorithm_type,
+ hashtree_error_mode);
+ if (sub_ret != AVB_SLOT_VERIFY_RESULT_OK) {
+ ret = sub_ret;
+ goto fail;
+ }
+ }
+
+ /* Substitute $(ANDROID_SYSTEM_PARTUUID) and friends. */
+ if (slot_data->cmdline != NULL) {
+ char* new_cmdline;
+ new_cmdline = avb_sub_cmdline(ops,
+ slot_data->cmdline,
+ ab_suffix,
+ using_boot_for_vbmeta,
+ additional_cmdline_subst);
+ if (new_cmdline != slot_data->cmdline) {
+ if (new_cmdline == NULL) {
+ ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
+ goto fail;
+ }
+ avb_free(slot_data->cmdline);
+ slot_data->cmdline = new_cmdline;
+ }
+ }
+
+ if (out_data != NULL) {
+ *out_data = slot_data;
+ } else {
+ avb_slot_verify_data_free(slot_data);
+ }
+ }
+
+ avb_free_cmdline_subst_list(additional_cmdline_subst);
+ additional_cmdline_subst = NULL;
+
+ 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);
+ }
+ if (additional_cmdline_subst != NULL) {
+ avb_free_cmdline_subst_list(additional_cmdline_subst);
+ }
+ 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 && !loaded_partition->preloaded) {
+ 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;
+ case AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_ARGUMENT:
+ ret = "ERROR_INVALID_ARGUMENT";
+ 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 0000000000..d1801023d4
--- /dev/null
+++ b/lib/libavb/avb_sysdeps_posix.c
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+//#include <endian.h>
+#include <stdarg.h>
+//#include <stdio.h>
+#include <stdlib.h>
+//#include <string.h>
+
+#include <libavb/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) {
+ panic ("avb abort\n");
+ //abort();
+}
+
+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);
+}
+
+uint32_t avb_div_by_10(uint64_t* dividend) {
+ uint32_t rem = (uint32_t)(*dividend % 10);
+ *dividend /= 10;
+ return rem;
+}
diff --git a/lib/libavb/avb_util.c b/lib/libavb/avb_util.c
new file mode 100644
index 0000000000..f1638ba964
--- /dev/null
+++ b/lib/libavb/avb_util.c
@@ -0,0 +1,430 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <libavb/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@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 (new_str == 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 (new_str == 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;
+}
+
+void avb_uppercase(char* str) {
+ size_t i;
+ for (i = 0; str[i] != '\0'; ++i) {
+ if (str[i] <= 0x7A && str[i] >= 0x61) {
+ str[i] -= 0x20;
+ }
+ }
+}
+
+char* avb_bin2hex(const uint8_t* data, size_t data_len) {
+ const char hex_digits[17] = "0123456789abcdef";
+ char* hex_data;
+ size_t n;
+
+ hex_data = avb_malloc(data_len * 2 + 1);
+ if (hex_data == NULL) {
+ return NULL;
+ }
+
+ 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';
+ return hex_data;
+}
diff --git a/lib/libavb/avb_vbmeta_image.c b/lib/libavb/avb_vbmeta_image.c
new file mode 100644
index 0000000000..26dabce0cb
--- /dev/null
+++ b/lib/libavb/avb_vbmeta_image.c
@@ -0,0 +1,308 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <libavb/avb_vbmeta_image.h>
+#include <libavb/avb_crypto.h>
+#include "avb_rsa.h"
+#include "avb_sha.h"
+#include <libavb/avb_util.h>
+#include <libavb/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 0000000000..ac24756022
--- /dev/null
+++ b/lib/libavb/avb_version.c
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <libavb/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/testkey.c b/lib/libavb/testkey.c
new file mode 100644
index 0000000000..34401465d7
--- /dev/null
+++ b/lib/libavb/testkey.c
@@ -0,0 +1,52 @@
+const char testkey2048[520] = {
+ 0x00, 0x00, 0x08, 0x00, 0xc9, 0xd8, 0x7d, 0x7b, 0xc6, 0x55, 0x51,
+ 0xdd, 0x32, 0x24, 0xa2, 0xe0, 0x0e, 0xbc, 0x7e, 0xfd, 0xbd, 0xa2,
+ 0x53, 0x80, 0x58, 0x69, 0x7e, 0xf5, 0x4a, 0x40, 0x87, 0x95, 0x90,
+ 0x54, 0x59, 0x3d, 0x55, 0xca, 0xff, 0x36, 0x34, 0x1a, 0xfa, 0xe1,
+ 0xe0, 0x90, 0x2a, 0x1a, 0x32, 0x68, 0x5b, 0xf3, 0xdf, 0xad, 0x0b,
+ 0xf9, 0xb1, 0xd0, 0xf7, 0xea, 0xab, 0x47, 0x1f, 0x76, 0xbe, 0x1b,
+ 0x98, 0x4b, 0x67, 0xa3, 0x62, 0xfa, 0xdf, 0xe6, 0xb5, 0xf8, 0xee,
+ 0x73, 0x16, 0x5f, 0xb8, 0xb1, 0x82, 0xde, 0x49, 0x89, 0xd5, 0x3d,
+ 0xd7, 0xa8, 0x42, 0x99, 0x81, 0x75, 0xc8, 0xd8, 0x84, 0x7b, 0xbd,
+ 0x54, 0xa8, 0x22, 0x64, 0x44, 0xbc, 0x34, 0x06, 0x10, 0x3c, 0x89,
+ 0xc2, 0xd1, 0xf3, 0x2c, 0x03, 0x65, 0x91, 0xb1, 0xa0, 0xd1, 0xc8,
+ 0x21, 0x56, 0x15, 0x99, 0x48, 0x20, 0x27, 0x74, 0xef, 0x01, 0x7a,
+ 0x76, 0xa5, 0x0b, 0x6b, 0xfd, 0xe3, 0xfa, 0xed, 0x0d, 0xf9, 0x0f,
+ 0x7a, 0x41, 0xfa, 0x76, 0x05, 0x37, 0x49, 0xfe, 0x34, 0x4f, 0x4b,
+ 0x01, 0x49, 0xe4, 0x98, 0xf7, 0x89, 0x8e, 0xcd, 0x36, 0xaa, 0x39,
+ 0x1d, 0xa9, 0x7d, 0x5d, 0x6b, 0x5a, 0x52, 0xd1, 0x75, 0x69, 0xa8,
+ 0xdf, 0x7c, 0xde, 0x1c, 0x1b, 0xf9, 0xd9, 0x19, 0x5b, 0xb7, 0x47,
+ 0x4c, 0xb9, 0x70, 0x2e, 0xad, 0xe5, 0xd6, 0x88, 0x7c, 0xed, 0x92,
+ 0x6e, 0x46, 0x08, 0x10, 0xb5, 0x76, 0x03, 0x3e, 0x09, 0xac, 0x4d,
+ 0xb6, 0x2c, 0xcd, 0x12, 0x00, 0xbd, 0xd4, 0xa7, 0x03, 0xd3, 0x1b,
+ 0x91, 0x08, 0x23, 0x36, 0x5b, 0x11, 0xfe, 0xaf, 0x59, 0x69, 0xb3,
+ 0x3c, 0x88, 0x24, 0x37, 0x2d, 0x61, 0xba, 0xc5, 0x99, 0x51, 0x18,
+ 0x97, 0xf9, 0x23, 0x42, 0x96, 0x9f, 0x87, 0x2e, 0xcd, 0xb2, 0x4d,
+ 0x5f, 0xa9, 0x24, 0xf2, 0x45, 0xda, 0xe2, 0x65, 0x26, 0x26, 0x4d,
+ 0x1e, 0xfa, 0x3b, 0x53, 0xab, 0xc5, 0xd3, 0x79, 0x53, 0x2f, 0x66,
+ 0xb8, 0x21, 0x94, 0x66, 0x9a, 0x93, 0x6f, 0x35, 0x26, 0x43, 0x8c,
+ 0x8f, 0x96, 0xb9, 0xff, 0xac, 0xcd, 0xf4, 0x00, 0x6e, 0xbe, 0xb6,
+ 0x73, 0x54, 0x84, 0x50, 0x85, 0x46, 0x53, 0xd5, 0xdd, 0x43, 0xfe,
+ 0xb2, 0x6a, 0x78, 0x40, 0x79, 0x56, 0x9f, 0x86, 0xf3, 0xd3, 0x81,
+ 0x3b, 0x3d, 0x40, 0x90, 0x35, 0x32, 0x9a, 0x51, 0x7f, 0xf8, 0xc3,
+ 0x4b, 0xc7, 0xd6, 0xa1, 0xca, 0x30, 0xfb, 0x1b, 0xfd, 0x27, 0x0a,
+ 0xb8, 0x64, 0x41, 0x34, 0xc1, 0x17, 0xde, 0xa1, 0x76, 0x9a, 0xeb,
+ 0xcf, 0x0c, 0x50, 0xd9, 0x13, 0xf5, 0x0d, 0x0b, 0x2c, 0x99, 0x24,
+ 0xcb, 0xb5, 0xb4, 0xf8, 0xc6, 0x0a, 0xd0, 0x26, 0xb1, 0x5b, 0xfd,
+ 0x4d, 0x44, 0x66, 0x9d, 0xb0, 0x76, 0xaa, 0x79, 0x9d, 0xc0, 0x5c,
+ 0x3b, 0x94, 0x36, 0xc1, 0x8f, 0xfe, 0xc9, 0xd2, 0x5a, 0x6a, 0xa0,
+ 0x46, 0xe1, 0xa2, 0x8b, 0x2f, 0x51, 0x61, 0x51, 0xa3, 0x36, 0x91,
+ 0x83, 0xb4, 0xfb, 0xcd, 0xa9, 0x40, 0x34, 0x46, 0x98, 0x8a, 0x1a,
+ 0x91, 0xdf, 0xd9, 0x2c, 0x3a, 0xbf, 0x57, 0x3a, 0x46, 0x46, 0x20,
+ 0xf2, 0xf0, 0xbc, 0x31, 0x5e, 0x29, 0xfe, 0x58, 0x90, 0x32, 0x5c,
+ 0x66, 0x97, 0x99, 0x9a, 0x8e, 0x15, 0x23, 0xeb, 0xa9, 0x47, 0xd3,
+ 0x63, 0xc6, 0x18, 0xbb, 0x8e, 0xd2, 0x20, 0x9f, 0x78, 0xaf, 0x71,
+ 0xb3, 0x2e, 0x08, 0x89, 0xa1, 0xf1, 0x7d, 0xb1, 0x30, 0xa0, 0xe6,
+ 0x1b, 0xbd, 0x6e, 0xc8, 0xf6, 0x33, 0xe1, 0xda, 0xb0, 0xbd, 0x16,
+ 0x41, 0xfe, 0x07, 0x6f, 0x6e, 0x97, 0x8b, 0x6a, 0x33, 0xd2, 0xd7,
+ 0x80, 0x03, 0x6a, 0x4d, 0xe7, 0x05, 0x82, 0x28, 0x1f, 0xef, 0x6a,
+ 0xa9, 0x75, 0x7e, 0xe1, 0x4e, 0xe2, 0x95, 0x5b, 0x4f, 0xe6, 0xdc,
+ 0x03, 0xb9, 0x81
+};
+
+const int testkey2048_length = 520;