RidgeRun Platform Security Manual - NXP i.MX95 Yocto Build Process: Secure Boot
🚧 Documentation is under development
The RidgeRun Platform Security Manual guide is currently under active development. Some sections may be incomplete or change without notice.
Questions? Contact RidgeRun or email to support@ridgerun.com.
- Introduction
- General Security Concepts
- Getting Started
- Contact Us
- Sponsor your Favorite Feature
Secure Boot
This procedure explains how to build and validate a signed Secure Boot image for a Toradex Verdin i.MX95 using Yocto. It covers the development workflow with CST private keys stored as files and the HSM-path workflow with PKCS#11 and SoftHSM2.
The procedure is intended for an OEM Open development module. It does not program fuses or close the device. Device closure is an irreversible production operation and must be handled only after the complete validation and recovery process has been approved.
The guide uses two signing workflows. In the filesystem-based workflow, CST reads the private signing keys from protected files on the development host. In the PKCS#11 workflow, CST accesses key objects through a token interface; SoftHSM2 provides the software token used for this validation. The workflows are introduced here before their individual procedures so that the key-storage difference is clear.
Prerequisites
This section only lists the tools and security artifacts used by the Secure Boot process described here.
The board is not needed for installing CST, creating the signing keys, configuring the host, or building the image. These steps run on the development host and update the Yocto build configuration or generate build artifacts. The board is needed later, when the image is installed and the boot and authentication results are validated.
| Tool or artifact | Purpose | Where to obtain it |
|---|---|---|
cst
|
Signs and inspects AHAB boot containers. | NXP CST download. The archive also contains srktool and AHAB key-generation scripts.
|
| SoftHSM2 and PKCS#11 utilities | Required only for the optional HSM-backed signing workflow. SoftHSM2 provides the local test token, while pkcs11-tool accesses the token objects.
|
Installed from the Linux distribution packages using the command below. |
Install the NXP CST
The CST download normally requires an NXP account and acceptance of the software license. The developer should select the CST release compatible with the selected BSP and use the Linux archive. The CST archive contains the cst, srktool, and AHAB key-generation tools used by this guide.
After downloading the package from NXP and unpacked, run this inside the active build directory:
cd "${BUILDDIR}"
mkdir -p keys
cd keys
tar -xf /path/to/IMX_CST_TOOL_NEW.tgz
mv cst-* cst
Set the paths used by the commands below:
export BUILD_DIR="${BUILDDIR}"
export KEYS_DIR="${BUILD_DIR}/keys"
export CST_DIR="${KEYS_DIR}/cst"
Verify the tools before generating keys:
test -x "${CST_DIR}/linux64/bin/cst"
test -x "${CST_DIR}/linux64/bin/srktool"
test -x "${CST_DIR}/keys/ahab_pki_tree.sh"
If all three files are present and executable, the commands finish without output and return to the shell prompt. A missing file causes test to return a non-zero status. For a visible confirmation, the developer can run:
echo "CST tools are available" CST tools are available
Install the HSM-backed signing
For the HSM-backed workflow, the following host packages are also required:
sudo apt update
sudo apt install -y cmake make gcc g++ autoconf automake libtool pkg-config \
bison flex libjson-c-dev softhsm2 opensc p11-kit gnutls-bin \
libp11-3 openssl libengine-pkcs11-openssl
The bison, flex, and libjson-c-dev packages are needed when CST is built from source with PKCS#11 support.
Configure Secure Boot
For this task it is important to consider that in the BSP configuration used by this guide, the boot image also includes the artifacts required to support encrypted boot, so no additional encrypted-boot configuration is needed at this stage.
With that in mind, in the project folder, edit ${BUILDDIR}/conf/local.conf and set the machine, distribution, license acceptance, and signing class:
MACHINE ?= "verdin-imx95" DISTRO ?= "tdx-xwayland" ACCEPT_FSL_EULA = "1" INHERIT += "tdx-signed" TDX_IMX_HAB_ENABLE = "1"
The tdx-signed class enables AHAB signing for the boot container, Toradex Secure Boot support, and FIT signing for the kernel, device trees, and initramfs.
For a build that also uses dm-verity for root-filesystem integrity, the alternative is:
INHERIT += "tdxref-signed" DM_VERITY_IMAGE = "tdx-reference-minimal-image"
The two signing classes should not be inherited together. The selected class must match the intended product design.
Secure Boot Workflows
Secure Boot signing has two workflows in this guide. Both workflows produce signed boot artifacts that can be validated on an OEM Open development module. The difference is how the signing keys are stored and accessed on the development host.
| Workflow | Key storage | Recommended use | Main consideration |
|---|---|---|---|
| Workflow A: Filesystem-Based Signing | CST private-key files | First implementation, development, and functional validation | The key directory must be protected and excluded from source control. |
| Workflow B: PKCS#11 Signing with SoftHSM2 | PKCS#11 token objects | Testing an HSM-style signing interface or preparing an integration path | The token and PINs must be managed as protected signing assets. |
The developer should start with Workflow A unless the project specifically requires PKCS#11-compatible signing. It has fewer moving parts and is sufficient to prove that the AHAB container, Yocto configuration, and validation process work. Workflow B follows the same security objective, but adds SoftHSM2, PKCS#11, and CST integration steps.
Both workflows use the same overall sequence:
- Generate or access the signing hierarchy.
- Configure Yocto to use the resulting certificates and signing flow.
- Build the signed image.
- Inspect the generated artifacts.
- Install the image and validate the boot result and AHAB status.
The workflows do not program fuses or close the device. The signing method should be validated first, and the production lifecycle transition should be handled only after the negative tests, recovery procedure, and release evidence have been approved.
Workflow A: Filesystem-Based Signing
This workflow stores the CST private keys as files. It is suitable for development and initial validation. The directory containing the keys must be protected and must not be committed to source control.
Generate the AHAB key tree
cd "${CST_DIR}/keys"
./ahab_pki_tree.sh
The interactive script should be answered with the values used for this validation:
Existing CA key: n Key type: rsa Key length: 2048 Digest: sha256 Duration: 10 SRK certificates with CA flag: y
The generated certificate directory should contain the four SRK certificates and the selected signing certificate. The private key files under ${CST_DIR}/keys must remain private.
Generate the SRK fuse table
The SRK table and fuse hash are generated from the public SRK certificates:
cd "${CST_DIR}/crts"
../linux64/bin/srktool -a 2 -s sha256 \
-t SRK_1_2_3_4_table.bin \
-e SRK_1_2_3_4_fuse.bin \
-f 1 \
-c ./SRK1_sha256_2048_65537_v3_ca_crt.pem,\
./SRK2_sha256_2048_65537_v3_ca_crt.pem,\
./SRK3_sha256_2048_65537_v3_ca_crt.pem,\
./SRK4_sha256_2048_65537_v3_ca_crt.pem
The printed SRKH values and generated fuse files should be saved as controlled validation evidence. They should not be executed during this procedure.
Point Yocto to the certificates
The following values should be added to ${BUILDDIR}/conf/local.conf:
TDX_IMX_HAB_CST_DIR = "${TOPDIR}/keys/cst"
TDX_IMX_HAB_CST_BIN = "${TDX_IMX_HAB_CST_DIR}/linux64/bin/cst"
TDX_IMX_HAB_CST_CERTS_DIR = "${TDX_IMX_HAB_CST_DIR}/crts"
TDX_IMX_HAB_CST_CRYPTO = "rsa"
TDX_IMX_HAB_CST_KEY_SIZE = "2048"
TDX_IMX_HAB_CST_KEY_EXP = "65537"
TDX_IMX_HAB_CST_DIG_ALGO = "sha256"
TDX_IMX_HAB_CST_SRK_CA = "1"
TDX_IMX_HAB_CST_SRK_INDEX = "1"
TDX_IMX_HAB_CST_SRK_CERT = "${TDX_IMX_HAB_CST_CERTS_DIR}/SRK1_sha256_2048_65537_v3_ca_crt.pem"
TDX_IMX_HAB_CST_SGK_CERT = "${TDX_IMX_HAB_CST_CERTS_DIR}/SGK1_1_sha256_2048_65537_v3_usr_crt.pem"
Build the signed image
cd "${BUILDDIR}"
bitbake tdx-reference-minimal-image
The build is successful when BitBake ends with an all-tasks-succeeded summary. On the Verdin i.MX95, CST may report that the bootloader is signed directly with the SRK because the target does not support subordinate signing keys in this flow. That warning should be recorded and should not be interpreted as a build failure.
Example of the expected result at the end of a successful build:
NOTE: Tasks Summary: Attempted ... tasks of which 100% succeeded
The task count varies with the build cache and BSP version. A signing error, a failed task, or a non-zero exit status requires investigation before the image is installed.
Workflow B: PKCS#11 Signing with SoftHSM2
SoftHSM2 provides a software token for validating the PKCS#11 path. It is not a production hardware HSM and should not be used as production key custody.
PINs and the SoftHSM2 token
The SoftHSM2 token is a protected container that stores the signing keys. The two PINs used when the token is initialized have different purposes:
| PIN | Purpose |
|---|---|
| SO PIN | Security Officer PIN used to initialize or administer the token. It is not normally used by CST to sign images. |
| User PIN | PIN used by CST and other PKCS#11 tools to log in to the token and use the stored signing keys. |
The PINs are not generated by Yocto, CST, or SoftHSM2. When a new token is created, the operator chooses both values and supplies them to softhsm2-util --init-token. The --so-pin value is the administrator PIN, while the --pin value is the signing-user PIN. If an existing token is used, its PINs must be obtained from the person or process that provisioned the token.
In this section, a secret means a value that grants access to protected signing material. This includes the SO PIN, the user PIN, private signing keys, and token credentials. The previous Dhalia test notes used values such as 0000 for the SO PIN and 1234 for the user PIN. Those values were test examples and must not be reused. The real PINs and key material must be kept out of the wiki, local.conf, shell history, and source control.
Configure SoftHSM2
export PKCS11_MODULE_PATH="/usr/lib/softhsm/libsofthsm2.so"
export SOFTHSM2_DIR="${KEYS_DIR}/softhsm"
export SOFTHSM2_CONF_DIR="${SOFTHSM2_DIR}/conf"
export SOFTHSM2_TOKENS_DIR="${SOFTHSM2_DIR}/tokens"
export SOFTHSM2_CONF="${SOFTHSM2_CONF_DIR}/softhsm2.conf"
mkdir -p "${SOFTHSM2_CONF_DIR}" "${SOFTHSM2_TOKENS_DIR}"
The configuration file should contain the absolute token directory:
directories.tokendir = /absolute/path/to/build-secboot-hsm/keys/softhsm/tokens objectstore.backend = file log.level = ERROR slots.removable = false slots.mechanisms = ALL
The token configuration must be exported before token operations and BitBake runs. The user PIN should exist only in the active shell:
export SOFTHSM2_CONF="${SOFTHSM2_CONF_DIR}/softhsm2.conf"
export USR_PIN="<replace-with-a-secret-PIN>"
The PIN should not be stored in local.conf, shell history, or source control.
Build CST with PKCS#11 support
The prebuilt CST binary may not include the PKCS#11 backend. Build CST from source:
cd "${CST_DIR}/src"
OSTYPE=linux64 ./scripts/build.sh -F -with-pkcs11 -no-pqc -no-json
./build/bin/cst --help | grep -i pkcs
The help output should include a PKCS#11 backend. If it does not, the source-built binary must not be used for the HSM workflow.
Example of the expected check:
PKCS#11 support: enabled
Create the CST token
softhsm2-util --init-token --free \
--label "cst-hsm" \
--so-pin "<replace-with-SO-PIN>" \
--pin "${USR_PIN}"
softhsm2-util --show-slots
The HSM-aware CST script can then create the AHAB key objects:
cd "${CST_DIR}/keys"
./hsm_ahab_pki_tree.sh \
-existing-ca n \
-use-ecc n \
-kl 2048 \
-da sha256 \
-duration 10 \
-srk-ca y
The public SRK table is generated with the same srktool command used in the filesystem workflow.
Create the FIT signing token
softhsm2-util --init-token --free \
--label "fit-hsm" \
--so-pin "<replace-with-SO-PIN>" \
--pin "${USR_PIN}"
pkcs11-tool --module "${PKCS11_MODULE_PATH}" \
--token-label "fit-hsm" \
--login --pin "${USR_PIN}" \
--keypairgen --key-type rsa:2048 \
--id 01 --label "fit-sign-key"
pkcs11-tool --module "${PKCS11_MODULE_PATH}" \
--token-label "fit-hsm" \
--login --pin "${USR_PIN}" \
--list-objects
The output should show the FIT signing object. The token label and object label must match the values used in local.conf.
Example of the relevant object listing:
Private Key Object; RSA 2048 bits label: fit-sign-key
Configure and build the HSM image
The HSM build uses the source-built CST binary and passes the PIN through the BitBake environment:
TDX_IMX_HAB_CST_BIN = "${TOPDIR}/keys/cst/src/build/bin/cst"
TDX_SIGNED_HSM = "1"
TDX_SIGNED_HSM_TOKEN_PIN ?= ""
TDX_SIGNED_HSM_PKCS11_MODULE_PATH = "/usr/lib/softhsm/libsofthsm2.so"
TDX_SIGNED_HSM_PKCS11_SOFTHSM_CONF = "${TOPDIR}/keys/softhsm/conf/softhsm2.conf"
TDX_SIGNED_HSM_FIT_TOKEN_LABEL = "fit-sign-key"
The exact certificate URI and token URL must match the objects listed by pkcs11-tool. The PIN is then passed only for the build:
export BB_ENV_PASSTHROUGH_ADDITIONS="${BB_ENV_PASSTHROUGH_ADDITIONS} TDX_SIGNED_HSM_TOKEN_PIN SOFTHSM2_CONF"
cd "${BUILDDIR}"
TDX_SIGNED_HSM_TOKEN_PIN="${USR_PIN}" \
bitbake tdx-reference-minimal-image
Inspect the Build Artifacts
After building the image, check the final outputs, the deploy directory is normally:
${BUILDDIR}/tmp/deploy/images/verdin-imx95/
The developer should list and record the main outputs:
cd "${BUILDDIR}/tmp/deploy/images/verdin-imx95"
ls -lh \
Verdin-iMX95_Reference-Minimal-Image-Tezi*.tar \
imx-boot* fitImage* fuse-cmds.txt imx-config.fuse
Expected outputs include a Tezi archive, imx-boot, a FIT image, fuse-cmds.txt, and imx-config.fuse. The exact version suffix depends on the build.
The fuse files should only be inspected:
sed -n '1,200p' fuse-cmds.txt sed -n '1,200p' imx-config.fuse sha256sum Verdin-iMX95_Reference-Minimal-Image-Tezi*.tar
Install and Validate the Signed Image
The board is not required while the host configuration, key setup, and Yocto build are performed. Those steps update the build configuration and create signed artifacts; they do not program the board or change its lifecycle state. The board must be connected when the image is installed and when boot, serial-console, AHAB, and Linux validation evidence is collected.
The Tezi archive should be extracted to a FAT32 SD card or USB drive prepared for Toradex Easy Installer:
cd "${BUILDDIR}/tmp/deploy/images/verdin-imx95"
sudo tar --no-same-owner --strip-components=1 \
-xvf Verdin-iMX95_Reference-Minimal-Image-Tezi_<version>.tar \
-C /media/<user>/TEZI
sync
sudo umount /media/<user>/TEZI
The developer should install the signed image through Tezi and confirm that it boots before running negative tests.
Collect Linux evidence
After Linux starts, the board may be reachable through the USB network at 192.168.11.1 when the selected BSP enables the default USB gadget-network configuration:
ssh root@192.168.11.1
If the connection is available, SSH displays the device login prompt or shell. This address is a BSP-specific USB-network default, not a universal address for every i.MX95 design or network. If it does not respond, the developer should check the USB gadget configuration, the host network interface, and the address assigned by the image. The following commands collect a useful baseline:
LOG_DIR="/tmp/secureboot-baseline-$(date +%Y%m%d-%H%M%S)"
mkdir -p "${LOG_DIR}"
tdx-info > "${LOG_DIR}/tdx-info.txt" 2>&1
uname -a > "${LOG_DIR}/uname.txt" 2>&1
cat /etc/os-release > "${LOG_DIR}/os-release.txt" 2>&1
cat /proc/cmdline > "${LOG_DIR}/cmdline.txt" 2>&1
lsblk -f > "${LOG_DIR}/lsblk.txt" 2>&1
mount > "${LOG_DIR}/mount.txt" 2>&1
dmesg -T > "${LOG_DIR}/dmesg.txt" 2>&1
journalctl -b > "${LOG_DIR}/journalctl-boot.txt" 2>&1
dmesg -T | grep -iE "ahab|ele|secure|optee|trust|auth|verify" \
> "${LOG_DIR}/security-dmesg.txt" 2>&1
tar -C /tmp -czf /tmp/secureboot-baseline-logs.tar.gz \
"$(basename "${LOG_DIR}")"
The archive should be copied to the host and stored with the image checksum and build configuration.
Capture the U-Boot log
U-Boot output must be captured through the serial console because it occurs before Linux and SSH are available:
ls -l /dev/serial/by-id/
mkdir -p "${HOME}/secureboot-logs"
sudo minicom -D /dev/ttyUSB0 -b 115200 \
-C "${HOME}/secureboot-logs/uboot-boot.log"
The serial recording should begin before power-on and continue until Linux reaches its login prompt.
Read AHAB status
During boot, the developer should stop U-Boot when it displays Hit any key to stop autoboot: and run:
ahab_status version printenv bootcmd printenv boot_targets mmc list mmc info
The expected output includes the AHAB/ELE status or version, the configured boot targets, and detected MMC information. The exact wording varies with the U-Boot and BSP versions. The raw output should be saved as ahab-status.log, and the lifecycle, ELE events, and authentication results must be reviewed together with the image checksum and SRK record.
Validation Criteria
The development validation is successful when:
- the signed image builds without signing errors;
- the expected Tezi, boot, FIT, and fuse artifacts are present;
- the signed image boots repeatedly on the intended board;
- the U-Boot serial log and
ahab_statusoutput are captured; - Linux baseline logs are collected;
- the generated SRK hash is saved and reviewed; and
- controlled negative tests reject unauthorized or modified boot artifacts according to the expected failure stage.
A successful Linux boot by itself does not prove fuse-backed Secure Boot enforcement. A module in OEM Open is still a development device. Production enforcement requires approved SRK provisioning, lifecycle closure, and post-closure negative testing.