Requirements

Digi Embedded Yocto uses NXP’s Code Signing Tool (CST) for the High Assurance Boot library when generating secure firmware images. If the tool is not found, the Digi Embedded Yocto TrustFence build fails. Follow these steps to install the CST tool in your workspace:

  1. Download the CST tool from https://www.nxp.com/webapp/Download?colCode=IMX_CST_TOOL_NEW&location=null.

  2. If you have not used your Digi Embedded Yocto workspace yet, create the downloads folder in the workspace.

  3. Place the tool in the downloads folder of your Digi Embedded Yocto project workspace.

Digi Embedded Yocto will try to use the latest CST that it supports. To use a different CST version than the latest one supported, see Advanced options.

To add secure boot support to your Digi Embedded Yocto project:

1. Configure secure boot

To build signed and encrypted artifacts, modify your conf/local.conf file to include the following:

conf/local.conf
# Required to include trustfence support.
INHERIT += "trustfence"

Image signing is enabled by default. To explicitly disable the generation of signed images, see Advanced options.

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.1. 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 dey-image-qt

When the build process finishes, several secure artifacts appear in the deployment directory:

  • u-boot-<platform>.imx: These are the default U-Boot images. They are not signed.

  • u-boot-dtb-signed-<platform>.imx: These are the signed U-Boot images. Like default U-Boot images, they are specific for each variant.

  • u-boot-dtb-usb-signed-<platform>.imx: These are special signed U-Boot images for USB recovery.

  • u-boot-dtb-encrypted-<platform>.imx: 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 dey-image-qt-x11-<platform>.boot.ubifs image containing the following:

    • zImage-<platform>.bin: Signed and encrypted Linux kernel image.

    • .dtb files: Signed and encrypted device tree blob files for all hardware platforms.

    • boot.scr: Signed and encrypted U-Boot bootscript.

    • dey-image-trustfence-initramfs-<platform>.cpio.gz.u-boot.tf: Signed and encrypted initramfs for rootfs encryption.

  • A dey-image-qt-x11-<platform>.recovery.ubifs image containing the following:

    • zImage-<platform>.bin: Signed and encrypted Linux kernel image.

    • .dtb files: Signed and encrypted device tree blob files for all hardware platforms.

    • boot.scr: Signed and encrypted U-Boot bootscript.

    • uramdisk-recovery.img: Signed and encrypted initramfs for recovery.

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 U-Boot image

The signed U-Boot images can be flashed like any other U-Boot image:

=> update uboot tftp u-boot-dtb-signed-<platform>.imx
Flashing a signed U-Boot does not enable any security features in the target. See Secure the device to learn how to close your device to only boot signed U-Boot images.
Do not program encrypted images on an open device, as the kernel will not boot.

Reset the device, and check that there are no secure events reported using the trustfence command:

=> reset
(...)
=> trustfence status
* SRK fuses:     [NOT PROGRAMMED]
   Key 0:           [OK]
   Key 1:           [OK]
   Key 2:           [OK]
   Key 3:           [OK]
* Secure boot:     [OPEN]
* Encrypted U-Boot:     [NO]
* HAB events:     [NO ERRORS]

The output shows the device is in open configuration, the SRK e-fuses are not burned, no keys are revoked, and the current U-Boot image is not encrypted.

In this case, no secure boot events are generated. This indicates the image should be able to boot the device when closed.

If secure boot events were present, you can get additional information with the hab_status command to understand why the signature verification failed. This is a U-Boot command that will dump extra debug information from the High Assurance Boot ROM.

See the NXP secure boot application notes for more information on event decoding.

4. 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:

4.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:

  1. Verify there are no HAB events (as explained above).

  2. From the U-Boot prompt, load the SRK_efuses.bin file 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.
  3. Program the device using the trustfence prog_srk command:

    => 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 filesize environment variable is automatically calculated from the previous tftp command to be equal to the size (in bytes) of the SRK_efuses.bin file.

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.

4.2. Close the device

This step is irreversible and could brick your device.

Before closing the device:

  • Verify you have programmed a signed, not encrypted, U-Boot image.

  • Run hab_status and:

    • Verify there are no HAB events

    • Verify the SRK eFuses are programmed. The SRK OTP bits are not verified on open devices. For a closed device to boot, all the SRK OTP bits must be burned. An open device booting with no HAB events will stop booting after being closed if the SRK OTP bits are invalid, not burned, or only partially burned.

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.

Booting signed images through USB on a closed device requires a specific U-Boot version with prefix u-boot-dtb-usb-signed-, which you can find at tmp/deploy/images/ in your project folder. See Recover your closed device.

After you have closed the device, consider the following ways to further secure your device:

  • Secure JTAG, so it cannot be used to boot the processor and avoid the secure boot. See Secure JTAG.

  • U-Boot will drop to a console after an unsuccessful firmware authentication for debugging purposes. Since a user could use this console for booting the system, Digi recommends you disable this console in production firmware. See Secure console modes.

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 it will overwrite the environment with encrypted data.

To ensure that both copies of the environment get encrypted, save the environment twice right after flashing a U-Boot with environment encryption support, as follows:

=> saveenv

Erasing NAND...
Erasing at 0x320000 -- 100% complete.
Writing to NAND... OK
=> saveenv

Erasing redundant NAND...
Erasing at 0x320000 -- 100% complete.
Writing to redundant NAND... OK

5. Program the encrypted artifacts on a closed device

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.

There are two ways to flash an encrypted U-Boot image: securing a new DEK or reusing an existing one.

5.1. 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 u-boot-dtb-encrypted-<platform>.imx 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.

5.2. Reuse an existing DEK

When a new U-Boot image is required (for example, for new features) but the same DEK is used, you don’t need to send the plain text DEK again. This is useful for updates performed in the field.

In this case, use the same command as when securing a new DEK but omit the DEK argument:

=> trustfence update tftp u-boot-dtb-encrypted-<platform>.imx

The U-Boot image being flashed must be 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.

5.3. Program the encrypted artifacts

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 containing all the encrypted artifacts:

=> update linux tftp dey-image-qt.boot.ubifs

To program the recovery partition containing all the encrypted artifacts:

=> update recovery tftp dey-image-qt.recovery.ubifs

Signed and encrypted artifacts are larger than regular unsigned artifacts. Therefore, both linux and recovery partition images may be greater than the allotted partition size in the U-Boot environment variable mtdparts.

If this is the case, you must follow these instructions to resize the partitions.

The device now boots into a trusted Linux kernel.

6. Set up your device with root file system encryption

Root file system encryption adds another layer of security to TrustFence. It uses the kernel’s cryptographic support to encrypt all the data you store in the root file system. Attempting to access this data without the correct encryption key returns random, meaningless bytes.

When you enable TrustFence (see Enable TrustFence support in Digi Embedded Yocto), you automatically enable root file system encryption. This makes it so any SWU packages built with the project enable root file system encryption when installed on a target.

Encryption of the root file system is not carried out by Digi Embedded Yocto and so, the rootfs artifact must not be programmed from U-Boot, or it won’t mount on a fully encrypted system. Run a firmware update process following these instructions to encrypt the root file system.

To explicitly disable root file system encryption, see Advanced options.

7. Program the encrypted rootfs

  1. Create a software update package. To create a software update package, bitbake your image recipe adding the suffix -swu. For example, if you have built image dey-image-qt with rootfs encryption enabled, run the following command to create a software update package:

    $ bitbake dey-image-qt-swu
  2. Make sure the resulting software update artifact (.swu file) is accessible by the device. For example, you can store it on the internal NAND, in the *update partition:

    $ ls -l /mnt/update/
    -rw-r--r--    1 root     root     731810304 Jan 26 18:15 dey-image-qt-swu-<platform>.swu

    Or on external media (microSD card, USB disk):

    $ ls -l /run/media/sda1
    -rwxrwx---    1 root     disk     241062400 Jan 18 19:30 dey-image-qt-swu-<platform>.swu
    $ ls -l /run/media/mmcblk1p1
    -rwxrwx---    1 root     disk     241062400 Jan 18 19:30 dey-image-qt-swu-<platform>.swu
    The *.swu file must be stored on the root folder of the partition. Subfolders are not supported.
  3. Configure the recovery commands to update the system with the previously generated package.

    # update-firmware file://dey-image-qt-swu-<platform>.swu

    The device boots in recovery mode and starts updating the system with the provided package. Once it finishes, the device reboots and the firmware update is complete.

After your first secure system deploy, you can use the update-firmware tool to trigger a new firmware update. See Program firmware from Linux.

Advanced options

Use a custom CST version

To check the CST versions supported by Digi Embedded Yocto, run the following command in your Digi Embedded Yocto project:

$ bitbake-layers show-recipes trustfence-cst
trustfence-cst:
  meta-digi-arm        3.3.1

If more than one version appears and you want to use a different CST version than the latest one supported, set the variable PREFERRED_VERSION_trustfence-cst-native in your conf/local.conf:

conf/local.conf
# Use a different CST version
PREFERRED_VERSION_trustfence-cst-native = "x.y.z"

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:

conf/local.conf
# Disable signed images
TRUSTFENCE_SIGN = "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 automatically generated. The default value is a new folder trustfence in the Digi Embedded Yocto project home location.

conf/local.conf
# 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 automatically generated. The default value is <TRUSTFENCE_SIGN_KEYS_PATH>/dek.bin. Define to 0 to disable the encryption of the signed images.

conf/local.conf
# Use a custom path to the Data Encryption Key (or set to "0" to disable encryption).
TRUSTFENCE_DEK_PATH = "/mnt/secure/encryption_key.bin"

Disable U-Boot environment encryption

To explicitly disable U-Boot environment encryption, set TRUSTFENCE_ENCRYPT_ENVIRONMENT to 0 as follows:

conf/local.conf
# 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 root file system encryption

To explicitly disable root file system encryption, set TRUSTFENCE_ENCRYPT_ROOTFS to 0 as follows:

conf/local.conf
TRUSTFENCE_ENCRYPT_ROOTFS = "0"

Then, generate an SWU package and install it on the target to disable the rootfs encryption.

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.