xref: /rk3399_rockchip-uboot/lib/avb/libavb/avb_vbmeta_image.c (revision 5b0bc491775b5fbdb7c2928102abff2e61be3376)
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 
avb_vbmeta_image_verify(const uint8_t * data,size_t length,const uint8_t ** out_public_key_data,size_t * out_public_key_length)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 
5769fdc596SJason Zhu   /* Before we byteswap or compare Magic, ensure length is long enough. */
5869fdc596SJason Zhu   if (length < sizeof(AvbVBMetaImageHeader)) {
5969fdc596SJason Zhu     avb_error("Length is smaller than header.\n");
6069fdc596SJason Zhu     goto out;
6169fdc596SJason Zhu   }
6269fdc596SJason 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:
181*5b0bc491SJoseph Chen 
182*5b0bc491SJoseph Chen       sha256_ctx.tot_len = sizeof(AvbVBMetaImageHeader) +
183*5b0bc491SJoseph Chen                                       h.auxiliary_data_block_size;
18437a7bc39SJason Zhu       avb_sha256_init(&sha256_ctx);
18537a7bc39SJason Zhu       avb_sha256_update(
18637a7bc39SJason Zhu           &sha256_ctx, header_block, sizeof(AvbVBMetaImageHeader));
18737a7bc39SJason Zhu       avb_sha256_update(
18837a7bc39SJason Zhu           &sha256_ctx, auxiliary_block, h.auxiliary_data_block_size);
18937a7bc39SJason Zhu       computed_hash = avb_sha256_final(&sha256_ctx);
19037a7bc39SJason Zhu       break;
19137a7bc39SJason Zhu     /* Explicit fall-through: */
19237a7bc39SJason Zhu     case AVB_ALGORITHM_TYPE_SHA512_RSA2048:
19337a7bc39SJason Zhu     case AVB_ALGORITHM_TYPE_SHA512_RSA4096:
19437a7bc39SJason Zhu     case AVB_ALGORITHM_TYPE_SHA512_RSA8192:
195*5b0bc491SJoseph Chen       sha512_ctx.tot_len = sizeof(AvbVBMetaImageHeader) +
196*5b0bc491SJoseph Chen                                       h.auxiliary_data_block_size;
19737a7bc39SJason Zhu       avb_sha512_init(&sha512_ctx);
19837a7bc39SJason Zhu       avb_sha512_update(
19937a7bc39SJason Zhu           &sha512_ctx, header_block, sizeof(AvbVBMetaImageHeader));
20037a7bc39SJason Zhu       avb_sha512_update(
20137a7bc39SJason Zhu           &sha512_ctx, auxiliary_block, h.auxiliary_data_block_size);
20237a7bc39SJason Zhu       computed_hash = avb_sha512_final(&sha512_ctx);
20337a7bc39SJason Zhu       break;
20437a7bc39SJason Zhu     default:
20537a7bc39SJason Zhu       avb_error("Unknown algorithm.\n");
20637a7bc39SJason Zhu       goto out;
20737a7bc39SJason Zhu   }
20837a7bc39SJason Zhu 
20937a7bc39SJason Zhu   if (avb_safe_memcmp(authentication_block + h.hash_offset,
21037a7bc39SJason Zhu                       computed_hash,
21137a7bc39SJason Zhu                       h.hash_size) != 0) {
21237a7bc39SJason Zhu     avb_error("Hash does not match!\n");
21337a7bc39SJason Zhu     ret = AVB_VBMETA_VERIFY_RESULT_HASH_MISMATCH;
21437a7bc39SJason Zhu     goto out;
21537a7bc39SJason Zhu   }
21637a7bc39SJason Zhu 
21737a7bc39SJason Zhu   verification_result =
21837a7bc39SJason Zhu       avb_rsa_verify(auxiliary_block + h.public_key_offset,
21937a7bc39SJason Zhu                      h.public_key_size,
22037a7bc39SJason Zhu                      authentication_block + h.signature_offset,
22137a7bc39SJason Zhu                      h.signature_size,
22237a7bc39SJason Zhu                      authentication_block + h.hash_offset,
22337a7bc39SJason Zhu                      h.hash_size,
22437a7bc39SJason Zhu                      algorithm->padding,
22537a7bc39SJason Zhu                      algorithm->padding_len);
22637a7bc39SJason Zhu 
22737a7bc39SJason Zhu   if (verification_result == 0) {
22837a7bc39SJason Zhu     ret = AVB_VBMETA_VERIFY_RESULT_SIGNATURE_MISMATCH;
22937a7bc39SJason Zhu     goto out;
23037a7bc39SJason Zhu   }
23137a7bc39SJason Zhu 
23237a7bc39SJason Zhu   if (h.public_key_size > 0) {
23337a7bc39SJason Zhu     if (out_public_key_data != NULL) {
23437a7bc39SJason Zhu       *out_public_key_data = auxiliary_block + h.public_key_offset;
23537a7bc39SJason Zhu     }
23637a7bc39SJason Zhu     if (out_public_key_length != NULL) {
23737a7bc39SJason Zhu       *out_public_key_length = h.public_key_size;
23837a7bc39SJason Zhu     }
23937a7bc39SJason Zhu   }
24037a7bc39SJason Zhu 
24137a7bc39SJason Zhu   ret = AVB_VBMETA_VERIFY_RESULT_OK;
24237a7bc39SJason Zhu 
24337a7bc39SJason Zhu out:
24437a7bc39SJason Zhu   return ret;
24537a7bc39SJason Zhu }
24637a7bc39SJason Zhu 
avb_vbmeta_image_header_to_host_byte_order(const AvbVBMetaImageHeader * src,AvbVBMetaImageHeader * dest)24737a7bc39SJason Zhu void avb_vbmeta_image_header_to_host_byte_order(const AvbVBMetaImageHeader* src,
24837a7bc39SJason Zhu                                                 AvbVBMetaImageHeader* dest) {
24937a7bc39SJason Zhu   avb_memcpy(dest, src, sizeof(AvbVBMetaImageHeader));
25037a7bc39SJason Zhu 
25137a7bc39SJason Zhu   dest->required_libavb_version_major =
25237a7bc39SJason Zhu       avb_be32toh(dest->required_libavb_version_major);
25337a7bc39SJason Zhu   dest->required_libavb_version_minor =
25437a7bc39SJason Zhu       avb_be32toh(dest->required_libavb_version_minor);
25537a7bc39SJason Zhu 
25637a7bc39SJason Zhu   dest->authentication_data_block_size =
25737a7bc39SJason Zhu       avb_be64toh(dest->authentication_data_block_size);
25837a7bc39SJason Zhu   dest->auxiliary_data_block_size =
25937a7bc39SJason Zhu       avb_be64toh(dest->auxiliary_data_block_size);
26037a7bc39SJason Zhu 
26137a7bc39SJason Zhu   dest->algorithm_type = avb_be32toh(dest->algorithm_type);
26237a7bc39SJason Zhu 
26337a7bc39SJason Zhu   dest->hash_offset = avb_be64toh(dest->hash_offset);
26437a7bc39SJason Zhu   dest->hash_size = avb_be64toh(dest->hash_size);
26537a7bc39SJason Zhu 
26637a7bc39SJason Zhu   dest->signature_offset = avb_be64toh(dest->signature_offset);
26737a7bc39SJason Zhu   dest->signature_size = avb_be64toh(dest->signature_size);
26837a7bc39SJason Zhu 
26937a7bc39SJason Zhu   dest->public_key_offset = avb_be64toh(dest->public_key_offset);
27037a7bc39SJason Zhu   dest->public_key_size = avb_be64toh(dest->public_key_size);
27137a7bc39SJason Zhu 
27237a7bc39SJason Zhu   dest->public_key_metadata_offset =
27337a7bc39SJason Zhu       avb_be64toh(dest->public_key_metadata_offset);
27437a7bc39SJason Zhu   dest->public_key_metadata_size = avb_be64toh(dest->public_key_metadata_size);
27537a7bc39SJason Zhu 
27637a7bc39SJason Zhu   dest->descriptors_offset = avb_be64toh(dest->descriptors_offset);
27737a7bc39SJason Zhu   dest->descriptors_size = avb_be64toh(dest->descriptors_size);
27837a7bc39SJason Zhu 
27937a7bc39SJason Zhu   dest->rollback_index = avb_be64toh(dest->rollback_index);
28037a7bc39SJason Zhu   dest->flags = avb_be32toh(dest->flags);
28137a7bc39SJason Zhu }
28237a7bc39SJason Zhu 
avb_vbmeta_verify_result_to_string(AvbVBMetaVerifyResult result)28337a7bc39SJason Zhu const char* avb_vbmeta_verify_result_to_string(AvbVBMetaVerifyResult result) {
28437a7bc39SJason Zhu   const char* ret = NULL;
28537a7bc39SJason Zhu 
28637a7bc39SJason Zhu   switch (result) {
28737a7bc39SJason Zhu     case AVB_VBMETA_VERIFY_RESULT_OK:
28837a7bc39SJason Zhu       ret = "OK";
28937a7bc39SJason Zhu       break;
29037a7bc39SJason Zhu     case AVB_VBMETA_VERIFY_RESULT_OK_NOT_SIGNED:
29137a7bc39SJason Zhu       ret = "OK_NOT_SIGNED";
29237a7bc39SJason Zhu       break;
29337a7bc39SJason Zhu     case AVB_VBMETA_VERIFY_RESULT_INVALID_VBMETA_HEADER:
29437a7bc39SJason Zhu       ret = "INVALID_VBMETA_HEADER";
29537a7bc39SJason Zhu       break;
29637a7bc39SJason Zhu     case AVB_VBMETA_VERIFY_RESULT_UNSUPPORTED_VERSION:
29737a7bc39SJason Zhu       ret = "UNSUPPORTED_VERSION";
29837a7bc39SJason Zhu       break;
29937a7bc39SJason Zhu     case AVB_VBMETA_VERIFY_RESULT_HASH_MISMATCH:
30037a7bc39SJason Zhu       ret = "HASH_MISMATCH";
30137a7bc39SJason Zhu       break;
30237a7bc39SJason Zhu     case AVB_VBMETA_VERIFY_RESULT_SIGNATURE_MISMATCH:
30337a7bc39SJason Zhu       ret = "SIGNATURE_MISMATCH";
30437a7bc39SJason Zhu       break;
30537a7bc39SJason Zhu       /* Do not add a 'default:' case here because of -Wswitch. */
30637a7bc39SJason Zhu   }
30737a7bc39SJason Zhu 
30837a7bc39SJason Zhu   if (ret == NULL) {
30937a7bc39SJason Zhu     avb_error("Unknown AvbVBMetaVerifyResult value.\n");
31037a7bc39SJason Zhu     ret = "(unknown)";
31137a7bc39SJason Zhu   }
31237a7bc39SJason Zhu 
31337a7bc39SJason Zhu   return ret;
31437a7bc39SJason Zhu }
315