Skip to content

Secure Boot on IMX with HABv4

This pages explains the bootloader authentication on Welma, for machines with i.MX applications processors that support High Assurance Boot version 4 (HAB4), typically machine sm2s-imx8plus-mbep5.

References:

  • NXP AN4581: i.MX Secure Boot on HABv4 Supported Devices, Rev. 0, 09/2012
  • NXP CST: i.MX High Assurance Boot Reference Code Signing Tool
  • U-Boot: doc/imx/habv4/guides/mx8m_secure_boot.txt

Acronyms:

  • CSF: Command Sequence File
  • CST: NXP Code-Signing Tool version >= 3.3.1
  • FIT: Flattened Image Tree. In this context, it is used as a container (for BL3 stages according to Trusted Firmware-A terminology)
  • HAB: High Assurance Boot
  • SPL: Second Program Loader, also known as BL2 according to Trusted Firmware-A terminology
  • SRK: Super Root Key

imx-boot structure

The built image is named imx-boot and is structured as follows (padding is not shown):

--------  +-----------------------------+ --------
Signed ^  |      u-boot-spl             |   ^
 Data  v  |      DDR FW                 |   |
--------- +-----------------------------+   | SPL (~BL2)
          | CSF (commands, SRK table,   |   | Block
          | signatures, certificates)   |   v
--------  +-----------------------------+ --------
Signed ^  |      FIT header             |   ^
Data   v  |                             |   |
--------- +-----------------------------+   |
          | CSF (commands, SRK table,   |   |
          | signatures, certificates)   |   | FIT (~BL3)
--------  +-----------------------------+   | Block
       ^  |     u-boot.bin              |   |
Signed |  |     u-boot.dtb              |   |
Data   |  |     bl31.bin (ATF)          |   |
       v  |     OP-TEE (Optional)       |   v
--------  +-----------------------------+ --------

The CSF contains all the commands that the ROM executes during the secure boot. These commands instruct HABv4 on which memory areas of the image to authenticate, which keys to install and use, what data to write to a register, and so on. In addition, the necessary certificates and signatures involved in the verification of the image, as well as the SRK table, are attached to the CSF binary signature.

Two CSF binaries are required:

  • CSF-SPL used by the boot ROM to authenticate and load the SPL image + DDR firmware
  • CSF-FIT used by SPL (through HAB APIs) to authenticate and load the FIT components

First, i.MX Boot ROM reads the eFuses to determine the security configuration of the SoC and the type of the boot device. The ROM then loads the SPL image and verifies its signature embedded in the CSF. If it succeeds, SPL is executed. A FIT image is used to package the next components which are:

  • U-boot and its control device tree blob
  • ARM trusted firmware
  • OP-TEE binary

If that second stage verification succeeds, control is passed to U-Boot which then loads the Linux kernel and initiates the boot process.

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 RSA 4096 with SHA-256 for hashing.

  1. SPL CSF Authentication:

    • Assets contained in the SPL CSF:

      • SRK_1_2_3_4: table of the 4 public keys SRK1, 2, 3, 4 (DER format)
      • CSFK: certificate (X.509 DER format)
      • IMGK: certificate (X.509 DER format)
    • Authentication:

      • The ROM loads the SPL block into on-chip RAM.
      • The ROM Code authenticates the SRK_1_2_3_4 table using OCOTP_SRK_HASH (SHA-256) stored in the OTP fuses.
      • The ROM Code authenticates CSFK using SRK1 (RSA-4096, SHA-256)
      • The ROM Code authenticates the SPL CSF using CSFK (RSA-4096, SHA-256)
  2. SPL Image Authentication:

    • Assets contained:

      • u-boot-spl
      • DDR FW
    • Authentication:

      • The ROM Code authenticates IMGK using SRK1 (RSA-4096, SHA-256)
      • The ROM Code authenticates the SPL image using IMGK (RSA-4096, SHA-256)
  3. The ROM Code starts u-boot-spl.

  4. FIT CSF Authentication:

    • Assets contained in the FIT CSF:

      • SRK_1_2_3_4: table of the 4 public keys SRK1, 2, 3, 4 (DER format)
      • CSFK: certificate (X.509 DER format)
      • IMGK: certificate (X.509 DER format)
    • Authentication:

      • u-boot-spl loads the FIT block into external RAM. The FIT header has references to U-boot bin and dtb, ATF, and OP-TEE.
      • u-boot-spl authenticates the SRK_1_2_3_4 table using OCOTP_SRK_HASH (SHA-256) stored in the OTP fuses.
      • u-boot-spl authenticates CSFK using SRK1 (RSA-4096, SHA-256)
      • u-boot-spl authenticates the FIT CSF using CSFK (RSA-4096, SHA-256)
  5. FIT Image Authentication:

    • Assets contained:

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

      • The SPL authenticates IMGK using SRK1 (RSA-4096, SHA-256)
      • The SPL authenticates the FIT image using IMGK (RSA-4096, SHA-256)
  6. u-boot-spl passes control ATF, OP-TEE, 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-imx8plus-mbep5)
  • Default Welma partition layout
  • Default Welma 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 = "hab4"
  • 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
    • CSF_KEY: Path to CSFK. Must be named %_crt.pem and have its related private key in ../keys/%.key.pem. (default: one of the development keys).
    • 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 imx-boot-offsets-sd file generated and deployed. It indicates which blocks of imx-boot shall be authenticated.
    • Have imx-boot signed with the development keys and embed all necessary certificates (execute imx-sign).
    • Have WELMA_KEY_SWK1_PUB injected (execute inject-pubkey-uboot-dtb).
  • u-boot:

    • Activate HAB (CONFIG_IMX_HAB)
    • 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

    • Extract u-boot-dtb from imx-boot (tool upcoming)
    • Inject SWK1.crt into u-boot-dtb:
      welma-signing-tools/common/inject-pubkey-uboot-dtb \
                      SWK1.crt \
                      u-boot-dtb \
                      sha256,rsa4096'
      
    • Replace u-boot-dtb in imx-boot (tool upcoming)
  • 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

Burning the eFuses

fuse-bootcmd.scr can be used in then u-boot command line interpreter to burn the eFuses.

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 hab_status command.

Example:

u-boot=> setenv ipaddr 169.254.142.1 && setenv serverip 169.254.142.224
u-boot=> tftp fuse-bootcmd.scr
Using ethernet@30bf0000 device
TFTP from server 169.254.142.224; our IP address is 169.254.142.1
Filename 'fuse-bootcmd.scr'.
Load address: 0x40480000
Loading: #
         67.4 KiB/s
done
Bytes transferred = 692 (2b4 hex)
u-boot=> source $loadaddr
## Executing script at 40480000
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
u-boot=>

Check the values written in the fuses with fuse sense in U-Boot:

u-boot=> fuse sense 6 0 4
Sensing bank 6:

Word 0x00000000: dadd030d 8b5d3ea7 4ec5a321 836ff123
u-boot=> fuse sense 7 0 4
Sensing bank 7:

Word 0x00000000: 6578c108 e7483aab 51fe0260 25f904da

When a device is closed, hab_status reflects the following:

u-boot=> hab_status
Secure boot enabled
HAB Configuration: 0xcc, HAB State: 0x99
No HAB Events Found!

Offline signing of imx-boot

In order to sign imx-boot with other keys, after a Yocto build (and out of the Yocto build environment), two scripts can to be used:

  1. imx-srk-table-gen: will create the SRK table for the new public keys
  2. imx-sign: will sign the binary file with the new private keys and insert the SRK table

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 hab4

$ imx-sign --sb-version hab4 \
           --csfk /path/to/csfk_crt.pem \
           --imgk /path/to/imgk_crt.pem \
           --srk-table /path/to/srk_table \
           --template /path/to/csf_template \
           --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 High Assurance Boot (HAB) events that might indicate a security breach or a failure in the secure boot process.

To check for HAB events, we stop the U-Boot execution and launch the hab_status command. This command displays the HAB events that occurred during the boot process. A successful test case will show no HAB 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 HAB events:

u-boot=> hab_status
Secure boot disabled

HAB Configuration: 0xf0, HAB State: 0x66
No HAB Events Found!

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 hab_status command will show a HAB event with a status of HAB_FAILURE, signifying a failure, and a reason of HAB_INV_CERTIFICATE, indicating an invalid certificate. This suggests that the key used to sign U-Boot does not match the one fused into the device, or that U-Boot was not signed at all.

Both give the following hab_status output:

u-boot=> hab_status

Secure boot disabled

HAB Configuration: 0xf0, HAB State: 0x66

--------- HAB Event 1 -----------------
event data:
        0xdb 0x00 0x14 0x45 0x33 0x21 0xc0 0x00
        0xbe 0x00 0x0c 0x00 0x03 0x17 0x02 0x00
        0x00 0x00 0x00 0x7c

STS = HAB_FAILURE (0x33)
RSN = HAB_INV_CERTIFICATE (0x21)
CTX = HAB_CTX_COMMAND (0xC0)
ENG = HAB_ENG_ANY (0x00)


--------- HAB Event 2 -----------------
event data:
        0xdb 0x00 0x14 0x45 0x33 0x0c 0xa0 0x00
        0x00 0x00 0x00 0x00 0x40 0x1f 0xdd 0xc0
        0x00 0x00 0x00 0x20

STS = HAB_FAILURE (0x33)
RSN = HAB_INV_ASSERTION (0x0C)
CTX = HAB_CTX_ASSERT (0xA0)
ENG = HAB_ENG_ANY (0x00)


--------- HAB Event 3 -----------------
event data:
        0xdb 0x00 0x14 0x45 0x33 0x0c 0xa0 0x00
        0x00 0x00 0x00 0x00 0x00 0x91 0xff 0xc0
        0x00 0x00 0x00 0x20

STS = HAB_FAILURE (0x33)
RSN = HAB_INV_ASSERTION (0x0C)
CTX = HAB_CTX_ASSERT (0xA0)
ENG = HAB_ENG_ANY (0x00)


--------- HAB Event 4 -----------------
event data:
        0xdb 0x00 0x14 0x45 0x33 0x0c 0xa0 0x00
        0x00 0x00 0x00 0x00 0x00 0x91 0xff 0xe0
        0x00 0x00 0x00 0x0c

STS = HAB_FAILURE (0x33)
RSN = HAB_INV_ASSERTION (0x0C)
CTX = HAB_CTX_ASSERT (0xA0)
ENG = HAB_ENG_ANY (0x00)


--------- HAB Event 5 -----------------
event data:
        0xdb 0x00 0x14 0x45 0x33 0x0c 0xa0 0x00
        0x00 0x00 0x00 0x00 0x00 0x92 0x00 0x00
        0x00 0x00 0x00 0x04

STS = HAB_FAILURE (0x33)
RSN = HAB_INV_ASSERTION (0x0C)
CTX = HAB_CTX_ASSERT (0xA0)
ENG = HAB_ENG_ANY (0x00)


--------- HAB Event 6 -----------------
event data:
        0xdb 0x00 0x14 0x45 0x33 0x0c 0xa0 0x00
        0x00 0x00 0x00 0x00 0x40 0x1f 0xcd 0xc0
        0x00 0x00 0x00 0x04

STS = HAB_FAILURE (0x33)
RSN = HAB_INV_ASSERTION (0x0C)
CTX = HAB_CTX_ASSERT (0xA0)
ENG = HAB_ENG_ANY (0x00)


--------- HAB Event 7 -----------------
event data:
        0xdb 0x00 0x14 0x45 0x33 0x21 0xc0 0x00
        0xbe 0x00 0x0c 0x00 0x03 0x17 0x00 0x00
        0x00 0x00 0x00 0x5c

STS = HAB_FAILURE (0x33)
RSN = HAB_INV_CERTIFICATE (0x21)
CTX = HAB_CTX_COMMAND (0xC0)
ENG = HAB_ENG_ANY (0x00)

The first HAB event indicates a failure (STS = HAB_FAILURE). The reason for the failure is an invalid certificate (RSN = HAB_INV_CERTIFICATE). This event occurred in the context of a command (CTX = HAB_CTX_COMMAND). The engine field (ENG = HAB_ENG_ANY) suggests that the event can be associated with any engine.

This is also true when the image is corrupted.

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:

Trying to boot from BOOTROM
image offset 0x8000, pagesize 0x200, ivt offset 0x0

Authenticate image from DDR location 0x401fcdc0...
spl: ERROR:  image authentication unsuccessful
resetting ...

To repair your device, you will need to re-install a properly signed imx-boot (using a SD card or the uuu tool).