前言
众所周知,安全问题现在越来越被大家所重视,目前运行Android系统的设备市场占有率很大,我们在这里就简单地分析下Android如何保证自己的系统运行安全的。
熟悉Android 系统的朋友们都知道,Android整个系统的的image有好多个。有bootloader、包含kernel的boot.img,还有system.img和vendor.img。
在芯片刚启动的时候会利用芯片中的OTP fuse的值对bootloader 镜像文件进行校验。bootloader启动后会根据Android verify boot 的规则去验证 kernel 也就是boot.img。kernel启动后会利用DM-verity 去验证system 和vendor的image。如果验证通过就正常运行。否则就会报错,运行失败。说起来有些繁琐,看下图,简单地描述这个部分的验证关系。其中AVB和DM-verity 我们将在接下来的章节里面介绍。
在进行安全验证的过程中离不开一个很重要的结构vbmeta struct.下一节我们首先介绍一下这个结构体。
1.VBmeta struct
标题1.1vbmeta struct 结构
在这一节我们介绍一个很重要的结构体:vbmeta struct。这个结构体是Android能够实现AVB功能的关键所在。
根据前面的图我们可以看到,在vbmeta 中包含了 数个descriptor ,每个descriptor 描述关于镜像文件的信息。例如 boot 镜像的hash值,dtbo 镜像的hash值。system和vendor分区比较大,因此在这里存放了这两个分区的Hashtree的数据。
在vbmeta的镜像文件中除了存放vbmeta struct,还有AVB 私钥(key0)对vbmeta image的签名数据,以及AVB 公钥的数据。
其结构具体如下:
1.2 AVB key
AVB key 是一对非对称密钥。私钥用来签名,公钥用来验证。如关系如图所示:
其中key在源代码中存放的位置如下:
私钥
${MY_ANDROID}/device/fsl/common/security/xxxx_private.pem
公钥
${MY_ANDROID}/device/fsl/common/security/xxxx_public.bin.
为了更直观地了解vbmeta struct deneirong,我们可以根据Android 提供的工具,分析下vbmeta文件镜像的内容。命令下下:
Vbmeta image can be parsed using avbtool in Android.
$ cd ${MY_ANDROID}/out/target/product/xxxx
$ ../../../../external/avb/avbtool info_image --image vbmeta.img > vbmeta.img.info
$ cat vbmeta.img.info
在这里我们的结果信息如下:
2. DM-verity
DM-verity 是Android 系统安全的另一重要部分,它能保证Android 的 vendor 和 system 镜像文件中的内容是真实可靠的。
那这个是怎么实现的呢,之前在vbmeta的镜像文件中有一个kernel cmdline descriptor 描述如何实现和system 相关的dm-verity。同时在vbmeta 中还包含system和vendor 镜像文件的hashtree的相关信息。
那么对于DM-verity 我们要对什么进行签名呢。答案是和hashtree 相对应的dm-verity table.。构建 dm-verity table,表会标明内核的块设备(或目标)以及哈希树的位置(是同一个值)。该映射表还会标明块的大小和 hash_start,即哈希树的起始位置(具体来说,就是哈希树在映像开头处的块编号)。
如需关于 Verity 目标映射表字段的详细说明,请参阅Google官方文档。在参考文档里面会有相关的链接【1】。
DM-verity 的私钥在source code的地址:
${MY_ANDROID}/build/target/product/security/verity_private_dev_key.
公钥所在地址:
${MY_ANDROID}/build/target/product/security/verity_key.
对dm-verity table 签名之后,公钥放在boot镜像文件所在的分区中。
总结
综上所述,在Android系统中,安全启动主要包括以下几部分。
1.在刚启动的时候芯片rom对bootloader,或者如果使能了TEE OS,还包括对TEE 镜像的验证。
2.bootloader 对boot.img(kernel) 进行验证.
3.kernel启动完成后,对/system /vendor分区进行验证
补充一点:
我们自己利用openssl产生公钥私钥的方法:
$ openssl genrsa -out verity_private_dev_key_tem 2048
$ openssl pkcs8 -topk8 -inform PEM -in verity_private_dev_key_tem -outverity_private_dev_key -outform PEM –nocrypt
$ pem2mincrypt verity_private_dev_key_tem verity_key
参考文档
【1】https://source.android.google.cn/security/verifiedboot/dm-verity?hl=zh-cn#mapping-table