I.MX8MM Secure Boot using High Assurance Boot v4
Introduction
This tutorial describes the information and usage on how to secure boot i.MX8MM chipsets using HABv4. The platform used in this tutorial is an Engicam Ctouch 2.0 based on i.M8M Mini chipset.
This tutorial is an addon to an already existing i.MX6 Secure Boot tutorial. The boot process for i.MX 8M family (including i.MX 8MQ, i.MX 8M Mini, i.MX 8M Nano and i.MX 8M Plus) is little different compared to older i.MX6/7 platforms which will be outlined in this tutorial.
For practical purposes and to make this tutorial more understandable, i.MX8M Mini based CTouch2.0 carrier board is used.
Why Secure Boot
To prevent unauthorized software execution during the device boot sequence, there should be a mechanism and the HABv4 secure boot feature uses digital signatures to prevent unauthorized software execution. For instance if a malware takes control of the boot sequence, sensitive data, services and network can be impacted.
HABv4 Secure Boot Architecture
The i.MX family of applications processors provides the High Assurance Boot (HAB) feature in the on-chip ROM. The ROM is responsible for loading the initial program image (U-Boot) from the boot media and HAB enables the ROM to authenticate and/or decrypt the program image by using cryptography operations.
The main features supported by the HABv4 are:
Authentication of software loaded from any boot device supported, including the Serial Download Protocol (SDP).
Authenticated USB download fail-over on any security failure.
Interface with the SNVS to guarantee the system security state.
Initialization of security components.
X.509 public key certificate support.
CMS signature format support.
1024, 2048, 3072, and 4096 bits RSA keys length support.
p256, p384, p521 ECC keys support.
SHA-256 message digest operations accelerated by hardware.
Manufacturing protection private key generation in supported devices.
Super Root Key (SRK) revocation support.
Figure I: HABv4 Secure Boot architecture[I]
The above Figure 1 can be understood in two parts: Code signing part which does the signing of images. The authentication part which checks whether the image to be booted is not tampered and if the verification is successful the root of trust is passed to the next image to be booted.
Figure II: HABv4 Secure Boot flow[II]
HABv4 authentication is based on public key cryptography using the RSA or ECDSA algorithms in which image data(for instance u-boot binary) is signed offline using a series of private keys. The resulting signed image data is then verified on the i.MX8M processor using the corresponding public keys.
This key structure is known as a Public Key Infrastructure(PKI) tree. Super Root Keys, or SRK, are components of the PKI tree. HABv4 relies on a table of the public SRKs to be hashed and placed in fuses on the target.
The i.MX Code SigningTool (CST) is used in this guide to generate the HABv4 signatures for images using the PKI tree data and SRK table. On the target, HABv4 evaluates the SRK table included in the signature by hashing it and comparing the result to the SRK fuse values. If the SRK verification is successful, the root of trust is established, and the remainder of the signature can be processed to 1authenticate the image.
The U-Boot image to be programmed into the boot media needs to be properly constructed i.e. it must contain a proper Command Sequence File (CSF).
The CSF is a binary data structure interpreted by the HAB to guide authentication process, this is generated by the Code Signing Tool[1]. The CSF structure contains the commands, SRK table, signatures and certificates.
i.MX8M Boot Flow
The boot flow on i.MX 8M family devices are slightly different when compared with i.MX 6, i.MX 7 series device. The boot flow changes are due to the different architecture, multiple firmware and software components required to initialize the device[I].
Figure III: i.MX8M Boot Flow[I]
NOTE: for i.MX8M mini hdmi/dp firmware is not required in the boot process
On reset, ROM code reads the efuse to determine the security configuration of the SoC and the type of the boot device. The ROM then locates flash.bin, layout shown in Figure IV.
Figure IV: i.MX8M Boot Flow[I]
The above Figure shows 2 CSF binaries required, one per verification stage:
CSF SPL that is used by Boot ROM to authenticate SPL + DDR FW
CSF FIT that is used by SPL (through HAB APIs) to authenticate FIT components
The ROM code first reads the Image Vector Table(IVT) and identifies the CSF location. It verifies and loads Second Program Loader (SPL) and DDR firmware onto OCRAM. It verifies the authenticity of the SPL binary both in memory and flash against the signature embedded in the CSF. This can be seen as the first stage verification. If signature verification fails, execution is not allowed to leave the ROM for securely configured SoCs, also called “closed” devices.
For an open device (meaning the fuse related to configuring SOC is not yet programmed), even if signature verification fails one will be able to see HAB events which will tell the programmer if the image would pass the authentication process.
During Verification, HAB evaluates the SRK table included in the signature by hashing it and comparing the result to the SRK fuse values. If the SRK verification is successful, this establishes the root of trust, and the remainder of the signature can be processed to authenticate the image.
If it succeeds (or if the device is open), the ROM code goes loads and jumps to SPL. SPL initializes the clocks, PMIC, LPDDR4 and UART. SPl then loads and verifies the rest of the components using the HAB APIs to extend the root of trust.
A FIT image is used to package all the components rtequired for i.MX8M mini which are:
U-Boot binary + device tree blob (dtb)
ARM Trusted Firmware (ATF)
OP-TEE binary (TrustZone - optional)
Once the DDR is available, the SPL code verifies and loads all the images included in the FIT structure to their specific execution addresses. This is the second stage and if the verification succeeds, ATF is executed which will in turn execute U-Boot.
The HABv4 APIs can be used to extend the root of trust additionally tothe Linux Kernel and Cortex-M images and can be authenticated at bootloader level.
i.MX8M Signed Image
The below procedure outlines on how signed secure boot has been created with Engicam i.CoreMX8M MINI CTouch2.0 board.
Download NXP Code Signing tool
$ git clone https://www.nxp.com/webapp/Download?colCode=IMX_CST_TOOL_NEW
$ tar xzf cst-3.3.1.tar.gz
$ cd cst-3.3.1/keys
Generate PKI tree (Private keys)
Create a serial file with an 8-digit content. OpenSSL uses the contents of this file for the certificate serial numbers.
Create key_pass.txt which contains your pass phrase that will protect the HAB code signing private keys.
$ echo "42424242" > serial
$ echo "Amarual357" > key_pass.txt
$ echo "Amarual357" >> key_pass.txt
$ ./hab4_pki_tree.sh
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
This script is a part of the Code signing tools for Freescale's
High Assurance Boot. It generates a basic PKI tree. The PKI
tree consists of one or more Super Root Keys (SRK), with each
SRK having two subordinate keys:
+ a Command Sequence File (CSF) key
+ Image key.
Additional keys can be added to the PKI tree but a separate
script is available for this. This this script assumes openssl
is installed on your system and is included in your search
path. Finally, the private keys generated are password
protectedwith the password provided by the file key_pass.txt.
The format of the file is the password repeated twice:
my_password
my_password
All private keys in the PKI tree are in PKCS #8 format will be
protected by the same password.
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Do you want to use an existing CA key (y/n)?: n
Do you want to use Elliptic Curve Cryptography (y/n)?: n
Enter key length in bits for PKI tree: 2048
Enter PKI tree duration (years): 10
How many Super Root Keys should be generated? 4
Do you want the SRK certificates to have the CA flag set? (y/n)?: y
Private keys will generate on keys directory and corresponding Certificates are placed in the crts directory.
Generate SRK table (Public keys)
$ 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
SRK_1_2_3_4_table.bin - SRK table contents with HAB data SRK_1_2_3_4_fuse.bin - contains SHA256 result to be burned to fuse
Build ARM Trusted firmware:
$ git clone https://source.codeaurora.org/external/imx/imx-atf -b imx_4.19.35_1.0.0
$ make PLAT=imx8mm bl31
Get the ddr firmware
$ wget https://www.nxp.com/lgfiles/NMG/MAD/YOCTO/firmware-imx-8.0.bin
$ chmod +x firmware-imx-8.0.bin
$ ./firmware-imx-8.0
Build U-Boot with HAB enabled
u-boot> git clone https://github.com/sunielmahesh/u-boot-cam-imx.git -b imx_v2020.04_5.4.70_2.3.0
$ export ATF_LOAD_ADDR=0x920000
$ make imx8mm_ctouch_defconfig
$ make ARCH=arm menuconfig
enable CONFIG_IMX_HAB=y
$ make CROSS_COMPILE=aarch64-buildroot-linux-gnu- flash.bin V=1
Preparing the FIT Image
Download imx-mkimage tool and copy ATF, ddr binaries, u-boot-nodtb.bin u-boot-spl.bin and dtb files. After the process flash.bin is created.
$ git clone https://github.com/sunielmahesh/imx-mkimage-imx8mm.git
$ cd imx-mkimage-imx8mm/iMX8M
$ cp ~atf/build/imx8mm/release/bl31.bin ./
$ cp ~firmware-imx-8.0/firmware/ddr/synopsys/lpddr4*.bin ./
$ cp ~u-boot/u-boot-nodtb.bin ./
$ cp ~u-boot/arch/arm/dts/imx8mm-ctouch.dtb ./
$ cp ~u-boot/spl/u-boot-spl.bin ./
$ cp ~uboot/tools/mkimage ./mkimage_uboot
$ make SOC=iMX8MM flash_ctouch_spl_uboot
Compiling mkimage_imx8
PLAT=imx8mm HDMI=no
Compiling mkimage_imx8
cc -O2 -Wall -std=c99 -static mkimage_imx8.c -o mkimage_imx8 -lz
19802+0 records in
19802+0 records out
79208 bytes (79 kB, 77 KiB) copied, 0.0230843 s, 3.4 MB/s
./../scripts/pad_image.sh tee.bin
Pad file tee.bin NOT found
./../scripts/pad_image.sh bl31.bin
./../scripts/pad_image.sh u-boot-nodtb.bin ctouch.dtb
DEK_BLOB_LOAD_ADDR=0x40400000 TEE_LOAD_ADDR=0xbe000000 ATF_LOAD_ADDR=0x00920000 ./mkimage_fit_atf.sh ctouch.dtb > u-boot.its
bl31.bin size:
37216
u-boot-nodtb.bin size:
580784
ctouch.dtb size:
29936
./mkimage_uboot -E -p 0x3000 -f u-boot.its u-boot.itb
u-boot.itb.tmp: Warning (unit_address_vs_reg): Node /images/uboot@1 has a unit name, but no reg property
u-boot.itb.tmp: Warning (unit_address_vs_reg): Node /images/fdt@1 has a unit name, but no reg property
u-boot.itb.tmp: Warning (unit_address_vs_reg): Node /images/atf@1 has a unit name, but no reg property
u-boot.itb.tmp: Warning (unit_address_vs_reg): Node /configurations/config@1 has a unit name, but no reg property
FIT description: Configuration to load ATF before U-Boot
Created: Sat Mar 13 02:04:05 2021
Image 0 (uboot@1)
Description: U-Boot (64-bit)
Created: Sat Mar 13 02:04:05 2021
Type: Standalone Program
Compression: uncompressed
Data Size: 580784 Bytes = 567.17 KiB = 0.55 MiB
Architecture: AArch64
Load Address: 0x40200000
Entry Point: unavailable
Image 1 (fdt@1)
Description: ctouch
Created: Sat Mar 13 02:04:05 2021
Type: Flat Device Tree
Compression: uncompressed
Data Size: 29936 Bytes = 29.23 KiB = 0.03 MiB
Architecture: Unknown Architecture
Image 2 (atf@1)
Description: ARM Trusted Firmware
Created: Sat Mar 13 02:04:05 2021
Type: Firmware
Compression: uncompressed
Data Size: 37216 Bytes = 36.34 KiB = 0.04 MiB
Architecture: AArch64
OS: Unknown OS
Load Address: 0x00920000
Default Configuration: 'config@1'
Configuration 0 (config@1)
Description: ctouch
Kernel: unavailable
Firmware: uboot@1
FDT: fdt@1
Loadables: atf@1
./mkimage_imx8 -version v1 -fit -loader u-boot-spl-ddr.bin 0x7E1000 -second_loader u-boot.itb 0x40200000 0x60000 -out flash.bin
Platform: i.MX8M (mScale)
ROM VERSION: v1
Using FIT image
LOADER IMAGE: u-boot-spl-ddr.bin start addr: 0x007e1000
SECOND LOADER IMAGE: u-boot.itb start addr: 0x40200000 offset: 0x00060000
Output: flash.bin
========= IVT HEADER [HDMI FW] =========
header.tag: 0x0
header.length: 0x0
header.version: 0x0
entry: 0x0
reserved1: 0x0
dcd_ptr: 0x0
boot_data_ptr: 0x0
self: 0x0
csf: 0x0
reserved2: 0x0
boot_data.start: 0x0
boot_data.size: 0x0
boot_data.plugin: 0x0
========= IVT HEADER [PLUGIN] =========
header.tag: 0x0
header.length: 0x0
header.version: 0x0
entry: 0x0
reserved1: 0x0
dcd_ptr: 0x0
boot_data_ptr: 0x0
self: 0x0
csf: 0x0
reserved2: 0x0
boot_data.start: 0x0
boot_data.size: 0x0
boot_data.plugin: 0x0
========= IVT HEADER [LOADER IMAGE] =========
header.tag: 0xd1
header.length: 0x2000
header.version: 0x41
entry: 0x7e1000
reserved1: 0x57c00
dcd_ptr: 0x0
boot_data_ptr: 0x7e0fe0
self: 0x7e0fc0
csf: 0x808bc0
reserved2: 0x0
boot_data.start: 0x7e0bc0
boot_data.size: 0x2a060
boot_data.plugin: 0x0
========= OFFSET dump =========
Loader IMAGE:
header_image_off 0x0
dcd_off 0x0
image_off 0x40
csf_off 0x27c00
spl hab block: 0x7e0fc0 0x0 0x27c00
Second Loader IMAGE:
sld_header_off 0x57c00
sld_csf_off 0x58c20
sld hab block: 0x401fcdc0 0x57c00 0x1020
Creating the CSF description files
The CSF description file sample is provided at u-boot/doc/imx/habv4/csf_examples
There are two files since we have two stage bootloader, csf_spl.txt and csf_fit.txt. Create a directory csf and copy both the files from u-boot/doc/imx/habv4/csf_examples.
For csf_spl.txt, in the Authenticate Data section replace Blocks with spl hab block content above:
Blocks = 0x7e0fc0 0x0 0x27c00 "flash.bin"
Adjust necessary paths.
For csf_fit.txt, in the Authenticate Data section replace the first line in Blocks with sld hab block content above and the next three lines by the output provided by the below command:
imx-mkimage$ make SOC=iMX8MM print_fit_hab
./../scripts/dtb_check.sh imx8mm-ctouch.dtb ctouch.dtb
Use u-boot DTB: imx8mm-ctouch.dtb
./../scripts/pad_image.sh tee.bin
Pad file tee.bin NOT found
./../scripts/pad_image.sh bl31.bin
./../scripts/pad_image.sh u-boot-nodtb.bin ctouch.dtb
u-boot-nodtb.bin + ctouch.dtb are padded to 610720
TEE_LOAD_ADDR=0xbe000000 ATF_LOAD_ADDR=0x00920000 VERSION=v1 ./print_fit_hab.sh 0x60000 ctouch.dtb
0x40200000 0x5AC00 0x8DCB0
0x4028DCB0 0xE88B0 0x74F0
0x920000 0xEFDA0 0x9160
The resulting Authenticate Data section in csf_fit.txt should be:
Blocks = 0x401fcdc0 0x57c00 0x01020 "flash.bin", \
0x40200000 0x5AC00 0x8DCB0 "flash.bin", \
0x4028DCB0 0xE88B0 0x074F0 "flash.bin", \
0x00920000 0xEFDA0 0x09160 "flash.bin"
Adjust necessary paths in both csf_spl.txt and csf_fit.txt.
Signing and Asembling the flash.bin binary
csf$ ../cst-3.3.1/linux64/bin/cst -i csf_spl.txt -o csf_spl.bin
Install SRK
Install CSFK
Authenticate CSF
Install key
Authenticate data
CSF Processed successfully and signed data available in csf_spl.bin
csf$ ../cst-3.3.1/linux64/bin/cst -i csf_fit.txt -o csf_fit.bin
Install SRK
Install CSFK
Authenticate CSF
Install key
Authenticate data
CSF Processed successfully and signed data available in csf_fit.bin
csf$ copy flash.bin from imx-mkimage/IMX8M to csf directory
csf$ cp flash.bin signed_flash.bin
csf$ dd if=csf_spl.bin of=signed_flash.bin seek=$((0x27c00)) bs=1 conv=notrunc
the seek above is csf_off
csf$ dd if=csf_fit.bin of=signed_flash.bin seek=$((0x58c20)) bs=1 conv=notrunc
the seek above is sld_csf_off
Flashing and Power on:
Flash signed_flash.bin onto SD card and power-on the board
$ sudo dd if=signed_flash.bin of=/dev/sdX bs=1024 seek=33
$ sync
U-Boot SPL 2020.04-00035-g7807920922 (Mar 12 2021 - 22:25:59 +0530)
Can't find PMIC:PCA9450
DDRINFO: start DRAM init
DDRINFO: DRAM rate 3000MTS
DDRINFO:ddrphy calibration done
DDRINFO: ddrmix config done
Normal Boot
Trying to boot from MMC1
hab fuse not enabled
Authenticate image from DDR location 0x401fcdc0...
U-Boot 2020.04-00035-g7807920922 (Mar 12 2021 - 22:25:59 +0530)
CPU: i.MX8MMQ rev1.0 1600 MHz (running at 1200 MHz)
CPU: Industrial temperature grade (-40C to 105C) at 38C
Reset cause: POR
Model: Engicam i.Core MX8M Mini C.TOUCH 2.0
DRAM: 2 GiB
MMC: FSL_SDHC: 0, FSL_SDHC: 2
Loading Environment from MMC... *** Warning - bad CRC, using default environment
In: serial
Out: serial
Err: serial
BuildInfo:
- ATF da29a16
- U-Boot 2020.04-00035-g7807920922
switch to partitions #0, OK
mmc0 is current device
Net:
Error: ethernet@30be0000 address not set.
Error: ethernet@30be0000 address not set.
No ethernet found.
Normal Boot
Hit any key to stop autoboot: 0
u-boot=>
u-boot=>
u-boot=>
u-boot=> hab_status
Secure boot disabled
HAB Configuration: 0xf0, HAB State: 0x66
No HAB Events Found!
The above is the bootlog and hab status doesnt show any HAB events meaning the signed images generated are as per procedure and each stage has verified the other successsully without any errors.
Programming e-fuse with SRK Hash
efuse dump
$ cd ../crts
$ hexdump -e '/4 "0x"' -e '/4 "%X""\n"' < ../cst-3.3.1/crts/SRK_1_2_3_4_fuse.bin
0x44DF5F5B
0xF82E1DA5
0x4DEC9AC4
0x8D48E35C
0x7D33FEC0
0xD267E7B6
0xF80E67B4
0xF69365A3
The fuse table generated in the above process is what needs to be flashed to the device. U-Boot fuse command can be used for programming eFuses.
Once the eFuses are programmed check for any errors using hab_status command. If there are no HAB events then we can close the device implies Secure Boot is enabled.
References
u-boot/doc/imx/habv4/introdcution_habv4.txt