To add secure boot support to your Digi Embedded Yocto project:
1. Configure secure boot
To build signed artifacts, modify your conf/local.conf file to include the following:
# Required to include trustfence support.
INHERIT += "trustfence"
1.1. Encryption of images
Image encryption is disabled by default on the ConnectCore 91 due to the poor decryption performance of the i.MX91.
To enable image encryption, modify your conf/local.conf file to include the following:
TRUSTFENCE_DEK_PATH = "default"
| Enabling image encryption increases the boot time by over six seconds. |
1.2. PKI tree
Digi Embedded Yocto generates by default a PKI tree under a new folder called trustfence inside in your project.
To specify a custom path for the PKI tree, see Advanced options.
1.3. U-Boot environment encryption
When enabling TrustFence, the U-Boot environment will be encrypted by default using the CAAM OTPMK and the secure internal unique key.
| This feature is only supported in closed devices. This setting has no effect on open devices. |
To explicitly disable U-Boot environment encryption, see Advanced options.
2. Build your target images
Once TrustFence is enabled and configured in your Digi Embedded Yocto project, you can build your target image. For example:
$ bitbake core-image-base
When the build process finishes, several secure artifacts appear in the deployment directory:
-
imx-boot-ccimx91-dvk.bin: These are the default U-Boot images. They are not signed. -
imx-boot-signed-ccimx91-dvk.bin: These are the signed U-Boot images. Like default U-Boot images, they are specific for each variant. -
imx-boot-encrypted-ccimx91-dvk.bin: These are signed and encrypted U-Boot images specific for each variant. -
SRK_efuses.bin: This is a file containing the hash of the SRK public keys. It will be required when setting up the device for secure boot. -
A
core-image-base-ccimx91-dvk.boot.vfatimage containing the following:-
fitImage-ccimx91-dvk.bin: Signed FIT image that contains the following artifacts: the linux kernel, the device tree, device tree overlays and the boot script.
-
-
A
core-image-base-ccimx91-dvk.recovery.vfatimage containing the following:-
fitImage-ccimx91-dvk.bin: Signed FIT image that contains the following artifacts: the linux kernel, the device tree, device tree overlays and the boot script.
-
-
A
core-image-base-ccimx91-dvk.sdcard.gzcompressed microSD card image able to boot the closed device once decompressed.If secure boot encryption is enabled, the microSD card image will be able to boot the closed device into U-Boot, but will not boot the OS.
The
core-image-base-ccimx91-dvk.recovery.vfatimage is only used in systems based on single boot and encrypted rootfs.
The PKI tree and the encryption key are also generated (when not provided).
They are stored at the specified TRUSTFENCE_SIGN_KEYS_PATH location.
The folder will contain the following:
-
crts/: directory containing the different certificates used for the signature -
keys/: directory containing the private key associated with each certificate and the passphrase protecting them -
dek.bin: data encryption key used to encrypt the images
The following files need to be securely stored in order to be used in the manufacturing of secure devices:
-
SRK e-fuses public keys hash bin file (
SRK_efuses.bin) -
PKI tree used to sign the firmware images, including the data encryption key in plain text
3. Program the signed artifacts
3.1. Program the signed bootloader
The signed bootloader can be flashed like any other bootloader image:
=> update uboot tftp imx-boot-signed-ccimx91-dvk.bin
3.2. Program the signed system images
By default, Digi Embedded Yocto produces signed, non-encrypted artifacts for the ConnectCore 91.
To program signed, non-encrypted artifacts from the U-Boot console, for example from TFTP, do the following:
To program the linux partition:
=> update linux tftp core-image-base.boot.vfat
To program the rootfs partition:
=> update rootfs tftp core-image-base.ext4
4. Check the TrustFence status
Reset the device, and check the result of command trustfence status:
=> trustfence status
* SRK fuses: [NOT PROGRAMMED]
* Secure boot: [OPEN]
* Encrypted U-Boot: [NO]
* AHAB events: [ERRORS PRESENT!]
The output shows the device has security events.
Get more information about the AHAB events with command ahab_status:
=> ahab_status
Lifecycle: 0x00000008, OEM Open
0x0287fad6
IPC = MU APD (0x2)
CMD = ELE_OEM_CNTN_AUTH_REQ (0x87)
IND = ELE_BAD_KEY_HASH_FAILURE_IND (0xFA)
STA = ELE_SUCCESS_IND (0xD6)
0x0287fad6
IPC = MU APD (0x2)
CMD = ELE_OEM_CNTN_AUTH_REQ (0x87)
IND = ELE_BAD_KEY_HASH_FAILURE_IND (0xFA)
STA = ELE_SUCCESS_IND (0xD6)
For the command field (CMD), the expected value at this step is 0x87 (ID for ELE_OEM_CNTN_AUTH_REQ). The indicator field (IND) shows the code ELE_BAD_KEY_HASH_FAILURE_IND (0xFA) because the key hash verification does not match the current OTPs. Once the OTP SRK hash fuses are programmed on the target OTPs, the AHAB events will no longer have errors.
See the NXP secure boot application notes for more information on event decoding.
5. Boot the FIT image
As part of the Digi Embedded Yocto project, the U-Boot recipe includes a U-Boot boot script to boot the ConnectCore 93 Development Kit. This script determines the variant of the ConnectCore 91 SoM and the version of the carrier board and selects the device tree overlays to apply on top of the base device tree (wireless, Bluetooth, etc.) before booting the kernel. This boot script is embedded in the FIT image and is run by default when you start the device.
|
The default U-Boot (without TrustFence) is prepared to boot a regular Linux kernel with zImage format.
This is determined by the variable If you used a different method to deploy the images, you must set this variable manually in U-Boot as follows:
|
Let U-Boot run, or run the boot command if you stopped at the U-Boot prompt.
Check the new messages that appear:
## Executing script at 84002000
sha256+ Booting from system A
Skip re-loading of FIT image
Moving Image from 0x84000000 to 0x98000000, end=98c38000
Explanation of output:
-
The FIT image authenticated and loaded into RAM memory; the boot script is executed
-
Image integrity is verified and the boot script prints the message:
"sha256+ Booting from system A". -
The boot script calls the
dbootcommand to boot the system. While this command typically loads the image into RAM, in this case the FIT image is not reloaded because it was already loaded to run the boot script.
Next, U-Boot loads the default configuration from the FIT image:
## Loading kernel from FIT Image at 84000000 ...
Using 'conf-ccimx91-dvk.dtb' configuration
Trying 'kernel-1' kernel subimage
Description: Linux kernel
Created: 2025-02-04 17:13:02 UTC
Type: Kernel Image
Compression: gzip compressed
Data Start: 0x840000e8
Data Size: 12715417 Bytes = 12.1 MiB
Architecture: AArch64
OS: Linux
Load Address: 0x80400000
Entry Point: 0x80400000
Hash algo: sha256
Hash value: 8f37609439ceac1a731e78681a12481ff7015a0388564b61e853c925cb1d0cef
Verifying Hash Integrity ... sha256+ OK
Explanation of output:
-
The first item in the default configuration is the Linux kernel.
-
U-Boot also verifies the integrity of the kernel image successfully.
-
Similar messages appear for the base device tree and the selected overlays that the boot script populated as a list in U-Boot environment variable
overlays. -
After all the artifacts have been verified, the Linux system boots.
| The FIT image is the only file that’s stored in the linux partition, as it includes all the required files to boot the system. |
6. Secure the device
The final step in configuring secure boot for a device is burning the secure eFuse configuration.
| The secure eFuse configuration can only be written once and is irreversible. |
To secure the device:
6.1. Program the SRK eFuse
The SRK fuses hold the hash of the SRK public keys. In open devices, they are never used. In closed devices, they are used to validate the public key contained in signed firmware images.
Before closing the device, you must store the hash of the public keys in the SRK OTP bits on the device.
This will allow the ROM loader to validate the public key included in signed firmware images.
When building signed U-Boot images, Yocto generates a file named SRK_efuses.bin, which can be used to program the SRK efuses from the U-Boot shell in a safe way following this procedure:
-
Verify there are no AHAB events (as explained above).
-
From the U-Boot prompt, load the
SRK_efuses.binfile to memory using TFTP:=> tftp ${loadaddr} SRK_efuses.bin Using FEC device TFTP from server 192.168.129.10; our IP address is 192.168.42.30 Filename 'deploy/SRK_efuses.bin'. Load address: 0x12000000 Loading: # 15.6 KiB/s done Bytes transferred = 32 (20 hex)Information in the console log may vary. -
Program the device using the
trustfence prog_srkcommand:=> trustfence prog_srk ${loadaddr} ${filesize} Warning: Programming fuses is an irreversible operation! This may brick your system. Use this command only if you are sure of what you are doing! Really perform this fuse programming? <y/N>The filesizeenvironment variable is automatically calculated from the previoustftpcommand to be equal to the size (in bytes) of theSRK_efuses.binfile.
To simplify key management, Digi recommends you program all devices with the same set of four keys.
See Revoke a key for steps to take if any of these keys are compromised.
6.2. Close the device
|
This step is irreversible and could brick your device. Before closing the device:
|
To close a device, issue Digi’s U-Boot trustfence close command as follows and then reset the target:
=> trustfence close
=> reset
After that, the device will only boot properly signed images.
The U-Boot environment encryption feature is enabled by default, so U-Boot will import the MAC addresses (and any other write-once environment variables) from the previous (not encrypted) environment, and will reset any other variable to the default values. After that, a save operation will overwrite the environment with encrypted data.
To ensure that both copies of the environment get encrypted, save the environment twice right after booting a closed device that has a U-Boot with environment encryption support, as follows:
=> saveenv
Saving Environment to MMC...
Writing to MMC(0)... done
=> saveenv
Saving Environment to MMC...
Writing to redundant MMC(0)... done
7. Program the signed and encrypted artifacts on a closed device
|
By default, boot artifacts encryption is disabled on the ConnectCore 91, so you can skip this section. To enable boot artifacts encryption, add the following to your conf/local.conf
Rebuild your image and then you can proceed with the instructions in this section. |
Once the device has been closed, the encryption uses the unique and secure OTPMK (One Time Programmable Master Key). The update process will encrypt the DEK into an encrypted blob and store it in the U-Boot partition. This must happen with the unique secure OTPMK, so be sure final programming happens after the device has been closed and restarted.
7.1. Program the encrypted bootloader
There are two ways to flash an encrypted U-Boot image:
Secure a new DEK
Use this method if you are using encrypted images for the first time, or if you want to change the DEK. In this case, you need two input artifacts:
-
The encrypted U-Boot image
-
The data encryption key (DEK) in plain text
Use the following command to flash the encrypted U-Boot image:
=> trustfence update tftp imx-boot-encrypted-ccimx91-dvk.bin dek.bin
With the above command, the U-Boot image is flashed and the DEK is secured and stored in the uboot partition.
On an open device, the encryption uses the test master key, while on a closed device the encryption uses the unique and secure OTPMK. For that reason, the final programming of the encrypted U-Boot image must be done after closing the device and resetting.
The DEK blob is secured only if a closed device was used. When using an open device, the DEK blob is not secured and both the DEK in plain text and the decrypted U-Boot could be recovered from the media.
The device now boots into a signed and encrypted U-Boot.
You can always recover a closed device by booting a properly signed U-Boot from recovery media. See Recover your device.
Reuse an existing DEK
Use this method if you are updating a bootloader that’s already encrypted with the same DEK. In this case you don’t need to send the plain text DEK anymore.
Use the same command as when securing a new DEK but omit the DEK argument:
=> trustfence update tftp imx-boot-encrypted-ccimx91-dvk.bin
The U-Boot image being flashed must have been encrypted with the existing DEK secured in the device. If the device does not have a DEK secured, the command will fail.
| If a different DEK is used, the device will stop booting. |
| When updating to a new U-Boot major version, Digi recommends installing first the signed version, rebooting and then installing the encrypted one. |
7.2. Program the encrypted system images
The rest of the encrypted artifacts (other than U-Boot) can be flashed using standard procedures for programming a boot partition. However, to use any encrypted artifact, the following additional requirements must be met:
-
You must use a closed device.
-
The device must contain a U-Boot image encrypted with the same encryption key.
To program the linux partition:
=> update linux tftp core-image-base.boot.vfat
To program the rootfs partition:
=> update rootfs tftp core-image-base.ext4
|
The default U-Boot is prepared to boot a regular Linux kernel with Image.gz format.
This is determined by variable If you manually programmed the images, you must set this variable manually in U-Boot as follows:
|
The device now boots into a trusted Linux kernel.
Advanced options
Disable signing of images
Signing of images is automatically enabled as part of TrustFence.
To explicitly disable the generation of signed images, define TRUSTFENCE_SIGN to 0:
# Disable signed images
TRUSTFENCE_SIGN = "0"
This also disables the encryption of boot images (boot loader, Linux artifacts).
Disable encryption
Digi Embedded Yocto provides encryption support for the following elements:
-
U-Boot environment
-
Boot artifacts (bootloader and Linux artifacts).
When you enable TrustFence, the following encryption is automatically enabled:
-
U-Boot environment
The following sections describe how to explicitly disable the encryption of these elements:
Disable U-Boot environment encryption
To explicitly disable U-Boot environment encryption, set:
# Disable U-Boot environment encryption
TRUSTFENCE_ENCRYPT_ENVIRONMENT = "0"
| When flashing U-Boot without the environment encryption feature in a device with an encrypted environment, all the values will be lost. Be sure to save any important data such as MAC addresses before you execute this procedure. |
Disable encryption of images
To disable the encryption of images (bootloader, Linux artifacts), set:
# Disable encryption of images
TRUSTFENCE_DEK_PATH = "0"
Use a custom PKI tree path
You can use the following parameters to customize the location of the sensitive keys:
-
TRUSTFENCE_SIGN_KEYS_PATH: Path to a folder containing the PKI tree. If the folder does not exist or does not contain a PKI tree, a new PKI tree will be generated automatically. The default value is a new foldertrustfencein the Digi Embedded Yocto project home location.
# Use a custom path to the signature keys and certificates.
TRUSTFENCE_SIGN_KEYS_PATH = "/mnt/secure/PKI_tree"
-
TRUSTFENCE_DEK_PATH: Path to the data encryption key. When provided, it must be a 128-, 192- or 256-bit binary file. Otherwise, a random 256-bit key will be generated automatically. The default value is<TRUSTFENCE_SIGN_KEYS_PATH>/dek.bin. Define to 0 to disable the encryption of the signed images.
# Use a custom path to the Data Encryption Key (or set to "0" to disable encryption).
TRUSTFENCE_DEK_PATH = "/mnt/secure/encryption_key.bin"
Read-only rootfs authentication
You can choose to build a read-only rootfs (see Read-only root file system). When TrustFence is enabled, the resulting rootfs image is signed and the bootloader authenticates it before booting. This guarantees the rootfs comes from a trusted source.