137a7bc39SJason Zhu /* 237a7bc39SJason Zhu * Copyright (C) 2016 The Android Open Source Project 337a7bc39SJason Zhu * 437a7bc39SJason Zhu * Permission is hereby granted, free of charge, to any person 537a7bc39SJason Zhu * obtaining a copy of this software and associated documentation 637a7bc39SJason Zhu * files (the "Software"), to deal in the Software without 737a7bc39SJason Zhu * restriction, including without limitation the rights to use, copy, 837a7bc39SJason Zhu * modify, merge, publish, distribute, sublicense, and/or sell copies 937a7bc39SJason Zhu * of the Software, and to permit persons to whom the Software is 1037a7bc39SJason Zhu * furnished to do so, subject to the following conditions: 1137a7bc39SJason Zhu * 1237a7bc39SJason Zhu * The above copyright notice and this permission notice shall be 1337a7bc39SJason Zhu * included in all copies or substantial portions of the Software. 1437a7bc39SJason Zhu * 1537a7bc39SJason Zhu * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 1637a7bc39SJason Zhu * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 1737a7bc39SJason Zhu * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 1837a7bc39SJason Zhu * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 1937a7bc39SJason Zhu * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 2037a7bc39SJason Zhu * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 2137a7bc39SJason Zhu * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 2237a7bc39SJason Zhu * SOFTWARE. 2337a7bc39SJason Zhu */ 2437a7bc39SJason Zhu 2537a7bc39SJason Zhu #include <android_avb/avb_vbmeta_image.h> 2637a7bc39SJason Zhu #include <android_avb/avb_crypto.h> 2737a7bc39SJason Zhu #include <android_avb/avb_rsa.h> 2837a7bc39SJason Zhu #include <android_avb/avb_sha.h> 2937a7bc39SJason Zhu #include <android_avb/avb_util.h> 3037a7bc39SJason Zhu #include <android_avb/avb_version.h> 3137a7bc39SJason Zhu 3237a7bc39SJason Zhu AvbVBMetaVerifyResult avb_vbmeta_image_verify( 3337a7bc39SJason Zhu const uint8_t* data, 3437a7bc39SJason Zhu size_t length, 3537a7bc39SJason Zhu const uint8_t** out_public_key_data, 3637a7bc39SJason Zhu size_t* out_public_key_length) { 3737a7bc39SJason Zhu AvbVBMetaVerifyResult ret; 3837a7bc39SJason Zhu AvbVBMetaImageHeader h; 3937a7bc39SJason Zhu uint8_t* computed_hash; 4037a7bc39SJason Zhu const AvbAlgorithmData* algorithm; 4137a7bc39SJason Zhu AvbSHA256Ctx sha256_ctx; 4237a7bc39SJason Zhu AvbSHA512Ctx sha512_ctx; 4337a7bc39SJason Zhu const uint8_t* header_block; 4437a7bc39SJason Zhu const uint8_t* authentication_block; 4537a7bc39SJason Zhu const uint8_t* auxiliary_block; 4637a7bc39SJason Zhu int verification_result; 4737a7bc39SJason Zhu 4837a7bc39SJason Zhu ret = AVB_VBMETA_VERIFY_RESULT_INVALID_VBMETA_HEADER; 4937a7bc39SJason Zhu 5037a7bc39SJason Zhu if (out_public_key_data != NULL) { 5137a7bc39SJason Zhu *out_public_key_data = NULL; 5237a7bc39SJason Zhu } 5337a7bc39SJason Zhu if (out_public_key_length != NULL) { 5437a7bc39SJason Zhu *out_public_key_length = 0; 5537a7bc39SJason Zhu } 5637a7bc39SJason Zhu 57*69fdc596SJason Zhu /* Before we byteswap or compare Magic, ensure length is long enough. */ 58*69fdc596SJason Zhu if (length < sizeof(AvbVBMetaImageHeader)) { 59*69fdc596SJason Zhu avb_error("Length is smaller than header.\n"); 60*69fdc596SJason Zhu goto out; 61*69fdc596SJason Zhu } 62*69fdc596SJason Zhu 6337a7bc39SJason Zhu /* Ensure magic is correct. */ 6437a7bc39SJason Zhu if (avb_safe_memcmp(data, AVB_MAGIC, AVB_MAGIC_LEN) != 0) { 6537a7bc39SJason Zhu avb_error("Magic is incorrect.\n"); 6637a7bc39SJason Zhu goto out; 6737a7bc39SJason Zhu } 6837a7bc39SJason Zhu 6937a7bc39SJason Zhu avb_vbmeta_image_header_to_host_byte_order((const AvbVBMetaImageHeader*)data, 7037a7bc39SJason Zhu &h); 7137a7bc39SJason Zhu 7237a7bc39SJason Zhu /* Ensure we don't attempt to access any fields if we do not meet 7337a7bc39SJason Zhu * the specified minimum version of libavb. 7437a7bc39SJason Zhu */ 7537a7bc39SJason Zhu if ((h.required_libavb_version_major != AVB_VERSION_MAJOR) || 7637a7bc39SJason Zhu (h.required_libavb_version_minor > AVB_VERSION_MINOR)) { 7737a7bc39SJason Zhu avb_error("Mismatch between image version and libavb version.\n"); 7837a7bc39SJason Zhu ret = AVB_VBMETA_VERIFY_RESULT_UNSUPPORTED_VERSION; 7937a7bc39SJason Zhu goto out; 8037a7bc39SJason Zhu } 8137a7bc39SJason Zhu 8237a7bc39SJason Zhu /* Ensure |release_string| ends with a NUL byte. */ 8337a7bc39SJason Zhu if (h.release_string[AVB_RELEASE_STRING_SIZE - 1] != '\0') { 8437a7bc39SJason Zhu avb_error("Release string does not end with a NUL byte.\n"); 8537a7bc39SJason Zhu goto out; 8637a7bc39SJason Zhu } 8737a7bc39SJason Zhu 8837a7bc39SJason Zhu /* Ensure inner block sizes are multiple of 64. */ 8937a7bc39SJason Zhu if ((h.authentication_data_block_size & 0x3f) != 0 || 9037a7bc39SJason Zhu (h.auxiliary_data_block_size & 0x3f) != 0) { 9137a7bc39SJason Zhu avb_error("Block size is not a multiple of 64.\n"); 9237a7bc39SJason Zhu goto out; 9337a7bc39SJason Zhu } 9437a7bc39SJason Zhu 9537a7bc39SJason Zhu /* Ensure block sizes all add up to at most |length|. */ 9637a7bc39SJason Zhu uint64_t block_total = sizeof(AvbVBMetaImageHeader); 9737a7bc39SJason Zhu if (!avb_safe_add_to(&block_total, h.authentication_data_block_size) || 9837a7bc39SJason Zhu !avb_safe_add_to(&block_total, h.auxiliary_data_block_size)) { 9937a7bc39SJason Zhu avb_error("Overflow while computing size of boot image.\n"); 10037a7bc39SJason Zhu goto out; 10137a7bc39SJason Zhu } 10237a7bc39SJason Zhu if (block_total > length) { 10337a7bc39SJason Zhu avb_error("Block sizes add up to more than given length.\n"); 10437a7bc39SJason Zhu goto out; 10537a7bc39SJason Zhu } 10637a7bc39SJason Zhu 10737a7bc39SJason Zhu uintptr_t data_ptr = (uintptr_t)data; 10837a7bc39SJason Zhu /* Ensure passed in memory doesn't wrap. */ 10937a7bc39SJason Zhu if (!avb_safe_add(NULL, (uint64_t)data_ptr, length)) { 11037a7bc39SJason Zhu avb_error("Boot image location and length mismatch.\n"); 11137a7bc39SJason Zhu goto out; 11237a7bc39SJason Zhu } 11337a7bc39SJason Zhu 11437a7bc39SJason Zhu /* Ensure hash and signature are entirely in the Authentication data block. */ 11537a7bc39SJason Zhu uint64_t hash_end; 11637a7bc39SJason Zhu if (!avb_safe_add(&hash_end, h.hash_offset, h.hash_size) || 11737a7bc39SJason Zhu hash_end > h.authentication_data_block_size) { 11837a7bc39SJason Zhu avb_error("Hash is not entirely in its block.\n"); 11937a7bc39SJason Zhu goto out; 12037a7bc39SJason Zhu } 12137a7bc39SJason Zhu uint64_t signature_end; 12237a7bc39SJason Zhu if (!avb_safe_add(&signature_end, h.signature_offset, h.signature_size) || 12337a7bc39SJason Zhu signature_end > h.authentication_data_block_size) { 12437a7bc39SJason Zhu avb_error("Signature is not entirely in its block.\n"); 12537a7bc39SJason Zhu goto out; 12637a7bc39SJason Zhu } 12737a7bc39SJason Zhu 12837a7bc39SJason Zhu /* Ensure public key is entirely in the Auxiliary data block. */ 12937a7bc39SJason Zhu uint64_t pubkey_end; 13037a7bc39SJason Zhu if (!avb_safe_add(&pubkey_end, h.public_key_offset, h.public_key_size) || 13137a7bc39SJason Zhu pubkey_end > h.auxiliary_data_block_size) { 13237a7bc39SJason Zhu avb_error("Public key is not entirely in its block.\n"); 13337a7bc39SJason Zhu goto out; 13437a7bc39SJason Zhu } 13537a7bc39SJason Zhu 13637a7bc39SJason Zhu /* Ensure public key metadata (if set) is entirely in the Auxiliary 13737a7bc39SJason Zhu * data block. */ 13837a7bc39SJason Zhu if (h.public_key_metadata_size > 0) { 13937a7bc39SJason Zhu uint64_t pubkey_md_end; 14037a7bc39SJason Zhu if (!avb_safe_add(&pubkey_md_end, 14137a7bc39SJason Zhu h.public_key_metadata_offset, 14237a7bc39SJason Zhu h.public_key_metadata_size) || 14337a7bc39SJason Zhu pubkey_md_end > h.auxiliary_data_block_size) { 14437a7bc39SJason Zhu avb_error("Public key metadata is not entirely in its block.\n"); 14537a7bc39SJason Zhu goto out; 14637a7bc39SJason Zhu } 14737a7bc39SJason Zhu } 14837a7bc39SJason Zhu 14937a7bc39SJason Zhu /* Bail early if there's no hash or signature. */ 15037a7bc39SJason Zhu if (h.algorithm_type == AVB_ALGORITHM_TYPE_NONE) { 15137a7bc39SJason Zhu ret = AVB_VBMETA_VERIFY_RESULT_OK_NOT_SIGNED; 15237a7bc39SJason Zhu goto out; 15337a7bc39SJason Zhu } 15437a7bc39SJason Zhu 15537a7bc39SJason Zhu /* Ensure algorithm field is supported. */ 15637a7bc39SJason Zhu algorithm = avb_get_algorithm_data(h.algorithm_type); 15737a7bc39SJason Zhu if (!algorithm) { 15837a7bc39SJason Zhu avb_error("Invalid or unknown algorithm.\n"); 15937a7bc39SJason Zhu goto out; 16037a7bc39SJason Zhu } 16137a7bc39SJason Zhu 16237a7bc39SJason Zhu /* Bail if the embedded hash size doesn't match the chosen algorithm. */ 16337a7bc39SJason Zhu if (h.hash_size != algorithm->hash_len) { 16437a7bc39SJason Zhu avb_error("Embedded hash has wrong size.\n"); 16537a7bc39SJason Zhu goto out; 16637a7bc39SJason Zhu } 16737a7bc39SJason Zhu 16837a7bc39SJason Zhu /* No overflow checks needed from here-on after since all block 16937a7bc39SJason Zhu * sizes and offsets have been verified above. 17037a7bc39SJason Zhu */ 17137a7bc39SJason Zhu 17237a7bc39SJason Zhu header_block = data; 17337a7bc39SJason Zhu authentication_block = header_block + sizeof(AvbVBMetaImageHeader); 17437a7bc39SJason Zhu auxiliary_block = authentication_block + h.authentication_data_block_size; 17537a7bc39SJason Zhu 17637a7bc39SJason Zhu switch (h.algorithm_type) { 17737a7bc39SJason Zhu /* Explicit fall-through: */ 17837a7bc39SJason Zhu case AVB_ALGORITHM_TYPE_SHA256_RSA2048: 17937a7bc39SJason Zhu case AVB_ALGORITHM_TYPE_SHA256_RSA4096: 18037a7bc39SJason Zhu case AVB_ALGORITHM_TYPE_SHA256_RSA8192: 18137a7bc39SJason Zhu avb_sha256_init(&sha256_ctx); 18237a7bc39SJason Zhu avb_sha256_update( 18337a7bc39SJason Zhu &sha256_ctx, header_block, sizeof(AvbVBMetaImageHeader)); 18437a7bc39SJason Zhu avb_sha256_update( 18537a7bc39SJason Zhu &sha256_ctx, auxiliary_block, h.auxiliary_data_block_size); 18637a7bc39SJason Zhu computed_hash = avb_sha256_final(&sha256_ctx); 18737a7bc39SJason Zhu break; 18837a7bc39SJason Zhu /* Explicit fall-through: */ 18937a7bc39SJason Zhu case AVB_ALGORITHM_TYPE_SHA512_RSA2048: 19037a7bc39SJason Zhu case AVB_ALGORITHM_TYPE_SHA512_RSA4096: 19137a7bc39SJason Zhu case AVB_ALGORITHM_TYPE_SHA512_RSA8192: 19237a7bc39SJason Zhu avb_sha512_init(&sha512_ctx); 19337a7bc39SJason Zhu avb_sha512_update( 19437a7bc39SJason Zhu &sha512_ctx, header_block, sizeof(AvbVBMetaImageHeader)); 19537a7bc39SJason Zhu avb_sha512_update( 19637a7bc39SJason Zhu &sha512_ctx, auxiliary_block, h.auxiliary_data_block_size); 19737a7bc39SJason Zhu computed_hash = avb_sha512_final(&sha512_ctx); 19837a7bc39SJason Zhu break; 19937a7bc39SJason Zhu default: 20037a7bc39SJason Zhu avb_error("Unknown algorithm.\n"); 20137a7bc39SJason Zhu goto out; 20237a7bc39SJason Zhu } 20337a7bc39SJason Zhu 20437a7bc39SJason Zhu if (avb_safe_memcmp(authentication_block + h.hash_offset, 20537a7bc39SJason Zhu computed_hash, 20637a7bc39SJason Zhu h.hash_size) != 0) { 20737a7bc39SJason Zhu avb_error("Hash does not match!\n"); 20837a7bc39SJason Zhu ret = AVB_VBMETA_VERIFY_RESULT_HASH_MISMATCH; 20937a7bc39SJason Zhu goto out; 21037a7bc39SJason Zhu } 21137a7bc39SJason Zhu 21237a7bc39SJason Zhu verification_result = 21337a7bc39SJason Zhu avb_rsa_verify(auxiliary_block + h.public_key_offset, 21437a7bc39SJason Zhu h.public_key_size, 21537a7bc39SJason Zhu authentication_block + h.signature_offset, 21637a7bc39SJason Zhu h.signature_size, 21737a7bc39SJason Zhu authentication_block + h.hash_offset, 21837a7bc39SJason Zhu h.hash_size, 21937a7bc39SJason Zhu algorithm->padding, 22037a7bc39SJason Zhu algorithm->padding_len); 22137a7bc39SJason Zhu 22237a7bc39SJason Zhu if (verification_result == 0) { 22337a7bc39SJason Zhu ret = AVB_VBMETA_VERIFY_RESULT_SIGNATURE_MISMATCH; 22437a7bc39SJason Zhu goto out; 22537a7bc39SJason Zhu } 22637a7bc39SJason Zhu 22737a7bc39SJason Zhu if (h.public_key_size > 0) { 22837a7bc39SJason Zhu if (out_public_key_data != NULL) { 22937a7bc39SJason Zhu *out_public_key_data = auxiliary_block + h.public_key_offset; 23037a7bc39SJason Zhu } 23137a7bc39SJason Zhu if (out_public_key_length != NULL) { 23237a7bc39SJason Zhu *out_public_key_length = h.public_key_size; 23337a7bc39SJason Zhu } 23437a7bc39SJason Zhu } 23537a7bc39SJason Zhu 23637a7bc39SJason Zhu ret = AVB_VBMETA_VERIFY_RESULT_OK; 23737a7bc39SJason Zhu 23837a7bc39SJason Zhu out: 23937a7bc39SJason Zhu return ret; 24037a7bc39SJason Zhu } 24137a7bc39SJason Zhu 24237a7bc39SJason Zhu void avb_vbmeta_image_header_to_host_byte_order(const AvbVBMetaImageHeader* src, 24337a7bc39SJason Zhu AvbVBMetaImageHeader* dest) { 24437a7bc39SJason Zhu avb_memcpy(dest, src, sizeof(AvbVBMetaImageHeader)); 24537a7bc39SJason Zhu 24637a7bc39SJason Zhu dest->required_libavb_version_major = 24737a7bc39SJason Zhu avb_be32toh(dest->required_libavb_version_major); 24837a7bc39SJason Zhu dest->required_libavb_version_minor = 24937a7bc39SJason Zhu avb_be32toh(dest->required_libavb_version_minor); 25037a7bc39SJason Zhu 25137a7bc39SJason Zhu dest->authentication_data_block_size = 25237a7bc39SJason Zhu avb_be64toh(dest->authentication_data_block_size); 25337a7bc39SJason Zhu dest->auxiliary_data_block_size = 25437a7bc39SJason Zhu avb_be64toh(dest->auxiliary_data_block_size); 25537a7bc39SJason Zhu 25637a7bc39SJason Zhu dest->algorithm_type = avb_be32toh(dest->algorithm_type); 25737a7bc39SJason Zhu 25837a7bc39SJason Zhu dest->hash_offset = avb_be64toh(dest->hash_offset); 25937a7bc39SJason Zhu dest->hash_size = avb_be64toh(dest->hash_size); 26037a7bc39SJason Zhu 26137a7bc39SJason Zhu dest->signature_offset = avb_be64toh(dest->signature_offset); 26237a7bc39SJason Zhu dest->signature_size = avb_be64toh(dest->signature_size); 26337a7bc39SJason Zhu 26437a7bc39SJason Zhu dest->public_key_offset = avb_be64toh(dest->public_key_offset); 26537a7bc39SJason Zhu dest->public_key_size = avb_be64toh(dest->public_key_size); 26637a7bc39SJason Zhu 26737a7bc39SJason Zhu dest->public_key_metadata_offset = 26837a7bc39SJason Zhu avb_be64toh(dest->public_key_metadata_offset); 26937a7bc39SJason Zhu dest->public_key_metadata_size = avb_be64toh(dest->public_key_metadata_size); 27037a7bc39SJason Zhu 27137a7bc39SJason Zhu dest->descriptors_offset = avb_be64toh(dest->descriptors_offset); 27237a7bc39SJason Zhu dest->descriptors_size = avb_be64toh(dest->descriptors_size); 27337a7bc39SJason Zhu 27437a7bc39SJason Zhu dest->rollback_index = avb_be64toh(dest->rollback_index); 27537a7bc39SJason Zhu dest->flags = avb_be32toh(dest->flags); 27637a7bc39SJason Zhu } 27737a7bc39SJason Zhu 27837a7bc39SJason Zhu const char* avb_vbmeta_verify_result_to_string(AvbVBMetaVerifyResult result) { 27937a7bc39SJason Zhu const char* ret = NULL; 28037a7bc39SJason Zhu 28137a7bc39SJason Zhu switch (result) { 28237a7bc39SJason Zhu case AVB_VBMETA_VERIFY_RESULT_OK: 28337a7bc39SJason Zhu ret = "OK"; 28437a7bc39SJason Zhu break; 28537a7bc39SJason Zhu case AVB_VBMETA_VERIFY_RESULT_OK_NOT_SIGNED: 28637a7bc39SJason Zhu ret = "OK_NOT_SIGNED"; 28737a7bc39SJason Zhu break; 28837a7bc39SJason Zhu case AVB_VBMETA_VERIFY_RESULT_INVALID_VBMETA_HEADER: 28937a7bc39SJason Zhu ret = "INVALID_VBMETA_HEADER"; 29037a7bc39SJason Zhu break; 29137a7bc39SJason Zhu case AVB_VBMETA_VERIFY_RESULT_UNSUPPORTED_VERSION: 29237a7bc39SJason Zhu ret = "UNSUPPORTED_VERSION"; 29337a7bc39SJason Zhu break; 29437a7bc39SJason Zhu case AVB_VBMETA_VERIFY_RESULT_HASH_MISMATCH: 29537a7bc39SJason Zhu ret = "HASH_MISMATCH"; 29637a7bc39SJason Zhu break; 29737a7bc39SJason Zhu case AVB_VBMETA_VERIFY_RESULT_SIGNATURE_MISMATCH: 29837a7bc39SJason Zhu ret = "SIGNATURE_MISMATCH"; 29937a7bc39SJason Zhu break; 30037a7bc39SJason Zhu /* Do not add a 'default:' case here because of -Wswitch. */ 30137a7bc39SJason Zhu } 30237a7bc39SJason Zhu 30337a7bc39SJason Zhu if (ret == NULL) { 30437a7bc39SJason Zhu avb_error("Unknown AvbVBMetaVerifyResult value.\n"); 30537a7bc39SJason Zhu ret = "(unknown)"; 30637a7bc39SJason Zhu } 30737a7bc39SJason Zhu 30837a7bc39SJason Zhu return ret; 30937a7bc39SJason Zhu } 310