By Toradex秦海
1). 简介
嵌入式设备对于网络安全的要求越来越高,而 Secure boot就是其中重要的一部分。 NXP i.MX8MM/i.MX8MP 处理器基于 HABv4 特性来提供 Secure boot 启动过程中的 Chain of Trust; HABv4 是基于公共密钥加密 (Public Key Cryptography) 和数字签名 (Digital Signature) 技术来实现 Secure boot 的,一个简单的流程图参考如下。本文就基于 NXP i.MX8M Mini 处理器平台测试部署 Secure boot 功能。
本文所演示的平台来自于 Toradex Verdini.MX8MM 嵌入式平台,主要测试基本的 Chain of Trust,也就是 U-boot和Linux Kernel 两个层级的加密和验证启动,后面 Rootfs 以及 Application 层面暂不涉及。
2. 准备
a). Verdin i.MX8MM ARM核心版配合Dahlia载板,并连接调试串口用于测试。
b). 参考>这里下载 Toradex Yocto Linux BSP6 Reference Image 用于后续测试,目前最新的是 6.6.0 版本。
3). 生成PKI Tree文件
a). 从NXP官方网站下载Code Signing Tools软件包(需注册),目前最新版本是3.4.0版本,然后解压后使用预设的脚本生成Public Key Infrastructure (PKI) tree,用于后面签名U-boot/Linux Kernel Image文件
--------------------------------
$ tree -L 1 cst-3.4.0/
cst-3.4.0/
├── add-ons
├── BUILD.md
├── ca
├── code
├── crts
├── Dockerfile
├── Dockerfile.hsm
├── docs
├── keys
├── LICENSE.bsd3
├── LICENSE.hidapi
├── LICENSE.openssl
├── linux32
├── linux64
├── Makefile
├── mingw32
├── Release_Notes.txt
└── Software_Content_Register_CST.txt
--------------------------------
b). 生成PKI TREE
./ 首先创建 serial和key_pass.txt 文件
--------------------------------
$ cd .../cst-3.4.0/keys
### create serial number for OpenSSL certification ###
$ vi serial
1234567C
### create key_pass for protection of private keys
$ vi key_pass.txt
Toradex123!
Toradex123!
--------------------------------
./ 运行CST工具预制脚本通过交互方式生成PKI TREE,这里生成一个2048bit RSA key SRK PKI TREE示例,更多可以参考如下U-Boot源代码中的文档说明
https://git.toradex.cn/cgit/u-boot-toradex.git/tree/doc/imx/habv4/introduction_habv4.txt?h=toradex_imx_lf_v2022.04
--------------------------------
### generate PKI TREE ###
$ ./hab4_pki_tree.sh
...
Do you want to use an existing CA key (y/n)?: n
Key type options (confirm targeted device supports desired key type):
Select the key type (possible values: rsa, rsa-pss, ecc)?: rsa
Enter key length in bits for PKI tree: 2048
Enter PKI tree duration (years): 10
How many Super Root Keys should be generated? 1
Do you want the SRK certificates to have the CA flag set? (y/n)?: y
...
### check generated SRK keys ###
$ ls SRK*
SRK1_sha256_2048_65537_v3_ca_key.der SRK1_sha256_2048_65537_v3_ca_key.pem
### generate HABv4 SRK Table 和 Efuse Hash ###
$ cd ../crts/
$ ../linux64/bin/srktool -h 4 -t SRK_1_2_3_4_table.bin \
-e SRK_1_2_3_4_fuse.bin -d sha256 -c \
./SRK1_sha256_2048_65537_v3_ca_crt.pem, \
./SRK2_sha256_2048_65537_v3_ca_crt.pem, \
./SRK3_sha256_2048_65537_v3_ca_crt.pem, \
./SRK4_sha256_2048_65537_v3_ca_crt.pem -f 1
Number of certificates = 1
SRK table binary filename = SRK_1_2_3_4_table.bin
SRK Fuse binary filename = SRK_1_2_3_4_fuse.bin
SRK Fuse binary dump:
SRK HASH[0] = 0x3D06A4A9
SRK HASH[1] = 0x4BC55D12
SRK HASH[2] = 0xA5F45E7F
SRK HASH[3] = 0x1F1F68FC
SRK HASH[4] = 0x3B9B4AE8
SRK HASH[5] = 0xFC658293
SRK HASH[6] = 0x40A706C9
SRK HASH[7] = 0x94A9139E
### check SRK Table and Efuse Hash ###
$ ls SRK_*
SRK_1_2_3_4_fuse.bin SRK_1_2_3_4_table.bin
--------------------------------
c). 上面最后生成的两个文件就是我们后面签名和 fuse 设备需要用到的,”SRK_1_2_3_4_table.bin”文件是 SRK Table ,用于签名 Container Image ;”SRK_1_2_3_4_fuse.bin”文件是Efuse Hash,用于 fuse 到 Verdin i.MX8MM 设备的 eFuse 。更多 CST 工具使用说明可以参考如下 CST User Guide 文档
cst-3.4.0/docs/CST_UG.pdf
4). Boot Container 配置和签名
a). 参考这里说明下载Toradex Yocto Linux BSP 6.x.y 版本 U-boot源代码,默认配置并未使能 HABv4 功能支持,需要在 config 中使能如下选项,当前 Verdin i.MX8MM 使用的 Downstream U-boot 版本 2022.04 还需要一个 patch 来保证开启 HABv4 后 SPL 启动成功,修改完成后重新编译 U-Boot 文件。
./ U-boot 配置修改
--------------------------------
### add HAB and related crypto driver support ###
→ ARM architecture
→ SPL / TPL
→ Init options > Start-up hooks
### remove some modules to reduce SPL size ###
→ SPL / TPL
[ ] Suppport USB Gadget drivers
Library routines > Hashing Support
[ ] Enable SHA1 support in SPL
--------------------------------
./ Patch 文件
--------------------------------
--- a/board/toradex/verdin-imx8mm/spl.c
+++ b/board/toradex/verdin-imx8mm/spl.c
@@ -59,7 +59,7 @@ void spl_board_init(void)
ret = uclass_get_device_by_driver(UCLASS_MISC, DM_DRIVER_GET(caam_jr), &dev);
if (ret)
- printf("Failed to initialize %s: %d\n", dev->name, ret);
+ printf("Failed to initialize caam_jr(FSL_CAAM) : %d\n", ret);
}
}
--------------------------------
b). 参考如下文档,使用编译生成的U-Boot 相关文件打包生成 Verdin iMX8MM Boot Container Image 文件 ”flash.bin”
https://developer.toradex.cn/linux-bsp/os-development/build-u-boot-and-linux-kernel-from-source-code/build-u-boot/build-u-boot-for-nxp-imx8m-mini-plus-modules/
./ imx-mkimage 工具生成 Boot container image 的一些打印参数需要保留后面生成 csf 文件时候需要
--------------------------------
### generate boot container image flash.bin ###
$ make clean; make SOC=iMX8MM V=1 dtbs=fsl-imx8mp-evk.dtb flash_evk_emmc_fastboot
...
...
========= OFFSET dump =========
Loader IMAGE:
header_image_off 0x0
dcd_off 0x0
image_off 0x40
csf_off 0x35c00
spl hab block: 0x7e0fc0 0x0 0x35c00
Second Loader IMAGE:
sld_header_off 0x5fc00
sld_csf_off 0x60c20
sld hab block: 0x401fcdc0 0x5fc00 0x1020
--------------------------------
## spl hab block: includes IVT (SPL) + u-boot-spl-ddr.bin
## sld hab block: includes FDT (FIT header) + IVT (FIT)
## csf_off: CSF SPL binary offset
## sld_csf_off: CSF FIT binary offset
### print fit image hab infomation ###
## change PRINT_FIT_HAB_OFFSET=0x60000if using “flash_evk”as target in flash.bin generation such as for i.MX8MP SoC ##
$ make SOC=iMX8MM V=1 dtbs=fsl-imx8mp-evk.dtb PRINT_FIT_HAB_OFFSET=0x68000 print_fit_hab
...
TEE_LOAD_ADDR=0xbe000000 ATF_LOAD_ADDR=0x00920000 VERSION=v1 ../iMX8M/print_fit_hab.sh 0x68000 evk.dtb
0x40200000 0x62C00 0xBC468
0x402BC468 0x11F068 0xE538
0x920000 0x12D5A0 0xA0D0
## above 3 lines stands for address/offset of:
## u-boot-nodtb.bin
## u-boot.dtb
## bl31.bin (ARM Trusted Firmware)
--------------------------------
c). 此时先将上一步骤生成的 “flash.bin”文件重命名为 “imx-boot”,然后通过这里的说明通过Toradex Easy Installer更新到 Verdin i.MX8MM 模块并启动查看 HAB 功能使能情况。
./ SPL 启动 log,由于 boot container image 没有完成签名,因此会提示 “CSF header command not found”。
--------------------------------
U-Boot SPL 2022.04-21749-g3428b47019-dirty (Apr 22 2024 - 17:52:20 +0800)
...
Authenticate image from DDR location 0x401fcdc0...
Error: CSF header command not found
...
--------------------------------
./ U-boot 命令行下查看 HAB 状态,目前会有4个 HAB Event 错误。从 Event2 的地址来看正好是 SPL IVT 的地址,也印证了因为没有签名从 SPL 加载就验证出错了。
--------------------------------
Verdin iMX8MM # hab_status
Secure boot disabled
HAB Configuration: 0xf0, HAB State: 0x66
--------- HAB Event 1 -----------------
event data:
0xdb 0x00 0x08 0x43 0x33 0x11 0xcf 0x00
...
--------- HAB Event 2 -----------------
event data:
0xdb 0x00 0x14 0x43 0x33 0x0c 0xa0 0x00
0x00 0x00 0x00 0x00 0x00 0x7e 0x0f 0xc0
0x00 0x00 0x00 0x20
...
--------- HAB Event 3 -----------------
...
--------- HAB Event 4 -----------------
...
--------------------------------
d). 通过CST工具对上一步骤使用 imx-mkimage 生成的Boot Container Image “flash.bin”文件进行签名
./ 首先生成 csf_spl.txt 文件
--------------------------------
### copy csf_spl.txt template to CST tool containing folder ###
$ cp u-boot-toradex/doc/imx/habv4/csf_examples/mx8m/csf_spl.txt .../cst-3.4.0/
### modify csf_spl.txt “Authenticate data”item according to 4.b chapter spl hab blockfield value ###
--- a/csf_spl.txt 2024-04-16 17:51:40.087230224 +0800
+++ b/csf_spl.txt 2024-04-23 12:17:38.322221868 +0800
@@ -8,12 +8,12 @@
[Install SRK]
# Index of the key location in the SRK table to be installed
- File = "../crts/SRK_1_2_3_4_table.bin"
+ File = "./crts/SRK_1_2_3_4_table.bin"
Source index = 0
[Install CSFK]
# Key used to authenticate the CSF data
- File = "../crts/CSF1_1_sha256_2048_65537_v3_usr_crt.pem"
+ File = "./crts/CSF1_1_sha256_2048_65537_v3_usr_crt.pem"
[Authenticate CSF]
@@ -28,10 +28,10 @@
# Target key slot in HAB key store where key will be installed
Target index = 2
# Key to install
- File = "../crts/IMG1_1_sha256_2048_65537_v3_usr_crt.pem"
+ File = "./crts/IMG1_1_sha256_2048_65537_v3_usr_crt.pem"
[Authenticate Data]
# Key slot index used to authenticate the image data
Verification index = 2
# Authenticate Start Address, Offset, Length and file
- Blocks = 0x7e0fc0 0x1a000 0x2a600 "flash.bin"
+ Blocks = 0x7e0fc0 0x0 0x35c00 "flash.bin"
--------------------------------
./ 然后生成 csf_fit.txt 文件
--------------------------------
### copy csf_fit.txt template to CST tool containing folder ###
$ cp u-boot-toradex/doc/imx/habv4/csf_examples/mx8m/csf_fit.txt .../cst-3.4.0/
### modify csf_fit.txt “Authenticate data”item according to 4.b chapter sld hab blockfield value and print_fit_haboutput information ###
--- a/csf_fit.txt.bak 2024-04-23 12:24:07.177249415 +0800
+++ b/csf_fit.txt 2024-04-23 12:40:15.342934544 +0800
@@ -8,12 +8,12 @@
[Install SRK]
# Index of the key location in the SRK table to be installed
- File = "../crts/SRK_1_2_3_4_table.bin"
+ File = "./crts/SRK_1_2_3_4_table.bin"
Source index = 0
[Install CSFK]
# Key used to authenticate the CSF data
- File = "../crts/CSF1_1_sha256_2048_65537_v3_usr_crt.pem"
+ File = "./crts/CSF1_1_sha256_2048_65537_v3_usr_crt.pem"
[Authenticate CSF]
@@ -23,14 +23,13 @@
# Target key slot in HAB key store where key will be installed
Target index = 2
# Key to install
- File = "../crts/IMG1_1_sha256_2048_65537_v3_usr_crt.pem"
+ File = "./crts/IMG1_1_sha256_2048_65537_v3_usr_crt.pem"
[Authenticate Data]
# Key slot index used to authenticate the image data
Verification index = 2
# Authenticate Start Address, Offset, Length and file
- Blocks = 0x401fcdc0 0x057c00 0x01020 "flash.bin", \
- 0x40200000 0x05CC00 0x9AAC8 "flash.bin", \
- 0x00910000 0x0F76C8 0x09139 "flash.bin", \
- 0xFE000000 0x100804 0x4D268 "flash.bin", \
- 0x4029AAC8 0x14DA6C 0x06DCF "flash.bin"
+ Blocks = 0x401fcdc0 0x5fc00 0x1020 "flash.bin", \
+ 0x40200000 0x62C00 0xBC468 "flash.bin", \
+ 0x402BC468 0x11F068 0xE538 "flash.bin", \
+ 0x920000 0x12D5A0 0xA0D0 "flash.bin"
--------------------------------
./ 创建 SPL CSF 和 FIT CSF binary 文件
--------------------------------
### copy boot container image file to CST tool containing folder ###
$ cp .../imx-mkimage/iMX8M/flash.bin .../cst-3.4.0/
### create SPL CSF binary ###
$ cd .../cst-3.4.0/
$ ./linux64/bin/cst -i csf_spl.txt -o csf_spl.bin
CSF Processed successfully and signed data available in csf_spl.bin
### create FIT CSF binary ###
$ ./linux64/bin/cst -i csf_fit.txt -o csf_fit.bin
CSF Processed successfully and signed data available in csf_fit.bin
--------------------------------
./ 组装CSF binary 到 flash.bin binary 以生成签名后的 Boot container image
--------------------------------
$ cd .../cst-3.4.0/
### Create a flash.bin copy###
$ cp flash.bin signed_flash.bin
### Insert csf_spl.bin in signed_flash.bin at offsetfrom 4.b chapter csf_offfield value ###
$ dd if=csf_spl.bin of=signed_flash.bin seek=$((0x35c00)) bs=1 conv=notrunc
### Insert csf_fit.bin in signed_flash.bin at offsetfrom 4.b chapter sld_csf_offfield value ###
$ dd if=csf_fit.bin of=signed_flash.bin seek=$((0x60c20)) bs=1 conv=notrunc
--------------------------------
e). 烧写SRK Hash
./ 签名的Boot Container Image文件要通过i.MX8MM SOC SRK_HASH[255:0] fuses 烧写的SRK Hash进行校验
./ 烧录的 SRK HASH 即3.b 章节 SRK Fuse binary dumpfield value,也可以通过如下命令重新导出SRK HASH fuse对应数值
--------------------------------
$ cd cst-3.4.0/crts/
### dump SRK HASH fuses value ###
$ hexdump -e '/4 "0x"' -e '/4 "%X""\n"' SRK_1_2_3_4_fuse.bin
0x3D06A4A9
0x4BC55D12
0xA5F45E7F
0x1F1F68FC
0x3B9B4AE8
0xFC658293
0x40A706C9
0x94A9139E
--------------------------------
./ 进入 Verdin i.MX8MM U-Boot 命令行,通过如下命令写入 fuses,注意这些fuses都是一次写入的,因此请务必保证一次写入正确。为了操作方便,可以将上述命令生成U-Boot脚本文件或者通过 NXP Universal Update Utility (UUU)工具脚本来进行操作,本文不做赘述。
--------------------------------
Verdin iMX8MM # fuse prog -y 6 0 0x3D06A4A9
Verdin iMX8MM # fuse prog -y 6 1 0x4BC55D12
Verdin iMX8MM # fuse prog -y 6 2 0xA5F45E7F
Verdin iMX8MM # fuse prog -y 6 3 0x1F1F68FC
Verdin iMX8MM # fuse prog -y 7 0 0x3B9B4AE8
Verdin iMX8MM # fuse prog -y 7 1 0xFC658293
Verdin iMX8MM # fuse prog -y 7 2 0x40A706C9
Verdin iMX8MM # fuse prog -y 7 3 0x94A9139E
--------------------------------
f). 此时再将上一步骤签名成功的 “signed_flash.bin”文件重命名为 “imx-boot”并更新到Verdin i.MX8MM 模块上面启动查看 HAB 功能使能情况。
./ SPL 启动 log,由于 boot container image 已经签名,因此提示已经变为 “Authenticate image ...”。
--------------------------------
U-Boot SPL 2022.04-21749-g3428b47019-dirty (Apr 22 2024 - 17:52:20 +0800)
...
Authenticate image from DDR location 0x401fcdc0...
...
--------------------------------
./ U-boot 命令行下查看 HAB 状态,已经没有错误事件。
--------------------------------
Verdin iMX8MM # hab_status
Secure boot disabled
HAB Configuration: 0xf0, HAB State: 0x66
No HAB Events Found!
--------------------------------
g). 更多关于此步骤的说明请参考如下文档
./ U-Boot documentation
https://git.toradex.cn/cgit/u-boot-toradex.git/tree/doc/imx/habv4/guides/mx8m_secure_boot.txt?h=toradex_imx_lf_v2022.04
./ NXP Application Note - AN4581 i.MX Secure Boot on HABv4 Supported Devices
5). 签名Linux kernel
a). 此步骤为可选步骤,如果不需要Linux Kernel Secure Boot功能则可以通过如下 patch 文件关闭 booti HAB 验证,然后 close 设备即可。
--------------------------------
--- a/cmd/booti.c
+++ b/cmd/booti.c
@@ -78,7 +78,7 @@ static int booti_start(struct cmd_tbl *cmdtp, int flag, int argc,
if (ret != 0)
return 1;
-#if defined(CONFIG_IMX_HAB) && !defined(CONFIG_AVB_SUPPORT)
+#if 0
extern int authenticate_image(
uint32_t ddr_start, uint32_t raw_image_size);
if (authenticate_image(ld, image_size) != 0) {
--------------------------------
b). 解压Toradex Ycoto Linux BSP 6.6 Multimedia Image,获得LInux Kernel文件
--------------------------------
### uncompress BSP Image package ###
$ tar xvf Verdin-iMX8MM_Reference-Multimedia-Image-Tezi_6.6.0+build.12.tar
$ cd Verdin-iMX8MM_Reference-Multimedia-Image-Tezi_6.6.0+build.12/
### uncompress boot filesystem ###
$ mkdir bootfs/
$ tar Jxf Reference-Multimedia-Image-verdin-imx8mm.bootfs.tar.xz -C bootfs/
### extract kernel image from compressed package ###
$ cd bootfs/
$ gzip -d Image.gz
$ file Image
Image: Linux kernel ARM64 boot executable Image, little-endian, 4K pages
--------------------------------
c). 签名 Linux kernel image 文件
./ Padding image 文件
--------------------------------
$ cd .../Verdin-iMX8MM_Reference-Multimedia-Image-Tezi_6.6.0+build.12/bootfs
### read Image size ###
$ od -x -j 0x10 -N 0x4 --endian=little Image
0000020 0000 01c3
0000024
### pad the Image, Image_pad.bin size = 0x1c30000###
$ objcopy -I binary -O binary --pad-to 0x1c30000 --gap-fill=0x00 Image Image_pad.bin
### get IVT generator script from U-boot source ###
$ cp .../u-boot-toradex/doc/imx/habv4/script_examples/genIVT.pl .../Verdin-iMX8MM_Reference-Multimedia-Image-Tezi_6.6.0+build.12/bootfs
### customized script according to your device kernel loading address ###
#! /usr/bin/perl -w
use strict;
open(my $out, '>:raw', 'ivt.bin') or die "Unable to open: $!";
print $out pack("V", 0x412000D1); # Signature
print $out pack("V", 0x48200000); # Load Address (*load_address)
print $out pack("V", 0x0); # Reserved
print $out pack("V", 0x0); # DCD pointer
print $out pack("V", 0x0); # Boot Data
print $out pack("V", 0x49e30000); # Self Pointer (*ivt)
print $out pack("V", 0x49e30020); # CSF Pointer (*csf)
print $out pack("V", 0x0); # Reserved
close($out);
## Load Address - kernel_addr_r value from U-boot env
## Self Pointer - 0x48200000(Load Address) + 0x1c30000(the size of Image_pad.bin)
## CSF Pointer - 0x49e30000(Self Pointer) + 0x20 (the size of IVT binary)
### generate IVT binary ###
$ ./genIVT.pl
### Append the ivt.bin at the end of the padded Image ###
$ cat Image_pad.bin ivt.bin > Image_pad_ivt.bin
--------------------------------
./ 然后生成 CSF 文件用于后续签名 kernel image
--------------------------------
### copy csf_additional_images.txt template to CST tool containing folder ###
$ cp .../u-boot-toradex/doc/imx/habv4/csf_examples/additional_images/csf_additional_images.txt .../cst-3.4.0/
### customized CSF file ###
--- csf_additional_images.txt.bak 2024-04-24 16:43:28.038751461 +0800
+++ csf_additional_images.txt 2024-04-24 16:50:40.484115829 +0800
@@ -8,12 +8,12 @@
[Install SRK]
# Index of the key location in the SRK table to be installed
- File = "../crts/SRK_1_2_3_4_table.bin"
+ File = "./crts/SRK_1_2_3_4_table.bin"
Source index = 0
[Install CSFK]
# Key used to authenticate the CSF data
- File = "../crts/CSF1_1_sha256_2048_65537_v3_usr_crt.pem"
+ File = "./crts/CSF1_1_sha256_2048_65537_v3_usr_crt.pem"
[Authenticate CSF]
@@ -23,12 +23,10 @@
# Target key slot in HAB key store where key will be installed
Target Index = 2
# Key to install
- File= "../crts/IMG1_1_sha256_2048_65537_v3_usr_crt.pem"
+ File= "./crts/IMG1_1_sha256_2048_65537_v3_usr_crt.pem"
[Authenticate Data]
# Key slot index used to authenticate the image data
Verification index = 2
# Authenticate Start Address, Offset, Length and file
- Blocks = 0x80800000 0x00000000 0x006EA000 "zImage", \
- 0x83800000 0x00000000 0x0000B927 "imx7d-sdb.dtb", \
- 0x84000000 0x00000000 0x000425B8 "uTee-7dsdb"
+ Blocks = 0x48200000 0x00000000 0x1c30020 "Image_pad_ivt.bin"
## Blocks =
## Image_length = 0x1c30020(the size of Image_pad_ivt.bin)
### create CSF binary file ###
$ ./linux64/bin/cst --i csf_additional_images.txt --o csf_Image.bin
CSF Processed successfully and signed data available in csf_Image.bin
--------------------------------
./ 签名 Kernel image
--------------------------------
$ cp .../Verdin-iMX8MM_Reference-Multimedia-Image-Tezi_6.6.0+build.12/bootfs/Image_pad_ivt.bin.../cst-3.4.0/
$ cd .../cst-3.4.0/
$ cat Image_pad_ivt.bin csf_Image.bin > Image_signed.bin
--------------------------------
d). 本文以 Kernel image 为例,实际其他的如 device tree 文件或者 FIT Image 等,都可以用类似方法进行签名。
6). 部署Kernel Image
a). 将上述签名好的 Kernel image 文件部署到 Verdin i.MX8MM 模块 Linux 系统 “/boot”目录下,替换原来的 Image 文件 “Image.gz”。
b). 重启进入 U-boot 命令行模式,通过如下命令行参数配置验证签名的 Kernel image 文件,如果没有任何 HAB Events,说明签名正确可以进行下一步。
--------------------------------
### set boot device info mmc 0:1 ###
Verdin iMX8MM # setenv pre_boot 'devnum=0; if mmc dev ${devnum}; then devtype=mmc; setenv load_cmd \"load ${devtype} ${devnum}:1\"; fi'
Verdin iMX8MM #run pre_boot
### signed kernel image loading ###
Verdin iMX8MM # setenv cntr_file 'Image_signed.bin'
Verdin iMX8MM # setenv cntr_load '${load_cmd} ${loadaddr} ${cntr_file}
Verdin iMX8MM #run cntr_load
### authenticate signed os container image ###
Verdin iMX8MM # setenv ivt_offset 0x1c30000
Verdin iMX8MM # setenv entr_filesize 0x1c30c34
## entr_filesize is the hex size of Image_signed.bin
## ivt_offset is the hex size of Image_pad_ivt.bin
Verdin iMX8MM # setenv auth_os 'hab_auth_img ${loadaddr} ${entr_filesize} ${ivt_offset}'
Verdin iMX8MM # run auth_os
hab fuse not enabled
Authenticate image from DDR location 0x48200000...
Secure boot disabled
HAB Configuration: 0xf0, HAB State: 0x66
No HAB Events Found!
--------------------------------
c). 将测试通过的签名 Kernel Image重新部署到刚才解压的Ycoto Linux Multimedia BSP6.6 bootfs中,并重新创建bootfs 压缩包
--------------------------------
### copy signed kernel image to bsp rootfs folder ###
$ cp Image_signed.bin .../Verdin-iMX8MM_Reference-Multimedia-Image-Tezi_6.6.0+build.12/bootfs/
### remove default boot script and linux kernel files ###
$ cd .../Verdin-iMX8MM_Reference-Multimedia-Image-Tezi_6.6.0+build.12/bootfs/
$ rm boot.scr Image
### check bootfs files ###
$ tree -L 1
.
├── Image_signed.bin
├── imx8mm-verdin-nonwifi-dahlia.dtb
├── imx8mm-verdin-nonwifi-dev.dtb
├── imx8mm-verdin-nonwifi-mallow.dtb
├── imx8mm-verdin-nonwifi-yavia.dtb
├── imx8mm-verdin-wifi-dahlia.dtb
├── imx8mm-verdin-wifi-dev.dtb
├── imx8mm-verdin-wifi-mallow.dtb
├── imx8mm-verdin-wifi-yavia.dtb
├── overlays
└── overlays.txt
### compress new bootfs package ###
$ tar Jcf ../Reference-Multimedia-Image-verdin-imx8mm.bootfs.tar.xz *
### obtain bootfs size ###
$ du bootfs/
36 bootfs/overlays
29452 bootfs/
### clear bootfs
$ cd ..
$ rm -rf bootfs/
--------------------------------
d). 修改BSP package中的 “image.json”文件,适配新的 bootfs 文件夹大小
--------------------------------
--- a/image.json 2024-04-25 15:02:40.445846395 +0800
+++ b/image.json 2024-04-25 15:03:10.010252080 +0800
@@ -32,7 +32,7 @@
"filesystem_type": "FAT",
"mkfs_options": "",
"filename": "Reference-Multimedia-Image-verdin-imx8mm.bootfs.tar.xz",
- "uncompressed_size": 11.671875
+ "uncompressed_size": 28.76171875
}
},
{
--------------------------------
e). 修改BSP package中的 “u-boot-initial-env-sd”文件,增加如下环境变量用于Secure Boot
./ 命令方式格式
--------------------------------
### set boot device info mmc 0:1 ###
Verdin iMX8MM # setenv pre_boot 'devnum=0; if mmc dev ${devnum}; then devtype=mmc; setenv load_cmd \"load ${devtype} ${devnum}:1\"; fi'
### signed kernel image loading info ###
Verdin iMX8MM # setenv cntr_file 'Image_signed.bin'
Verdin iMX8MM # setenv cntr_load '${load_cmd} ${loadaddr} ${cntr_file}'
### authenticate signed os container image ###
Verdin iMX8MM # setenv ivt_offset 0x1c30000
Verdin iMX8MM # setenv entr_filesize 0x1c30c34
Verdin iMX8MM # setenv auth_os 'hab_auth_img ${loadaddr} ${entr_filesize} ${ivt_offset}'
### device tree overlay apply ###
Verdin iMX8MM # setenv overlays_file 'overlays.txt'
Verdin iMX8MM # setenv overlays_prefix 'overlays/'
Verdin iMX8MM # setenv load_overlays_file '${load_cmd} ${loadaddr} ${overlays_file} && env import -t ${loadaddr} ${filesize}'
Verdin iMX8MM # setenv fdt_resize 'fdt addr ${fdt_addr_r} && fdt resize 0x20000'
Verdin iMX8MM # setenv apply_overlays 'for overlay_file in ${fdt_overlays}; do echo Applying Overlay: ${overlay_file} && ${load_cmd} ${loadaddr} ${overlays_prefix}\${overlay_file} && fdt apply ${loadaddr}; env set overlay_file; done; true'
Verdin iMX8MM # setenv bootcmd_overlays 'run load_overlays_file && run fdt_resize && run apply_overlays'
### prepare arguments ###
Verdin iMX8MM # setenv root_part2
Verdin iMX8MM # setenv uuid_set 'part uuid ${devtype} ${devnum}:${root_part} uuid'
Verdin iMX8MM # setenv rootfsargs_set 'run uuid_set && env set rootfsargs root=PARTUUID=${uuid} ro rootwait'
Verdin iMX8MM # setenv bootcmd_args 'run rootfsargs_set && env set bootargs ${defargs} ${rootfsargs} ${setupargs} ${vidargs} ${tdxargs}'
### prepare device tree loading ###
Verdin iMX8MM # setenv set_bootcmd_dtb 'env set bootcmd_dtb "echo Loading DeviceTree: \\${fdtfile}; ${load_cmd} \\${fdt_addr_r} \\${fdtfile}"'
### boot kernel&dtb ###
Verdin iMX8MM # setenv bootcmd_boot 'echo "Bootargs: \${bootargs}" && booti ${kernel_addr_r} - ${fdt_addr_r}'
### config for all boot process ###
Verdin iMX8MM # setenv bootcmd_run 'run pre_boot && run set_bootcmd_dtb&& run bootcmd_dtb&& run bootcmd_overlays && run bootcmd_args &&run cntr_load&& run auth_os&& run bootcmd_boot; echo "Booting from ${devtype} failed!" && false'
### auto run config ###
Verdin iMX8MM # setenv bootcmd 'run bootcmd_run'
--------------------------------
./ 文件方式定义
--------------------------------
--- a/u-boot-initial-env-sd 2024-04-25 14:55:07.599626789 +0800
+++ b/u-boot-initial-env-sd 2024-04-25 15:34:22.349957180 +0800
@@ -14,7 +14,7 @@
boot_scripts=boot.scr.uimg boot.scr
boot_syslinux_conf=extlinux/extlinux.conf
boot_targets=mmc1 mmc0 dhcp
-bootcmd=run distro_bootcmd
+bootcmd=run bootcmd_run
bootcmd_dhcp=devtype=dhcp; run boot_net_usb_start; if dhcp ${scriptaddr} ${boot_script_dhcp}; then source ${scriptaddr}; fi;setenv efi_fdtfile ${fdtfile}; setenv efi_old_vci ${bootp_vci};setenv efi_old_arch ${bootp_arch};setenv bootp_vci PXEClient:Arch:00011:UNDI:003000;setenv bootp_arch 0xb;if dhcp ${kernel_addr_r}; then tftpboot ${fdt_addr_r} dtb/${efi_fdtfile};if fdt addr ${fdt_addr_r}; then bootefi ${kernel_addr_r} ${fdt_addr_r}; else bootefi ${kernel_addr_r} ${fdtcontroladdr};fi;fi;setenv bootp_vci ${efi_old_vci};setenv bootp_arch ${efi_old_arch};setenv efi_fdtfile;setenv efi_old_arch;setenv efi_old_vci;
bootcmd_mmc0=devnum=0; run mmc_boot
bootcmd_mmc1=devnum=1; run mmc_boot
@@ -51,3 +51,22 @@
update_uboot=askenv confirm Did you load flash.bin (y/N)?; if test "$confirm" = "y"; then setexpr blkcnt ${filesize} + 0x1ff && setexpr blkcnt ${blkcnt} / 0x200; mmc dev 0 1; mmc write ${loadaddr} 0x2 ${blkcnt}; fi
usb_boot=usb start; if usb dev ${devnum}; then devtype=usb; run scan_dev_for_boot_part; fi
vendor=toradex
+pre_boot=devnum=0; if mmc dev ${devnum}; then devtype=mmc; setenv load_cmd \"load ${devtype} ${devnum}:1\"; fi
+cntr_file=Image_signed.bin
+cntr_load=${load_cmd} ${loadaddr} ${cntr_file}
+ivt_offset=0x1c30000
+entr_filesize=0x1c30c34
+auth_os=hab_auth_img ${loadaddr} ${entr_filesize} ${ivt_offset}
+overlays_file=overlays.txt
+overlays_prefix=overlays/
+load_overlays_file=${load_cmd} ${loadaddr} ${overlays_file} && env import -t ${loadaddr} ${filesize}
+fdt_resize=fdt addr ${fdt_addr_r} && fdt resize 0x20000
+apply_overlays=for overlay_file in ${fdt_overlays}; do echo Applying Overlay: ${overlay_file} && ${load_cmd} ${loadaddr} ${overlays_prefix}\${overlay_file} && fdt apply ${loadaddr}; env set overlay_file; done; true
+bootcmd_overlays=run load_overlays_file && run fdt_resize && run apply_overlays
+root_part=2
+uuid_set=part uuid ${devtype} ${devnum}:${root_part} uuid
+rootfsargs_set=run uuid_set && env set rootfsargs root=PARTUUID=${uuid} ro rootwait
+bootcmd_args=run rootfsargs_set && env set bootargs ${defargs} ${rootfsargs} ${setupargs} ${vidargs} ${tdxargs}
+set_bootcmd_dtb=env set bootcmd_dtb "echo Loading DeviceTree: \\${fdtfile}; ${load_cmd} \\${fdt_addr_r} \\${fdtfile}"
+bootcmd_boot=echo "Bootargs: \${bootargs}" && booti ${kernel_addr_r} - ${fdt_addr_r}
+bootcmd_run=run pre_boot && run set_bootcmd_dtb && run bootcmd_dtb && run bootcmd_overlays && run bootcmd_args && run cntr_load && run auth_os && run bootcmd_boot; echo "Booting from ${devtype} failed!" && false
--------------------------------
f). 需要注意的是由于Kernel阶段的Secure Boot相关认证和加载都是基于U-Boot命令行来实现的, 因此如果要让这个启动机制更加安全可靠,则要让U-Boot保持在上述安全启动路径,而不能通过其他启动介质或者脚本来启动而绕开Secure Boot,比如Toradex U-Boot默认是使能Distro Boot功能的,可以自动扫描外设介质的启动脚本,那么这个功能就需要关闭掉,类似这样的U-Boot定制化和启动路径固化可以参考如下文章,本文不做具体测试。
https://developer.toradex.cn/torizon/security/u-boot-hardening-for-secure-boot/
g). 如果你的 Linux BSP Image 是通过 Yocto Project 编译生成,那么如下是一个包含上述全部内容的 Meta Layer,你可以直接将其集成到你的 Yocto Project 编译环境中,然后按照说明配置后直接生成签名好的 BSP Image。
https://github.com/toradex/meta-toradex-security
7). 部署测试
a). 参考这里将上述制作的支持Secure Boot的Image通过Toradex Easy Installer更新到 Verdin i.MX8MM 模块
./ 启动后查看启动log,可以看到 U-Boot 和 Linux Kernel Image Secure Boot验证签名成功并最终完整启动
--------------------------------
U-Boot SPL 2022.04-21749-g3428b47019-dirty (Apr 22 2024 - 17:52:20 +0800)
...
Authenticate image from DDR location 0x401fcdc0...
NOTICE: BL31: v2.6(release):lf_v2.6-g3c1583ba0a
NOTICE: BL31: Built : 11:00:38, Nov 21 2022
U-Boot 2022.04-21749-g3428b47019-dirty (Apr 22 2024 - 17:52:20 +0800)
CPU: i.MX8MMQ rev1.0 1600 MHz (running at 1200 MHz)
CPU: Industrial temperature grade (-40C to 105C) at 59C
...
switch to partitions #0, OK
mmc0(part 0) is current device
Loading DeviceTree: imx8mm-verdin-wifi-dev.dtb
66160 bytes read in 2 ms (31.5 MiB/s)
86 bytes read in 1 ms (84 KiB/s)
Applying Overlay: verdin-imx8mm_dsi-to-hdmi_overlay.dtbo
2317 bytes read in 2 ms (1.1 MiB/s)
Applying Overlay: verdin-imx8mm_spidev_overlay.dtbo
561 bytes read in 2 ms (273.4 KiB/s)
29559860 bytes read in 191 ms (147.6 MiB/s)
hab fuse not enabled
Authenticate image from DDR location 0x48200000...
Secure boot disabled
HAB Configuration: 0xf0, HAB State: 0x66
No HAB Events Found!
Bootargs: root=PARTUUID=ba09f564-02 ro rootwait
...
Starting kernel ...
[ 0.000000] Booting Linux on physical CPU 0x0000000000 [0x410fd034]
[ 0.000000] Linux version 5.15.148-6.6.0-6.6.0+git.23a8e831749d (oe-user@oe-host) (aarch64-tdx
...
TDX Wayland with XWayland 6.6.0+build.12 (kirkstone) verdin-imx8mm-07276322 -
Verdin-iMX8MM_Reference-Multimedia-Image
verdin-imx8mm-07276322 login:
--------------------------------
b). Close设备
经过上述测试已经确认从U-Boot到Linux Kernel Secure Boot正常,即可以在U-Boot命令行下面执行下面命令Close设备,请注意此操作之后,没有签名的Image就无法再在此模块加载运行了,因此请谨慎操作。
--------------------------------
### Program SRK_LOCK###
Verdin iMX8MM # fuse prog 0 0 0x200
### Program DIR_BT_DIS###
Verdin iMX8MM # fuse prog 1 3 0x8000000
### Program SJC_DISABLE###
Verdin iMX8MM # fuse prog 1 3 0x200000
### JTAG_SMODE###
Verdin iMX8MM # fuse prog 1 3 0xC00000
--------------------------------
8). 总结
本文基于 NXP i.MX8M Mini 处理器演示了基于 HABv4 的 Secure Boot 功能,涉及 U-Boot 和 Linux Kernel ,至于 Rootfs 的加密,则需要配置类似 Squashfs 只读文件系统配合 Initramfs RAM Disk 镜像进行加解密挂载启动,可以结合参考如下两篇文章和相关 meta-toradex-security layer 数据参考,本文不做具体测试。
./ 嵌入式 ARM 平台使用dm-crypt加密磁盘分区
./ 使用Squashfs和Overlayfs提高嵌入式Linux文件系统可靠性
./ https://github.com/toradex/meta-toradex-security
作者: hai.qin_651820742, 来源:面包板社区
链接: https://mbb.eet-china.com/blog/uid-me-1864768.html
版权声明:本文为博主原创,未经本人允许,禁止转载!
文章评论(0条评论)
登录后参与讨论