A primer on how NXP's High Assurance Boot turns any board into a provably-trusted node on a decentralized peer-to-peer network.
| Platform | Core | Secure | Storage | Use Case |
|---|---|---|---|---|
| i.MX93 | Dual A55 (Cortex-A55) | M33 (Cortex-M33) + ELE-AP | 256MB/512MB/1GB DDR | Primary compute nodes, network coordinators, full Linux |
| RT1180 B0 | Dual A7 (Cortex-A7) | M33 (Cortex-M33) + ELE | 1MB RAM (no DDR) | Edge nodes, attestation proxies, storage sharing |
Both use HAB4 for measured boot. i.MX93 adds ELE-AP (next-gen enclave) with stronger crypto. RT1180 shares storage via USB/SD for lightweight peers.
Anyone can buy an off-the-shelf embedded board. Anyone can also flash custom firmware onto it. If you want a P2P network where devices run private computation for each other, you need a way to distinguish "running the agreed-upon code" from "running whatever someone installed."
The answer is a measured boot chain. You prove what code you're running before you're allowed to participate.
High Assurance Boot v4 is NXP's secure boot engine. It sits between the immutable boot ROM and your application. Every image in the boot chain is cryptographically verified and measured before execution.
The boot sequence:
Boot ROM (immutable, in silicon)
→ verifies SPL / first-stage bootloader
→ SPL verifies second-stage bootloader
→ bootloader verifies kernel / application
→ application runs
Each step verifies the next step's signature before handing off execution. If verification fails, boot stops. Unless the device is in open lifecycle (development mode), where failures are logged but execution continues.
Each boot image carries a CSF — Configuration Service File — that tells HAB4 how to verify it:
- Signature scheme — RSA-PSS or ECDSA with SHA-256/384/512
- Certificate chain — one or more certificates authenticating the signing key
- Hashes — SHA-256 digest of the image data to verify integrity
- IVT — Image Vector Table pointing HAB4 at the CSF location
The root of trust is the SRKH — Super Root Key Hash. It's a SHA-256 hash of a signing public key, burned into OCOTP fuses. The certificates in the CSF chain back to this root. If they don't, HAB4 rejects the image.
HAB4 doesn't just verify — it measures. Each verified image has its SHA-256 hash recorded in a hardware register:
HAB4 reg0 → SPL hash (32 bytes)
HAB4 reg1 → U-Boot / bootloader hash (32 bytes)
HAB4 reg2 → kernel or FIT image hash (32 bytes)
HAB4 reg3 → optional extension / second-stage hash (32 bytes)
These registers are readable by software but writable only by HAB4 hardware. You can't fake them — they reflect what actually booted.
This is the trust signal. Not who signed the image. What the image's content hash is. The measurements are independent of the signing key.
[Header]
HDR.Ver = 4
HDR.Scene = 3
HDR.Hash = 0xXXXXXXXXXXXXXXXX
HDR.Size = 0x00000534
[InstallCSFK]
Csph.Algo = SHA256
Csph.Key = <public key hash>
[AuthenticateCSP]
CSP.Prev = InstallCSFK
CSP.Algo = ECDSA_NP256
CSP.PKey = <signing public key>
CSP.Sign = <signature over certificate>
CSP.Hash = <cert hash>
[VerifyBootDst]
Image.Verifier = AuthenticateCSP
Image.Location = QSPI
Image.Start = 0x08080000
Image.Len = 0x100000
[AuthenticateImage]
Image.Prev = VerifyBootDst
Image.Algo = ECDSA_NP256
Image.Key = <key used to sign the image>
Image.Sign = <image signature>Generated by NXP signing tools (MCUXpresso or signing-tools).
The i.MX93 is the main compute platform. Dual Cortex-A55 cores with full Linux, Cortex-M33 for secure world, and the next-generation ELE-AP (EdgeLock Secure Enclave — Advanced Platform).
i.MX93 supports three boot modes — the M33 secure processor runs in all of them:
| Mode | A55 | M33 | Use Case |
|---|---|---|---|
| LP Boot (Low Power) | A55 boots first (fastest) | M33 runs concurrently | Production — A55 Linux nodes |
| Single Boot | A55 only | M33 idle | Reduced power, no attestation |
| Dual Boot | A55 + M33 boot together | Full secure world | Development / debugging |
LP Boot is the production default — A55 boots Linux while M33 runs the attestation stack in parallel.
ELE-AP on i.MX93 is the next-gen secure enclave with expanded crypto:
| Capability | ELE (RT1180) | ELE-AP (i.MX93) |
|---|---|---|
| RSA | 2048 | 2048 |
| ECDSA | NIST P-256 | NIST P-256, P-384, P-521, BrainPool |
| AES | 128/256 | 128/256/512 |
| ECC | NIST curves | NIST + BrainPool curves |
| Hash | SHA-256, SHA-384, SHA-512 | SHA-256, SHA-384, SHA-512 |
| DH | No | Diffie-Hellman |
| Key wrapping | HKDF, SHA-256 | HKDF, SHA-256 |
| Sealing | Yes (device attributes) | Yes (enhanced attributes) |
| RNG | DRBG | DRBG |
Network → Challenge (32-byte nonce)
↓
ELE-AP → Signs nonce + device identity (S3MU)
↓
Response → 272 bytes: signature + device ID + measurements
↓
Verifier → Validates ELE-AP signature + checks HAB4 measurements
ELE-AP provides hardware key storage with 3 key types:
| Key Type | Storage | Export |
|---|---|---|
| Permanent | Hardware fuses | No |
| Non-Volatile | Secure NV memory | No |
| Volatile | RAM only | No (cleared on reboot) |
Sealing binds keys to device attributes (fuses, S3MU, lifecycle state). A sealed key can only be unsealed on the specific device it was sealed on — or a device with matching attributes. Prevents key extraction and migration to untrusted hardware.
Boot ROM (imx-mkimage) → ATF (A55) → U-Boot SPL → U-Boot → Linux FIT
↕
M33 (ELE-AP)
# Clone i.MX93 SDK components
git clone https://github.com/nxp-imx/imx-atf.git # ARM Trust Firmware
git clone https://github.com/nxp-imx/imx-secure-enclave.git # Secure enclave
git clone https://github.com/nxp-imx/imx-smw.git # Secure Monitor Wrapper
git clone https://github.com/nxp-imx/imx-mkimage.git # Boot image tools
git clone https://github.com/nxp-imx/uboot-imx.git # U-Boot bootloader
git clone https://github.com/nxp-imx/linux-imx.git # NXP Linux kernel
# Build SPL + U-Boot
make -C uboot-imx imx93_11x11_evk_defconfig
make -C uboot-imx -j$(nproc)
# Build ATF
make -C imx-atf PLAT=imx CROSS_COMPILE=aarch64-linux-gnu- bl31
# Build kernel + DTB
make -C linux-imx imx93_11x11_evk_defconfig
make -C linux-imx Image dtbs -j$(nproc)
# Create FIT image
mkimage -f fit_image.its fit_image.itbThe RT1180 is a lighter platform suitable for edge nodes and attestation proxies. Dual A7 cores, no DDR (1MB internal RAM), but shares storage via USB/SD.
Boot ROM → M33 (ELE) → A7 (Linux/OpenWrt)
| Feature | RT1180 B0 | i.MX93 |
|---|---|---|
| Application core | Dual Cortex-A7 | Dual Cortex-A55 |
| Secure core | Cortex-M33 | Cortex-M33 |
| Enclave | ELE | ELE-AP (next-gen) |
| RAM | 1MB internal | 256MB/512MB/1GB DDR |
| Storage | SD/USB share | eMMC/SD/USB |
| Use case | Edge node, proxy | Primary compute |
There is no organization. No central authority. So how does the signing key work?
Option A: shared public key — The firmware repo includes a well-known signing key pair. Published in the repo, not secret. Anyone builds firmware, signs with it, flashes their board. The signing key isn't protecting secrets — it's just a HAB4 requirement to get images through verification.
Option B: per-device self-signing — Each device generates its own signing key, burns its own SRKH into fuses, self-signs its firmware. HAB4 still verifies and measures everything identically.
Option C: open lifecycle, no signing required — In OEM Open lifecycle, HAB4 verifies images but continues on failure. You still get measurements of what actually booted. The measurements are the trust signal, not the signature.
In all cases, the network verifier doesn't care who signed. It checks: do the measured hashes match the published reference for this firmware version?
The FIT (Flattened Image Tree) format lets you bundle kernel, device tree, and initramfs into a single verified image:
FIT Image (.itb):
├── kernel (Image or zImage)
├── device tree (.dtb)
├── initramfs (cpio.gz)
└── signatures + hashes for each component
HAB4 verifies the entire FIT image as one unit. All components are measured together. This means the kernel, device tree, and initramfs are all cryptographically verified and measured before execution.
# Create FIT image configuration (fit_image.its)
mkimage -f fit_image.its fit_image.itb
# Sign with HAB4-compatible CSF
signing-tools --sign --csf fit.csf --image fit_image.itb \
--key sign_key.pem --cert sign_cert.pem --out fit_signed.itb| Role | Platform | Function |
|---|---|---|
| Compute Node | i.MX93 | Full Linux, runs inference/workloads |
| Coordinator | i.MX93 | Network sync, challenge distribution |
| Edge Node | RT1180 | Lightweight attestation, storage proxy |
| Proxy | RT1180 | Bridges edge devices to compute nodes |
Silicon (immutable Boot ROM)
↓
HAB4 (verifies images, records SHA-256 measurements)
↓
ELE/ELE-AP (signs attestation with hardware key)
↓
Network verifier (checks measurements match published reference)
↓
Device eligible to participate
Trust = open-source code + hardware-proven measurements
The firmware is open source. Anyone audits it, builds it, verifies the reference hashes. HAB4 proves the device is running that specific code. ELE proves it's genuine silicon. The network accepts attested devices.
Not "trusted by organization X." Just "running the code we all agreed on, proven by hardware."
The verifier is the network component that validates new devices. It runs on the existing attested nodes and handles the challenge-response protocol:
# Pseudocode — runs on verifier nodes
class NetworkVerifier:
def __init__(self, reference_hashes: Dict[str, str]):
self.reference = reference_hashes # Published boot measurements
def verify_new_device(self, device_id: str) -> AttestationResult:
# 1. Generate challenge nonce
nonce = os.urandom(32)
# 2. Send challenge to device
device_response = send_challenge(device_id, nonce)
# 3. Verify ELE/ELE-AP signature
verify_ele_signature(device_response, nonce)
# 4. Check boot measurements
measured = device_response.measurements
assert measured[0] == self.reference['spl']
assert measured[1] == self.reference['uboot']
assert measured[2] == self.reference['fit']
# 5. Device is attested → eligible to join
return AttestationResult.ELIGIBLEThe verifier doesn't use a "shared networkwide private key." Instead, it uses:
- Reference hashes — Published SHA-256 hashes of the approved firmware
- ELE/ELE-AP verification — Hardware-proven attestation signatures
- Challenge-response — Nonce-based freshness to prevent replay attacks
# Main firmware components
git clone --depth 1 https://github.com/nxp-imx/imx-atf.git
git clone --depth 1 https://github.com/nxp-imx/imx-secure-enclave.git
git clone --depth 1 https://github.com/nxp-imx/imx-smw.git
git clone --depth 1 https://github.com/nxp-imx/imx-mkimage.git
git clone --depth 1 https://github.com/nxp-imx/uboot-imx.git
# Reference attestation code
git clone --depth 1 https://github.com/confidential-containers/guest-components.git
git clone --depth 1 https://github.com/confidential-containers/trustee.git# SPL
make -C u-boot-imx spl/u-boot-spl.bin
# U-Boot
make -C u-boot-imx u-boot.bin
# Kernel + FIT image
make -C linux-nxp Image dtbs
make -C initramfs initramfs.cpio.gz
mkimage -f fit_image.its fit_image.itb# Sign each stage with your key
signing-tools --sign --csf spl.csf --image spl/u-boot-spl.bin \
--key sign_key.pem --cert sign_cert.pem --out spl_signed.bin
signing-tools --sign --csf uboot.csf --image u-boot.bin \
--key sign_key.pem --cert sign_cert.pem --out uboot_signed.bin
signing-tools --sign --csf fit.csf --image fit_image.itb \
--key sign_key.pem --cert sign_cert.pem --out fit_signed.itb# These are the trust anchors — published in the firmware repo
sha256sum spl_signed.bin uboot_signed.bin fit_signed.itb > reference_hashes.txt
# Commit reference_hashes.txt to the repo alongside the source code// Pseudocode — runs on device
hab_status = HAB4_GetStatus(); // must == HAB4_SUCCESS
HAB4_GetMeasurementReg(0, reg0); // SPL hash
HAB4_GetMeasurementReg(1, reg1); // U-Boot hash
HAB4_GetMeasurementReg(2, reg2); # FIT image hash
HAB4_GetMeasurementReg(3, reg3); # optional extension hash
nonce = receive_challenge_from_network();
ELE_Attest(S3MU, nonce, response); # 272-byte signed device identity
send_to_network(response, reg0, reg1, reg2, reg3);# On the verifier side
attest_resp = receive_from_device()
# 1. Check ELE/ELE-AP signature (prevents replay, proves genuine silicon)
verify_ele_signature(attest_resp, nonce)
# 2. Check measurements against published reference
# This is the trust decision — nothing else matters
measured = attest_resp.measurements
reference = load_reference_hashes()
assert measured[0] == reference['spl']
assert measured[1] == reference['uboot']
assert measured[2] == reference['fit'] # kernel + DTB + initramfs + Hermes
assert measured[3] == reference['extension']
# Device is attested → eligible to joinThe verifier never checks "who signed this." It checks "does what booted match the published code?"
// U-Boot HAB4 core implementation (hab.c — not ahab.c)
// File: [arch/arm/mach-imx/hab.c](https://github.com/nxp-imx/uboot-imx/blob/lf_v2025.04/arch/arm/mach-imx/hab.c#L232)
// Key functions: hab_rvt_authenticate_image(L232), imx_hab_authenticate_image(L907), authenticate_image(L1024)
// i.MX8 HAB4 container authentication
// File: [arch/arm/mach-imx/imx8/ahab.c](https://github.com/nxp-imx/uboot-imx/blob/lf_v2025.04/arch/arm/mach-imx/imx8/ahab.c#L31)
// Key functions: ahab_auth_cntr_hdr(L31), ahab_auth_release(L48), ahab_verify_cntr_image(L59), authenticate_os_container(L127)
// ELE-specific HAB4 integration
// File: [arch/arm/mach-imx/ele_ahab.c](https://github.com/nxp-imx/uboot-imx/blob/lf_v2025.04/arch/arm/mach-imx/ele_ahab.c#L260)
// Key functions: ahab_auth_cntr_hdr(L260), ahab_auth_release(L282), ahab_verify_cntr_image(L296), ahab_dump(L596), decode_ele_message(L798)
// U-Boot image types for HAB4
// File: [include/image.h](https://github.com/nxp-imx/uboot-imx/blob/lf_v2025.04/include/image.h#L222)
#define IH_TYPE_FIRMWARE_IVT // Firmware Image with HABv4 IVT (L222)// ELE API header in U-Boot
// File: [arch/arm/include/asm/mach-imx/ele_api.h](https://github.com/nxp-imx/uboot-imx/blob/lf_v2025.04/arch/arm/include/asm/mach-imx/ele_api.h#L9)
// Defines ELE version constants (L9-12), command macros (L20-49), response macros, data structures
// ELE driver implementation
// File: [drivers/misc/imx_ele/ele_api.c](https://github.com/nxp-imx/uboot-imx/blob/lf_v2025.04/drivers/misc/imx_ele/ele_api.c#L34)
// Key functions: ele_release_rdc(L34), ele_auth_oem_ctnr(L79), ele_verify_image(L137), ele_get_info(L445)// DICE attestation in ARM TF (under include/lib/dice/)
// File: [include/lib/dice/dice.h](https://github.com/nxp-imx/imx-atf/blob/lf_v2.12/include/lib/dice/dice.h#L25)
// DICE constants: CDI_SIZE, HASH_SIZE, etc. (L25-30), evidence structures (L85+)
// PSA delegated attestation
// File: [include/lib/psa/delegated_attestation.h](https://github.com/nxp-imx/imx-atf/blob/lf_v2.12/include/lib/psa/delegated_attestation.h#L19)
// RSE delegated attestation commands (L19-20), PSA API functions (L76+)
// Measured boot metadata (under include/drivers/measured_boot/)
// File: [include/drivers/measured_boot/metadata.h](https://github.com/nxp-imx/imx-atf/blob/lf_v2.12/include/drivers/measured_boot/metadata.h#L11)
// Measurement sizes (L11-19), boot stage identifiers (L36-49)// Attestation key management (under core/keymgr/)
// File: [core/keymgr/keymgr_attest.c](https://github.com/nxp-imx/imx-smw/blob/release%2Fversion_5.x/core/keymgr/keymgr_attest.c#L22)
// Key functions: key_attestation_convert_attributes(L22), key_attestation_convert_args(L48), smw_keymgr_get_attest_chal(L88), smw_keymgr_get_attest_cert(L109)
// HSM API for attestation
// File: [include/hsm/hsm_api.h](https://github.com/nxp-imx/imx-secure-enclave/blob/lf-6.12.49_2.2.0/include/hsm/hsm_api.h#L15)
// HSM module includes: handle, key, utils, crypto, import/export (L15-50)// SHE (Secure Hardware Extension) API
// File: [include/she/she_api.h](https://github.com/nxp-imx/imx-secure-enclave/blob/lf-6.12.49_2.2.0/include/she/she_api.h#L11)
// SHE module includes: session, cipher, RNG, key management (L11-24)
// Device identification (under include/she/internal/)
// File: [include/she/internal/she_get_id.h](https://github.com/nxp-imx/imx-secure-enclave/blob/lf-6.12.49_2.2.0/include/she/internal/she_get_id.h#L21)
// Constants: SHE_CHALLENGE_SIZE (L21), SHE_ID_SIZE (L23), she_get_id() function (L53)
// Attestation test (under test/she/seco/)
// File: [test/she/seco/she_test.c](https://github.com/nxp-imx/imx-secure-enclave/blob/lf-6.12.49_2.2.0/test/she/seco/she_test.c#L29)
// Test entry point: main() (L29), she_test_usage() (L12)// mkimage for i.MX8/i.MX93
// File: [src/mkimage_imx8.c](https://github.com/nxp-imx/imx-mkimage/blob/lf-6.12.49_2.2.0/src/mkimage_imx8.c#L587)
// Entry point: main() (L587), copy_file() (L104), split_dtb_from_uboot() (L496)// System Controller firmware recipe
// File: [recipes-bsp/imx-sc-firmware/imx-scfw-porting-kit_1.15.0.bb](https://github.com/nxp-imx/meta-imx-scfw/blob/master/recipes-bsp/imx-sc-firmware/imx-scfw-porting-kit_1.15.0.bb#L3)
// DESCRIPTION (L3), SRC_URI (L10), checksums (L12-15)
// TEE evidence generation (under attestation-agent/attester/)
// File: [attestation-agent/attester/src/lib.rs](https://github.com/confidential-containers/guest-components/blob/main/attestation-agent/attester/src/lib.rs#L49)
// BoxedAttester type (L49), Tee → Attester conversion (L51+)
// SE (Secure Enclave) attester (under attestation-agent/attester/src/se/)
// File: [attestation-agent/attester/src/se/mod.rs](https://github.com/confidential-containers/guest-components/blob/main/attestation-agent/attester/src/se/mod.rs#L82)
// SeAttester struct (L82), get_evidence() impl (L86), SeAttestationRequest (L43)
// Verifier interface (under deps/verifier/)
// File: [deps/verifier/src/lib.rs](https://github.com/confidential-containers/trustee/blob/main/deps/verifier/src/lib.rs#L53)
// VerifierConfig struct (L53), to_verifier() function (L69)| State | Boot | Attestation | Debug | Notes |
|---|---|---|---|---|
| OEM Open | Verify, continue on failure | Available | JTAG enabled | Development/testing |
| OEM Closed | Halt on failure | Available | JTAG disabled | Production |
| Field Return | Halt on failure | Limited | Disabled | End of life |
Start in OEM Open during development. Lock to OEM Closed for production. One-way fuse blow.
Key NXP reference manuals:
- i.MX93 Application Processor Reference Manual (i.MX93-RM)
- RT1180 Reference Manual (RT1180-RM)
- HAB4 User's Guide (AN12603)
- ELE/ELE-AP SDK documentation
v2.0 — Dual-platform (i.MX93 primary, RT1180 edge). ELE-AP attestation, boot modes, sealing, network roles. Source code references maintained.