基于 NXP iMX8MM 测试 Secure Boot 功能

供稿:韬睿(上海)计算机科技有限公司

  • 关键词:ARM,Linux,iMX8M
  • 作者:By Toradex秦海
  • 摘要:嵌入式设备对于网络安全的要求越来越高,而 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 功能。

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 功能

基于 NXP iMX8MM 测试 Secure Boot 功能349.png 

 

本文所演示的平台来自于 Toradex Verdin i.MX8MM 嵌入式平台,主要测试基本的 Chain of Trust,也就是 U-bootLinux 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

./ 首先创建 serialkey_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 的一些打印参数需要保留后面生成 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_offCSF SPL binary offset

## sld_csf_offCSF 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 状态,目前会有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"

--------------------------------

 

./ 创建 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 章节 SRK Fuse binary dump field 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_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命令行来实现的, 因此如果要让这个启动机制更加安全可靠,则要让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 BootImage通过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-BootLinux 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加密磁盘分区

./ 使用SquashfsOverlayfs提高嵌入式Linux文件系统可靠性

./ https://github.com/toradex/meta-toradex-security 



发布时间:2024年4月25日 16:44  人气:   审核编辑(王静 )
相关链接

我有需求