前言
首先要介绍一下本篇文章的两个目标,带着这两个目标我们来分析一下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
1、bool FirstStageMountVBootV2::InitAvbHandle()
@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; }
2、AvbUniquePtr AvbHandle::Open()
实现在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之后的结果代码也比较简单就不分析了,我们重点分析校验流程
3、 avb_ops.AvbSlotVerify
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校验
1、入口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); }
2、load_and_verify_vbmeta
我们回到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); 好了,这个函数到这里就基本上差不多了。
现在这个函数中,还有两个子函数还没有分析,
3、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; }
4、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); }
我们单独开一篇好好分析一下。