原创 基于 NXP iMX8MM 测试 Secure Boot 功能

2024-4-25 16:35 922 4 4 分类: MCU/ 嵌入式

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

  • 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_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条评论)

    登录后参与讨论
    我要评论
    0
    4
    关闭 站长推荐上一条 /2 下一条