Skip to content

i.MX9 Advanced High Assurance Boot (AHAB) / Secure Boot

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/ECDSA 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.

HAB operation.png

References

Code signing step by step instructions

NXP Provides documentation for enabling AHAB for the i.MX 9 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/lf_v2025.04_6.12.49-2.2.0_var01/doc/imx/ahab/

The following documentation is helpful to review:

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:

Meta-variscite-hab-io-v2.png

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:

  1. Follow the Build Yocto from source code guide to setup a build environment
  2. Download NXP Code Signing Tool (CST)
  3. Use CST to generate Public Key Infrastructure (PKI) tree (one time)
  4. Configure local.conf, machine.conf, or variscite.inc
  5. Enable hab machine override
  6. Provide git repository for private keys
  7. Provide certificate serial and passkeys
  8. Provide U-Boot and kernel device tree names
  9. Build a signed SD card image
  10. Program a recovery SD card
  11. Program SOC e-fuses
  12. Boot recovery SD card and interrupt U-Boot
  13. U-Boot: Program the SRK (public keys) to the SOC e-fuses
  14. U-Boot: Verify public keys and signed image by running ahab_status
  15. U-Boot: Secure (Close) the device

The remainder of the guide walks through this process.

Walkthrough: 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-fsl-yocto && cd ~/var-fsl-yocto
repo init -u https://github.com/varigit/variscite-bsp-platform -b walnascar -m imx-6.12.49-2.2.0.xml
repo sync -j4

Setup environment to build XWayland GUI demo image

cd ~/var-fsl-yocto
MACHINE=imx95-var-dart DISTRO=fsl-imx-xwayland . var-setup-release.sh build_xwayland

Walkthrough: Download NXP Code Signing Tool (CST)

Download the NXP Code Signing Tool (CST) for the High Assurance Boot (HAB) library and the Advanced High Assurance Boot (AHAB) subsystem: https://www.nxp.com/webapp/Download?colCode=IMX_CST_TOOL_NEW

Unpack the downloaded archive:

tar xf ~/Downloads/IMX_CST_TOOL_NEW.tgz -C ~/.

You are encouraged to read the documents under ~/cst-4.0.1/doc

Walkthrough: Generate Public Key Infrastructure (PKI) tree

cd ~/cst-4.0.1/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:

./ahab_pki_tree.sh

And complete the interactive questions. For example:

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)?: ecc
Enter length for elliptic curve to be used for PKI tree:
Possible values p256, p384, p521: p384
Enter the digest algorithm to use: sha384
Enter PKI tree duration (years): 20
Do you want the SRK certificates to have the CA flag set? (y/n)?: n

Generate Super Root Key (SRK) table

cd ../crts/
../linux64/bin/srktool \
  --ahab_ver 2 \
  --digest sha512 \
  --sign_digest sha384 \
  --table SRK1234table.bin \
  --efuses SRK1234fuse.bin \
  --fuse_format 1 \
  --certs \
SRK1_sha384_secp384r1_v3_usr_crt.pem,\
SRK2_sha384_secp384r1_v3_usr_crt.pem,\
SRK3_sha384_secp384r1_v3_usr_crt.pem,\
SRK4_sha384_secp384r1_v3_usr_crt.pem

Note: For the SoC i.MX 95 B0, the Message Digest algorithm (option --digest) is always sha512. As for the Signing Digest algorithm (option --sign_digest) it should match the one from the PKI tree generation.

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

Info: Instead of using a git repository, you may configure CST_CERTS_URI to fetch an archive or any other Yocto compatible URL.

Walkthrough: 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-imx/conf/machine/imx95-var-dart.conf, or ../sources/meta-variscite-bsp-imx/conf/machine/variscite.inc (use whichever file you prefer):

Variable Description
OVERRIDES =. "ahab:" Machine override used to enable Variscite HAB functions in meta-variscite-hab
SIG_TOOL_PATH Signing tool path that needs to be set to the SPSDK installation location (when using Variscite Docker container the path is: /usr/local/bin/spsdk).
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 ?= "0b2c9c39fbc5020b5faf8c7f1d0db5381c680785"
CST_SERIAL Certificate serial number from previous step
CST_KEYPASS Key password from previous step
UBOOT_DTB_DEFAULT

The imx-boot images contain a FIT image with one or more U-Boot device tree files. Currently, signed imx-boot images can contain only a single device tree file.

Select the U-Boot device tree file to sign:

# For DART-MX95 on VAR-DT8MCustomBoard
UBOOT_DTB_DEFAULT = "imx95-var-dart-dt8mcustomboard.dtb"
KERNEL_DTB_DEFAULT Required for i.MX 95 Family

Like imx-boot, currently only a single Linux device tree can be signed. Below is an example of how to perform this signing:

# For DART-MX95 on Sonata-Board
KERNEL_DTB_DEFAULT = "imx95-var-dart-sonata.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 =. "ahab:"

# Set signing tool path
SIG_TOOL_PATH = "/usr/local/bin/spsdk"

# Select the U-Boot device tree file to sign
UBOOT_DTB_DEFAULT = "imx95-var-dart-dt8mcustomboard.dtb"

# Select the kernel device tree file for DART-MX95 on Sonata-Board to sign:
KERNEL_DTB_DEFAULT = "imx95-var-dart-sonata.dtb"

You may override any of Variscite's default variables, see below for an example local.conf for the imx95-var-dart:

local.conf

# Enable Variscite HAB machine override
OVERRIDES =. "ahab:"

# Set signing tool path
SIG_TOOL_PATH = "/usr/local/bin/spsdk"

# Select the U-Boot device tree file to sign
UBOOT_DTB_DEFAULT = "imx95-var-dart-dt8mcustomboard.dtb"
# Select the kernel device tree file for DART-MX95 on Sonata-Board to sign:
KERNEL_DTB_DEFAULT = "imx95-var-dart-sonata.dtb"
GIT Repository for private certificates
# Note: The `CST_CERTS_REV` and `CST_CERTS_URI` variables are used by the `var-hab-certs`
recipe to provide the repository containing the certificates needed for U-Boot signing. By default, the `var-hab-certs`
repository from Variscite is used. To add your own repository and use your keys, simply modify these variables:

CST_CERTS_REV = "0b2c9c39fbc5020b5faf8c7f1d0db5381c680785"

CST_CERTS_URI = "git://github.com/varigit/var-hab-certs.git;protocol=https;branch=master;rev=${CST_CERTS_REV}"

# Configure certificate serial and passwords (These should be secret)
CST_SERIAL = "1248163E"
CST_KEYPASS = "Variscite_password"

Walkthrough: 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 var-hab-certs
bitbake -c cleansstate var-cst-signer
bitbake -c cleansstate os-cntr-sign
bitbake -c cleansstate fsl-image-gui
# Or combined into a single command:
bitbake -c cleansstate linux-variscite u-boot-variscite imx-boot var-hab-certs var-cst-signer os-cntr-sign fsl-image-gui

Build a signed image:

bitbake fsl-image-gui

Create a recovery SD card:

cd ~/var-fsl-yocto
sudo MACHINE=imx95-var-dart sources/meta-variscite-sdk-imx/scripts/var_mk_yocto_sdcard/var-create-yocto-sdcard.sh <options> /dev/sdX
(Replace /dev/sdX with your actual device)

Walkthrough: 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.

SRK1234fuse.bin.u-boot-cmds:

cat build_xwayland/tmp/deploy/images/imx95-var-dart/SRK1234fuse.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 16 0 0xD29A2548
fuse prog -y 16 1 0x61170CAB
fuse prog -y 16 2 0xB7729FAE
fuse prog -y 16 3 0x37497065
fuse prog -y 16 4 0xB3AF221F
fuse prog -y 16 5 0xFC0C2B8D
fuse prog -y 16 6 0xF7242BA9
fuse prog -y 16 7 0xB58CEE0A
fuse prog -y 17 0 0xE7A3B3C3
fuse prog -y 17 1 0xB7701664
fuse prog -y 17 2 0x57ED6934
fuse prog -y 17 3 0x1698B627
fuse prog -y 17 4 0x4662AB81
fuse prog -y 17 5 0xE31F5C7C
fuse prog -y 17 6 0x5BE8741E
fuse prog -y 17 7 0x4229F2CD

# 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.

ahab_close

One can read back the programmed e-fuses, like:

fuse read 16 0 8
Reading bank 16:

Word 0x00000000: d29a2548 61170cab b7729fae 37497065
Word 0x00000004: b3af221f fc0c2b8d f7242ba9 b58cee0a

fuse read 17 0 8
Reading bank 17:

Word 0x00000000: e7a3b3c3 b7701664 57ed6934 1698b627
Word 0x00000004: 4662ab81 e31f5c7c 5be8741e 4229f2cd

Walkthrough: Verify AHAB successfully authenticates the signed image

AHAB generates events when processing the commands if it encounters issues. The U-Boot "ahab_status" command displays any events that were generated. Run it at the U-Boot command line:

=> ahab_status

If everything is okay you should get the following output:

Lifecycle: 0x00000010, OEM Open


        No Events Found!

Note: You will receive SECO events if you have not programmed the SRK (public keys) to the SOC e-fuses.

Warning: Make sure there are not events before proceeding to the next step.

Walkthrough: Secure the device

After the device successfully boots a signed image without generating any AHAB 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.
=> ahab_close

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.