Jump to content

RidgeRun Platform Security Manual - NXP i.MX95 Yocto Build Process: Secure Boot

From RidgeRun Developer Wiki

🚧 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.

Follow us on: YouTube Twitter LinkedIn Email Share this page

Share This Page

NVIDIA partner logo NXP partner logo




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

Info
The BSP, Yocto source tree, build directory, and required Yocto layers must already be prepared. For more information check the Yocto Build Process section.


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

Encrypted boot support
The Toradex Yocto BSP configuration used by this guide already includes the artifacts required for encrypted boot in the generated boot image.

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:

  1. Generate or access the signing hierarchy.
  2. Configure Yocto to use the resulting certificates and signing flow.
  3. Build the signed image.
  4. Inspect the generated artifacts.
  5. 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


Warning
Warning: fuse-cmds.txt and imx-config.fuse are provisioning inputs and validation evidence. They must not be executed during the normal development build or test.


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_status output 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.




Cookies help us deliver our services. By using our services, you agree to our use of cookies.