From ab608f806ee1d7fa63a18cc035e8ea62b67634e5 Mon Sep 17 00:00:00 2001 From: Jason Zhu Date: Mon, 11 Jun 2018 16:52:48 +0800 Subject: [PATCH] lib: avb: update avb source code according to google lib avb commit id: 44e07124afb1f46af0d745d83481f49c482900b1 Change-Id: Ie59a7265699e3e6b1673bb64da6d1c7a1e7b6201 Signed-off-by: Jason Zhu --- include/android_avb/avb_ab_flow.h | 0 include/android_avb/avb_ab_ops.h | 0 include/android_avb/avb_atx_ops.h | 9 + include/android_avb/avb_atx_types.h | 18 + include/android_avb/avb_atx_validate.h | 14 + .../avb_chain_partition_descriptor.h | 0 include/android_avb/avb_cmdline.h | 36 +- include/android_avb/avb_crypto.h | 9 + include/android_avb/avb_descriptor.h | 0 include/android_avb/avb_footer.h | 0 include/android_avb/avb_hash_descriptor.h | 17 +- include/android_avb/avb_hashtree_descriptor.h | 17 +- .../avb_kernel_cmdline_descriptor.h | 0 include/android_avb/avb_ops.h | 64 +++- include/android_avb/avb_ops_user.h | 0 include/android_avb/avb_property_descriptor.h | 0 include/android_avb/avb_rsa.h | 0 include/android_avb/avb_sha.h | 0 include/android_avb/avb_slot_verify.h | 9 + include/android_avb/avb_sysdeps.h | 0 include/android_avb/avb_user_verification.h | 0 include/android_avb/avb_user_verity.h | 0 include/android_avb/avb_util.h | 10 + include/android_avb/avb_vbmeta_image.h | 0 include/android_avb/avb_version.h | 2 +- include/android_avb/libavb.h | 0 include/android_avb/libavb_ab.h | 0 include/android_avb/libavb_atx.h | 0 include/android_avb/libavb_user.h | 0 include/android_avb/rk_avb_ops_user.h | 0 lib/avb/libavb/Kconfig | 0 lib/avb/libavb/Makefile | 0 .../libavb/avb_chain_partition_descriptor.c | 0 lib/avb/libavb/avb_cmdline.c | 123 +++++-- lib/avb/libavb/avb_crc32.c | 0 lib/avb/libavb/avb_crypto.c | 0 lib/avb/libavb/avb_descriptor.c | 0 lib/avb/libavb/avb_footer.c | 0 lib/avb/libavb/avb_hash_descriptor.c | 1 + lib/avb/libavb/avb_hashtree_descriptor.c | 1 + .../libavb/avb_kernel_cmdline_descriptor.c | 0 lib/avb/libavb/avb_property_descriptor.c | 0 lib/avb/libavb/avb_rsa.c | 0 lib/avb/libavb/avb_sha256.c | 0 lib/avb/libavb/avb_sha512.c | 0 lib/avb/libavb/avb_slot_verify.c | 310 +++++++++++++++--- lib/avb/libavb/avb_sysdeps_posix.c | 7 +- lib/avb/libavb/avb_util.c | 27 ++ lib/avb/libavb/avb_vbmeta_image.c | 0 lib/avb/libavb/avb_version.c | 0 lib/avb/libavb_ab/Kconfig | 0 lib/avb/libavb_ab/Makefile | 0 lib/avb/libavb_ab/avb_ab_flow.c | 0 lib/avb/libavb_atx/Kconfig | 0 lib/avb/libavb_atx/Makefile | 0 lib/avb/libavb_atx/avb_atx_validate.c | 169 +++++++++- lib/avb/libavb_user/Kconfig | 0 lib/avb/libavb_user/Makefile | 0 lib/avb/libavb_user/avb_ops_user.c | 0 lib/avb/libavb_user/avb_user_verification.c | 0 lib/avb/libavb_user/avb_user_verity.c | 0 lib/avb/rk_avb_user/Kconfig | 0 lib/avb/rk_avb_user/Makefile | 0 lib/avb/rk_avb_user/rk_avb_ops_user.c | 0 64 files changed, 756 insertions(+), 87 deletions(-) mode change 100644 => 100755 include/android_avb/avb_ab_flow.h mode change 100644 => 100755 include/android_avb/avb_ab_ops.h mode change 100644 => 100755 include/android_avb/avb_atx_ops.h mode change 100644 => 100755 include/android_avb/avb_atx_types.h mode change 100644 => 100755 include/android_avb/avb_atx_validate.h mode change 100644 => 100755 include/android_avb/avb_chain_partition_descriptor.h mode change 100644 => 100755 include/android_avb/avb_cmdline.h mode change 100644 => 100755 include/android_avb/avb_crypto.h mode change 100644 => 100755 include/android_avb/avb_descriptor.h mode change 100644 => 100755 include/android_avb/avb_footer.h mode change 100644 => 100755 include/android_avb/avb_hash_descriptor.h mode change 100644 => 100755 include/android_avb/avb_hashtree_descriptor.h mode change 100644 => 100755 include/android_avb/avb_kernel_cmdline_descriptor.h mode change 100644 => 100755 include/android_avb/avb_ops.h mode change 100644 => 100755 include/android_avb/avb_ops_user.h mode change 100644 => 100755 include/android_avb/avb_property_descriptor.h mode change 100644 => 100755 include/android_avb/avb_rsa.h mode change 100644 => 100755 include/android_avb/avb_sha.h mode change 100644 => 100755 include/android_avb/avb_slot_verify.h mode change 100644 => 100755 include/android_avb/avb_sysdeps.h mode change 100644 => 100755 include/android_avb/avb_user_verification.h mode change 100644 => 100755 include/android_avb/avb_user_verity.h mode change 100644 => 100755 include/android_avb/avb_util.h mode change 100644 => 100755 include/android_avb/avb_vbmeta_image.h mode change 100644 => 100755 include/android_avb/avb_version.h mode change 100644 => 100755 include/android_avb/libavb.h mode change 100644 => 100755 include/android_avb/libavb_ab.h mode change 100644 => 100755 include/android_avb/libavb_atx.h mode change 100644 => 100755 include/android_avb/libavb_user.h mode change 100644 => 100755 include/android_avb/rk_avb_ops_user.h mode change 100644 => 100755 lib/avb/libavb/Kconfig mode change 100644 => 100755 lib/avb/libavb/Makefile mode change 100644 => 100755 lib/avb/libavb/avb_chain_partition_descriptor.c mode change 100644 => 100755 lib/avb/libavb/avb_cmdline.c mode change 100644 => 100755 lib/avb/libavb/avb_crc32.c mode change 100644 => 100755 lib/avb/libavb/avb_crypto.c mode change 100644 => 100755 lib/avb/libavb/avb_descriptor.c mode change 100644 => 100755 lib/avb/libavb/avb_footer.c mode change 100644 => 100755 lib/avb/libavb/avb_hash_descriptor.c mode change 100644 => 100755 lib/avb/libavb/avb_hashtree_descriptor.c mode change 100644 => 100755 lib/avb/libavb/avb_kernel_cmdline_descriptor.c mode change 100644 => 100755 lib/avb/libavb/avb_property_descriptor.c mode change 100644 => 100755 lib/avb/libavb/avb_rsa.c mode change 100644 => 100755 lib/avb/libavb/avb_sha256.c mode change 100644 => 100755 lib/avb/libavb/avb_sha512.c mode change 100644 => 100755 lib/avb/libavb/avb_slot_verify.c mode change 100644 => 100755 lib/avb/libavb/avb_sysdeps_posix.c mode change 100644 => 100755 lib/avb/libavb/avb_util.c mode change 100644 => 100755 lib/avb/libavb/avb_vbmeta_image.c mode change 100644 => 100755 lib/avb/libavb/avb_version.c mode change 100644 => 100755 lib/avb/libavb_ab/Kconfig mode change 100644 => 100755 lib/avb/libavb_ab/Makefile mode change 100644 => 100755 lib/avb/libavb_ab/avb_ab_flow.c mode change 100644 => 100755 lib/avb/libavb_atx/Kconfig mode change 100644 => 100755 lib/avb/libavb_atx/Makefile mode change 100644 => 100755 lib/avb/libavb_atx/avb_atx_validate.c mode change 100644 => 100755 lib/avb/libavb_user/Kconfig mode change 100644 => 100755 lib/avb/libavb_user/Makefile mode change 100644 => 100755 lib/avb/libavb_user/avb_ops_user.c mode change 100644 => 100755 lib/avb/libavb_user/avb_user_verification.c mode change 100644 => 100755 lib/avb/libavb_user/avb_user_verity.c mode change 100644 => 100755 lib/avb/rk_avb_user/Kconfig mode change 100644 => 100755 lib/avb/rk_avb_user/Makefile mode change 100644 => 100755 lib/avb/rk_avb_user/rk_avb_ops_user.c diff --git a/include/android_avb/avb_ab_flow.h b/include/android_avb/avb_ab_flow.h old mode 100644 new mode 100755 diff --git a/include/android_avb/avb_ab_ops.h b/include/android_avb/avb_ab_ops.h old mode 100644 new mode 100755 diff --git a/include/android_avb/avb_atx_ops.h b/include/android_avb/avb_atx_ops.h old mode 100644 new mode 100755 index 726dd6a8a1..a7da29a7dd --- a/include/android_avb/avb_atx_ops.h +++ b/include/android_avb/avb_atx_ops.h @@ -68,6 +68,15 @@ struct AvbAtxOps { void (*set_key_version)(AvbAtxOps* atx_ops, size_t rollback_index_location, uint64_t key_version); + + /* Generates |num_bytes| random bytes and stores them in |output|, + * which must point to a buffer large enough to store the bytes. + * + * Returns AVB_IO_RESULT_OK on success, otherwise an error code. + */ + AvbIOResult (*get_random)(AvbAtxOps* atx_ops, + size_t num_bytes, + uint8_t* output); }; #ifdef __cplusplus diff --git a/include/android_avb/avb_atx_types.h b/include/android_avb/avb_atx_types.h old mode 100644 new mode 100755 index 9b1c36a3c3..6985ac0be8 --- a/include/android_avb/avb_atx_types.h +++ b/include/android_avb/avb_atx_types.h @@ -41,6 +41,9 @@ extern "C" { /* Size in bytes of an Android Things product ID. */ #define AVB_ATX_PRODUCT_ID_SIZE 16 +/* Size in bytes of an Android Things unlock challenge. */ +#define AVB_ATX_UNLOCK_CHALLENGE_SIZE 16 + /* Size in bytes of a serialized public key with a 4096-bit modulus. */ #define AVB_ATX_PUBLIC_KEY_SIZE (sizeof(AvbRSAPublicKeyHeader) + 1024) @@ -73,6 +76,21 @@ typedef struct AvbAtxPublicKeyMetadata { AvbAtxCertificate product_signing_key_certificate; } AVB_ATTR_PACKED AvbAtxPublicKeyMetadata; +/* Data structure of an Android Things unlock challenge. */ +typedef struct AvbAtxUnlockChallenge { + uint32_t version; + uint8_t product_id_hash[AVB_SHA256_DIGEST_SIZE]; + uint8_t challenge[AVB_ATX_UNLOCK_CHALLENGE_SIZE]; +} AVB_ATTR_PACKED AvbAtxUnlockChallenge; + +/* Data structure of an Android Things unlock credential. */ +typedef struct AvbAtxUnlockCredential { + uint32_t version; + AvbAtxCertificate product_intermediate_key_certificate; + AvbAtxCertificate product_unlock_key_certificate; + uint8_t challenge_signature[AVB_RSA4096_NUM_BYTES]; +} AVB_ATTR_PACKED AvbAtxUnlockCredential; + #ifdef __cplusplus } #endif diff --git a/include/android_avb/avb_atx_validate.h b/include/android_avb/avb_atx_validate.h old mode 100644 new mode 100755 index 9989bb1ddb..8f784cd466 --- a/include/android_avb/avb_atx_validate.h +++ b/include/android_avb/avb_atx_validate.h @@ -72,6 +72,20 @@ AvbIOResult avb_atx_validate_vbmeta_public_key( size_t public_key_metadata_length, bool* out_is_trusted); +/* Generates a challenge which can be used to create an unlock credential. */ +AvbIOResult avb_atx_generate_unlock_challenge( + AvbAtxOps* atx_ops, AvbAtxUnlockChallenge* out_unlock_challenge); + +/* Validates an unlock credential. The certificate validation is very similar to + * the validation of public key metadata except in place of the PSK is a Product + * Unlock Key (PUK) and the certificate usage field identifies it as such. The + * challenge signature field is verified against this PUK. + */ +AvbIOResult avb_atx_validate_unlock_credential( + AvbAtxOps* atx_ops, + const AvbAtxUnlockCredential* unlock_credential, + bool* out_is_trusted); + #ifdef __cplusplus } #endif diff --git a/include/android_avb/avb_chain_partition_descriptor.h b/include/android_avb/avb_chain_partition_descriptor.h old mode 100644 new mode 100755 diff --git a/include/android_avb/avb_cmdline.h b/include/android_avb/avb_cmdline.h old mode 100644 new mode 100755 index 717381a3f4..8e5caf61b0 --- a/include/android_avb/avb_cmdline.h +++ b/include/android_avb/avb_cmdline.h @@ -45,12 +45,24 @@ */ #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); +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, @@ -59,4 +71,24 @@ AvbSlotVerifyResult avb_append_options( 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/include/android_avb/avb_crypto.h b/include/android_avb/avb_crypto.h old mode 100644 new mode 100755 index b99a905d70..258a938093 --- a/include/android_avb/avb_crypto.h +++ b/include/android_avb/avb_crypto.h @@ -46,12 +46,21 @@ extern "C" { /* Size of a RSA-8192 signature. */ #define AVB_RSA8192_NUM_BYTES 1024 +/* Size in bytes of a SHA-1 digest. */ +#define AVB_SHA1_DIGEST_SIZE 20 + /* Size in bytes of a SHA-256 digest. */ #define AVB_SHA256_DIGEST_SIZE 32 /* Size in bytes of a SHA-512 digest. */ #define AVB_SHA512_DIGEST_SIZE 64 +/* Possible digest types supported by libavb routines. */ +typedef enum { + AVB_DIGEST_TYPE_SHA256, + AVB_DIGEST_TYPE_SHA512, +} AvbDigestType; + /* Algorithms that can be used in the vbmeta image for * verification. An algorithm consists of a hash type and a signature * type. diff --git a/include/android_avb/avb_descriptor.h b/include/android_avb/avb_descriptor.h old mode 100644 new mode 100755 diff --git a/include/android_avb/avb_footer.h b/include/android_avb/avb_footer.h old mode 100644 new mode 100755 diff --git a/include/android_avb/avb_hash_descriptor.h b/include/android_avb/avb_hash_descriptor.h old mode 100644 new mode 100755 index ef3f27117a..633b2691de --- a/include/android_avb/avb_hash_descriptor.h +++ b/include/android_avb/avb_hash_descriptor.h @@ -37,6 +37,16 @@ extern "C" { #endif +/* Flags for hash descriptors. + * + * AVB_HASH_DESCRIPTOR_FLAGS_DO_NOT_USE_AB: Do not apply the default A/B + * partition logic to this partition. This is intentionally a negative boolean + * because A/B should be both the default and most used in practice. + */ +typedef enum { + AVB_HASH_DESCRIPTOR_FLAGS_DO_NOT_USE_AB = (1 << 0), +} AvbHashDescriptorFlags; + /* A descriptor containing information about hash for an image. * * This descriptor is typically used for boot partitions to verify the @@ -48,6 +58,10 @@ extern "C" { * * The |reserved| field is for future expansion and must be set to NUL * bytes. + * + * Changes in v1.1: + * - flags field is added which supports AVB_HASH_DESCRIPTOR_FLAGS_USE_AB + * - digest_len may be zero, which indicates the use of a persistent digest */ typedef struct AvbHashDescriptor { AvbDescriptor parent_descriptor; @@ -56,7 +70,8 @@ typedef struct AvbHashDescriptor { uint32_t partition_name_len; uint32_t salt_len; uint32_t digest_len; - uint8_t reserved[64]; + uint32_t flags; + uint8_t reserved[60]; } AVB_ATTR_PACKED AvbHashDescriptor; /* Copies |src| to |dest| and validates, byte-swapping fields in the diff --git a/include/android_avb/avb_hashtree_descriptor.h b/include/android_avb/avb_hashtree_descriptor.h old mode 100644 new mode 100755 index d579275e73..e447ebf8aa --- a/include/android_avb/avb_hashtree_descriptor.h +++ b/include/android_avb/avb_hashtree_descriptor.h @@ -37,6 +37,16 @@ extern "C" { #endif +/* Flags for hashtree descriptors. + * + * AVB_HASHTREE_DESCRIPTOR_FLAGS_DO_NOT_USE_AB: Do not apply the default A/B + * partition logic to this partition. This is intentionally a negative boolean + * because A/B should be both the default and most used in practice. + */ +typedef enum { + AVB_HASHTREE_DESCRIPTOR_FLAGS_DO_NOT_USE_AB = (1 << 0), +} AvbHashtreeDescriptorFlags; + /* A descriptor containing information about a dm-verity hashtree. * * Hash-trees are used to verify large partitions typically containing @@ -50,6 +60,10 @@ extern "C" { * * The |reserved| field is for future expansion and must be set to NUL * bytes. + * + * Changes in v1.1: + * - flags field is added which supports AVB_HASHTREE_DESCRIPTOR_FLAGS_USE_AB + * - digest_len may be zero, which indicates the use of a persistent digest */ typedef struct AvbHashtreeDescriptor { AvbDescriptor parent_descriptor; @@ -66,7 +80,8 @@ typedef struct AvbHashtreeDescriptor { uint32_t partition_name_len; uint32_t salt_len; uint32_t root_digest_len; - uint8_t reserved[64]; + uint32_t flags; + uint8_t reserved[60]; } AVB_ATTR_PACKED AvbHashtreeDescriptor; /* Copies |src| to |dest| and validates, byte-swapping fields in the diff --git a/include/android_avb/avb_kernel_cmdline_descriptor.h b/include/android_avb/avb_kernel_cmdline_descriptor.h old mode 100644 new mode 100755 diff --git a/include/android_avb/avb_ops.h b/include/android_avb/avb_ops.h old mode 100644 new mode 100755 index 2a418454d4..f58f18cae8 --- a/include/android_avb/avb_ops.h +++ b/include/android_avb/avb_ops.h @@ -37,6 +37,9 @@ extern "C" { #endif +/* Well-known names of named persistent values. */ +#define AVB_NPV_PERSISTENT_DIGEST_PREFIX "avb.persistent_digest." + /* Return codes used for I/O operations. * * AVB_IO_RESULT_OK is returned if the requested operation was @@ -53,13 +56,25 @@ extern "C" { * AVB_IO_RESULT_ERROR_RANGE_OUTSIDE_PARTITION is returned if the * range of bytes requested to be read or written is outside the range * of the partition. + * + * AVB_IO_RESULT_ERROR_NO_SUCH_VALUE is returned if a named persistent value + * does not exist. + * + * AVB_IO_RESULT_ERROR_INVALID_VALUE_SIZE is returned if a named persistent + * value size is not supported or does not match the expected size. + * + * AVB_IO_RESULT_ERROR_INSUFFICIENT_SPACE is returned if a buffer is too small + * for the requested operation. */ typedef enum { AVB_IO_RESULT_OK, AVB_IO_RESULT_ERROR_OOM, AVB_IO_RESULT_ERROR_IO, AVB_IO_RESULT_ERROR_NO_SUCH_PARTITION, - AVB_IO_RESULT_ERROR_RANGE_OUTSIDE_PARTITION + AVB_IO_RESULT_ERROR_RANGE_OUTSIDE_PARTITION, + AVB_IO_RESULT_ERROR_NO_SUCH_VALUE, + AVB_IO_RESULT_ERROR_INVALID_VALUE_SIZE, + AVB_IO_RESULT_ERROR_INSUFFICIENT_SPACE, } AvbIOResult; struct AvbOps; @@ -247,6 +262,53 @@ struct AvbOps { AvbIOResult (*get_size_of_partition)(AvbOps* ops, const char* partition, uint64_t* out_size_num_bytes); + + /* Reads a persistent value corresponding to the given |name|. The value is + * returned in |out_buffer| which must point to |buffer_size| bytes. On + * success |out_num_bytes_read| contains the number of bytes read into + * |out_buffer|. If AVB_IO_RESULT_ERROR_INSUFFICIENT_SPACE is returned, + * |out_num_bytes_read| contains the number of bytes that would have been read + * which can be used to allocate a buffer. + * + * The |buffer_size| may be zero and the |out_buffer| may be NULL, but if + * |out_buffer| is NULL then |buffer_size| *must* be zero. + * + * Returns AVB_IO_RESULT_OK on success, otherwise an error code. + * + * If the value does not exist, is not supported, or is not populated, returns + * AVB_IO_RESULT_ERROR_NO_SUCH_VALUE. If |buffer_size| is smaller than the + * size of the stored value, returns AVB_IO_RESULT_ERROR_INSUFFICIENT_SPACE. + * + * This operation is currently only used to support persistent digests. If a + * device does not use persistent digests this function pointer can be set to + * NULL. + */ + AvbIOResult (*read_persistent_value)(AvbOps* ops, + const char* name, + size_t buffer_size, + uint8_t* out_buffer, + size_t* out_num_bytes_read); + + /* Writes a persistent value corresponding to the given |name|. The value is + * supplied in |value| which must point to |value_size| bytes. Any existing + * value with the same name is overwritten. If |value_size| is zero, future + * calls to |read_persistent_value| will return + * AVB_IO_RESULT_ERROR_NO_SUCH_VALUE. + * + * Returns AVB_IO_RESULT_OK on success, otherwise an error code. + * + * If the value |name| is not supported, returns + * AVB_IO_RESULT_ERROR_NO_SUCH_VALUE. If the |value_size| is not supported, + * returns AVB_IO_RESULT_ERROR_INVALID_VALUE_SIZE. + * + * This operation is currently only used to support persistent digests. If a + * device does not use persistent digests this function pointer can be set to + * NULL. + */ + AvbIOResult (*write_persistent_value)(AvbOps* ops, + const char* name, + size_t value_size, + const uint8_t* value); }; #ifdef __cplusplus diff --git a/include/android_avb/avb_ops_user.h b/include/android_avb/avb_ops_user.h old mode 100644 new mode 100755 diff --git a/include/android_avb/avb_property_descriptor.h b/include/android_avb/avb_property_descriptor.h old mode 100644 new mode 100755 diff --git a/include/android_avb/avb_rsa.h b/include/android_avb/avb_rsa.h old mode 100644 new mode 100755 diff --git a/include/android_avb/avb_sha.h b/include/android_avb/avb_sha.h old mode 100644 new mode 100755 diff --git a/include/android_avb/avb_slot_verify.h b/include/android_avb/avb_slot_verify.h old mode 100644 new mode 100755 index 1b7932496c..8b40676a6b --- a/include/android_avb/avb_slot_verify.h +++ b/include/android_avb/avb_slot_verify.h @@ -262,6 +262,15 @@ typedef struct { uint64_t rollback_indexes[AVB_MAX_NUMBER_OF_ROLLBACK_INDEX_LOCATIONS]; } AvbSlotVerifyData; +/* Calculates a digest of all vbmeta images in |data| using + * the digest indicated by |digest_type|. Stores the result + * in |out_digest| which must be large enough to hold a digest + * of the requested type. + */ +void avb_slot_verify_data_calculate_vbmeta_digest(AvbSlotVerifyData* data, + AvbDigestType digest_type, + uint8_t* out_digest); + /* Frees a |AvbSlotVerifyData| including all data it points to. */ void avb_slot_verify_data_free(AvbSlotVerifyData* data); diff --git a/include/android_avb/avb_sysdeps.h b/include/android_avb/avb_sysdeps.h old mode 100644 new mode 100755 diff --git a/include/android_avb/avb_user_verification.h b/include/android_avb/avb_user_verification.h old mode 100644 new mode 100755 diff --git a/include/android_avb/avb_user_verity.h b/include/android_avb/avb_user_verity.h old mode 100644 new mode 100755 diff --git a/include/android_avb/avb_util.h b/include/android_avb/avb_util.h old mode 100644 new mode 100755 index d23c961e10..99e94d0ac7 --- a/include/android_avb/avb_util.h +++ b/include/android_avb/avb_util.h @@ -272,6 +272,16 @@ uint32_t avb_crc32(const uint8_t* buf, size_t buf_size); */ const char* avb_basename(const char* str); +/* Converts any ascii lowercase characters in |str| to uppercase in-place. + * |str| must be NUL-terminated and valid UTF-8. + */ +void avb_uppercase(char* str); + +/* Converts |data_len| bytes of |data| to hex and returns the result. Returns + * NULL on OOM. Caller must free the returned string with avb_free. + */ +char* avb_bin2hex(const uint8_t* data, size_t data_len); + #ifdef __cplusplus } #endif diff --git a/include/android_avb/avb_vbmeta_image.h b/include/android_avb/avb_vbmeta_image.h old mode 100644 new mode 100755 diff --git a/include/android_avb/avb_version.h b/include/android_avb/avb_version.h old mode 100644 new mode 100755 index 48e11705a9..9fa509ea45 --- a/include/android_avb/avb_version.h +++ b/include/android_avb/avb_version.h @@ -39,7 +39,7 @@ extern "C" { /* The version number of AVB - keep in sync with avbtool. */ #define AVB_VERSION_MAJOR 1 -#define AVB_VERSION_MINOR 0 +#define AVB_VERSION_MINOR 1 #define AVB_VERSION_SUB 0 /* Returns a NUL-terminated string for the libavb version in use. The diff --git a/include/android_avb/libavb.h b/include/android_avb/libavb.h old mode 100644 new mode 100755 diff --git a/include/android_avb/libavb_ab.h b/include/android_avb/libavb_ab.h old mode 100644 new mode 100755 diff --git a/include/android_avb/libavb_atx.h b/include/android_avb/libavb_atx.h old mode 100644 new mode 100755 diff --git a/include/android_avb/libavb_user.h b/include/android_avb/libavb_user.h old mode 100644 new mode 100755 diff --git a/include/android_avb/rk_avb_ops_user.h b/include/android_avb/rk_avb_ops_user.h old mode 100644 new mode 100755 diff --git a/lib/avb/libavb/Kconfig b/lib/avb/libavb/Kconfig old mode 100644 new mode 100755 diff --git a/lib/avb/libavb/Makefile b/lib/avb/libavb/Makefile old mode 100644 new mode 100755 diff --git a/lib/avb/libavb/avb_chain_partition_descriptor.c b/lib/avb/libavb/avb_chain_partition_descriptor.c old mode 100644 new mode 100755 diff --git a/lib/avb/libavb/avb_cmdline.c b/lib/avb/libavb/avb_cmdline.c old mode 100644 new mode 100755 index ecf582ebd9..a4bb2edc34 --- a/lib/avb/libavb/avb_cmdline.c +++ b/lib/avb/libavb/avb_cmdline.c @@ -33,8 +33,11 @@ * 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) { +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)", @@ -68,7 +71,7 @@ char* avb_sub_cmdline(AvbOps* ops, const char* cmdline, const char* ab_suffix, io_ret = ops->get_unique_guid_for_partition( ops, part_name, guid_buf, sizeof guid_buf); if (io_ret == AVB_IO_RESULT_ERROR_OOM) { - return NULL; + goto fail; } else if (io_ret != AVB_IO_RESULT_OK) { avb_error("Error getting unique GUID for partition.\n"); goto fail; @@ -86,6 +89,22 @@ char* avb_sub_cmdline(AvbOps* ops, const char* cmdline, const char* ab_suffix, } } + 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: @@ -186,22 +205,11 @@ static int cmdline_append_hex(AvbSlotVerifyData* slot_data, const char* key, const uint8_t* data, size_t data_len) { - char hex_digits[17] = "0123456789abcdef"; - char* hex_data; int ret; - size_t n; - - hex_data = avb_malloc(data_len * 2 + 1); + char* hex_data = avb_bin2hex(data, data_len); if (hex_data == NULL) { return 0; } - - for (n = 0; n < data_len; n++) { - hex_data[n * 2] = hex_digits[data[n] >> 4]; - hex_data[n * 2 + 1] = hex_digits[data[n] & 0x0f]; - } - hex_data[n * 2] = '\0'; - ret = cmdline_append_option(slot_data, key, hex_data); avb_free(hex_data); return ret; @@ -261,13 +269,11 @@ AvbSlotVerifyResult avb_append_options( 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); + uint8_t vbmeta_digest[AVB_SHA256_DIGEST_SIZE]; + avb_slot_verify_data_calculate_vbmeta_digest( + slot_data, AVB_DIGEST_TYPE_SHA256, vbmeta_digest); 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( @@ -276,7 +282,7 @@ AvbSlotVerifyResult avb_append_options( slot_data, "androidboot.vbmeta.size", total_size) || !cmdline_append_hex(slot_data, "androidboot.vbmeta.digest", - avb_sha256_final(&ctx), + vbmeta_digest, AVB_SHA256_DIGEST_SIZE)) { ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM; goto out; @@ -286,13 +292,11 @@ AvbSlotVerifyResult avb_append_options( 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); + uint8_t vbmeta_digest[AVB_SHA512_DIGEST_SIZE]; + avb_slot_verify_data_calculate_vbmeta_digest( + slot_data, AVB_DIGEST_TYPE_SHA512, vbmeta_digest); 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( @@ -301,7 +305,7 @@ AvbSlotVerifyResult avb_append_options( slot_data, "androidboot.vbmeta.size", total_size) || !cmdline_append_hex(slot_data, "androidboot.vbmeta.digest", - avb_sha512_final(&ctx), + vbmeta_digest, AVB_SHA512_DIGEST_SIZE)) { ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM; goto out; @@ -369,3 +373,68 @@ 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/avb/libavb/avb_crc32.c b/lib/avb/libavb/avb_crc32.c old mode 100644 new mode 100755 diff --git a/lib/avb/libavb/avb_crypto.c b/lib/avb/libavb/avb_crypto.c old mode 100644 new mode 100755 diff --git a/lib/avb/libavb/avb_descriptor.c b/lib/avb/libavb/avb_descriptor.c old mode 100644 new mode 100755 diff --git a/lib/avb/libavb/avb_footer.c b/lib/avb/libavb/avb_footer.c old mode 100644 new mode 100755 diff --git a/lib/avb/libavb/avb_hash_descriptor.c b/lib/avb/libavb/avb_hash_descriptor.c old mode 100644 new mode 100755 index 294f3d648e..ef9921a20c --- a/lib/avb/libavb/avb_hash_descriptor.c +++ b/lib/avb/libavb/avb_hash_descriptor.c @@ -44,6 +44,7 @@ bool avb_hash_descriptor_validate_and_byteswap(const AvbHashDescriptor* src, 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); diff --git a/lib/avb/libavb/avb_hashtree_descriptor.c b/lib/avb/libavb/avb_hashtree_descriptor.c old mode 100644 new mode 100755 index 0e95e8762d..19de1e3d70 --- a/lib/avb/libavb/avb_hashtree_descriptor.c +++ b/lib/avb/libavb/avb_hashtree_descriptor.c @@ -52,6 +52,7 @@ bool avb_hashtree_descriptor_validate_and_byteswap( 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); diff --git a/lib/avb/libavb/avb_kernel_cmdline_descriptor.c b/lib/avb/libavb/avb_kernel_cmdline_descriptor.c old mode 100644 new mode 100755 diff --git a/lib/avb/libavb/avb_property_descriptor.c b/lib/avb/libavb/avb_property_descriptor.c old mode 100644 new mode 100755 diff --git a/lib/avb/libavb/avb_rsa.c b/lib/avb/libavb/avb_rsa.c old mode 100644 new mode 100755 diff --git a/lib/avb/libavb/avb_sha256.c b/lib/avb/libavb/avb_sha256.c old mode 100644 new mode 100755 diff --git a/lib/avb/libavb/avb_sha512.c b/lib/avb/libavb/avb_sha512.c old mode 100644 new mode 100755 diff --git a/lib/avb/libavb/avb_slot_verify.c b/lib/avb/libavb/avb_slot_verify.c old mode 100644 new mode 100755 index 972fda0e9c..d6a843853f --- a/lib/avb/libavb/avb_slot_verify.c +++ b/lib/avb/libavb/avb_slot_verify.c @@ -27,6 +27,7 @@ #include #include #include +#include #include #include #include @@ -65,10 +66,11 @@ static inline bool result_should_continue(AvbSlotVerifyResult result) { 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) { +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; @@ -110,9 +112,12 @@ static AvbSlotVerifyResult load_full_partition( 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); + 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) { @@ -128,6 +133,47 @@ static AvbSlotVerifyResult load_full_partition( 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, @@ -148,6 +194,9 @@ static AvbSlotVerifyResult load_and_verify_hash_partition( size_t digest_len; const char* found; uint64_t image_size = 0; + 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)) { @@ -177,15 +226,35 @@ static AvbSlotVerifyResult load_and_verify_hash_partition( goto out; } - if (!avb_str_concat(part_name, - sizeof part_name, - (const char*)desc_partition_name, - hash_desc.partition_name_len, - ab_suffix, - avb_strlen(ab_suffix))) { - avb_error("Partition name and suffix does not fit.\n"); + 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 @@ -244,14 +313,31 @@ static AvbSlotVerifyResult load_and_verify_hash_partition( goto out; } - if (digest_len != hash_desc.digest_len) { + 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, desc_digest, digest_len) != 0) { + 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); @@ -352,7 +438,7 @@ static AvbSlotVerifyResult load_requested_partitions( goto out; } loaded_partition->data_size = image_size; - loaded_partition->data = image_buf; /* Transferring the owner. */ + loaded_partition->data = image_buf; /* Transferring the owner. */ loaded_partition->preloaded = image_preloaded; image_buf = NULL; image_preloaded = false; @@ -382,7 +468,8 @@ static AvbSlotVerifyResult load_and_verify_vbmeta( const uint8_t* expected_public_key, size_t expected_public_key_length, AvbSlotVerifyData* slot_data, - AvbAlgorithmType* out_algorithm_type) { + AvbAlgorithmType* out_algorithm_type, + AvbCmdlineSubstList* out_additional_cmdline_subst) { char full_partition_name[AVB_PART_NAME_MAX_SIZE]; AvbSlotVerifyResult ret; AvbIOResult io_ret; @@ -518,7 +605,8 @@ static AvbSlotVerifyResult load_and_verify_vbmeta( NULL /* expected_public_key */, 0 /* expected_public_key_length */, slot_data, - out_algorithm_type); + out_algorithm_type, + out_additional_cmdline_subst); goto out; } else { avb_errorv(full_partition_name, ": Error loading vbmeta data.\n", NULL); @@ -714,7 +802,8 @@ static AvbSlotVerifyResult load_and_verify_vbmeta( * checks that it matches what's in the hash descriptor. * * - hashtree descriptor: Do nothing since verification happens - * on-the-fly from within the OS. + * 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 @@ -785,18 +874,20 @@ static AvbSlotVerifyResult load_and_verify_vbmeta( 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 */); + 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)) { @@ -882,9 +973,90 @@ static AvbSlotVerifyResult load_and_verify_vbmeta( } } break; - /* Explicit fall-through */ + 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: - case AVB_DESCRIPTOR_TAG_HASHTREE: /* Do nothing. */ break; } @@ -932,6 +1104,7 @@ AvbSlotVerifyResult avb_slot_verify(AvbOps* ops, 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. * @@ -976,6 +1149,12 @@ AvbSlotVerifyResult avb_slot_verify(AvbOps* ops, 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, @@ -987,7 +1166,8 @@ AvbSlotVerifyResult avb_slot_verify(AvbOps* ops, NULL /* expected_public_key */, 0 /* expected_public_key_length */, slot_data, - &algorithm_type); + &algorithm_type, + additional_cmdline_subst); if (!allow_verification_error && ret != AVB_SLOT_VERIFY_RESULT_OK) { goto fail; } @@ -1032,9 +1212,11 @@ AvbSlotVerifyResult avb_slot_verify(AvbOps* ops, /* 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); + 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; @@ -1044,8 +1226,11 @@ AvbSlotVerifyResult avb_slot_verify(AvbOps* ops, /* 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); + 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; @@ -1063,6 +1248,9 @@ AvbSlotVerifyResult avb_slot_verify(AvbOps* ops, } } + avb_free_cmdline_subst_list(additional_cmdline_subst); + additional_cmdline_subst = NULL; + if (!allow_verification_error) { avb_assert(ret == AVB_SLOT_VERIFY_RESULT_OK); } @@ -1073,6 +1261,9 @@ 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; } @@ -1153,3 +1344,42 @@ const char* avb_slot_verify_result_to_string(AvbSlotVerifyResult result) { return ret; } + +void avb_slot_verify_data_calculate_vbmeta_digest(AvbSlotVerifyData* data, + AvbDigestType digest_type, + uint8_t* out_digest) { + bool ret = false; + size_t n; + + switch (digest_type) { + case AVB_DIGEST_TYPE_SHA256: { + AvbSHA256Ctx ctx; + avb_sha256_init(&ctx); + for (n = 0; n < data->num_vbmeta_images; n++) { + avb_sha256_update(&ctx, + data->vbmeta_images[n].vbmeta_data, + data->vbmeta_images[n].vbmeta_size); + } + avb_memcpy(out_digest, avb_sha256_final(&ctx), AVB_SHA256_DIGEST_SIZE); + ret = true; + } break; + + case AVB_DIGEST_TYPE_SHA512: { + AvbSHA512Ctx ctx; + avb_sha512_init(&ctx); + for (n = 0; n < data->num_vbmeta_images; n++) { + avb_sha512_update(&ctx, + data->vbmeta_images[n].vbmeta_data, + data->vbmeta_images[n].vbmeta_size); + } + avb_memcpy(out_digest, avb_sha512_final(&ctx), AVB_SHA512_DIGEST_SIZE); + ret = true; + } break; + + /* Do not add a 'default:' case here because of -Wswitch. */ + } + + if (!ret) { + avb_fatal("Unknown digest type"); + } +} diff --git a/lib/avb/libavb/avb_sysdeps_posix.c b/lib/avb/libavb/avb_sysdeps_posix.c old mode 100644 new mode 100755 index 9df018f7c8..638ce9867a --- a/lib/avb/libavb/avb_sysdeps_posix.c +++ b/lib/avb/libavb/avb_sysdeps_posix.c @@ -22,6 +22,7 @@ * SOFTWARE. */ +#include #include #include #include @@ -31,8 +32,10 @@ #include -void abort(void); - +void abort(void) +{ + +} int avb_memcmp(const void* src1, const void* src2, size_t n) { return memcmp(src1, src2, n); } diff --git a/lib/avb/libavb/avb_util.c b/lib/avb/libavb/avb_util.c old mode 100644 new mode 100755 index 434cb39e2b..7b2053b5bd --- a/lib/avb/libavb/avb_util.c +++ b/lib/avb/libavb/avb_util.c @@ -401,3 +401,30 @@ const char* avb_basename(const char* str) { } 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/avb/libavb/avb_vbmeta_image.c b/lib/avb/libavb/avb_vbmeta_image.c old mode 100644 new mode 100755 diff --git a/lib/avb/libavb/avb_version.c b/lib/avb/libavb/avb_version.c old mode 100644 new mode 100755 diff --git a/lib/avb/libavb_ab/Kconfig b/lib/avb/libavb_ab/Kconfig old mode 100644 new mode 100755 diff --git a/lib/avb/libavb_ab/Makefile b/lib/avb/libavb_ab/Makefile old mode 100644 new mode 100755 diff --git a/lib/avb/libavb_ab/avb_ab_flow.c b/lib/avb/libavb_ab/avb_ab_flow.c old mode 100644 new mode 100755 diff --git a/lib/avb/libavb_atx/Kconfig b/lib/avb/libavb_atx/Kconfig old mode 100644 new mode 100755 diff --git a/lib/avb/libavb_atx/Makefile b/lib/avb/libavb_atx/Makefile old mode 100644 new mode 100755 diff --git a/lib/avb/libavb_atx/avb_atx_validate.c b/lib/avb/libavb_atx/avb_atx_validate.c old mode 100644 new mode 100755 index e0f205a728..74a34fd0fd --- a/lib/avb/libavb_atx/avb_atx_validate.c +++ b/lib/avb/libavb_atx/avb_atx_validate.c @@ -29,6 +29,9 @@ #include #include +/* The most recent unlock challenge generated. */ +static uint8_t last_unlock_challenge[AVB_ATX_UNLOCK_CHALLENGE_SIZE]; + /* Computes the SHA256 |hash| of |length| bytes of |data|. */ static void sha256(const uint8_t* data, uint32_t length, @@ -59,7 +62,7 @@ static void sha256_str(const char* str, uint8_t hash[AVB_SHA256_DIGEST_SIZE]) { /* Verifies structure and |expected_hash| of permanent |attributes|. */ static bool verify_permanent_attributes( const AvbAtxPermanentAttributes* attributes, - uint8_t expected_hash[AVB_SHA256_DIGEST_SIZE]) { + const uint8_t expected_hash[AVB_SHA256_DIGEST_SIZE]) { uint8_t hash[AVB_SHA256_DIGEST_SIZE]; if (attributes->version != 1) { @@ -75,10 +78,11 @@ static bool verify_permanent_attributes( } /* Verifies the format, key version, usage, and signature of a certificate. */ -static bool verify_certificate(AvbAtxCertificate* certificate, - uint8_t authority[AVB_ATX_PUBLIC_KEY_SIZE], - uint64_t minimum_key_version, - uint8_t expected_usage[AVB_SHA256_DIGEST_SIZE]) { +static bool verify_certificate( + const AvbAtxCertificate* certificate, + const uint8_t authority[AVB_ATX_PUBLIC_KEY_SIZE], + uint64_t minimum_key_version, + const uint8_t expected_usage[AVB_SHA256_DIGEST_SIZE]) { const AvbAlgorithmData* algorithm_data; uint8_t certificate_hash[AVB_SHA512_DIGEST_SIZE]; @@ -115,9 +119,10 @@ static bool verify_certificate(AvbAtxCertificate* certificate, } /* Verifies signature and fields of a PIK certificate. */ -static bool verify_pik_certificate(AvbAtxCertificate* certificate, - uint8_t authority[AVB_ATX_PUBLIC_KEY_SIZE], - uint64_t minimum_version) { +static bool verify_pik_certificate( + const AvbAtxCertificate* certificate, + const uint8_t authority[AVB_ATX_PUBLIC_KEY_SIZE], + uint64_t minimum_version) { uint8_t expected_usage[AVB_SHA256_DIGEST_SIZE]; sha256_str("com.google.android.things.vboot.ca", expected_usage); @@ -131,10 +136,10 @@ static bool verify_pik_certificate(AvbAtxCertificate* certificate, /* Verifies signature and fields of a PSK certificate. */ static bool verify_psk_certificate( - AvbAtxCertificate* certificate, - uint8_t authority[AVB_ATX_PUBLIC_KEY_SIZE], + const AvbAtxCertificate* certificate, + const uint8_t authority[AVB_ATX_PUBLIC_KEY_SIZE], uint64_t minimum_version, - uint8_t product_id[AVB_ATX_PRODUCT_ID_SIZE]) { + const uint8_t product_id[AVB_ATX_PRODUCT_ID_SIZE]) { uint8_t expected_subject[AVB_SHA256_DIGEST_SIZE]; uint8_t expected_usage[AVB_SHA256_DIGEST_SIZE]; @@ -148,7 +153,32 @@ static bool verify_psk_certificate( if (0 != avb_safe_memcmp(certificate->signed_data.subject, expected_subject, AVB_SHA256_DIGEST_SIZE)) { - avb_error("Product ID mismatch.\n"); + avb_error("PSK: Product ID mismatch.\n"); + return false; + } + return true; +} + +/* Verifies signature and fields of a PUK certificate. */ +static bool verify_puk_certificate( + const AvbAtxCertificate* certificate, + const uint8_t authority[AVB_ATX_PUBLIC_KEY_SIZE], + uint64_t minimum_version, + const uint8_t product_id[AVB_ATX_PRODUCT_ID_SIZE]) { + uint8_t expected_subject[AVB_SHA256_DIGEST_SIZE]; + uint8_t expected_usage[AVB_SHA256_DIGEST_SIZE]; + + sha256_str("com.google.android.things.vboot.unlock", expected_usage); + if (!verify_certificate( + certificate, authority, minimum_version, expected_usage)) { + avb_error("Invalid PUK certificate.\n"); + return false; + } + sha256(product_id, AVB_ATX_PRODUCT_ID_SIZE, expected_subject); + if (0 != avb_safe_memcmp(certificate->signed_data.subject, + expected_subject, + AVB_SHA256_DIGEST_SIZE)) { + avb_error("PUK: Product ID mismatch.\n"); return false; } return true; @@ -254,3 +284,118 @@ AvbIOResult avb_atx_validate_vbmeta_public_key( *out_is_trusted = true; return AVB_IO_RESULT_OK; } + +AvbIOResult avb_atx_generate_unlock_challenge( + AvbAtxOps* atx_ops, AvbAtxUnlockChallenge* out_unlock_challenge) { + AvbIOResult result = AVB_IO_RESULT_OK; + AvbAtxPermanentAttributes permanent_attributes; + + /* We need the permanent attributes to compute the product_id_hash. */ + result = atx_ops->read_permanent_attributes(atx_ops, &permanent_attributes); + if (result != AVB_IO_RESULT_OK) { + avb_error("Failed to read permanent attributes.\n"); + return result; + } + result = atx_ops->get_random( + atx_ops, AVB_ATX_UNLOCK_CHALLENGE_SIZE, last_unlock_challenge); + if (result != AVB_IO_RESULT_OK) { + avb_error("Failed to generate random challenge.\n"); + return result; + } + out_unlock_challenge->version = 1; + sha256(permanent_attributes.product_id, + AVB_ATX_PRODUCT_ID_SIZE, + out_unlock_challenge->product_id_hash); + avb_memcpy(out_unlock_challenge->challenge, + last_unlock_challenge, + AVB_ATX_UNLOCK_CHALLENGE_SIZE); + return result; +} + +AvbIOResult avb_atx_validate_unlock_credential( + AvbAtxOps* atx_ops, + const AvbAtxUnlockCredential* unlock_credential, + bool* out_is_trusted) { + AvbIOResult result = AVB_IO_RESULT_OK; + AvbAtxPermanentAttributes permanent_attributes; + uint8_t permanent_attributes_hash[AVB_SHA256_DIGEST_SIZE]; + uint64_t minimum_version; + const AvbAlgorithmData* algorithm_data; + uint8_t challenge_hash[AVB_SHA512_DIGEST_SIZE]; + + /* Be pessimistic so we can exit early without having to remember to clear. + */ + *out_is_trusted = false; + + /* Sanity check the credential. */ + if (unlock_credential->version != 1) { + avb_error("Unsupported unlock credential format.\n"); + return AVB_IO_RESULT_OK; + } + + /* Read and verify permanent attributes. */ + result = atx_ops->read_permanent_attributes(atx_ops, &permanent_attributes); + if (result != AVB_IO_RESULT_OK) { + avb_error("Failed to read permanent attributes.\n"); + return result; + } + result = atx_ops->read_permanent_attributes_hash(atx_ops, + permanent_attributes_hash); + if (result != AVB_IO_RESULT_OK) { + avb_error("Failed to read permanent attributes hash.\n"); + return result; + } + if (!verify_permanent_attributes(&permanent_attributes, + permanent_attributes_hash)) { + return AVB_IO_RESULT_OK; + } + + /* Verify the PIK certificate. */ + result = atx_ops->ops->read_rollback_index( + atx_ops->ops, AVB_ATX_PIK_VERSION_LOCATION, &minimum_version); + if (result != AVB_IO_RESULT_OK) { + avb_error("Failed to read PIK minimum version.\n"); + return result; + } + if (!verify_pik_certificate( + &unlock_credential->product_intermediate_key_certificate, + permanent_attributes.product_root_public_key, + minimum_version)) { + return AVB_IO_RESULT_OK; + } + + /* Verify the PUK certificate. The minimum version is shared with the PSK. */ + result = atx_ops->ops->read_rollback_index( + atx_ops->ops, AVB_ATX_PSK_VERSION_LOCATION, &minimum_version); + if (result != AVB_IO_RESULT_OK) { + avb_error("Failed to read PSK minimum version.\n"); + return result; + } + if (!verify_puk_certificate( + &unlock_credential->product_unlock_key_certificate, + unlock_credential->product_intermediate_key_certificate.signed_data + .public_key, + minimum_version, + permanent_attributes.product_id)) { + return AVB_IO_RESULT_OK; + } + + /* Verify the challenge signature. */ + algorithm_data = avb_get_algorithm_data(AVB_ALGORITHM_TYPE_SHA512_RSA4096); + sha512(last_unlock_challenge, AVB_ATX_UNLOCK_CHALLENGE_SIZE, challenge_hash); + if (!avb_rsa_verify(unlock_credential->product_unlock_key_certificate + .signed_data.public_key, + AVB_ATX_PUBLIC_KEY_SIZE, + unlock_credential->challenge_signature, + AVB_RSA4096_NUM_BYTES, + challenge_hash, + AVB_SHA512_DIGEST_SIZE, + algorithm_data->padding, + algorithm_data->padding_len)) { + avb_error("Invalid unlock challenge signature.\n"); + return AVB_IO_RESULT_OK; + } + + *out_is_trusted = true; + return AVB_IO_RESULT_OK; +} diff --git a/lib/avb/libavb_user/Kconfig b/lib/avb/libavb_user/Kconfig old mode 100644 new mode 100755 diff --git a/lib/avb/libavb_user/Makefile b/lib/avb/libavb_user/Makefile old mode 100644 new mode 100755 diff --git a/lib/avb/libavb_user/avb_ops_user.c b/lib/avb/libavb_user/avb_ops_user.c old mode 100644 new mode 100755 diff --git a/lib/avb/libavb_user/avb_user_verification.c b/lib/avb/libavb_user/avb_user_verification.c old mode 100644 new mode 100755 diff --git a/lib/avb/libavb_user/avb_user_verity.c b/lib/avb/libavb_user/avb_user_verity.c old mode 100644 new mode 100755 diff --git a/lib/avb/rk_avb_user/Kconfig b/lib/avb/rk_avb_user/Kconfig old mode 100644 new mode 100755 diff --git a/lib/avb/rk_avb_user/Makefile b/lib/avb/rk_avb_user/Makefile old mode 100644 new mode 100755 diff --git a/lib/avb/rk_avb_user/rk_avb_ops_user.c b/lib/avb/rk_avb_user/rk_avb_ops_user.c old mode 100644 new mode 100755