Secure boot has the objective of protecting the integrity and authenticity of the operating system components (bootloader, kernel, root filesystem, etc) at boot time.
Secure boot is currently supported on the following SoMs:
- Apalis iMX6
- Apalis iMX8
- Colibri iMX6DL
- Colibri iMX6ULL (1GB eMMC variant only)
- Colibri iMX7D (1GB eMMC variant only)
- Colibri iMX8X
- Verdin AM62
- Verdin iMX8MM
- Verdin iMX8MP
The secure boot implementation provided by this layer is based on the verification of digital signatures, where every component of the operating system is signed, and its signature is checked at boot time.
For this, the following features are available (details on the level of support and how to configure might vary depending on the SoM):
- Bootloader signature checking: bootloader images are signed at build time and their signature is verified at runtime by the SoC's ROM code.
- U-Boot hardening: a few patches are applied to the U-Boot bootloader to make it harder for an attacker to bypass the secure boot process.
- FIT image signature checking: a FIT image with the kernel and its artifacts (device trees, ramdisk, etc) is signed at build time and its signature is verified at runtime by the bootloader.
- Rootfs signature checking: the rootfs image is generated using the dm-verity kernel feature and its root hash is added to the ramdisk image. The ramdisk will only mount the rootfs if the root hash matches the
dm-verity
image. Since the ramdisk is signed and its signature is checked by the bootloader, this ensures the integrity and authenticity of the rootfs image.
The features actually enabled depend on the class chosen. The options are:
tdxref-signed
: all features listed above are enabled (the level of support might vary depending on the SoM, so check the detailed documentation in the following sessions if you need more details).tdx-signed
: all features are enabled except the "Rootfs signature checking". This class may be more suitable thantdxref-signed
if the rootfs protection viadm-verity
is not desired (for example, because it's not compatible with the used distro or because the rootfs is protected by other means).
To use the selected class, inherit from it globally by adding the following to an OE configuration file (e.g. your local.conf
):
INHERIT += "<chosen-class>"
For example, to enable all features, including rootfs signature checking:
INHERIT += "tdxref-signed"
The following sessions describe in detail each of these features.
The bootloader signature checking implementation is dependent on the System on Chip (SoC).
For details on the bootloader signature checking implementation for SoMs that use NXP iMX-based platforms (i.e. iMX6/7/8), see the README-secure-boot-imx.md file.
For details on the bootloader signature checking implementation for SoMs that use TI K3-based platforms (i.e. AM62), see the README-secure-boot-k3.md file.
Toradex is implementing various changes to U-Boot (currently as a series of patches) with the purpose of hardening it for secure boot. The hardening includes the following features:
- Command whitelisting: this part of the hardening is responsible for limiting the set of commands available to boot scripts once the device is in closed state - by default, only a small set of commands remain available in that state (mostly those strictly required for booting a secure boot image) alongside a few others considered strictly secure and potentially useful for future boot scripts.
- Protection against execution of unsigned software by
bootm
: for securely booting secure boot images the "bootm" command is used in the boot scripts, but this command can also be used insecurely; this part of the hardening tries to ensure only the secure use of the command is possible so that the only possible code path at runtime is that for booting from signed FIT images. - CLI access prevention: this is an extra safeguard whereby the access to the U-Boot CLI gets disabled once the device is in closed state; this is what happens by default (but can be overridden).
- Kernel command-line protection: normally U-Boot passes the contents of its environment variable
bootargs
directly to the Linux kernel and this variable in turn has its value set in the persistent U-Boot environment or it is dynamically built by the boot scripts (with Torizon OS following the latter approach) - either way, it is a vector of attack; to prevent tampering ofbootargs
the present protection causes the build to store a copy of the "expected" kernel arguments inside the (signed) FIT image and a related patch to U-Boot to checkbootargs
against that copy at runtime, possibly stopping the boot process in case of a mismatch.
The hardening features above are controlled by the following variables:
Variable | Description | Default value |
---|---|---|
TDX_UBOOT_HARDENING_ENABLE |
Enable hardening features as a whole | 1 if both secure boot support (controlled by variable TDX_IMX_HAB_ENABLE (NXP) or TDX_K3_HSSE_ENABLE (TI)) and FIT signing (controlled by UBOOT_SIGN_ENABLE ) are enabled; 0 otherwise |
TDX_SECBOOT_REQUIRED_BOOTARGS |
Expected value for the fixed part of the kernel command line | Different value for each machine |
TDX_AMEND_BOOT_SCRIPT |
When set to 1 the boot script will be amended to make it suitable for secure boot; this only works with the script provided by Toradex for BSP reference images; users employing a custom script should set this to 0 |
Same value as variable TDX_UBOOT_HARDENING_ENABLE |
The behavior of the different hardening features can be set via the control FDT (see Devicetree Control in U-Boot). Setting the control FDT at build time can be achieved by adding extra device-tree .dtsi fragments to U-Boot and setting the Kconfig variable CONFIG_DEVICE_TREE_INCLUDES
appropriately; with Yocto/OE this would normally involve adding small patches to U-Boot and appending changes to its recipe but the details are outside the scope of the present document.
The following device-tree fragment shows all the nodes and properties that can be present in the control FDT:
/ {
chosen {
toradex,secure-boot { /* if not present: disable Toradex hardening at runtime */
disabled; /* if present: disable Toradex hardening at runtime */
enable-cli-when-closed; /* if present: keep u-boot CLI enabled when device is closed */
bootloader-commands {
allow-open = <...>; /* list of command categories allowed when device is open */
allow-closed = <...>; /* list of command categories allowed when device is closed */
deny-open = <...>; /* list of command categories denied when device is open (use is discouraged) */
deny-closed = <...>; /* list of command categories denied when device is closed (use is discouraged) */
needed = <...> /* list of command categories strictly needed to boot (use is discouraged) */
};
};
};
};
The command categories are currently only available as part of a patch in header cmd-categories.h
. The default FDT is part of another patch in file tdx-secboot.dtsi
.
- On the Verdin AM62 SoM, the hardening does not cover the bootloader running on the R5 processor (the boot master); we have plans to evaluate the need for such a protection and implementing it if actually needed.
When the tdx-signed
or tdxref-signed
class is inherited, generating and signing a FIT image is enabled by default. Set UBOOT_SIGN_ENABLE
to 0
to disable it.
This feature uses the default FIT image signing support provided by the uboot-sign
and kernel-fitimage
classes from OpenEmbedded Core. See the Yocto Project documentation for more details.
A few variables can be used to configure this feature, including:
Variable | Description | Default value |
---|---|---|
UBOOT_SIGN_ENABLE |
Enable signing of FIT image | 1 |
FIT_GENERATE_KEYS |
Generate signing keys | 1 |
UBOOT_SIGN_KEYDIR |
Location of the RSA key and certificate used for signing | ${TOPDIR}/keys/fit |
UBOOT_SIGN_KEYNAME |
The name of the key used for signing configuration nodes | dev |
UBOOT_SIGN_IMG_KEYNAME |
The name of the key used for signing individual images | dev2 |
The complete list of variables can be found in the tdx-signed-fit-image.inc
file.
- On the Verdin AM62 SoM, some of the configuration variables (e.g.
UBOOT_SIGN_KEYDIR
,UBOOT_SIGN_KEYNAME
(check the complete list intdx-signed-fit-image.inc
)) are set through overridek3
to ensure the values coming from layermeta-toradex-security
override those from layermeta-ti-bsp
. Due to this, the recommended way to set those variables is via overrideforcevariable
.
When the tdxref-signed
class is inherited, the rootfs image will be generated using the dm-verity
kernel feature.
The variable DM_VERITY_IMAGE
must be configured with the name of the image recipe you are building. For example, if you are building an image recipe called my-custom-image
:
DM_VERITY_IMAGE = "my-custom-image"
In case you don't want to boot a signed rootfs image, then instead of inheriting tdxref-signed
, you should inherit tdx-signed
. When inheriting tdx-signed
the bootloader and the FIT image will be signed, but the rootfs image signing process with dm-verity
will be skipped.
When tdxref-signed
is used to enable secure boot, the rootfs image is generated using the dm-verity
kernel feature.
Because dm-verity
is read-only, you might want to create an additional partition in the eMMC to store persistent data.
If that is the case, you can use the tdx-tezi-data-partition
class. For more information, have a look at its documentation (README-data-partition.md).