1*d8f9d2afSIgor Opaniuk /* 2*d8f9d2afSIgor Opaniuk * Copyright (C) 2016 The Android Open Source Project 3*d8f9d2afSIgor Opaniuk * 4*d8f9d2afSIgor Opaniuk * SPDX-License-Identifier: MIT 5*d8f9d2afSIgor Opaniuk */ 6*d8f9d2afSIgor Opaniuk 7*d8f9d2afSIgor Opaniuk #include "avb_vbmeta_image.h" 8*d8f9d2afSIgor Opaniuk #include "avb_crypto.h" 9*d8f9d2afSIgor Opaniuk #include "avb_rsa.h" 10*d8f9d2afSIgor Opaniuk #include "avb_sha.h" 11*d8f9d2afSIgor Opaniuk #include "avb_util.h" 12*d8f9d2afSIgor Opaniuk #include "avb_version.h" 13*d8f9d2afSIgor Opaniuk 14*d8f9d2afSIgor Opaniuk AvbVBMetaVerifyResult avb_vbmeta_image_verify( 15*d8f9d2afSIgor Opaniuk const uint8_t* data, 16*d8f9d2afSIgor Opaniuk size_t length, 17*d8f9d2afSIgor Opaniuk const uint8_t** out_public_key_data, 18*d8f9d2afSIgor Opaniuk size_t* out_public_key_length) { 19*d8f9d2afSIgor Opaniuk AvbVBMetaVerifyResult ret; 20*d8f9d2afSIgor Opaniuk AvbVBMetaImageHeader h; 21*d8f9d2afSIgor Opaniuk uint8_t* computed_hash; 22*d8f9d2afSIgor Opaniuk const AvbAlgorithmData* algorithm; 23*d8f9d2afSIgor Opaniuk AvbSHA256Ctx sha256_ctx; 24*d8f9d2afSIgor Opaniuk AvbSHA512Ctx sha512_ctx; 25*d8f9d2afSIgor Opaniuk const uint8_t* header_block; 26*d8f9d2afSIgor Opaniuk const uint8_t* authentication_block; 27*d8f9d2afSIgor Opaniuk const uint8_t* auxiliary_block; 28*d8f9d2afSIgor Opaniuk int verification_result; 29*d8f9d2afSIgor Opaniuk 30*d8f9d2afSIgor Opaniuk ret = AVB_VBMETA_VERIFY_RESULT_INVALID_VBMETA_HEADER; 31*d8f9d2afSIgor Opaniuk 32*d8f9d2afSIgor Opaniuk if (out_public_key_data != NULL) { 33*d8f9d2afSIgor Opaniuk *out_public_key_data = NULL; 34*d8f9d2afSIgor Opaniuk } 35*d8f9d2afSIgor Opaniuk if (out_public_key_length != NULL) { 36*d8f9d2afSIgor Opaniuk *out_public_key_length = 0; 37*d8f9d2afSIgor Opaniuk } 38*d8f9d2afSIgor Opaniuk 39*d8f9d2afSIgor Opaniuk /* Ensure magic is correct. */ 40*d8f9d2afSIgor Opaniuk if (avb_safe_memcmp(data, AVB_MAGIC, AVB_MAGIC_LEN) != 0) { 41*d8f9d2afSIgor Opaniuk avb_error("Magic is incorrect.\n"); 42*d8f9d2afSIgor Opaniuk goto out; 43*d8f9d2afSIgor Opaniuk } 44*d8f9d2afSIgor Opaniuk 45*d8f9d2afSIgor Opaniuk /* Before we byteswap, ensure length is long enough. */ 46*d8f9d2afSIgor Opaniuk if (length < sizeof(AvbVBMetaImageHeader)) { 47*d8f9d2afSIgor Opaniuk avb_error("Length is smaller than header.\n"); 48*d8f9d2afSIgor Opaniuk goto out; 49*d8f9d2afSIgor Opaniuk } 50*d8f9d2afSIgor Opaniuk avb_vbmeta_image_header_to_host_byte_order((const AvbVBMetaImageHeader*)data, 51*d8f9d2afSIgor Opaniuk &h); 52*d8f9d2afSIgor Opaniuk 53*d8f9d2afSIgor Opaniuk /* Ensure we don't attempt to access any fields if we do not meet 54*d8f9d2afSIgor Opaniuk * the specified minimum version of libavb. 55*d8f9d2afSIgor Opaniuk */ 56*d8f9d2afSIgor Opaniuk if ((h.required_libavb_version_major != AVB_VERSION_MAJOR) || 57*d8f9d2afSIgor Opaniuk (h.required_libavb_version_minor > AVB_VERSION_MINOR)) { 58*d8f9d2afSIgor Opaniuk avb_error("Mismatch between image version and libavb version.\n"); 59*d8f9d2afSIgor Opaniuk ret = AVB_VBMETA_VERIFY_RESULT_UNSUPPORTED_VERSION; 60*d8f9d2afSIgor Opaniuk goto out; 61*d8f9d2afSIgor Opaniuk } 62*d8f9d2afSIgor Opaniuk 63*d8f9d2afSIgor Opaniuk /* Ensure |release_string| ends with a NUL byte. */ 64*d8f9d2afSIgor Opaniuk if (h.release_string[AVB_RELEASE_STRING_SIZE - 1] != '\0') { 65*d8f9d2afSIgor Opaniuk avb_error("Release string does not end with a NUL byte.\n"); 66*d8f9d2afSIgor Opaniuk goto out; 67*d8f9d2afSIgor Opaniuk } 68*d8f9d2afSIgor Opaniuk 69*d8f9d2afSIgor Opaniuk /* Ensure inner block sizes are multiple of 64. */ 70*d8f9d2afSIgor Opaniuk if ((h.authentication_data_block_size & 0x3f) != 0 || 71*d8f9d2afSIgor Opaniuk (h.auxiliary_data_block_size & 0x3f) != 0) { 72*d8f9d2afSIgor Opaniuk avb_error("Block size is not a multiple of 64.\n"); 73*d8f9d2afSIgor Opaniuk goto out; 74*d8f9d2afSIgor Opaniuk } 75*d8f9d2afSIgor Opaniuk 76*d8f9d2afSIgor Opaniuk /* Ensure block sizes all add up to at most |length|. */ 77*d8f9d2afSIgor Opaniuk uint64_t block_total = sizeof(AvbVBMetaImageHeader); 78*d8f9d2afSIgor Opaniuk if (!avb_safe_add_to(&block_total, h.authentication_data_block_size) || 79*d8f9d2afSIgor Opaniuk !avb_safe_add_to(&block_total, h.auxiliary_data_block_size)) { 80*d8f9d2afSIgor Opaniuk avb_error("Overflow while computing size of boot image.\n"); 81*d8f9d2afSIgor Opaniuk goto out; 82*d8f9d2afSIgor Opaniuk } 83*d8f9d2afSIgor Opaniuk if (block_total > length) { 84*d8f9d2afSIgor Opaniuk avb_error("Block sizes add up to more than given length.\n"); 85*d8f9d2afSIgor Opaniuk goto out; 86*d8f9d2afSIgor Opaniuk } 87*d8f9d2afSIgor Opaniuk 88*d8f9d2afSIgor Opaniuk uintptr_t data_ptr = (uintptr_t)data; 89*d8f9d2afSIgor Opaniuk /* Ensure passed in memory doesn't wrap. */ 90*d8f9d2afSIgor Opaniuk if (!avb_safe_add(NULL, (uint64_t)data_ptr, length)) { 91*d8f9d2afSIgor Opaniuk avb_error("Boot image location and length mismatch.\n"); 92*d8f9d2afSIgor Opaniuk goto out; 93*d8f9d2afSIgor Opaniuk } 94*d8f9d2afSIgor Opaniuk 95*d8f9d2afSIgor Opaniuk /* Ensure hash and signature are entirely in the Authentication data block. */ 96*d8f9d2afSIgor Opaniuk uint64_t hash_end; 97*d8f9d2afSIgor Opaniuk if (!avb_safe_add(&hash_end, h.hash_offset, h.hash_size) || 98*d8f9d2afSIgor Opaniuk hash_end > h.authentication_data_block_size) { 99*d8f9d2afSIgor Opaniuk avb_error("Hash is not entirely in its block.\n"); 100*d8f9d2afSIgor Opaniuk goto out; 101*d8f9d2afSIgor Opaniuk } 102*d8f9d2afSIgor Opaniuk uint64_t signature_end; 103*d8f9d2afSIgor Opaniuk if (!avb_safe_add(&signature_end, h.signature_offset, h.signature_size) || 104*d8f9d2afSIgor Opaniuk signature_end > h.authentication_data_block_size) { 105*d8f9d2afSIgor Opaniuk avb_error("Signature is not entirely in its block.\n"); 106*d8f9d2afSIgor Opaniuk goto out; 107*d8f9d2afSIgor Opaniuk } 108*d8f9d2afSIgor Opaniuk 109*d8f9d2afSIgor Opaniuk /* Ensure public key is entirely in the Auxiliary data block. */ 110*d8f9d2afSIgor Opaniuk uint64_t pubkey_end; 111*d8f9d2afSIgor Opaniuk if (!avb_safe_add(&pubkey_end, h.public_key_offset, h.public_key_size) || 112*d8f9d2afSIgor Opaniuk pubkey_end > h.auxiliary_data_block_size) { 113*d8f9d2afSIgor Opaniuk avb_error("Public key is not entirely in its block.\n"); 114*d8f9d2afSIgor Opaniuk goto out; 115*d8f9d2afSIgor Opaniuk } 116*d8f9d2afSIgor Opaniuk 117*d8f9d2afSIgor Opaniuk /* Ensure public key metadata (if set) is entirely in the Auxiliary 118*d8f9d2afSIgor Opaniuk * data block. */ 119*d8f9d2afSIgor Opaniuk if (h.public_key_metadata_size > 0) { 120*d8f9d2afSIgor Opaniuk uint64_t pubkey_md_end; 121*d8f9d2afSIgor Opaniuk if (!avb_safe_add(&pubkey_md_end, 122*d8f9d2afSIgor Opaniuk h.public_key_metadata_offset, 123*d8f9d2afSIgor Opaniuk h.public_key_metadata_size) || 124*d8f9d2afSIgor Opaniuk pubkey_md_end > h.auxiliary_data_block_size) { 125*d8f9d2afSIgor Opaniuk avb_error("Public key metadata is not entirely in its block.\n"); 126*d8f9d2afSIgor Opaniuk goto out; 127*d8f9d2afSIgor Opaniuk } 128*d8f9d2afSIgor Opaniuk } 129*d8f9d2afSIgor Opaniuk 130*d8f9d2afSIgor Opaniuk /* Bail early if there's no hash or signature. */ 131*d8f9d2afSIgor Opaniuk if (h.algorithm_type == AVB_ALGORITHM_TYPE_NONE) { 132*d8f9d2afSIgor Opaniuk ret = AVB_VBMETA_VERIFY_RESULT_OK_NOT_SIGNED; 133*d8f9d2afSIgor Opaniuk goto out; 134*d8f9d2afSIgor Opaniuk } 135*d8f9d2afSIgor Opaniuk 136*d8f9d2afSIgor Opaniuk /* Ensure algorithm field is supported. */ 137*d8f9d2afSIgor Opaniuk algorithm = avb_get_algorithm_data(h.algorithm_type); 138*d8f9d2afSIgor Opaniuk if (!algorithm) { 139*d8f9d2afSIgor Opaniuk avb_error("Invalid or unknown algorithm.\n"); 140*d8f9d2afSIgor Opaniuk goto out; 141*d8f9d2afSIgor Opaniuk } 142*d8f9d2afSIgor Opaniuk 143*d8f9d2afSIgor Opaniuk /* Bail if the embedded hash size doesn't match the chosen algorithm. */ 144*d8f9d2afSIgor Opaniuk if (h.hash_size != algorithm->hash_len) { 145*d8f9d2afSIgor Opaniuk avb_error("Embedded hash has wrong size.\n"); 146*d8f9d2afSIgor Opaniuk goto out; 147*d8f9d2afSIgor Opaniuk } 148*d8f9d2afSIgor Opaniuk 149*d8f9d2afSIgor Opaniuk /* No overflow checks needed from here-on after since all block 150*d8f9d2afSIgor Opaniuk * sizes and offsets have been verified above. 151*d8f9d2afSIgor Opaniuk */ 152*d8f9d2afSIgor Opaniuk 153*d8f9d2afSIgor Opaniuk header_block = data; 154*d8f9d2afSIgor Opaniuk authentication_block = header_block + sizeof(AvbVBMetaImageHeader); 155*d8f9d2afSIgor Opaniuk auxiliary_block = authentication_block + h.authentication_data_block_size; 156*d8f9d2afSIgor Opaniuk 157*d8f9d2afSIgor Opaniuk switch (h.algorithm_type) { 158*d8f9d2afSIgor Opaniuk /* Explicit fall-through: */ 159*d8f9d2afSIgor Opaniuk case AVB_ALGORITHM_TYPE_SHA256_RSA2048: 160*d8f9d2afSIgor Opaniuk case AVB_ALGORITHM_TYPE_SHA256_RSA4096: 161*d8f9d2afSIgor Opaniuk case AVB_ALGORITHM_TYPE_SHA256_RSA8192: 162*d8f9d2afSIgor Opaniuk avb_sha256_init(&sha256_ctx); 163*d8f9d2afSIgor Opaniuk avb_sha256_update( 164*d8f9d2afSIgor Opaniuk &sha256_ctx, header_block, sizeof(AvbVBMetaImageHeader)); 165*d8f9d2afSIgor Opaniuk avb_sha256_update( 166*d8f9d2afSIgor Opaniuk &sha256_ctx, auxiliary_block, h.auxiliary_data_block_size); 167*d8f9d2afSIgor Opaniuk computed_hash = avb_sha256_final(&sha256_ctx); 168*d8f9d2afSIgor Opaniuk break; 169*d8f9d2afSIgor Opaniuk /* Explicit fall-through: */ 170*d8f9d2afSIgor Opaniuk case AVB_ALGORITHM_TYPE_SHA512_RSA2048: 171*d8f9d2afSIgor Opaniuk case AVB_ALGORITHM_TYPE_SHA512_RSA4096: 172*d8f9d2afSIgor Opaniuk case AVB_ALGORITHM_TYPE_SHA512_RSA8192: 173*d8f9d2afSIgor Opaniuk avb_sha512_init(&sha512_ctx); 174*d8f9d2afSIgor Opaniuk avb_sha512_update( 175*d8f9d2afSIgor Opaniuk &sha512_ctx, header_block, sizeof(AvbVBMetaImageHeader)); 176*d8f9d2afSIgor Opaniuk avb_sha512_update( 177*d8f9d2afSIgor Opaniuk &sha512_ctx, auxiliary_block, h.auxiliary_data_block_size); 178*d8f9d2afSIgor Opaniuk computed_hash = avb_sha512_final(&sha512_ctx); 179*d8f9d2afSIgor Opaniuk break; 180*d8f9d2afSIgor Opaniuk default: 181*d8f9d2afSIgor Opaniuk avb_error("Unknown algorithm.\n"); 182*d8f9d2afSIgor Opaniuk goto out; 183*d8f9d2afSIgor Opaniuk } 184*d8f9d2afSIgor Opaniuk 185*d8f9d2afSIgor Opaniuk if (avb_safe_memcmp(authentication_block + h.hash_offset, 186*d8f9d2afSIgor Opaniuk computed_hash, 187*d8f9d2afSIgor Opaniuk h.hash_size) != 0) { 188*d8f9d2afSIgor Opaniuk avb_error("Hash does not match!\n"); 189*d8f9d2afSIgor Opaniuk ret = AVB_VBMETA_VERIFY_RESULT_HASH_MISMATCH; 190*d8f9d2afSIgor Opaniuk goto out; 191*d8f9d2afSIgor Opaniuk } 192*d8f9d2afSIgor Opaniuk 193*d8f9d2afSIgor Opaniuk verification_result = 194*d8f9d2afSIgor Opaniuk avb_rsa_verify(auxiliary_block + h.public_key_offset, 195*d8f9d2afSIgor Opaniuk h.public_key_size, 196*d8f9d2afSIgor Opaniuk authentication_block + h.signature_offset, 197*d8f9d2afSIgor Opaniuk h.signature_size, 198*d8f9d2afSIgor Opaniuk authentication_block + h.hash_offset, 199*d8f9d2afSIgor Opaniuk h.hash_size, 200*d8f9d2afSIgor Opaniuk algorithm->padding, 201*d8f9d2afSIgor Opaniuk algorithm->padding_len); 202*d8f9d2afSIgor Opaniuk 203*d8f9d2afSIgor Opaniuk if (verification_result == 0) { 204*d8f9d2afSIgor Opaniuk ret = AVB_VBMETA_VERIFY_RESULT_SIGNATURE_MISMATCH; 205*d8f9d2afSIgor Opaniuk goto out; 206*d8f9d2afSIgor Opaniuk } 207*d8f9d2afSIgor Opaniuk 208*d8f9d2afSIgor Opaniuk if (h.public_key_size > 0) { 209*d8f9d2afSIgor Opaniuk if (out_public_key_data != NULL) { 210*d8f9d2afSIgor Opaniuk *out_public_key_data = auxiliary_block + h.public_key_offset; 211*d8f9d2afSIgor Opaniuk } 212*d8f9d2afSIgor Opaniuk if (out_public_key_length != NULL) { 213*d8f9d2afSIgor Opaniuk *out_public_key_length = h.public_key_size; 214*d8f9d2afSIgor Opaniuk } 215*d8f9d2afSIgor Opaniuk } 216*d8f9d2afSIgor Opaniuk 217*d8f9d2afSIgor Opaniuk ret = AVB_VBMETA_VERIFY_RESULT_OK; 218*d8f9d2afSIgor Opaniuk 219*d8f9d2afSIgor Opaniuk out: 220*d8f9d2afSIgor Opaniuk return ret; 221*d8f9d2afSIgor Opaniuk } 222*d8f9d2afSIgor Opaniuk 223*d8f9d2afSIgor Opaniuk void avb_vbmeta_image_header_to_host_byte_order(const AvbVBMetaImageHeader* src, 224*d8f9d2afSIgor Opaniuk AvbVBMetaImageHeader* dest) { 225*d8f9d2afSIgor Opaniuk avb_memcpy(dest, src, sizeof(AvbVBMetaImageHeader)); 226*d8f9d2afSIgor Opaniuk 227*d8f9d2afSIgor Opaniuk dest->required_libavb_version_major = 228*d8f9d2afSIgor Opaniuk avb_be32toh(dest->required_libavb_version_major); 229*d8f9d2afSIgor Opaniuk dest->required_libavb_version_minor = 230*d8f9d2afSIgor Opaniuk avb_be32toh(dest->required_libavb_version_minor); 231*d8f9d2afSIgor Opaniuk 232*d8f9d2afSIgor Opaniuk dest->authentication_data_block_size = 233*d8f9d2afSIgor Opaniuk avb_be64toh(dest->authentication_data_block_size); 234*d8f9d2afSIgor Opaniuk dest->auxiliary_data_block_size = 235*d8f9d2afSIgor Opaniuk avb_be64toh(dest->auxiliary_data_block_size); 236*d8f9d2afSIgor Opaniuk 237*d8f9d2afSIgor Opaniuk dest->algorithm_type = avb_be32toh(dest->algorithm_type); 238*d8f9d2afSIgor Opaniuk 239*d8f9d2afSIgor Opaniuk dest->hash_offset = avb_be64toh(dest->hash_offset); 240*d8f9d2afSIgor Opaniuk dest->hash_size = avb_be64toh(dest->hash_size); 241*d8f9d2afSIgor Opaniuk 242*d8f9d2afSIgor Opaniuk dest->signature_offset = avb_be64toh(dest->signature_offset); 243*d8f9d2afSIgor Opaniuk dest->signature_size = avb_be64toh(dest->signature_size); 244*d8f9d2afSIgor Opaniuk 245*d8f9d2afSIgor Opaniuk dest->public_key_offset = avb_be64toh(dest->public_key_offset); 246*d8f9d2afSIgor Opaniuk dest->public_key_size = avb_be64toh(dest->public_key_size); 247*d8f9d2afSIgor Opaniuk 248*d8f9d2afSIgor Opaniuk dest->public_key_metadata_offset = 249*d8f9d2afSIgor Opaniuk avb_be64toh(dest->public_key_metadata_offset); 250*d8f9d2afSIgor Opaniuk dest->public_key_metadata_size = avb_be64toh(dest->public_key_metadata_size); 251*d8f9d2afSIgor Opaniuk 252*d8f9d2afSIgor Opaniuk dest->descriptors_offset = avb_be64toh(dest->descriptors_offset); 253*d8f9d2afSIgor Opaniuk dest->descriptors_size = avb_be64toh(dest->descriptors_size); 254*d8f9d2afSIgor Opaniuk 255*d8f9d2afSIgor Opaniuk dest->rollback_index = avb_be64toh(dest->rollback_index); 256*d8f9d2afSIgor Opaniuk dest->flags = avb_be32toh(dest->flags); 257*d8f9d2afSIgor Opaniuk } 258*d8f9d2afSIgor Opaniuk 259*d8f9d2afSIgor Opaniuk const char* avb_vbmeta_verify_result_to_string(AvbVBMetaVerifyResult result) { 260*d8f9d2afSIgor Opaniuk const char* ret = NULL; 261*d8f9d2afSIgor Opaniuk 262*d8f9d2afSIgor Opaniuk switch (result) { 263*d8f9d2afSIgor Opaniuk case AVB_VBMETA_VERIFY_RESULT_OK: 264*d8f9d2afSIgor Opaniuk ret = "OK"; 265*d8f9d2afSIgor Opaniuk break; 266*d8f9d2afSIgor Opaniuk case AVB_VBMETA_VERIFY_RESULT_OK_NOT_SIGNED: 267*d8f9d2afSIgor Opaniuk ret = "OK_NOT_SIGNED"; 268*d8f9d2afSIgor Opaniuk break; 269*d8f9d2afSIgor Opaniuk case AVB_VBMETA_VERIFY_RESULT_INVALID_VBMETA_HEADER: 270*d8f9d2afSIgor Opaniuk ret = "INVALID_VBMETA_HEADER"; 271*d8f9d2afSIgor Opaniuk break; 272*d8f9d2afSIgor Opaniuk case AVB_VBMETA_VERIFY_RESULT_UNSUPPORTED_VERSION: 273*d8f9d2afSIgor Opaniuk ret = "UNSUPPORTED_VERSION"; 274*d8f9d2afSIgor Opaniuk break; 275*d8f9d2afSIgor Opaniuk case AVB_VBMETA_VERIFY_RESULT_HASH_MISMATCH: 276*d8f9d2afSIgor Opaniuk ret = "HASH_MISMATCH"; 277*d8f9d2afSIgor Opaniuk break; 278*d8f9d2afSIgor Opaniuk case AVB_VBMETA_VERIFY_RESULT_SIGNATURE_MISMATCH: 279*d8f9d2afSIgor Opaniuk ret = "SIGNATURE_MISMATCH"; 280*d8f9d2afSIgor Opaniuk break; 281*d8f9d2afSIgor Opaniuk /* Do not add a 'default:' case here because of -Wswitch. */ 282*d8f9d2afSIgor Opaniuk } 283*d8f9d2afSIgor Opaniuk 284*d8f9d2afSIgor Opaniuk if (ret == NULL) { 285*d8f9d2afSIgor Opaniuk avb_error("Unknown AvbVBMetaVerifyResult value.\n"); 286*d8f9d2afSIgor Opaniuk ret = "(unknown)"; 287*d8f9d2afSIgor Opaniuk } 288*d8f9d2afSIgor Opaniuk 289*d8f9d2afSIgor Opaniuk return ret; 290*d8f9d2afSIgor Opaniuk } 291