High Assurance Boot MX8
HAB introduction
HAB is an optional feature in the i.MX SOC family, which allows you to make sure only software images signed by you can be executed on the SOC.
It incorporates boot ROM level security which cannot be altered after programming the appropriate one-time electrically programmable fuses (eFuses). The boot ROM is responsible for loading the initial software image from the boot medium (usually this initial software is a bootloader such as SPL/U-Boot. HAB enables the boot ROM to authenticate the initial software image by using digital signatures. It also provides a mechanism to establish a chain of trust for the remaining software components (such as the kernel image) and thus to establish a secure state of the system.
HAB authentication is based on public key cryptography using the RSA algorithm.
It consists of the following stages:
1. Offline signing of the software images using private keys.
The image data is signed offline using a series of private keys. This is done using NXP's Code Signing Tool, and Variscite's scripts, which make the process extremely easy and simple.
2. Fusing the i.MX SOC with the corresponding public keys.
The key structure is called a PKI tree and Super Root Keys (SRK) are components of it. A table of the public SRKs are hashed and permanently written to the SOC using eFuses.
You have the option to let the processor keep running unsigned images, while creating useful HAB messages, until you decide to “close” it by writing a dedicated bit using another eFuse. This allows you to test the sign-authenticate process and verify that it was done correctly before completely and permanently “closing” the processor to only execute your signed images.
3. Authentication of the software images on the target during boot time.
The signed image data is verified on the i.MX processor using the corresponding public keys.
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.
Once the initial bootloader is authenticated and executed, the chain of trust continues by authenticating each of the next loaded images before executing them.
E.g. The boot ROM authenticates SPL, SPL authenticates U-Boot, and U-Boot authenticates the Linux kernel.
References
- i.MX Applications Processor Trust Architecture
- i.MX Secure Boot on HABv4 Supported Devices
- i.MX 6 Linux High Assurance Boot (HAB) User's Guide
Code signing step by step instructions
NXP Provides documentation for enabling HAB for the i.MX8M Family. The information in this wiki is derived from NXP's documentation.
The U-Boot source code provides a directory with documentation and examples: https://github.com/varigit/uboot-imx/blob/imx_v2020.04_5.4.70_2.3.2_var01/doc/imx/habv4/
The following documentation is helpful to review:
- U-Boot doc/imx/habv4/introduction_habv4.txt
- U-Boot doc/imx/habv4/guides/mx8m_secure_boot.txt
- NXP AN12263 HABv4 RVT Guidelines and Recommendations
Please continue reading below to learn how Variscite's Yocto layer simplifies this process.
Code signing using Yocto
Introduction to meta-variscite-hab
Variscite provides a Yocto layer to simplify signing the imx-boot and Linux images and generate a fully signed recovery SD card image. meta-variscite-hab requires two inputs:
NXP Code Signing Tool
- NXP proprietary tool for signing images. Users must download this tool from NXP and provide an absolute path to meta-variscite-hab.
Private Keys
- Users must generate private keys and provide an absolute path or git repository to meta-variscite-hab.
meta-variscite-hab extends the imx-boot, uboot-variscite, and linux-variscite recipes to sign the imx-boot and Linux images using the NXP Code Signing Tool and private keys.
The general process for creating a signed image using meta-variscite-hab is:
- Follow the Build Yocto from source code guide to setup a build environment
- Download NXP Code Signing Tool (CST)
- Use CST to generate Public Key Infrastructure (PKI) tree (one time)
- Configure local.conf, machine.conf, or variscite.inc
- Enable hab machine override
- Provide absolute path to NXP Code Signing Tool
- Provide git repository for private keys
- Provide certificate serial and passkeys
- Provide U-Boot and kernel device tree names
- Build a signed SD card image
- Program a recovery SD card
- Program SOC e-fuses
- Boot recovery SD card and interrupt U-Boot
- U-Boot: Program the SRK (public keys) to the SOC e-fuses
- U-Boot: Verify public keys and signed image by running hab_status
- U-Boot: Secure (Close) the device
The remainder of the guide walks through this process.
Walkthough: Setup a build environment
This section assumes familiarity with building Yocto. For more information, please follow the Build Yocto from source code guide.
Download the latest revision:
$ mkdir ~/var-fslc-yocto && cd ~/var-fslc-yocto $ repo init -u https://github.com/varigit/variscite-bsp-platform.git -b hardknott -m hardknott-5.10.xml $ repo sync -j4
Setup environment to build XWayland GUI demo image
$ cd ~/var-fslc-yocto $ MACHINE=imx8mm-var-dart DISTRO=fslc-xwayland . var-setup-release.sh build_xwayland
Walkthough: Download NXP Code Signing Tool (CST)
Download the Freescale Code Signing Tool (CST) for the High Assurance Boot (HAB) library from the NXP website (registration required): https://www.nxp.com/webapp/sps/download/license.jsp?colCode=IMX_CST_TOOL
Unpack the downloaded archive:
$ cd ~ $ tar xf ~/Downloads/cst-3.1.0.tar.gz
You are encouraged to read the documents under ~/cst-3.1.0/docs
Walkthough: Generate Public Key Infrastructure (PKI) tree
$ cd ~/cst-3.1.0/keys
Create a text file called "serial", which contains 8 digits. It will be used for the certificate serial numbers.
For example:
$ echo 1248163E > serial
Create a text file called "key_pass.txt", which contains two lines of a password repeated twice.
This password will be used to protect the generated private keys.
All private keys in the PKI tree are in PKCS #8 format will be protected by the same password.
For example:
$ echo Variscite_password > key_pass.txt $ echo Variscite_password >> key_pass.txt
Now, to generate the PKI tree, run the following:
$ ./hab4_pki_tree.sh
And complete the interactive questions. For example:
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: 4096 Enter PKI tree duration (years): 20 How many Super Root Keys should be generated? 4 Do you want the SRK certificates to have the CA flag set? (y/n)?: y
Generate Super Root Key (SRK) table
$ 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_4096_65537_v3_ca_crt.pem,./SRK2_sha256_4096_65537_v3_ca_crt.pem,./SRK3_sha256_4096_65537_v3_ca_crt.pem,./SRK4_sha256_4096_65537_v3_ca_crt.pem -f 1
Next, add the contents of the './crts' and './keys' to a git repository matching 'CST_CERTS_URI' (defined below) in local.conf. Make sure to remove './keys/serial' and './keys/key_pass.txt'. See Variscite's repository for an example: https://github.com/varigit/var-hab-certs
Note: Instead of using a git repository, you may configure CST_CERTS_URI to fetch an archive or any other Yocto compatible URL.
Walkthough: Configure local.conf, machine.conf, or variscite.inc
There are several variables that need to be configured in conf/local.conf
, ../sources/meta-variscite-bsp/conf/machine/imx8mm-var-dart.conf
, or ../sources/meta-variscite-bsp/conf/machine/variscite.inc
(use whichever file you prefer):
Variable | Description |
---|---|
OVERRIDES =. "hab:" | Machine override used to enable Variscite HAB functions in meta-variscite-hab |
CST_CERTS_URI | SRC_URI definition for cloning certificates repository. Below is the default configuration for Variscite's example var-hab-certs repository:
CST_CERTS_URI ?= "git://github.com/varigit/var-hab-certs.git;protocol=https;branch=master;rev=${CST_CERTS_REV}" |
CST_CERTS_REV | Git commit ID for CST_CERTS_URI. Below is the default definition (commit ID may change):
CST_CERTS_REV ?= "56ad83a9962fb1cd8b4a18dc72993de7e7894bc5" |
CST_SERIAL | Certificate serial number from previous step |
CST_KEYPASS | Key password from previous step |
NXP_CST_URI | Path to downloaded NXP CST archive. |
UBOOT_DTBS |
imx-boot images for the i.MX8M family contain a fit image with one ore more U-Boot device tree files. Currently, signed imx-boot images can only contain a single device tree file. Therefore, an imx-boot image will be created, signed, and deployed for each UBOOT_DTBS entry. Signed imx-boot images use the following naming convention:
Only modify the default value of UBOOT_DTBS if you have added a new device tree to the U-Boot source code. |
UBOOT_DTB_DEFAULT |
When UBOOT_DTBS contains more then one device tree (and therefore multiple imx-boot images are deployed), UBOOT_DTB_DEFAULT is used to select the default imx-boot for the SD card image. The default configuration is: UBOOT_DTB_DEFAULT ?= "" UBOOT_DTB_DEFAULT_mx8mm ?= "-imx8mm-var-som-symphony" UBOOT_DTB_DEFAULT_mx8mp ?= "-imx8mp-var-som-symphony" |
SIGN_DTB | Required for i.MX8QM and i.MX8QXP Family Only, optional for i.MX8M family
Like UBOOT_DTBS, currently only a single Linux device tree can be signed. The default configuration is: # mx8m family: Unsigned SIGN_DTB ?= "" # mx8qm/mx8qxp family: SIGN_DTB_mx8qm ?= "${B}/${KERNEL_OUTPUT_DIR}/dts/freescale/imx8qm-var-som-lvds.dtb" SIGN_DTB_mx8x ?= "${B}/${KERNEL_OUTPUT_DIR}/dts/freescale/imx8qxp-var-som-symphony-sd.dtb" |
To get started using Variscite's default configuration and keys (not recommended for production), add the following to local.conf:
local.conf
... # Enable Variscite HAB machine override OVERRIDES =. "hab:" ...
You may override any of Variscite's default variables, see below for an example local.conf for the imx8mm-var-dart:
local.conf
... # Enable Variscite HAB machine override OVERRIDES =. "hab:"
# Configure certificate serial and passwords (These should be secret) CST_SERIAL="1248163E" CST_KEYPASS="Variscite_password" # sign imx-boot images for both imx8mm-var-dart and imx8mm-var-som symphony (default configuration) UBOOT_DTBS_mx8mm="imx8mm-var-dart-customboard.dtb imx8mm-var-som-symphony.dtb" # Use signed imx8mm-var-dart-customboard.dtb in the SD card image UBOOT_DTB_DEFAULT_mx8mm="-imx8mm-var-dart-customboard" # Sign kernel device tree file: SIGN_DTB_mx8mm="${B}/${KERNEL_OUTPUT_DIR}/dts/freescale/imx8mm-var-dart-dt8mcustomboard.dtb" # GIT Repository for private certificates # Note: CST_CERTS_REV is mandatory and used by var-hab.bbclass as well as CST_CERTS_URI CST_CERTS_REV="56ad83a9962fb1cd8b4a18dc72993de7e7894bc5" CST_CERTS_URI="git://github.com/varigit/var-hab-certs.git;protocol=https;branch=master;rev=${CST_CERTS_REV}" ...
Walkthough: Build a signed SD card image
To be safe, clean all relevant recipes:
$ bitbake -c cleansstate linux-variscite $ bitbake -c cleansstate u-boot-variscite $ bitbake -c cleansstate imx-boot $ bitbake -c cleansstate fsl-image-gui # Or...combine into a single command $ bitbake -c cleansstate linux-variscite && bitbake -c cleansstate u-boot-variscite && bitbake -c cleansstate imx-boot && bitbake -c cleansstate fsl-image-gui
Build a signed image:
$ bitbake fsl-image-gui
Create a recovery SD card:
$ cd ~/var-fslc-yocto $ sudo MACHINE=imx8mm-var-dart sources/meta-variscite-sdk/scripts/var_mk_yocto_sdcard/var-create-yocto-sdcard.sh <options> /dev/sdX (Replace /dev/sdX with your actual device)
Walkthough: Program the SRK (public keys) to the SOC e-fuses
Boot the board, hit any key at the right time to stop autoboot and get to the U-Boot command line, and run the commands outputted by the above script.
The commands should look similar to the following.
Important notes:
- The following values are just an example - you should use your own values!
- These are One-Time Programmable e-fuses. Once you write them you can't go back, so get it right the first time.
- Do not run the command at the end of the script to close the device. We will do that later.
SRK_1_2_3_4_fuse.bin.u-boot-cmds:
$ cat build_xwayland/tmp/deploy/images/imx8mm-var-dart/SRK_1_2_3_4_fuse.bin.u-boot-cmds # Note: These are One-Time Programmable e-fuses. Once you write them you can't go back, so get it right the first time. fuse prog -y 6 0 0xDA6B9ADB fuse prog -y 6 1 0xDC9B55A1 fuse prog -y 6 2 0x93D10134 fuse prog -y 6 3 0x5CDC8DA3 fuse prog -y 7 0 0x143709F8 fuse prog -y 7 1 0xC6E305A7 fuse prog -y 7 2 0x3E718DA2 fuse prog -y 7 3 0xC6AC85B6 # After the device successfully boots a signed image without generating any HAB events, it is safe to secure, or 'close', the device. # This is the last step in the process. Once the fuse is blown, the chip does not load an image that has not been signed using the correct PKI tree. # Important notes: # - This is again a One-Time Programmable e-fuse. Once you write it you can't go back, so get it right the first time. # - If anything in the previous steps wasn't done correctly, the SOM will not boot after writing this bit. fuse prog 1 3 0x02000000
Walkthrough: Verify HAB successfully authenticates the signed image
HAB generates events when processing the commands if it encounters issues.
The U-Boot "hab_status" command displays any events that were generated.
Run it at the U-Boot command line:
=> hab_status
If everything is okay you should get the following output:
Secure boot disabled HAB Configuration: 0xf0, HAB State: 0x66 No HAB Events Found!
Walkthrough: Secure the device
After the device successfully boots a signed image without generating any HAB events, it is safe to
secure, or "close", the device.
This is the last step in the process, and is completed by blowing the SEC_CONFIG[1] fuse bit.
Once the fuse is blown, the chip does not load an image that has not been signed using the correct PKI tree.
Important notes:
- This is again a One-Time Programmable e-fuse. Once you write it you can't go back, so get it right the first time.
- If anything in the previous steps wasn't done correctly, the SOM will not boot after writing this bit.
=> fuse prog 1 3 0x2000000
Next Steps
This guide demonstrates how to build and boot a signed image. However, it does not cover every aspect of securing a device.
For more information, refer to NXP's documentation. A good place to start is AN4581: i.MX Secure Boot on HABv4 Supported Devices by NXP.