背景
本文将介绍NXP的AHAB
和HAB
机制以及差异,详细说明如何一步步使用CST
工具对镜像进行签名以及验签的过程。
NXP AHAB介绍(i.MX8使用)
资料来源u-boot/doc/imx/ahab/introduction_ahab.txt
:
AHAB认证基于数字签名,其中使用一个或多个private key
离线对镜像数据进行签名。然后使用相应的public key
在i.MX处理器上验证所得到的签名镜像数据。public key
包含在最终二进制文件中,SRK hash在SoC的fuse中(OTP
),用于建立信任根(确认SRK是否一致)。
这里面涉及到的private key
和public key
都是在CST
工具中生成,CST
在这里可以认为是一个CA
。i.MX8 secure boot流程:
1 | 1 - At reset, the SCU ROM and SECO ROM both start execution. |
NXP HAB介绍(i.MX7以下的使用)
根据NXP官方文档:Secure Boot on i.MX 50, i.MX 53, i.MX 6 and i.MX 7 Series using HABv4 ,我们可以研究一下HAB是个什么东西。
官方定义
1 | Executing trusted and authentic code on an applications processor starts with securely booting the device. |
官方术语
CA(Certificate Authority)
:持有private key
并对public key
签名生成数字证书
;CAAM(Cryptographic Acceleration and Assurance Module)
:用于加密,流密码和散列算法的加速器,使用随机数生成器和运行时完整性检查程序;CSF(Command Sequence File)
:由HAB解释的二进制数据结构,用于指导身份验证操作;CST(Code Signing Tool)
:在构建主机上运行的应用程序,用于生成CSF
和相关的数字签名,产生NXP所需要的SRK
等;HAB(High Assurance Boot)
:启动时在NXP处理器的内部ROM中执行的软件库,通过CSF
验证数字签名来验证外部存储器中的软件;OTP(One-Time Programmable)
:OTP硬件包括屏蔽ROM和电可编程保险丝(eFuse),只能烧写一次,不可改变;PKI(Public Key Infrastructure)
:公钥证书的层次结构,其中每个证书(根证书除外)都可以使用其上方的公钥进行验证;SRK(Super Root Key)
:一个RSA密钥对(SRK公钥和秘钥),它构成了启动时认证链的起点。SRK公钥的散列使用OTP硬件嵌入在处理器中。 SRK私钥由CA持有。
HAB身份验证过程
HAB身份验证基于使用RSA算法加密的public key
,验证镜像数据,使用一系列private key
对镜像数据在安全的环境中进行脱机签名。然后在i.MX处理器上使用相应的public key
(SRK)验证所得到的签名镜像数据。
在上图中:
1、在安全的环境中对SW Image
内容hash化生成摘要A
,然后使用private key
对摘要A
进行签名(采用RSA算法),得到SW Image
和Signature
;
2、将该SW Image
和Signature
烧录到flash中后去启动;
3、在启动的时候会将SW Image
内容hash化生成摘要B
(如果SW Image
没有被修改过,摘要A
和摘要B
肯定相等),使用Fuse中的public key
进行对Signature
进行验签得到摘要C
,如果摘要B
和摘要C
相等,表示认证成功,就去启动OS。
注意,这里i.MX处理器中芯片存储的是SRK
,而不是hash化后的值,所以该SRK
可以直接进行验签。
HAB和AHAB
HAB Library
是boot rom code
中的一个子模块,AHAB
是某些特定的NXP处理器中的安全子系统。他们负责验证作为产品软件一部分的数字签名,并确保当处理器配置为安全设备时,不允许运行未经身份验证的代码。
使用HAB的启动流程
对于HAB,引导加载程序映像包含引导加载程序本身以及:HAB用于验证映像的命令,数字签名
数据和public key数字证书
数据,统称为命令序列文件(CSF)
数据,使用代码签名工具(CST)离线生成CSF数据。
使用AHAB(SECO)的启动流程
使用CST工具进行数字签名
可以在IMX_CST_TOOL 下载CST工具,该工具用于对HAB和AHAB进行代码签名。
- CST输入文件:
要签名的Image镜像 + CSF文件(CSF文件提供了一系列指令给CST,比如说数据镜像从哪里开始签名,使用哪个key去签名) - CST输出文件:
Image镜像 + 数字签名 + CSF文件(该文件只有HAB有)。
CST目录结构
ca\
:包含OpenSSL配置文件。 使用OpenSSL命令行工具生成签名密钥和证书时,将使用这些配置文件;crts\
:包含用于签名的public key
证书,最初此目录为空;linux32/
和linux64/
:包含CST工具执行的文件。bin/cst
用于CST执行对代码签名;bin/srktool
为HAB4和AHAB生成SRK表和e-fuse文件;keys/
:包含用于签名的private key
,最初时候此目录只包含生成PKI tree
的脚本,格式如下:
包含的脚本如下:habx_pki_tree.sh/.bat
脚本,其中x
为3或者4,该脚本有Linux和Windows两种,都是用于生成支持HABx所需要的一系列密钥和证书;ahab_pki_tree.sh/.bat
脚本,该脚本有Linux和Windows两种,都是用于生成支持AHAB
所需要的一系列密钥和证书;
一步步porting security boot
生成PKI tree
主要生成private key
和public key 数字证书
,生成的PKI tree
包含4个SRK
。
在csf文件
中会指定使用哪个SRK,签名后会往container中相应字段的值写入,这样的话在读取到container head之后就可以根据这个值来判断使用fuse的哪个SRK。
那为什么要用4个呢?通常情况下,可以让不同的批次指定不同的SRK。或者是同一个SRK永久了,可以指定换另外一个SRK。废弃掉的SRK可以在csf文件
中使用Revocations
来指定废弃哪个。csf文件
用例如下:
1 | [Header] |
我对SRK
可以理解为private key
和public key certificates
,前者用于对镜像进行签名或者是对public key
进行加密生成数字证书
。使用以下命令生成PKI tree
。
1 | # tar -zxvf cst-3.1.0.tgz |
生成的PKI tree
结构如下,不带SGK
。运行结果如下。
1 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
生成SRK table
和SRK hash
- 输入文件是在上一个步骤中创建的
public key certificates
; - 输出文件是
SRK table
和SRK hash
。
通过CA
的private key
对public key certificates
进行解密
就可以拿到可以对镜像认证的public key
。
在AHAB架构中:
SRK table
就是一系列的public key
证书,SRK table
会打包到已签名的镜像中;SRK hash
是SRK table
hash化生成的数字摘要
,会被烧写到i.MX芯片的SOC SRK_HASH[511:0]
OTP中;
在认证过程期间的目标设备上,AHAB代码(SECO
)会将镜像中的SRK table
hash化然后与SoC SRK_HASH
中的SRK hash
比较,如果相等,则说明用于验签的public key
是正确的,AHAB代码可以用该public key
进行后续的镜像认证。对于SRK table
中未使用的4个密钥中的任何一个,相应的密钥位将设置为0。后续的镜像认证,就是完全按照HAB的过程来了。
为什么生成SRK table
后还要生成SRK hash
呢?主要原因是:
- 由于
OTP
空间小,将public key
hash化之后,可以减小存储空间; - 为了防止
public key
和private key
被替换。假设有个图谋不轨的人,使用CST
生成private key
对自己的镜像签名,然后再将public key
加入到镜像中,镜像中的public key
被hash化后肯定不与fuse
中的SRK hash
不一致,因此无法验签通过。
1 | # cd ../crts/ |
各个参数含义如下:
1 | -a, --ahab_ver: |
用户可以使用如下命令验证生成的SRK table
和SRK hash
的sha256sum是否一致。
1 | # od -t x4 --endian=big SRK_1_2_3_4_fuse.bin |
对镜像签名
将镜像和csf
文件拷贝到cst目录下,按照csf
要求对镜像进行签名。其中使用mkimage
生成flash.bin的时候会打印如下log,csf_boot_image.txt
文件中的offset
字段必须根据这个log的内容做相应的修改。csf
文件用于指定从哪块区域的image去验证,使用哪个key去验证。
1 | CST: CONTAINER 0 offset: 0x400 |
对镜像签名命令如下,生成flash.signed.bin
的签名文件。
1 | # cd ../../ |
烧写SRK fuse
到soc中
执行如下命令,获取到烧写fuse的值:
1 | # od -t x4 SRK_1_2_3_4_fuse.bin |
因此,烧写fuse的值为(只针对i.MX8QXP),可以在uboot命令行中使用fuse
命令进行烧写。
1 | fuse prog 0 730 0x475e1dca |
烧写fuse的原理如下: https://imxdev.gitlab.io/tutorial/Burning_eFuses_on_i.MX8_and_i.MX8x_families/
验证签名的boot镜像是否认证成功
将第3步生成的签名镜像flash.signed.bin
烧写到板子上,从板子启动。
在最新的imx_v2018.03_4.14.98_2.0.0_ga
分支上,无需通过scu的串口来查看。直接在uboot命令行中使用ahab_status
就可以确定是否验证成功。
配置SCFW
支持debug monitor
配置SCFW
如下几个功能:
- 如果使用板子上使用
AF28(SCU.UART0.RX)
和AH30(SCU.UART0.TX)
做为SCU
的串口,那么必须在platform/board/mx8qx_mek/board.c
文件中打开ALT_DEBUG_SCU_UART
宏,否则就是使用到M4 UART; - 编译
scfw_tcm.bin
的时候使用make qx B=mek V=1 R=B0 M=1 D=1 DL=2
命令,M=1
表示打开debug monitor
功能,也就是可以通过串口与SCFW
交互,D=1
表示打开debug功能,DL=2
表示debug level。
详细的可以参考[System Controller Firmware Porting Guide.pdf]和[sc_fw_port.pdf]下面的debug monitor
的功能:
OS镜像签名
将kernel编译出来的Image
和.dtb
文件拷贝到imx-mkimage
环境中,这个可以从 imx-mkimage 下载。假定目前处于imx-mkimage
环境下。
1、拷贝所需要的镜像和dtb
1 | # cp -rf ~/work2/xxx/kernel-imx/arch/arm64/boot/Image ./iMX8QX/ |
2、修改soc.mk
为:
1 | flash_linux flash_b0_linux: $(MKIMG) Image xxxxx.dtb |
3、编译生成OS镜像的flash_os.bin 镜像拷贝到cst
目录下。
1 | # make SOC=iMX8QX flash_linux |
4、拷贝OS镜像签名所需的csf文件csf_linux_img.txt
5、修改csf_linux_img.txt
文件中的offset
字段。
6、在cst
目录下对flash_os.bin
进行签名:
1 | # ./release/linux64/bin/cst -i csf_linux_img.txt -o os_cntr_signed.bin |
SPL(Secondary Program Loader)的特殊处理
SPL被用于在初始化ARM ATF和u-boot之前初始化引导程序。u-boot中支持AHAB功能,这个功能对于完全验证flash.bin至关重要。
在SPL目标上,只有SCFW,SPL,M4镜像在SCU ROM阶段验证。为了验证ATF和U-boot,必须在SPL阶段调用sc_misc_seco_authenticate()
进行验证。
包含SPL的启动镜像
包含SPL的镜像包含3个container,如下:
- 第1个container只包含SECO FW,NXP签名,在SCU ROM阶段使用SECO ROM验证;
- 第2个container包含SCFW,SPL,M4镜像,这些由OEM签名,在SCU ROM阶段使用SECO FW验证;
- 第3个container包含u-boot和ATF,SPL负责load这个container,和使用接口通过SCU发送命令给SECO FW对container进行验证;
对包含SPL的镜像签名
(1)、编译生成第3个container镜像:
1 | make SOC=iMX8QX u-boot-atf-container.img |
编译的log如下:
1 | AP file_offset = 0x91800 size = 0x4d800 |
(2)、对第3个container签名:
a. 在cst中创建csf_uboot_atf.txt
文件,内容如下:
1 | [Header] |
b. 对镜像进行签名
1 | ./release/linux64/bin/cst -i csf_uboot_atf.txt -o signed-u-boot-atf-container.img |
将生成的signed-u-boot-atf-container.img
拷贝到imx-mkimage
目录中重新打包,并重命名为u-boot-atf-container.img
。
c、编译生成flash.bin
镜像
1 | make SOC=iMX8QX flash_spl_container |
编译的log如下:
1 | CST: CONTAINER 0 offset: 0x400 |
d、对flash.bin
镜像签名
将生成的flash.bin
镜像拷贝到cst目录中签名。
1 | ./release/linux64/bin/cst -i csf_boot_image.txt -o signed-flash.bin |
带SPL和不带SPL签名的差异
- 带SPL的镜像总共有3个container,不带SPL只有2个container;
- 带SPL的镜像需要将第3个container(u-boot + ATF)先签名,然后将签名后的镜像再跟第2个container(SCFW,SPL,M4镜像)打包再一起再进行签名最终生成
flash.bin
镜像。
参考资料
i.MX High Assurance Boot (HAB) / Secure Boot
mx8_mx8x_secure_boot.txt
mx8_mx8x_spl_secure_boot.txt
introduction_ahab.txt:
CAAM测试程序
i.MX HAB介绍
High Assurance Boot (HAB) for dummies