Skip to content

Generate an AHAB PKI Tree

This guide covers generating the SRK key set, signing configuration, and eFuse hash required to sign i.MX9 boot images with AHAB, using the NXP Secure Provisioning SDK (SPSDK). The resulting key set is consumed by Enable NXP Authenticated Boot.


Prerequisites

  • SPSDK installed in a virtual environment:
python3 -m venv venv
source venv/bin/activate
pip install spsdk

Generate the PKI Tree

nxpcrypto pki-tree ahab \
    -k secp384r1 \
    -n 4 \
    -d 10 \
    -o ./ahab-pki
Option Value Description
-k secp384r1 Key type: rsa2048, rsa3072, rsa4096, secp256r1, secp384r1, secp521r1
-n 4 Number of SRKs; four leaves one that can never be revoked
-d 10 Certificate validity in years
-o ./ahab-pki Output directory
-p Optional passphrase encrypting the private keys
-ca Optional; also generates SGK keys beneath the SRK certificates

Output:

ahab-pki/
├── crts/                              # X.509 certificates
│   ├── CA0_secp384r1_ca_cert.pem
│   └── SRK{0..3}_secp384r1_cert.pem
└── keys/                              # private keys, with their public counterparts
    ├── CA0_secp384r1_ca_key.pem
    ├── CA0_secp384r1_ca_key.pub
    ├── SRK{0..3}_secp384r1_key.pem
    └── SRK{0..3}_secp384r1_key.pub

ahab-pki/keys/key_pass.txt must exist, since imx_signer always points SPSDK at that file. If -p was used, write the same passphrase into it; otherwise leave it empty.

Warning

Restrict permissions on keys/ and never commit it. In production, hold the PKI tree on a host separate from the build machine, or use an SPSDK signature provider backed by an HSM.


Assemble the Signing Configuration

Generate a template, or start from devel-keys/secure-boot/ahab/spsdk_ahab.yaml:

nxpimage ahab get-template -f mimx9352 -o spsdk_ahab.yaml

Set these fields:

Field Value
srk_set oem
used_srk_id Index of the SRK used to sign — 0 for SRK0
srk_table.hash_algorithm sha384 for secp384r1
srk_table.srk_array The four SRK{0..3}_secp384r1_cert.pem filenames
signer Private key matching used_srk_id, for example SRK0_secp384r1_key.pem

Warning

srk_array and signer take bare filenames, never paths. imx_signer rewrites them to ${SIG_DATA_PATH}/crts/… and to a type=file signature provider under ${SIG_DATA_PATH}/keys/.

Note

Do not hand-maintain family:. The imx-boot-signature recipe rewrites it from SPSDK_FAMILY, which xhab.bbclass derives per machine.


Wire the Key Set into the Build

<SIG_DATA_PATH>/
├── spsdk_ahab.yaml
├── crts/
│   └── SRK{0..3}_secp384r1_cert.pem
└── keys/
    ├── SRK{0..3}_secp384r1_key.pem
    └── key_pass.txt

Point the build at the tool and the data directory, then continue with Enable NXP Authenticated Boot:

SIG_TOOL_PATH = "/path/to/venv/bin"
SIG_DATA_PATH = "${BSPDIR}/keys/ahab"

SIG_TOOL_PATH must be the directory containing the spsdk and nxpimage executables — the virtual environment's bin/ directory, not its root.


Compute the SRK Hash

SPSDK has no standalone command that turns a certificate set into fuse values. Compute the hash directly from the four certificates:

from spsdk.crypto.utils import extract_public_key
from spsdk.image.ahab.ahab_srk import SRKTable

srk = SRKTable()
for i in range(4):
    srk.add_record(extract_public_key(f"crts/SRK{i}_secp384r1_cert.pem"))
srk.update_fields()
print(srk.compute_srk_hash().hex())

Split the 32-byte digest into eight 32-bit words. They map to OTP IDs 128–135, in order.

Alternatively, exporting a complete AHAB container writes the same values plus a programming script:

nxpimage ahab export -c <container-config>.yaml
Artifact Contents
*_srk_hash.txt OTP IDs 128–135 and their 32-bit values
*.bcf nxpele batch script with one write-fuse per OTP ID
OTP ID: 128, Value: 0x09102e77
OTP ID: 129, Value: 0xd52d6dc6
...
OTP ID: 135, Value: 0x374f6438

Note

nxpimage ahab export needs a configuration describing the container images, not the signing-only configuration in SIG_DATA_PATH. The build invokes nxpimage ahab sign, which does not emit these artifacts, so this is a separate manual step.


Program the SRK Hash into eFuses

Danger

eFuse writes are irreversible. A wrong SRK hash permanently prevents the SoC from booting once the lifecycle is advanced to OEM closed. Program the hash, read it back, boot a signed image with no AHAB events, and only then close the device.

The values below are for i.MX93. Other AHAB families use family-specific OTP indices; the fuse map in the SoC reference manual is authoritative.

Replay the generated batch script over the ELE serial interface:

nxpele -f mx93 -p /dev/ttyUSB0 batch <container>_oem0.bcf

Or program the fuses from the U-Boot console. SRKH occupies OTP IDs 128–135, and i.MX9 OCOTP banks hold eight words each, so OTP ID 128 is bank 16 word 0:

u-boot=> fuse prog -y 16 0 <OTP 128>
u-boot=> fuse prog -y 16 1 <OTP 129>
u-boot=> fuse prog -y 16 2 <OTP 130>
u-boot=> fuse prog -y 16 3 <OTP 131>
u-boot=> fuse prog -y 16 4 <OTP 132>
u-boot=> fuse prog -y 16 5 <OTP 133>
u-boot=> fuse prog -y 16 6 <OTP 134>
u-boot=> fuse prog -y 16 7 <OTP 135>

Read the values back, then boot the signed image and confirm AHAB reports no events:

u-boot=> fuse read 16 0 8
u-boot=> ahab_status

Advance the lifecycle to OEM closed. This is the final, irreversible step:

u-boot=> ahab_close

Automation

SRK hash extraction and fuse programming are manual today. The secure boot recipes under meta-tolomeo-nxp may automate both in a future release.


Development Keys

DAVE provides a pre-generated AHAB key set in devel-keys/ for build validation without a production PKI:

File Purpose
devel-keys/secure-boot/ahab/spsdk_ahab.yaml AHAB signing configuration for mimx9352
devel-keys/secure-boot/ahab/crts/ SRK0–SRK3 certificates (secp384r1) and the root CA
devel-keys/secure-boot/ahab/keys/ Matching private keys and key_pass.txt
SIG_DATA_PATH = "${BSPDIR}/devel-keys/secure-boot/ahab"

Warning

The keys in devel-keys/ are publicly known and exist only for build validation. Never use them on a production device, and never fuse their SRK hash into a shipping SoC.

See also