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