本篇android AVB2.0学习总结系统的第四篇,接上篇android AVB2.0(三)Init阶段安全启动流程, 这里介绍一下libavb库的详细实现。
首先要介绍一下本篇文章的两个目标,带着这两个目标我们来分析一下libavb库的实现。
1、android AVB是如何完成verify校验这项任务的?
2、采用了什么样的设计来完成verify校验任务?
上篇内容之一:“InitAvbHandle:AVB调用exterlan/avb/libavb库完成分区的校验”
没有源码的,可以看google提供的路径:https://android.googlesource.com/platform/system/core/+/master/init/first_stage_mount.cpp
@first_stage_mount.cpp
bool FirstStageMountVBootV2::InitAvbHandle() {
if (avb_handle_) return true; // Returns true if the handle is already initialized.
avb_handle_ = AvbHandle::Open();
if (!avb_handle_) {
PLOG(ERROR) << "Failed to open AvbHandle";
return false;
}
// Sets INIT_AVB_VERSION here for init to set ro.boot.avb_version in the second stage.
setenv("INIT_AVB_VERSION", avb_handle_->avb_version().c_str(), 1);
return true;
}
实现在fs_avb.cpp中
AvbUniquePtr AvbHandle::Open() {
//判断设备是否lock,这里是通过读系统属性ro.boot.verifiedbootstate来判断的,这个后面我专门搞篇文章来讲一下。
bool allow_verification_error = IsAvbPermissive();
//创建AvbHandle实例
AvbUniquePtr avb_handle(new AvbHandle());
if (!avb_handle) {
LERROR << "Failed to allocate AvbHandle";
return nullptr;
}
//实例化AvbOps管理类对象,私有成员中有AvbOps avb_ops_
FsManagerAvbOps avb_ops;
AvbSlotVerifyFlags flags = allow_verification_error
? AVB_SLOT_VERIFY_FLAGS_ALLOW_VERIFICATION_ERROR
: AVB_SLOT_VERIFY_FLAGS_NONE;
//调用AvbSlotVerify函数进行verify校验
AvbSlotVerifyResult verify_result =
avb_ops.AvbSlotVerify(fs_mgr_get_slot_suffix(), flags, &avb_handle->vbmeta_images_);
...
//后面verify之后的结果代码也比较简单就不分析了,我们重点分析校验流程
AvbSlotVerify实现在avb_ops.cpp中的avb_slot_verify函数,注意这里requested_partitions默认为空,不管是Uboot中调用libavb库,还是android init中调用libavb库,都是类似的处理逻辑。
AvbSlotVerifyResult FsManagerAvbOps::AvbSlotVerify(const std::string& ab_suffix,
AvbSlotVerifyFlags flags,
std::vector<VBMetaData>* out_vbmeta_images) {
const char* requested_partitions[] = {nullptr};
// Local resource to store vbmeta images from avb_slot_verify();
AvbSlotVerifyData* avb_slot_data;
// The |hashtree_error_mode| field doesn't matter as it only
// influences the generated kernel cmdline parameters.
auto verify_result =
avb_slot_verify(&avb_ops_, requested_partitions, ab_suffix.c_str(), flags,
AVB_HASHTREE_ERROR_MODE_RESTART_AND_INVALIDATE, &avb_slot_data);
if (!avb_slot_data) return verify_result;
一、入口avb_slot_verify.c
avb_slot_verify函数流程会非常的长,对这个代码不熟悉的人估计会晕在里面,会有函数嵌套调用。我们分段进行说明:
第一个参数ops,是一个函数结构体对象指针
FsManagerAvbOps::FsManagerAvbOps() {
//初始化avb_ops_成员的对象,主要有这六个回调函数,这些google设计的非常巧妙,用户将来可自定义各家的实现方式,google不做限制,只保留空的回调接口,在avb验证流程中会触发,后面代码分析流程中会做介绍。
memset(&avb_ops_, 0, sizeof(AvbOps));
avb_ops_.read_from_partition = read_from_partition;
avb_ops_.read_rollback_index = dummy_read_rollback_index;
avb_ops_.validate_vbmeta_public_key = dummy_validate_vbmeta_public_key;
avb_ops_.read_is_device_unlocked = dummy_read_is_device_unlocked;
avb_ops_.get_unique_guid_for_partition = dummy_get_unique_guid_for_partition;
avb_ops_.get_size_of_partition = dummy_get_size_of_partition;
// Sets user_data for GetInstanceFromAvbOps() to convert it back to FsManagerAvbOps.
avb_ops_.user_data = this;
}
我们进入到avb_slot_verify函数中分析
AvbSlotVerifyResult avb_slot_verify(AvbOps* ops,
const char* const* requested_partitions,
const char* ab_suffix,
AvbSlotVerifyFlags flags,
AvbHashtreeErrorMode hashtree_error_mode,
AvbSlotVerifyData** out_data) {
AvbSlotVerifyResult ret;
AvbSlotVerifyData* slot_data = NULL;
AvbAlgorithmType algorithm_type = AVB_ALGORITHM_TYPE_NONE;
bool using_boot_for_vbmeta = false;
AvbVBMetaImageHeader toplevel_vbmeta;
bool allow_verification_error =
(flags & AVB_SLOT_VERIFY_FLAGS_ALLOW_VERIFICATION_ERROR);
AvbCmdlineSubstList* additional_cmdline_subst = NULL;
/* Fail early if we're missing the AvbOps needed for slot verification. */
//先判断下面五个基本的回调函数接口是否存在,不存在会报错,即使不实现也需要实现个空内容。
avb_assert(ops->read_is_device_unlocked != NULL);
avb_assert(ops->read_from_partition != NULL);
avb_assert(ops->get_size_of_partition != NULL);
avb_assert(ops->read_rollback_index != NULL);
avb_assert(ops->get_unique_guid_for_partition != NULL);
。。。
//判断是否没有vbmeta分区,默认是有vbmeta分区设计的,但是也可以append到其他分区上 这种我们先不考虑
if (flags & AVB_SLOT_VERIFY_FLAGS_NO_VBMETA_PARTITION) {
if (ops->validate_public_key_for_partition == NULL) {
avb_error(
"AVB_SLOT_VERIFY_FLAGS_NO_VBMETA_PARTITION was passed but the "
"validate_public_key_for_partition() operation isn't implemented.\n");
ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_ARGUMENT;
goto fail;
}
} else {
//默认我们是使用这种方式,需要校验vbmeta分区的public key接口是否存在,这个接口用来判断vbmeta公钥hash key是否匹配。
avb_assert(ops->validate_vbmeta_public_key != NULL);
}
//alloc分配内存
slot_data = avb_calloc(sizeof(AvbSlotVerifyData));
if (slot_data == NULL) {
ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
goto fail;
}
slot_data->vbmeta_images =
avb_calloc(sizeof(AvbVBMetaData) * MAX_NUMBER_OF_VBMETA_IMAGES);
if (slot_data->vbmeta_images == NULL) {
ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
goto fail;
}
slot_data->loaded_partitions =
avb_calloc(sizeof(AvbPartitionData) * MAX_NUMBER_OF_LOADED_PARTITIONS);
if (slot_data->loaded_partitions == NULL) {
ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
goto fail;
}
//给additional_cmdline_subst也alloc分配内存,这个是后面需要将avb校验的结果转成数据append到cmdline中,传递给init使用的。
additional_cmdline_subst = avb_new_cmdline_subst_list();
if (additional_cmdline_subst == NULL) {
ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
goto fail;
}
if (flags & AVB_SLOT_VERIFY_FLAGS_NO_VBMETA_PARTITION) {
...
//同上,我们不分析没有vbmeta分区的情况
} else {
//加载和校验vbmeta分区,这个函数流程非常长,我们等会分析,先看完后续的流程
ret = load_and_verify_vbmeta(ops,
requested_partitions,
ab_suffix,
flags,
allow_verification_error,
0 /* toplevel_vbmeta_flags */,
0 /* rollback_index_location */,
"vbmeta",
avb_strlen("vbmeta"),
NULL /* expected_public_key */,
0 /* expected_public_key_length */,
slot_data,
&algorithm_type,
additional_cmdline_subst);
//在设备lock的情况且校验失败,直接异常
if (!allow_verification_error && ret != AVB_SLOT_VERIFY_RESULT_OK) {
goto fail;
}
}
//根据校验结果判断是否可继续引导启动
if (!result_should_continue(ret)) {
goto fail;
}
//将校验的结果数据slot_data拷贝给toplevel_vbemta,避免修改原数据。
avb_vbmeta_image_header_to_host_byte_order(
(const AvbVBMetaImageHeader*)slot_data->vbmeta_images[0].vbmeta_data,
&toplevel_vbmeta);
//根据toplevel_vbmeta vbmete头信息中flags bit位是否为disable verification,
//这个就是传说中的adb disable-verity修改的那个Bit位了,估计很多人都不知道adb这条命令干了啥,其实就是修改了vbmeta分区Header头信息中的这个bit位
if (toplevel_vbmeta.flags & AVB_VBMETA_IMAGE_FLAGS_VERIFICATION_DISABLED) {
/* Since verification is disabled we didn't process any
* descriptors and thus there's no cmdline... so set root= such
* that the system partition is mounted.
*/
avb_assert(slot_data->cmdline == NULL);
// Devices with dynamic partitions won't have system partition.
// Instead, it has a large super partition to accommodate *.img files.
// See b/119551429 for details.
if (has_system_partition(ops, ab_suffix)) {
slot_data->cmdline =
avb_strdup("root=PARTUUID=$(ANDROID_SYSTEM_PARTUUID)");
} else {
// The |cmdline| field should be a NUL-terminated string.
slot_data->cmdline = avb_strdup("");
}
if (slot_data->cmdline == NULL) {
ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
goto fail;
}
} else {
/* If requested, manage dm-verity mode... */
//这里是不是很奇怪,怎么又判断了hashtree了?其实是google设计的函数共用的功能,这个函数也可以用来校验其他Hashtree类型的分区,比如system和vendor等
AvbHashtreeErrorMode resolved_hashtree_error_mode = hashtree_error_mode;
if (hashtree_error_mode ==
AVB_HASHTREE_ERROR_MODE_MANAGED_RESTART_AND_EIO) {
AvbIOResult io_ret;
io_ret = avb_manage_hashtree_error_mode(
ops, flags, slot_data, &resolved_hashtree_error_mode);
if (io_ret != AVB_IO_RESULT_OK) {
ret = AVB_SLOT_VERIFY_RESULT_ERROR_IO;
if (io_ret == AVB_IO_RESULT_ERROR_OOM) {
ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
}
goto fail;
}
//调用avb_append_options追加androidboot.xxx属性到cmdline中,这个比较简单就不深入分析了。
sub_ret = avb_append_options(ops,
flags,
slot_data,
&toplevel_vbmeta,
algorithm_type,
hashtree_error_mode,
resolved_hashtree_error_mode);
if (slot_data->cmdline != NULL && avb_strlen(slot_data->cmdline) != 0) {
char* new_cmdline;
new_cmdline = avb_sub_cmdline(ops,
slot_data->cmdline,
ab_suffix,
using_boot_for_vbmeta,
additional_cmdline_subst);
if (new_cmdline != slot_data->cmdline) {
if (new_cmdline == NULL) {
ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
goto fail;
}
avb_free(slot_data->cmdline);
slot_data->cmdline = new_cmdline;
}
}
if (out_data != NULL) {
*out_data = slot_data;
} else {
avb_slot_verify_data_free(slot_data);
}
我们回到load_and_verify_vbmeta这个函数,看下如何加载和校验vbmeta分区及vbmeta下的子分区的
static AvbSlotVerifyResult load_and_verify_vbmeta(
AvbOps* ops,
const char* const* requested_partitions,
const char* ab_suffix,
AvbSlotVerifyFlags flags,
bool allow_verification_error,
AvbVBMetaImageFlags toplevel_vbmeta_flags,
int rollback_index_location,
const char* partition_name,
size_t partition_name_len,
const uint8_t* expected_public_key,
size_t expected_public_key_length,
AvbSlotVerifyData* slot_data,
AvbAlgorithmType* out_algorithm_type,
AvbCmdlineSubstList* out_additional_cmdline_subst) {
...
//在分析load_and_verify_vbmeta前,我们先看一下AvbVBMetaImageHeader结构体
AvbVBMetaImageHeader vbmeta_header;
不分析AvbVBMetaImageHeader 结构体,估计很难明白这个函数是在校验啥东东。
//能看到AvbVBMetaImageHeader头信息中主要由三部分组成
Header data: vbmeta的header数据,固定长度256字节。
Authentication data:认证校验数据,长度不固定,主要包含签名和公钥等信息。
Auxiliary data:辅助数据,主要包含vbmeta中其他分区的descriptor描述信息。
* +-----------------------------------------+
* | Header data - fixed size |
* +-----------------------------------------+
* | Authentication data - variable size |
* +-----------------------------------------+
* | Auxiliary data - variable size |
* +-----------------------------------------+
//每一项参数,代码中都有进行说明
typedef struct AvbVBMetaImageHeader {
魔术AVB0占四个字节
/* 0: Four bytes equal to "AVB0" (AVB_MAGIC). */
uint8_t magic[AVB_MAGIC_LEN];
AVB的版本号信息1.0.0
/* 4: The major version of libavb required for this header. */
uint32_t required_libavb_version_major;
/* 8: The minor version of libavb required for this header. */
uint32_t required_libavb_version_minor;
签名信息长度和辅助信息长度
/* 12: The size of the signature block. */
uint64_t authentication_data_block_size;
/* 20: The size of the auxiliary data block. */
uint64_t auxiliary_data_block_size;
使用的签名算法类型
/* 28: The verification algorithm used, see |AvbAlgorithmType| enum. */
uint32_t algorithm_type;
签名数据的在header中的Body的Hash偏移位置
/* 32: Offset into the "Authentication data" block of hash data. */
uint64_t hash_offset;
数据Body的Hash大小
/* 40: Length of the hash data. */
uint64_t hash_size;
签名数据的偏移位置
/* 48: Offset into the "Authentication data" block of signature data. */
uint64_t signature_offset;
签名数据的大小
/* 56: Length of the signature data. */
uint64_t signature_size;
公钥的偏移位置
/* 64: Offset into the "Auxiliary data" block of public key data. */
uint64_t public_key_offset;
公钥的长度
/* 72: Length of the public key data. */
uint64_t public_key_size;
公钥metadata的偏移位置和长度
/* 80: Offset into the "Auxiliary data" block of public key metadata. */
uint64_t public_key_metadata_offset;
/* 88: Length of the public key metadata. Must be set to zero if there
* is no public key metadata.
*/
uint64_t public_key_metadata_size;
子分区的descriptor描述信息的偏移位置和长度
/* 96: Offset into the "Auxiliary data" block of descriptor data. */
uint64_t descriptors_offset;
/* 104: Length of descriptor data. */
uint64_t descriptors_size;
vbmeta的rollback回滚值
/* 112: The rollback index which can be used to prevent rollback to
* older versions.
*/
uint64_t rollback_index;
vbmeta的flags标志位,是否disable-verification等
/* 120: Flags from the AvbVBMetaImageFlags enumeration. This must be
* set to zero if the vbmeta image is not a top-level image.
*/
uint32_t flags;
预留的字节,为将来可扩展准备
/* 124: Reserved to ensure |release_string| start on a 16-byte
* boundary. Must be set to zeroes.
*/
uint8_t reserved0[4];
/* 128: The release string from avbtool, e.g. "avbtool 1.0.0" or
* "avbtool 1.0.0 xyz_board Git-234abde89". Is guaranteed to be NUL
* terminated. Applications must not make assumptions about how this
* string is formatted.
*/
uint8_t release_string[AVB_RELEASE_STRING_SIZE];
/* 176: Padding to ensure struct is size AVB_VBMETA_IMAGE_HEADER_SIZE
* bytes. This must be set to zeroes.
*/
uint8_t reserved[80];
} AVB_ATTR_PACKED AvbVBMetaImageHeader;
好了,知道vbmeta头结构体后,我们继续分析load_and_verify_vbmeta代码
//alloc申请内存
vbmeta_buf = avb_malloc(vbmeta_size);
if (vbmeta_buf == NULL) {
ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
goto out;
}
//触发avb_ops.cpp中第一个回调函数,本文的下面段落中有说明
//android侧只实现了这一个回调函数,其余的都留给厂商自己实现了,在UBOOT中就可以开发定制了。
io_ret = ops->read_from_partition(ops,
full_partition_name,
vbmeta_offset,
vbmeta_size,
vbmeta_buf,
&vbmeta_num_read);
//加载完vbmeta数据后,需要对vbmeta数据进行校验,调用avb_vbmeta_image_verify函数
//本文下面专门讲,这里先分析后续的流程
vbmeta_ret =
avb_vbmeta_image_verify(vbmeta_buf, vbmeta_num_read, &pk_data, &pk_len);
//vbmeta基础数据verify通过后,校验一下公钥hash是否匹配,是否本次andorid源码编译产生的key
//这个数据是在android编译的时候产生的,
//validate_vbmeta_public_key是第二个回调函数,厂家可自定义实现,比如把key存储中其他地方
//android默认为空,直接返回
avb_assert(is_main_vbmeta);
io_ret = ops->validate_vbmeta_public_key(ops,
pk_data,
pk_len,
pk_metadata,
pk_metadata_len,
&key_is_trusted);
//紧接着会校验vbmeta的rollback回滚值,android默认为空,直接返回
//这是第三个回调函数
io_ret = ops->read_rollback_index(
ops, rollback_index_location_to_use, &stored_rollback_index);
//同时下面代码还有rollback_index回滚值的比较判断,主要是比较存储中的index值和vbmeta中的index值
//更新策略为:当vbmeta中的index大于存储中的值,将存储中的值更新到存储空间;
//如果vbmeta中的index小于存储中的值,启动boot失败,防止用户降级版本。
//android默认为空实现,默认index为0,不需要更新写入。
//加载vbmeta中descrptor其他分区的信息,比如vbmeta_system/boot/vendor_boot等分区的信息
descriptors =
avb_descriptor_get_all(vbmeta_buf, vbmeta_num_read, &num_descriptors);
for (n = 0; n < num_descriptors; n++) {
AvbDescriptor desc;
if (!avb_descriptor_validate_and_byteswap(descriptors[n], &desc)) {
avb_errorv(full_partition_name, ": Descriptor is invalid.\n", NULL);
ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA;
goto out;
}
//如果decriptor分区是hash类型,比如boot分区,调用load_and_verify_hash_partition计算hash并进行比较
switch (desc.tag) {
case AVB_DESCRIPTOR_TAG_HASH: {
AvbSlotVerifyResult sub_ret;
sub_ret = load_and_verify_hash_partition(ops,
requested_partitions,
ab_suffix,
allow_verification_error,
descriptors[n],
slot_data);
if (sub_ret != AVB_SLOT_VERIFY_RESULT_OK) {
ret = sub_ret;
if (!allow_verification_error || !result_should_continue(ret)) {
goto out;
}
}
} break;
case AVB_DESCRIPTOR_TAG_CHAIN_PARTITION: {
case AVB_DESCRIPTOR_TAG_KERNEL_CMDLINE: {
//如果是hashtree类型,比如system分区,调用read_persistent_digest读此分区的digest信息
case AVB_DESCRIPTOR_TAG_HASHTREE: {
ret = read_persistent_digest(ops,
part_name,
digest_len,
NULL /* initial_digest */,
digest_buf);
好了,这个函数到这里就基本上差不多了。
现在这个函数中,还有两个子函数还没有分析,
1、read_from_partition函数
其中ReadFromPartition的实现比较简单,找到vbmeta的dev节点名称,打开fd,调用read函数,将64KB的vbmeta数据全加载出来。
static AvbIOResult read_from_partition(AvbOps* ops, const char* partition, int64_t offset,
size_t num_bytes, void* buffer, size_t* out_num_read) {
return FsManagerAvbOps::GetInstanceFromAvbOps(ops)->ReadFromPartition(
partition, offset, num_bytes, buffer, out_num_read);
}
AvbIOResult FsManagerAvbOps::ReadFromPartition(const char* partition, int64_t offset,
size_t num_bytes, void* buffer,
size_t* out_num_read) {
std::string path = "/dev/block/by-name/"s + partition;
// Ensures the device path (a symlink created by init) is ready to access.
if (!WaitForFile(path, 1s)) {
LERROR << "Device path not found: " << path;
// Falls back to logical path if the physical path is not found.
// This mostly only works for emulator (no bootloader). Because in normal
// device, bootloader is unable to read logical partitions. So if libavb in
// the bootloader failed to read a physical partition, it will failed to boot
// the HLOS and we won't reach the code here.
path = GetLogicalPath(partition);
if (path.empty() || !WaitForFile(path, 1s)) return AVB_IO_RESULT_ERROR_NO_SUCH_PARTITION;
LINFO << "Fallback to use logical device path: " << path;
}
android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(path.c_str(), O_RDONLY | O_CLOEXEC)));
if (fd < 0) {
PERROR << "Failed to open " << path;
return AVB_IO_RESULT_ERROR_IO;
}
// If offset is negative, interprets its absolute value as the
// number of bytes from the end of the partition.
if (offset < 0) {
off64_t total_size = lseek64(fd, 0, SEEK_END);
if (total_size == -1) {
PERROR << "Failed to lseek64 to end of the partition";
return AVB_IO_RESULT_ERROR_IO;
}
offset = total_size + offset;
// Repositions the offset to the beginning.
if (lseek64(fd, 0, SEEK_SET) == -1) {
PERROR << "Failed to lseek64 to the beginning of the partition";
return AVB_IO_RESULT_ERROR_IO;
}
}
// On Linux, we never get partial reads from block devices (except
// for EOF).
ssize_t num_read = TEMP_FAILURE_RETRY(pread64(fd, buffer, num_bytes, offset));
if (num_read < 0 || (size_t)num_read != num_bytes) {
PERROR << "Failed to read " << num_bytes << " bytes from " << path << " offset " << offset;
return AVB_IO_RESULT_ERROR_IO;
}
if (out_num_read != nullptr) {
*out_num_read = num_read;
}
return AVB_IO_RESULT_OK;
}
2、avb_vbmeta_image_verify函数
这个函数因为这里面涉及到RSA算法的验签流程,内容也很多,慢慢分析一下。
AvbVBMetaVerifyResult avb_vbmeta_image_verify(
const uint8_t* data,
size_t length,
const uint8_t** out_public_key_data,
size_t* out_public_key_length) {
...
//首先判断是不是以“AVB0”开头的,vim打开vbmeta.img就可以看到是以AVB0开头
/* Ensure magic is correct. */
if (avb_safe_memcmp(data, AVB_MAGIC, AVB_MAGIC_LEN) != 0) {
avb_error("Magic is incorrect.\n");
goto out;
}
//把数据拷贝到到h AvbVBMetaImageHeader中
avb_vbmeta_image_header_to_host_byte_order((const AvbVBMetaImageHeader*)data,
&h);
//比较avbtool的版本号 avbtool 1.10
if ((h.required_libavb_version_major != AVB_VERSION_MAJOR) ||
(h.required_libavb_version_minor > AVB_VERSION_MINOR)) {
avb_error("Mismatch between image version and libavb version.\n");
ret = AVB_VBMETA_VERIFY_RESULT_UNSUPPORTED_VERSION;
goto out;
}
//判断authentication和auxiliary数据大小是不是64字节的整数倍
if ((h.authentication_data_block_size & 0x3f) != 0 ||
(h.auxiliary_data_block_size & 0x3f) != 0) {
avb_error("Block size is not a multiple of 64.\n");
goto out;
}
//判断hash和signature内容在vbmeta header中
uint64_t hash_end;
if (!avb_safe_add(&hash_end, h.hash_offset, h.hash_size) ||
hash_end > h.authentication_data_block_size) {
avb_error("Hash is not entirely in its block.\n");
goto out;
}
uint64_t signature_end;
if (!avb_safe_add(&signature_end, h.signature_offset, h.signature_size) ||
signature_end > h.authentication_data_block_size) {
avb_error("Signature is not entirely in its block.\n");
goto out;
}
//判断public key和public key metadata内容在vbmeta header中
/* Ensure public key is entirely in the Auxiliary data block. */
uint64_t pubkey_end;
if (!avb_safe_add(&pubkey_end, h.public_key_offset, h.public_key_size) ||
pubkey_end > h.auxiliary_data_block_size) {
avb_error("Public key is not entirely in its block.\n");
goto out;
}
/* Ensure public key metadata (if set) is entirely in the Auxiliary
* data block. */
if (h.public_key_metadata_size > 0) {
uint64_t pubkey_md_end;
if (!avb_safe_add(&pubkey_md_end,
h.public_key_metadata_offset,
h.public_key_metadata_size) ||
pubkey_md_end > h.auxiliary_data_block_size) {
avb_error("Public key metadata is not entirely in its block.\n");
goto out;
}
}
//判断RSA algorithm的type和长度是不是符合
if (h.algorithm_type == AVB_ALGORITHM_TYPE_NONE) {
ret = AVB_VBMETA_VERIFY_RESULT_OK_NOT_SIGNED;
avb_error("pis algoth type none AVB_VBMETA_VERIFY_RESULT_OK_NOT_SIGNED!\n");
goto out;
}
/* Ensure algorithm field is supported. */
algorithm = avb_get_algorithm_data(h.algorithm_type);
if (!algorithm) {
avb_error("Invalid or unknown algorithm.\n");
goto out;
}
/* Bail if the embedded hash size doesn't match the chosen algorithm. */
if (h.hash_size != algorithm->hash_len) {
avb_error("Embedded hash has wrong size.\n");
goto out;
}
//到这里基本的检查项就完成了,接下来就是验证数据是不是匹配了
header_block = data;
authentication_block = header_block + sizeof(AvbVBMetaImageHeader);
auxiliary_block = authentication_block + h.authentication_data_block_size;
//我们编译vbmeta应该是使用的SHA256_RSA4096,所以走下面这段逻辑
switch (h.algorithm_type) {
/* Explicit fall-through: */
case AVB_ALGORITHM_TYPE_SHA256_RSA2048:
case AVB_ALGORITHM_TYPE_SHA256_RSA4096:
case AVB_ALGORITHM_TYPE_SHA256_RSA8192:
avb_sha256_init(&sha256_ctx);
avb_sha256_update(
&sha256_ctx, header_block, sizeof(AvbVBMetaImageHeader));
avb_sha256_update(
&sha256_ctx, auxiliary_block, h.auxiliary_data_block_size);
computed_hash = avb_sha256_final(&sha256_ctx);
break;
//验证hash是否相等
if (avb_safe_memcmp(authentication_block + h.hash_offset,
computed_hash,
h.hash_size) != 0) {
avb_error("Hash does not match!\n");
ret = AVB_VBMETA_VERIFY_RESULT_HASH_MISMATCH;
goto out;
}
//验证signature签名是否匹配
verification_result =
avb_rsa_verify(auxiliary_block + h.public_key_offset,
h.public_key_size,
authentication_block + h.signature_offset,
h.signature_size,
authentication_block + h.hash_offset,
h.hash_size,
algorithm->padding,
algorithm->padding_len);
}
---------------------------------------------- 分割一下 ------------------------------------------------------------
我们单独来分析一下,一共有两个验证,一个是hash比较,一个是signature签名比较。
在了解下面这段之前,可以先看看我之前写过的博客python实现RSA加密解密 及 签名验签功能 简单看下第3节 “私钥签名 公钥验签”,要理解下面这个函数的内容,得先看一下vbmeta.img镜像header的签名打包流程,将新创建一篇博客太记录吧,本篇内容有点长。
请见AVB之镜像的签名及验证签名详解hash比较
avb_sha256_init(&sha256_ctx);
avb_sha256_update(
&sha256_ctx, header_block, sizeof(AvbVBMetaImageHeader));
avb_sha256_update(
&sha256_ctx, auxiliary_block, h.auxiliary_data_block_size);
computed_hash = avb_sha256_final(&sha256_ctx);
signature签名比较
verification_result =
avb_rsa_verify(auxiliary_block + h.public_key_offset,
h.public_key_size,
authentication_block + h.signature_offset,
h.signature_size,
authentication_block + h.hash_offset,
h.hash_size,
algorithm->padding,
algorithm->padding_len);