You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
191 lines
7.6 KiB
191 lines
7.6 KiB
/*
|
|
* Copyright (C) 2020 The Android Open Source Project
|
|
*
|
|
* Permission is hereby granted, free of charge, to any person
|
|
* obtaining a copy of this software and associated documentation
|
|
* files (the "Software"), to deal in the Software without
|
|
* restriction, including without limitation the rights to use, copy,
|
|
* modify, merge, publish, distribute, sublicense, and/or sell copies
|
|
* of the Software, and to permit persons to whom the Software is
|
|
* furnished to do so, subject to the following conditions:
|
|
*
|
|
* The above copyright notice and this permission notice shall be
|
|
* included in all copies or substantial portions of the Software.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
|
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
|
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
|
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
* SOFTWARE.
|
|
*/
|
|
|
|
#include "libavb_aftl/avb_aftl_verify.h"
|
|
|
|
#include <libavb/avb_cmdline.h>
|
|
#include <libavb/avb_slot_verify.h>
|
|
#include <libavb/avb_util.h>
|
|
|
|
#include "libavb_aftl/avb_aftl_types.h"
|
|
#include "libavb_aftl/avb_aftl_util.h"
|
|
#include "libavb_aftl/avb_aftl_validate.h"
|
|
|
|
/* Read the vbmeta partition, after the AvbVBMetaImageHeader structure, to find
|
|
* the AftlImage.
|
|
*/
|
|
static AftlSlotVerifyResult avb_aftl_find_aftl_image(AvbOps* ops,
|
|
const char* part_name,
|
|
size_t vbmeta_size,
|
|
uint8_t* out_image_buf,
|
|
size_t* out_image_size) {
|
|
AvbIOResult io_ret;
|
|
|
|
avb_assert(vbmeta_size <= AVB_AFTL_MAX_AFTL_IMAGE_SIZE);
|
|
io_ret = ops->read_from_partition(ops,
|
|
part_name,
|
|
vbmeta_size /* offset */,
|
|
AVB_AFTL_MAX_AFTL_IMAGE_SIZE - vbmeta_size,
|
|
out_image_buf,
|
|
out_image_size);
|
|
switch (io_ret) {
|
|
case AVB_IO_RESULT_OK:
|
|
break;
|
|
case AVB_IO_RESULT_ERROR_OOM:
|
|
return AFTL_SLOT_VERIFY_RESULT_ERROR_OOM;
|
|
case AVB_IO_RESULT_ERROR_RANGE_OUTSIDE_PARTITION:
|
|
case AVB_IO_RESULT_ERROR_NO_SUCH_PARTITION:
|
|
return AFTL_SLOT_VERIFY_RESULT_ERROR_IMAGE_NOT_FOUND;
|
|
default:
|
|
avb_errorv(
|
|
part_name, ": Error loading AftlImage from partition.\n", NULL);
|
|
return AFTL_SLOT_VERIFY_RESULT_ERROR_IO;
|
|
}
|
|
|
|
if (*out_image_size < 4 || (out_image_buf[0] != 'A') ||
|
|
(out_image_buf[1] != 'F') || (out_image_buf[2] != 'T') ||
|
|
(out_image_buf[3] != 'L')) {
|
|
avb_errorv(part_name, ": Unexpected AftlImage magic.\n", NULL);
|
|
return AFTL_SLOT_VERIFY_RESULT_ERROR_IMAGE_NOT_FOUND;
|
|
}
|
|
|
|
return AFTL_SLOT_VERIFY_RESULT_OK;
|
|
}
|
|
|
|
/* Performs the three validation steps for an AFTL image:
|
|
1. Ensure the vbmeta image hash matches that in the image.
|
|
2. Ensure the root hash of the Merkle tree matches that in the image.
|
|
3. Verify the signature using the transparency log public key.
|
|
*/
|
|
static AftlSlotVerifyResult avb_aftl_verify_image(uint8_t* cur_vbmeta_data,
|
|
size_t cur_vbmeta_size,
|
|
uint8_t* aftl_blob,
|
|
size_t aftl_size,
|
|
uint8_t* key_bytes,
|
|
size_t key_num_bytes) {
|
|
size_t i;
|
|
AftlImage* image;
|
|
AftlSlotVerifyResult result = AFTL_SLOT_VERIFY_RESULT_ERROR_VERIFICATION;
|
|
|
|
/* Attempt to parse the AftlImage pointed to by aftl_blob. */
|
|
image = parse_aftl_image(aftl_blob, aftl_size);
|
|
if (!image) {
|
|
return AFTL_SLOT_VERIFY_RESULT_ERROR_INVALID_IMAGE;
|
|
}
|
|
|
|
/* Now that a valid AftlImage has been parsed, attempt to verify
|
|
the inclusion proof(s) in three steps. */
|
|
for (i = 0; i < image->header.icp_count; i++) {
|
|
/* 1. Ensure that the vbmeta hash stored in the AftlIcpEntry matches
|
|
the one that represents the partition. */
|
|
if (!avb_aftl_verify_vbmeta_hash(
|
|
cur_vbmeta_data, cur_vbmeta_size, image->entries[i])) {
|
|
avb_error("AFTL vbmeta hash verification failed.\n");
|
|
result = AFTL_SLOT_VERIFY_RESULT_ERROR_VBMETA_HASH_MISMATCH;
|
|
break;
|
|
}
|
|
/* 2. Ensure that the root hash of the Merkle tree representing
|
|
the transparency log entry matches the one stored in the
|
|
AftlIcpEntry. */
|
|
if (!avb_aftl_verify_icp_root_hash(image->entries[i])) {
|
|
avb_error("AFTL root hash verification failed.\n");
|
|
result = AFTL_SLOT_VERIFY_RESULT_ERROR_TREE_HASH_MISMATCH;
|
|
break;
|
|
}
|
|
/* 3. Verify the signature using the transparency log public
|
|
key stored on device. */
|
|
if (!avb_aftl_verify_entry_signature(
|
|
key_bytes, key_num_bytes, image->entries[i])) {
|
|
avb_error("AFTL signature verification failed on entry.\n");
|
|
result = AFTL_SLOT_VERIFY_RESULT_ERROR_INVALID_PROOF_SIGNATURE;
|
|
break;
|
|
}
|
|
result = AFTL_SLOT_VERIFY_RESULT_OK;
|
|
}
|
|
free_aftl_image(image);
|
|
return result;
|
|
}
|
|
|
|
AftlSlotVerifyResult aftl_slot_verify(AvbOps* ops,
|
|
AvbSlotVerifyData* slot_verify_data,
|
|
uint8_t* key_bytes,
|
|
size_t key_size) {
|
|
size_t i;
|
|
size_t aftl_image_size;
|
|
size_t vbmeta_size;
|
|
uint8_t* current_aftl_blob;
|
|
char part_name[AVB_PART_NAME_MAX_SIZE];
|
|
char* pname;
|
|
AftlSlotVerifyResult ret = AFTL_SLOT_VERIFY_RESULT_ERROR_VERIFICATION;
|
|
|
|
avb_assert(slot_verify_data != NULL);
|
|
avb_assert(key_bytes != NULL);
|
|
avb_assert(key_size == AVB_AFTL_PUB_KEY_SIZE);
|
|
if (slot_verify_data->vbmeta_images == NULL) {
|
|
return AFTL_SLOT_VERIFY_RESULT_ERROR_INVALID_ARGUMENT;
|
|
}
|
|
|
|
current_aftl_blob = avb_malloc(AVB_AFTL_MAX_AFTL_IMAGE_SIZE);
|
|
if (current_aftl_blob == NULL) {
|
|
return AFTL_SLOT_VERIFY_RESULT_ERROR_OOM;
|
|
}
|
|
|
|
/* Walk through each vbmeta blob in the AvbSlotVerifyData struct. */
|
|
for (i = 0; i < slot_verify_data->num_vbmeta_images; i++) {
|
|
/* Rebuild partition name, appending the suffix */
|
|
pname = slot_verify_data->vbmeta_images[i].partition_name;
|
|
if (!avb_str_concat(part_name,
|
|
sizeof part_name,
|
|
(const char*)pname,
|
|
avb_strlen(pname),
|
|
slot_verify_data->ab_suffix,
|
|
avb_strlen(slot_verify_data->ab_suffix))) {
|
|
avb_error("Partition name and suffix does not fit.\n");
|
|
ret = AFTL_SLOT_VERIFY_RESULT_ERROR_VERIFICATION;
|
|
break;
|
|
}
|
|
|
|
/* Use the partition info to find the AftlImage */
|
|
vbmeta_size = slot_verify_data->vbmeta_images[i].vbmeta_size;
|
|
ret = avb_aftl_find_aftl_image(
|
|
ops, part_name, vbmeta_size, current_aftl_blob, &aftl_image_size);
|
|
if (ret != AFTL_SLOT_VERIFY_RESULT_OK) {
|
|
avb_errorv(part_name, ": Unable to find the AftlImage.\n", NULL);
|
|
break;
|
|
}
|
|
|
|
/* Validate the AFTL image in the vbmeta image. */
|
|
ret = avb_aftl_verify_image(slot_verify_data->vbmeta_images[i].vbmeta_data,
|
|
vbmeta_size,
|
|
current_aftl_blob,
|
|
aftl_image_size,
|
|
key_bytes,
|
|
key_size);
|
|
if (ret != AVB_SLOT_VERIFY_RESULT_OK) break;
|
|
}
|
|
|
|
avb_free(current_aftl_blob);
|
|
return ret;
|
|
}
|