Skip to content

Secure Boot on IMX93 with AHAB

This page explains the bootloader authentication on Welma, for machines with i.MX applications processors that support Advanced High Assurance Boot (AHAB), typically machine sm2s-imx93-mbep5.

References:

Acronyms:

  • CSF: Command Sequencer File
  • CST: Code-Signing Tool
  • AHAB: Advanced High Assurance Boot
  • IVT: Initial Vector Table
  • SPL: Second Program Loader
  • SRK: Super Root Key

imx-boot structure

The built image is named imx-boot, it consists of 3 containers and is structured as follows:

Compared to HABv4, AHAB does not use CSF binaries. The SRK table and Signature for container headers and image information is inserted into the Signature Block region of the imx-boot binary.

All 3 containers must be signed to successfully boot into U-Boot with AHAB enabled. 1st container is proprietary binary and it comes signed already. We only have to sign 2nd and 3rd containers.

The idea is generally the same as what's done for HABv4 - imx-boot's do_compile log is parsed to figure out correct offsets. Those offsets are later used to generate CSF files used as input to CST.

i.MX93 supports ECC and RSA keys, however PSS needs to be used as signature algorithm when RSA keys are chosen. However, it was decided to use the EC keys, as they're suggested default.

Secure boot stages

The secure boot process involves multiple stages of verification, each using specific assets and cryptographic algorithms. The default cryptographic algorithm used is EC P384, SHA-384 as signature hashing algorithm, and SHA256 as digest algorithm.

ELE FW is the image inside of the 1st container of imx-boot. It's being authenticated first, and, if successful, ELE jumps to ELE FW that handles the rest of the boot process. ELE FW is NXP proprietary binary and comes pre-signed with NXP keys.

  1. ELE FW Authentication: This comes from NXP and is a proprietary binary

    • Assets:

      • "NXP header and signature" (image above):

        • SRK TABLE: table of the public keys
        • Signature: signature that signs Container Headers, Signature Headers and SRK Table
      • ELE FW

    • Authentication:

      • The A35 ROM loads ELE FW into internal RAM.
      • The ELE ROM code authenticates the ELE FW signature.
      • ELE switches from ROM to authenticated FW.
      • ELE authenticates OEM container header
      • The container header are loaded to target RAM (A35 in singleboot (our) case)
      • ELE authenticates container header currently being processed and returns status response to boot core.
  2. SPL Image Authentication:

    • Assets contained:

      • u-boot-spl
    • Authentication:

      • SRK Table (inside of BL2 header and signature) is verified against the NXP/OEM SRK fuses.
      • The container signature is verified against the SRK.
  3. FIT Image Loading: The SPL loads the contents of the 3rd container (BL3) into external RAM. The 3rd container packages the next components which are U-boot binary with device tree blob, ARM trusted firmware, and OP-TEE binary.

  4. The ROM Code starts u-boot SPL.

  5. BL3 container authentication:

    • Assets contained in BL3 container:

      • bl31.bin (ATF)
      • u-boot
      • tee.bin (OP-TEE)
    • Authentication:

      • SRK Table (inside of BL3 header and signature) is verified against the NXP/OEM SRK fuses.
      • The container signature is verified against the SRK.
  6. Execution of U-Boot:

    • The SPL passes control to ATF, OP-TEE and U-Boot.

Setting up your Secure Boot

This section will guide you through the process of building and running an image with secure boot.

It is assumed the following context:

  • IMX machine (eg: sm2s-imx93-mbep5)
  • Default Welma partition layout
  • Default Welma AHAB development keys used in the Yocto build
  • Production keys owned by a separate entity (other than the development team)

Building your Image

This section explains what you need to do to support secure boot on a new board. Welma supported boards already have all this.

Welma requirements:

  • machine.conf:

    • Set BOOT_SIGNING_MECHANISM = "imx"
    • Set BOOT_SIGNING_MECHANISM_VERSION = "ahab"
  • In local.conf

    • Activate secure boot by defining WELMA_SECURE_BOOT = "1" (this is the default)
    • Adjust or keep the default values for WELMA_KEY_SWK1_PUB and WELMA_KEY_SWK1_PRIV
  • Other variables:

    • WELMA_KEYS_DIR: Directory of the public keys used for the SRK table
    • IMG_KEY: Path to IMGK. Must be named %_crt.pem and have its related private key in ../keys/%.key.pem. (default: one of the development keys).
  • imx-boot:

    • Have the uboot-offsets-sd file generated and deployed. It is produced by a patch to U-Boot. It indicates nodtb U-Boot's size and U-Boot's FDT size. These parameters are later inserted into imx-boot-offsets-sd.
    • Have the imx-boot-offsets-sd file generated and deployed. It indicates which blocks of imx-boot shall be authenticated.
    • Have WELMA_KEY_SWK1_PUB injected (execute imx-uboot-tool-ahab).
    • Have imx-boot signed with the selected keys and embed all necessary certificates (execute imx-sign).
  • u-boot:

    • Activate AHAB, FIT signature and legacy image format (CONFIG_AHAB_BOOT, CONFIG_FIT_SIGNATURE)
    • Ensure another patch to U-Boot allowing to use hexvalue option for fdt command to U-Boot is applied
    • Deactivate the HAB authentication of the kernel FIT image because it is replaced by the regular U-Boot mechanism.
    • Disable the U-Boot command line or restrict its access by a password, because it would allow an attacker to bypass the secure boot mechanism.
  • In SYSRO and APPRO: have your programs not start other programs located in SYSRW, as this filesystem is not covered by secure boot. Keep in mind that /home is located in SYSRW and make sure that files such as ~/.profile, ~/.bashrc, etc. do not get executed automatically if they were created by an attacker.

The following files are output in DEPLOYDIR:

  • ${DEPLOYDIR}/fuse-bootcmd.scr
  • ${DEPLOYDIR}/imx-boot-tools/imx-boot-offsets-sd

Signing your Image with Production Keys

Input:

  • Generated by the build:

    • imx-boot
    • imx-boot-offsets-sd
    • fitImage (BOOT)
    • .verity images (SYSRO, APPRO)
  • Production Keys: SWK1.priv, SWK1.crt

Ouput (signed images provisioned with necessary public keys):

  • imx-boot
  • BOOT vfat partition
  • SYSRO and APPRO verity partitions

Steps:

  • Inject SWK1.crt into imx-boot

    • Execute imx-uboot-tool-ahab (will extract u-boot-dtb from imx-boot; inject SWK1.crt into u-boot-dtb; replace u-boot-dtb in imx-boot)

imx-boot's 3rd container layout

Note

Some padding is added to dt.dtb, used to provide enough space in dt.dtb for it to be injected with the SWK1 pubkey. Controlled from yocto build by the variable WELMA_DTB_PADDING. Currently set to 4096 (should be at least 3072 in case of sha256,rsa4096 hash sign algos).

welma-signing-tools/imx/imx-uboot-tool-ahab inject-pubkey \
                --imx-boot imx-boot \
                --offsets-file imx-boot-offsets-sd \
                --cert SWK1.crt \
                --uboot-pubkey-algo sha256,rsa4096
  • Sign imx-boot

  • Sign fitImage:

    welma-signing-tools/common/sign-fitimage SWK1.priv fitImage
    

  • Create the BOOT partition (vfat) populated with the signed fitImage, using mkdosfs & mcopy

  • Sign .verity images:

    welma-signing-tools/common/sign-verity-device \
                --device <appro.verity> \
                --key SWK1.priv
    
    welma-signing-tools/common/sign-verity-device \
                --device <sysro.verity> \
                --key SWK1.priv
    

Fusing your Products

Scripts to use to generate the needed keys and signatures

The files are located in the repository welma-signing-tools. It contains three scripts:

  • imx-keygen: This script will create a set of keys to be used to sign the bootloader. The default key for AHAB is EC p384 with 30 years of validity. The --remove-passphrase option is mandatory for AHAB version of the script.
  • imx-sign: This takes the binary to sign, secure boot version (habv4 or ahab), the CSF files templates, the directory containing the keys and the mkimage log files generated at build time. It then generates a new signed binary file to be flashed on the board.
  • imx-srk-table-gen: This script is used to generate the eFuses dump. It copies necessary key and certificate files, runs the SRK tool to generate fuse binaries, and create s a boot environment file with commands to program the fuses. It also provides a formatted output of the fuse programming commands for manual use.

Those scripts can be called within Yocto or externally.

Yocto Build variables

In order to activate the needed feature the build must be modified to include WELMA_SECURE_BOOT = "1" in the local.conf file. It is possible to override some default variables for signing.

The following variables in the build process can be overridden in your local.conf file:

  • WELMA_KEYS_DIR: This variable is used to define the path to the keys. The default value for sm2s-imx93-mbep5 MACHINE is ${STAGING_DATADIR_NATIVE}/default-dev-keys-ahab.

  • CSF_TEMPLATE: This variable is used to define the path to the CSF templates. The default value is ${STAGING_DATADIR_NATIVE}/templates.

  • IMG_KEY: This variable is used to define the path to the sign key, relative to WELMA_KEYS_DIR. The default value for sm2s-imx93-mbep5 MACHINE is ./crts/SRK1_sha384_secp384r1_v3_usr_crt.pem.

Burning the eFuses

During the Yoco build, a file named fuse-bootcmd.scr is created. It is installed in the DEPLOYDIR.

Warning

These commands are writing to One-Time Programmable (OTP) eFuses. Each eFuse is one bit, and the registers are 32 bits. These eFuses can only be written to once. However, while a bit is 0, it can be set to 1 even if the full 32-bit word has been written. Be absolutely certain that you want to write to the OTP before running these commands. Once a bit is set to 1, the data cannot be changed or erased. Before closing the device, ensure there are no pending events by running the ahab_status command.

In U-Boot download the script using tftp:

u-boot=> setenv ipaddr 10.0.0.2 && setenv serverip 10.0.0.1
u-boot=> tftp fuse-bootcmd.scr
Using ethernet@42890000 device
TFTP from server 10.0.0.1; our IP address is 10.0.0.2
Filename 'fuse-bootcmd.scr'.
Load address: 0x80400000
Loading: #
     545.9 KiB/s
done
Bytes transferred = 1119 (45f hex)
u-boot=> source $loadaddr
## Executing script at 80400000
New commands available:

run mfg_fuse_rot_otp
run mfg_close_device

WARNING! THESE COMMANDS ARE WRITING TO OTP REGISTERS AND CAN BE RUN ONLY ONCE ON A PART
BE SURE YOU REALLY WANT TO WRITE OTP BEFORE RUNNING THESE COMMANDS
BEFORE CLOSING DEVICE CHECK LACK OF EVENTS WITH COMMAND hab_status

It is possible to check the values written in the fuses with fuse sense in U-Boot:

u-boot=> fuse sense 16 0 8
Sensing bank 16:

Word 0x00000000: a0dc1592 13632529 e3b8625f 75dd7454
Word 0x00000004: 7f4595e0 a9bb9995 25fc6ad4 6d6d22a9

Offline signing of imx-boot

In order to sign imx-boot with other keys than the default ones after a Yocto build, two scripts need to be called:

  1. imx-srk-table-gen will create the fuse table for the new keys
  2. imx-sign will sign the binary file with the new keys

Pre-requisites:

  • python3
  • have srktool and cst in PATH.

Inputs:

  • imx-boot
  • private and public keys
  • offset file (imx-boot-offsets-sd)

Outputs:

  • imx-boot (provisioned with public keys and signed)
  • u-boot fuse commands

Example:

$ imx-srk-table-gen --keys /path/to/SRK*_crt.pem \
                     --srk-table /path/to/srk_table \
                     --srk-fuse-instructions-uboot /path/to/fuse-bootcmd.env \
                     --sb-version ahab

$ imx-sign \
        --sb-version ahab \
        --imgk /path/to/SRK1_sha384_secp384r1_v3_usr_crt.pem \
        --srk-table /path/to/srk_table \
        --template /path/to/template_csf_ahab.txt \
        --bootloader /path/to/imx-boot \
        --output /path/to/imx-boot.signed \
        --imx-boot-offsets /path/to/imx-boot-offsets-sd

Test cases

The following test cases are designed to verify the secure boot process. The main objective is to ensure that there are no Advanced High Assurance Boot (AHAB) events that might indicate a security breach or a failure in the secure boot process.

To check for AHAB events, we stop the U-Boot execution and launch the ahab_status command. This command displays the AHAB events that occurred during the boot process. A successful test case will show no AHAB events.

Note

These test cases are performed on a non-closed device. In a non-closed device, the secure boot is not fully enforced, allowing for testing and debugging.

U-Boot signed with matching keys

This is the nominal case, where the keys used have been properly fused. In this case there will be no AHAB events.

  • Case of a non-closed device:
=> ahab_status
Lifecycle: 0x00000008, OEM Open


    No Events Found!
  • Case of a closed device:

(information upcoming in a future version of this document)

Unsigned U-Boot or signed with a wrong key

When U-Boot is unsigned or signed with an incorrect key, HAB events are triggered. These events indicate a failure in the secure boot process. The ahab_status command will show an AHAB event with a indicator either of:

  • ELE_NO_AUTHENTICATION_FAILURE_IND (U-Boot was not signed at all)
  • ELE_BAD_KEY_HASH_FAILURE_IND
  • ...

Example:

=> ahab_status
Lifecycle: 0x00000008, OEM Open


    0x0287fad6
    IPC = MU APD (0x2)
    CMD = ELE_OEM_CNTN_AUTH_REQ (0x87)
    IND = ELE_BAD_KEY_HASH_FAILURE_IND (0xFA)
    STA = ELE_SUCCESS_IND (0xD6)

    0x0287fad6
    IPC = MU APD (0x2)
    CMD = ELE_OEM_CNTN_AUTH_REQ (0x87)
    IND = ELE_BAD_KEY_HASH_FAILURE_IND (0xFA)
    STA = ELE_SUCCESS_IND (0xD6)

Note

For more information, see EdgeLock Secure Enclave (ELE) API Reference Guide for possible IND (indication) fields (section 4.3 "Response Indication") or possibe CMD (command) fields (section 3 "Messages").

Badly signed or corrupted imx-boot on a closed device

In case the device has been closed, no boot can occur if the keys are not good, or if the imx-boot image is corrupted in some way. In this case, u-boot will not be started and the result is:

(information upcoming in a future version of this document)

In this case, to fix your device, do a first installation with a properly signed imx-boot.