android AVB2.0(七)AVB移植经验

前言

本篇应该是AVB系列的最后一篇博客了,前面的六篇博客基本上把AVB涉及到的技术点都过了一遍,因为平时要开发项目比较忙 所以有点时间就上来写写,文笔不是很好 大家将就着看看了~~
感兴趣的朋友可以从这里开始android AVB2.0学习总结

当然我的博客可能有更多的细节没有讲到,比如android提供的README.md文档和UBOOT中的AVB设计。我其实刚开始是有计划去把README.md翻译和解析一遍,这个文档里面基本上包含到了android设计AVB的细节,我刚开始学习AVB的时候就是啃的这个文档,包括后面自己在AIOT项目上移植AVB功能,都是参考的这篇文档,建议对AVB感兴趣的朋友认真看看README.md。

好了,言归正传,下面我讲一下我在AIOT上如何实现AVB校验分区功能,把前面博客中介绍到的技术抽离出来自己实现AVB功能。

原创不易,转载请注明出处 https://blog.csdn.net/jackone12347/article/details/122121118

本篇博客主要包括项目需求、设计思路、详细设计,内容如下。

一、移植需求

在AIOT非android项目上实现system的AVB校验功能,需要移植android AVB功能上来。
好了,需求就是这个,离开android框架,自己搭建AVB环境,实现整套的AVB校验。

二、分解需求

我们的项目是基于buid root搭建的架子,下面是我分解的需求:

· 在编译build root前,生成RSA公私钥对,并抽出公钥hash存到veritydm模块的.h头文件中;
· 对编译的system镜像打包前,预留出签名所需要的空间;
· 全部编译完成后,分别对vbmeta.img和system.img进行签名,并生成带签名的vbmeta.img和system.img;
· 在开机挂载system分区前,调用veritydm程序对system进行签名验证并使能dm verity table到kernel md驱动;
· 设计veritydm程序,移植android的libavb库,并调用libavb库完成AVB校验,
  从vbmeta中获取system分区的digest和拼接参数组合成hash tree table,
  调用dmsetup程序将参数通过ioctl方式传递给kernel,完成device mapper的映射功能。

三、详细设计

整个的设计流程如下:
生成RSA密钥 ==》对system.img签名 ==》生成vbmeta.img ==> Verifydm程序验证签名 ==》
进行AVB校验 ==》 组建hash tree table ==》 创建device mapper映射

1. RSA密钥生成

项目上的源码不方便直接贴出,但我会尽量将涉及的技术点讲一下。
下面是shell脚本实现的RSA相关密钥的产生。

make_key是从andorid项目的development/tools/make_key移植过来的。

#下面是制作RSA时用到的变量
export PRI_KEY_CONTENT='/C=CN/ST=PD/L=SH/O=XXX/OU=SS/CN=China/emailAddress=xxx@xxx.com'
SALT_DATA='5c83818fd6371cbe4ecae7ff169a5857a5cae2e8e7b7d4b0168ac3e4fd42176t'
#make_key是从andorid项目的development/tools/make_key移植过来的
MAKE_KEY_PATH=make_key
KEY_PK8=veritykey.pk8
KEY_VERITY=veritykey.pem
#avbtool是从android移植 external/avb/avbtoo.py
AVBTOOL_PATH=avbtool
# bin2header工具我在AVB系列博客中"AVB中将公钥转换成字符数组头文件的实现"有介绍
BIN2HEADER_PATH=bin2header

下面是制作的脚本内容
$MAKE_KEY_PATH veritykey $PRI_KEY_CONTENT
openssl pkcs8 -inform DER -nocrypt -in veritykey.pk8 -out $KEY_VERITY
python $AVBTOOL_PATH extract_public_key --key $KEY_VERITY --output vbmeta_pub_key.bin
$BIN2HEADER_PATH vbmeta_pub_key.bin  vbmeta_key >> vbmeta_key_header.h

执行完成上面步骤后,产生了RSA私钥和公钥,以及公钥对应的header头文件。

2. 镜像签名和生成vbmeta镜像

有了私钥文件后,接下来就可以对system.img进行签名了

SYSTEM_IMG_PATH=system.img
export SHA_ALGORITHM=SHA256_RSA2048
export SYSTEM_ROLLBACK=1

#
调用avbtool.py脚本的calc_max_image_size函数,计算system的最大可用size
#因为要给hash tree预留空间
SIZE=`python $AVBTOOL_PATH add_hashtree_footer  --do_not_generate_fec --partition_size $yourpartitionsize --calc_max_image_size`

#调用avbtool.py脚本,添加footer数据,其中$KEY_VERITY就是前面步骤产生的私钥
 python $AVBTOOL_PATH add_hashtree_footer --partition_size ${SIZE} --partition_name system --image $SYSTEM_IMG_PATH\
    --salt $SALT_DATA --do_not_generate_fec --key $KEY_VERITY --hash_algorithm sha256 \
    --algorithm $SHA_ALGORITHM --rollback_index $SYSTEM_ROLLBACK

接下来是生成vbmeta.img,且将system.img的信息添加到vbmeta.img镜像中,主要是“–include_descriptors_from_image”这句了。

python $AVBTOOL_PATH make_vbmeta_image --output vbmeta.img --key $KEY_VERITY --algorithm $SHA_ALGORITHM --include_descriptors_from_image $SYSTEM_IMG_PATH  --padding_size 4096

这样vbmeta.img和system.img就生成好了,可以使用“info_image”命令查看一下vbmeta.img和system.img的信息,查看一下他们是否匹配。

python $AVBTOOL_PATH info_image --image vbmeta.img

3. VeritySetup程序设计

签名的system.img镜像和vbmeta.img都有了,接下就是开机运行的校验了,那谁来执行这个校验呢? android中是由init的第一阶段的程序完成校验,我们这里只能自己写程序去校验了,得自己造轮子~~~
内容如下:

3.1 主程序设计

#include "libavb/libavb.h“
int load_image_and_auth()
{
...
    user_data = avb_calloc(sizeof (AvbOpsUserData));
… 
    ops = avb_ops_new(user_data);
 
    slot_suffix = "\0";
    result = avb_slot_verify(ops, (const char *const *)requested_partition,
                slot_suffix, verify_flag, verity_flag, &slot_data);}

AvbOps *avb_ops_new(void *user_data);

typedef struct {
    bool is_user_key;
    bool is_multi_slot;
    uint32_t public_key_len;
    char* public_key[MAX_USER_KEY_SIZE];
} AvbOpsUserData;

AvbOps *avb_ops_new(void *user_data)
{
    AvbOps *ops = avb_calloc(sizeof(AvbOps));
    ops->user_data = user_data;
    ops->read_from_partition = avb_read_from_partition;
    ops->read_rollback_index = dummy_read_rollback_index;
    ops->validate_vbmeta_public_key = avb_validate_vbmeta_public_key;
    ops->read_is_device_unlocked = dummy_read_is_device_unlocked;
    ops->get_size_of_partition = dummy_get_size_of_partition;}

3.1 公钥比对接口设计

其中公钥比较是在avb_validate_vbmeta_public_key完成的

AvbIOResult
avb_validate_vbmeta_public_key(AvbOps *ops, const uint8_t *public_key_data,
                           size_t public_key_len, const uint8_t *public_key_metadata,
                           size_t public_key_metadata_len, bool *key_is_trusted)
{
...
if (memcmp(vbmeta_key, public_key_data, public_key_len) == 0) {
        *key_is_trusted = true;
} else {
       return AVB_IO_RESULT_ERROR_IO;
}
...
}

3.2 读取vbmeta分区设计

读取vbmeta分区的信息, avb_read_from_partition方法需要自己实现,
Google这几个接口默认没有实现,预留给开发者自行定义。
这里是直接read读取整个vbmeta分区。

AvbIOResult avb_read_from_partition(AvbOps *ops, const char *partition, int64_t offset, size_t num_bytes, void *buffer, size_t *out_num_read)
{
    if ((fd = open(DM_VBMETA_NODE, O_RDWR)) < 0) {
       return AVB_IO_RESULT_ERROR_IO;
    }
    size_t num_read = read(fd, buffer, num_bytes);
    if (num_read != num_bytes) {
        return AVB_IO_RESULT_ERROR_IO;
    }
 
    if (out_num_read != NULL) {
        *out_num_read = num_read;
    }}

其他的接口我就不描述了,比如lock和rollback的,如果有需求请自行实现即可,难度不是很大~

3.3 DM verity设计

有了接口了后,接下来要把读出来的hash tree设置到kernel驱动侧。
至于为什么是下面这个位置添加代码逻辑,需要理解我前面博客中读到的AVB验证流程,
因为最终我们的system是采用hash tree类型的处理。

@avb_slot_verify.c

case AVB_DESCRIPTOR_TAG_HASHTREE: {
       if (!avb_hashtree_descriptor_validate_and_byteswap(
     …
          ret =   AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA;
          goto out;
        }
...
##可以从hashtree_desc中获取到想要的信息,比如partition_name_len/image_size/data_block_size/hash_block_size/tree_offset

##然后就可以拼接hashtable了,参数如下
        sprintf(hashtable, "0 %ld %s %d %s %s %ld %ld %ld %ld sha256 %s %s",
            img_size / 512, "verity", dm_version, DM_SYSTEM_NODE, DM_SYSTEM_NODE, data_bsize, hash_bsize,
            img_size / 4096, img_size / 4096, avb_verity.root_digest, avb_verity.part_salt);


##hashtable OK后,就可以设置参数到kernel md模块了,我这里将用了build root自带的dmsetup程序完成。当然也可以参考android的那个ioctl方式来传递,都是可以的。
sprintf(cmd_buff, "./sbin/dmsetup create verity --readonly  --table \"%s\"", hashtable);

3.4 分区挂载校验

上面的主程序编译出来是verfydm,我们在开机的流程中去执行这个程序,执行完成后,会自动产生/dev/dm-0节点出来,这个和android是十分类似的。也很好理解,kernel不区分android还是linux,只要合理的ioctl成功,且底层能正常解析,就可以产生dm-x节点。

./sbin/verifydm

if [ $runResult == 0 -a -e /dev/dm-0 ]; then
    /bin/mount -t ext4 -o ro /dev/dm-0 /usr

下面是整个校验过程的完整日志,看下AVB校验的过程:

[main] test veritysetup world!
[libavb] avb_slot_verify entry...
[libavb] avb_slot_verify usual mode load vbmeta and verify.
[libavb] load_and_verify_vbmeta entry ====>
[libavb] load_and_verify_vbmeta partition_name:vbmeta
[libavb] load_and_verify_vbmeta read_from_partition: vbmeta
[avbops] avb_read_from_partition vbmeta entry ===
[avbops] avb_read_from_partition start to read data ===
[avbops] readResult offset: 0 num_read: 65536  buffer: 0x2e66e6d0
[libavb] load_and_verify_vbmeta read_from_partition done.
[libavb] avb_vbmeta_image_verify handle vbmeta header.
[libavb] avb_vbmeta_image_verify algorithm type is sha256.
[libavb] avb_vbmeta_image_verify start to check hash whether is matched...
[libavb] avb_vbmeta_image_verify avb_rsa_verify done.
[libavb] avb_vbmeta_image_verify hash and signature is matched!
[libavb] avb_vbmeta_image_verify all done <=====
[libavb] load_and_verify_vbmeta start to check key whether is expected.
[avbops] avb_validate_vbmeta_public_key public_key_len:520
[avbops] avb_validate_vbmeta_public key is equal!
[libavb] load_and_verify_vbmeta start to read rollback index... 
[libavb] load_and_verify_vbmeta num_descriptors inside.
[libavb] load_and_verify_vbmeta hashtree type.
[libavb] load_and_verify_vbmeta hashtree all successfully!
[libavb] load_and_verify_vbmeta all done!
[libavb] load_and_verify_vbmeta result:0
[libavb] avb_slot_verify manage dm-verity mode
[libavb] avb_slot_verify avb_sub_cmdline done
[libavb] avb_slot_verify function all done!
[main] avb_slot_verify result:0

总结

到这里AVB的移植就介绍差不多了。

为方便与大家及时交流,弄了一个微信公众号,欢迎大家留言沟通~
在这里插入图片描述

### 回答1: Android AVB (Android Verified Boot) 是安卓系统中的一种安全功能,目的是确保用户设备上的操作系统和应用程序未被篡改。它使用了基于密钥的验证方法,以验证设备上的固件和启动程序的完整性和可靠性。 Android AVB的工作原理是,在设备启动时,固件和启动程序会被验证。首先,设备会检查固件和启动程序的数字签名,以确保它们是由受信任的开发者签名的。如果签名验证通过,则设备会继续启动,否则会发出警告或者拒绝启动。 除了验证签名外,Android AVB还会检查系统分区的哈希值是否与预期的哈希值匹配。这些哈希值是在设备正常运行时生成的,并被记录在一个被称为AVB表的数据结构中。如果发现系统分区的哈希值与预期的哈希值不匹配,设备将中断启动并显示一条警告信息。 通过使用Android AVB,设备能够有效防止来自未经授权的来源的操作系统和启动程序的篡改。这增加了设备的安全性,使用户能够放心使用设备,而不担心潜在的恶意软件或未经授权的更改。 总之,Android AVB是安卓系统中的一种安全功能,它通过验证数字签名和哈希值来确保设备上的操作系统和启动程序的完整性。它帮助防止未经授权的篡改,提高了设备的安全性。 ### 回答2: Android AVBAndroid Verified Boot)是安卓系统中的一种验证引导机制,它通过在设备启动过程中验证系统的完整性,防止未经授权的修改及恶意软件损害系统安全。以下是关于Android AVB的一些要点。 首先,Android AVB使用数字签名验证系统引导映像的完整性。在设备启动时,引导加载程序(Bootloader)会验证引导映像的签名,只有通过数字证书签名的映像才能被加载,这样可以确保系统引导过程没有受到非法篡改。 其次,Android AVB启用分区级别的验证,每个分区的映像都需要通过数字签名进行验证。这使得系统分区、供应商分区和OEM分区等可以被独立验证,并且可以防止未经授权修改。 另外,Android AVB还使用了完整性元数据(Integrity Metadata)来确保系统分区的数据安全。完整性元数据存储了每个分区的哈希值和签名信息,设备启动时会加载并验证这些元数据,以确保分区的数据没有被篡改。 最后,Android AVB还可以在设备上使用强制加密(Force Encryption)来确保用户数据的密钥只能被正确验证的引导映像解锁。这可以防止未经授权的访问或修改用户数据。 总的来说,Android AVB通过数字签名、分区级别的验证以及完整性元数据等机制,确保了安卓设备系统引导过程的完整性和安全性,并且防止了未经授权的修改和恶意软件的攻击。 ### 回答3: Android AVB是指Android Verified Boot的缩写,是一种用于验证和保护Android设备的引导过程的安全机制。它的目标是检测和阻止未经授权的软件从设备的启动过程中加载和运行。 Android Verified Boot通过使用数字签名和哈希算法来验证引导镜像的完整性和真实性。在设备启动的过程中,它会使用设备制造商预装的公钥来验证引导镜像的数字签名是否有效,并且只有当验证通过时才会加载和运行系统。这样可以防止未经授权的软件或者恶意代码被插入到引导过程中,提高了设备的安全性。 此外,Android AVB还可以更容易地检测到设备的Root状态和未经授权的修改。通过保护系统分区和检测分区是否已被修改,它可以提供更可靠的保护机制,防止未经授权的软件或者恶意代码对设备进行篡改。这可以帮助用户避免安全漏洞和数据泄露。 总之,Android AVB是一种用于验证和保护设备启动过程的安全机制,通过验证引导镜像的完整性和真实性,检测设备的Root状态和分区是否被修改,提高了Android设备的安全性。这有助于保护用户的个人数据和设备免受恶意软件和未经授权的修改的威胁。
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值