基于 NXP iMX8MM 測試 Secure Boot 功能
1). 簡介
嵌入式設備對于網(wǎng)絡安全的要求越來越高,而 Secure boot就是其中重要的一部分。 NXP i.MX8MM/i.MX8MP 處理器基于 HABv4 特性來提供 Secure boot 啟動過程中的 Chain of Trust; HABv4 是基于公共密鑰加密 (Public Key Cryptography) 和數(shù)字簽名 (Digital Signature) 技術來實現(xiàn) Secure boot 的,一個簡單的流程圖參考如下。本文就基于 NXP i.MX8M Mini 處理器平臺測試部署 Secure boot 功能。
本文所演示的平臺來自于 Toradex Verdin i.MX8MM 嵌入式平臺,主要測試基本的 Chain of Trust,也就是 U-boot和Linux Kernel 兩個層級的加密和驗證啟動,后面 Rootfs 以及 Application 層面暫不涉及。
2. 準備
a). Verdin i.MX8MM ARM核心版配合Dahlia 載板,并連接調(diào)試串口用于測試。
b). 參考這里下載 Toradex Yocto Linux BSP6 Reference Image 用于后續(xù)測試,目前最新的是 6.6.0 版本。
3). 生成PKI Tree文件
a). 從NXP官方網(wǎng)站下載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
./ 首先創(chuàng)建 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
[*] Support i.MX HAB features
→ SPL / TPL
[*] Support crypto drivers
→ Init options > Start-up hooks
[*] Call arch-specific init after relocation, when console is ready
### 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 的一些打印參數(shù)需要保留后面生成 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=0x60000 if 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 狀態(tài),目前會有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 block field 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 block field value and print_fit_hab output 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"
--------------------------------
./ 創(chuàng)建 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 offset from 4.b chapter csf_off field 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 offset from 4.b chapter sld_csf_off field 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 章節(jié) SRK Fuse binary dump field value,也可以通過如下命令重新導出SRK HASH fuse對應數(shù)值
--------------------------------
$ 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 已經(jīng)簽名,因此提示已經(jīng)變?yōu)?nbsp;“ 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 狀態(tài),已經(jīng)沒有錯誤事件。
--------------------------------
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 文件用于后續(xù)簽名 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 系統(tǒng) “/boot” 目錄下,替換原來的 Image 文件 “Image.gz”。
b). 重啟進入 U-boot 命令行模式,通過如下命令行參數(shù)配置驗證簽名的 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中,并重新創(chuàng)建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” 文件,增加如下環(huán)境變量用于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_part 2
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命令行來實現(xiàn)的, 因此如果要讓這個啟動機制更加安全可靠,則要讓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 編譯生成,那么如下是一個包含上述全部內(nèi)容的 Meta Layer,你可以直接將其集成到你的 Yocto Project 編譯環(huán)境中,然后按照說明配置后直接生成簽名好的 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設備
經(jīng)過上述測試已經(jīng)確認從U-Boot到Linux Kernel Secure Boot正常,即可以在U-Boot命令行下面執(zhí)行下面命令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 只讀文件系統(tǒng)配合 Initramfs RAM Disk 鏡像進行加解密掛載啟動,可以結合參考如下兩篇文章和相關 meta-toradex-security layer 數(shù)據(jù)參考,本文不做具體測試。
./ 嵌入式 ARM 平臺使用dm-crypt加密磁盤分區(qū)
./ 使用Squashfs和Overlayfs提高嵌入式Linux文件系統(tǒng)可靠性
./ https://github.com/toradex/meta-toradex-security
提交
Verdin AM62 LVGL 移植
隆重推出 Aquila - 新一代 Toradex 計算機模塊
Verdin iMX8MP 調(diào)試串口更改
NXP iMX8MM Cortex-M4 核心 GPT Capture 測試
嵌入式Linux下使用 Plymouth 實現(xiàn)開機畫面示例