How-To-Tutorials · September 22, 2025

How to Implement Secure Boot on NXP i.MX6ULL for Firmware Protection

how to implement secure boot on nxp i mx6ull for firmware protection

Secure Boot on i.MX6ULL: Stopping Unauthorized Firmware Cold

If someone can swap out the firmware on your device, they own it. Secure Boot on the NXP i.MX6ULL uses the chip's High Assurance Boot (HAB) feature to cryptographically verify every piece of code before it executes. If the signature doesn't check out, the processor refuses to run it. Period.

This isn't just a nice-to-have for IoT products shipping into the real world — it's becoming a regulatory requirement in many markets. The i.MX6ULL's HAB mechanism is well-documented and field-proven, but it has a steep learning curve and some irreversible steps. You'll want to understand the full process before you start burning OTP fuses.

Prerequisites

  • Experience with embedded Linux and bootloader development
  • An NXP i.MX6ULL development board (EVK or custom)
  • NXP's Code Signing Tool (CST) — download from nxp.com (requires an NXP account)
  • A Linux development machine (Ubuntu 22.04+ recommended)
  • OpenSSL installed for key generation
  • A working U-Boot build for your i.MX6ULL board

Parts/Tools

  • NXP i.MX6ULL EVK or custom board
  • USB OTG cable (for serial download mode) and USB-to-serial adapter
  • SD card or eMMC for firmware storage
  • Linux PC with NXP CST and an ARM cross-compiler installed
  • UUU (Universal Update Utility) from NXP for initial provisioning

Steps

  1. Generate your PKI key hierarchy
    1. NXP's HAB uses a specific PKI tree structure: a Super Root Key (SRK) table that gets burned into OTP fuses, and subordinate keys (CSF and IMG) used for actual signing. Use the CST's key generation scripts:
      cd /path/to/cst/keys
      ./hab4_pki_tree.sh
      The script will ask you about key lengths and validity periods. Use 4096-bit RSA keys (or ECDSA P-256 if your CST version supports it). SHA-256 is the minimum hash you should use.
    2. This generates multiple key pairs in the keys/ and crts/ directories. Back these up to secure offline storage immediately. If you lose the SRK private key and your device has secure boot locked down, that board is bricked forever.
  2. Generate the SRK hash and fuse values
    1. The SRK table hash gets burned into the i.MX6ULL's OTP fuses. Generate it:
      cd /path/to/cst/crts
      ../linux64/bin/srktool \
        --hab_ver 4 \
        --table SRK_1_2_3_4_table.bin \
        --efuses SRK_1_2_3_4_fuse.bin \
        --digest sha256 \
        --certs 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
    2. The SRK_1_2_3_4_fuse.bin file contains the 256-bit hash that will go into OTP. Keep the SRK_1_2_3_4_table.bin — it gets embedded in your signed firmware.
  3. Sign your U-Boot image
    1. Create a CSF (Command Sequence File) that tells the CST how to sign your U-Boot image. Here's a minimal example:
      [Header]
      Version = 4.3
      Hash Algorithm = sha256
      Engine = ANY
      Engine Configuration = 0
      Certificate Format = X509
      Signature Format = CMS
      
      [Install SRK]
      File = "../crts/SRK_1_2_3_4_table.bin"
      Source index = 0
      
      [Install CSFK]
      File = "../crts/CSF1_1_sha256_4096_65537_v3_usr_crt.pem"
      
      [Authenticate CSF]
      
      [Install Key]
      Verification index = 0
      Target index = 2
      File = "../crts/IMG1_1_sha256_4096_65537_v3_usr_crt.pem"
      
      [Authenticate Data]
      Verification index = 2
      Blocks = 0x877ff400 0x000 0x0009EC00 "u-boot-dtb.imx"
      The Blocks line is the tricky part. The load address and size must match your actual U-Boot binary exactly. Get these from your u-boot.imx image using hexdump or the i.MX image header info.
    2. Run the CST to generate the signed image:
      ../linux64/bin/cst --o u-boot-signed.csf --i csf_uboot.txt
    3. Combine the CSF data with your U-Boot image. The exact method depends on your image format, but typically:
      objcopy -I binary -O binary --pad-to=0x2000 --gap-fill=0x00 u-boot-dtb.imx u-boot-padded.imx
      cat u-boot-padded.imx u-boot-signed.csf > u-boot-signed.imx
  4. Test in open (non-secure) mode first
    1. Before burning any fuses, flash the signed image and verify HAB accepts it. Boot the board and check HAB status in U-Boot:
      hab_status
      If you see "No HAB events found" — your signature is valid. If you see HAB failure events, something is wrong with your signing (usually the Blocks address/size). Fix those before proceeding.
    2. This is your last safe checkpoint. The board is still in open mode, so unsigned code will still run. Everything works the same, but HAB reports whether signatures would have passed.
  5. Burn the SRK fuses (point of no return)
    1. Once you've verified signing works, burn the SRK hash into OTP. In U-Boot:
      fuse prog 3 0 0xAAAAAAAA
      fuse prog 3 1 0xBBBBBBBB
      fuse prog 3 2 0xCCCCCCCC
      fuse prog 3 3 0xDDDDDDDD
      fuse prog 3 4 0xEEEEEEEE
      fuse prog 3 5 0xFFFFFFFF
      fuse prog 3 6 0x11111111
      fuse prog 3 7 0x22222222
      Replace the hex values with the actual values from your SRK_1_2_3_4_fuse.bin. Double-check each value — these fuses are write-once.
  6. Close the device (lock secure boot)
    1. After confirming everything works with the SRK fuses programmed, close the HAB by setting the SEC_CONFIG fuse:
      fuse prog 0 6 0x00000002
      Once this fuse is set, the i.MX6ULL will only execute signed code. Unsigned or incorrectly signed firmware will not boot. At all. Test your signed image one more time before this step.

Troubleshooting

  • HAB events showing authentication failures:
    • 99% of the time, this is a mismatch in the Blocks line of your CSF file. The load address and image size must be byte-exact. Use hexdump -C u-boot-dtb.imx | head to verify the IVT (Image Vector Table) header, and cross-reference with your CSF.
  • Board won't boot after closing HAB:
    • If you closed the device with a bad SRK hash or without a properly signed image, the board is likely bricked. This is why step 4 (testing in open mode) is not optional. Some boards have a serial download mode that can recover this, but it depends on your fuse configuration.
  • CST tool reports key errors:
    • Make sure your key files match the exact names expected by the CSF. The certificate chain must be intact — SRK CA signs the CSF key, CSF key signs the IMG key. Regenerate from scratch if you're unsure about the chain.
  • Signature valid but wrong image boots:
    • HAB only authenticates the regions you specify in the CSF Authenticate Data blocks. If you leave gaps (like the device tree or initramfs), an attacker could modify those unsigned regions. Sign every component that executes or gets parsed during boot.

Where to Go from Here

With secure boot locked down, your i.MX6ULL will reject any unsigned firmware. But secure boot alone isn't a complete security solution. You should also encrypt your firmware image (so competitors can't reverse-engineer it), implement secure firmware updates (signed OTA packages), and consider enabling the i.MX6ULL's CAAM (Cryptographic Acceleration and Assurance Module) for runtime crypto operations.

I'd also strongly recommend setting up a key revocation plan. The SRK table supports up to four root keys — if one is compromised, you can revoke it and switch to another by blowing a revocation fuse. Plan for this from day one, not after an incident.