Secure Boot on STM32MP25x¶
This pages explains the bootloader authentication and secure
boot setup, for STM32MP25x
machines.
References:
Acronyms:
- BL2: Boot Loader stage 2
- CoT: Chain Of Trust
- FIP: Firmware Image Package
- PKH: Public Key Hash
- PKHTH: Public Key Hash Table Hash
- PKI: Public Key Infrastructure
- ROTPK: Root Of Trust Public Key
- TBBR: Trusted Board Boot Requirements
- TFA: Trusted Firmware-A
STM32 Secure boot Overview¶
When the SoC powers on, the ROM code (BL1) loads the TF-A BL2 binary, which must be in STM32 format (refer to the STM32 BL2 structure) to be recognized.
The ROM code starts the BL2 authentication process. Upon successful authentication,
BL2 is executed to initialise the board, locates and reads the metadata to load
the corresponding FIP file (refer to the
STM32 FIP structure) in DDR
.
The secure boot steps are detailed in Secure boot stages section
STM32 BL2 structure¶
The STM32 BL2 built image is structured as follows and is meant
to be loaded into the SoC's internal SRAM
:
00h+-----------------------+----- ^ ------ ^
------>48h| STM32 HEADER | | |
Signed | | | |
Data | (PK, PKH table, key | 512 Bytes |
------>78h| index, signature) | | |
------>80h| | | |
^ | | | |
| +-----------------------+----- v |
| | BL2 Device tree | |
Signed +-----------------------+ Must fit in SRAM
Data | | |
| | BL2 Binary | |
| | (The actual TF-A BL2 | |
| | ELF) | |
v | | |
--------> +-----------------------+-------------- v
The STM32 header consists of a base header and three extensions: authentication, decryption, and padding.
The base header primarily includes the signature and option flags that
enable each of the three extensions. The signature is computed from offset
0x48
to the end of the binary, excluding the bytes between offsets 0x78
and 0x80
.
The authentication extension primarily contains the index of the public key used for the authentication process, along with a table of eight public key hashes.
In the Welma Secure Boot implementation, the decryption extension is not used. The padding extension then handles the remaining bytes.
STM32 FIP structure¶
The FIP (Firmware Image Package) is utilized by the TF-A BL2 firmware to load and authenticate the next-stage binaries. It consolidates all boot firmware, configuration files, and certificates into a single archive.
The FIP file can be created and modified using the TF-A fiptool
.
This utility enables the addition, removal, or replacement of elements
within the FIP file.
Each element within the FIP is assigned a command-line flag to enable
access to it. In the context of STM32 secure boot, an ST version of
fiptool
is used (patched-version of mainline tool) to handle
STM32-specific files.
The table below outlines the included binaries along with their corresponding command-line flags.
+----------------------------+-----------------+
| Binary | Command line |
+----------------------------+-----------------+
| BL31 Secure Monitor | --soc-fw |
+----------------------------+-----------------+
| BL31 Device Tree | --soc-fw-config |
+----------------------------+-----------------+
| BL32 Firmware | --tos-fw |
+----------------------------+-----------------+
| Trusted OS pager | --tos-fw-extra1 |
+----------------------------+-----------------+
| Trusted OS pageable | --tos-fw-extra2 |
+----------------------------+-----------------+
| Firmware conf file (FCONF) | --fw-config |
+----------------------------+-----------------+
| BL33 DTB | --hw-config |
+----------------------------+-----------------+
| BL33 Firmware | --nt-fw |
+----------------------------+-----------------+
| DDR Firmware | --ddr-fw |
+----------------------------+-----------------+
To guarantee the authenticity of the binaries within the FIP, TF-A employs a standard PKI mechanism known as the Chain of Trust. This authentication process is integrated into the BL2 firmware through the TBBR implementation. It relies on key certificates to validate public keys and content certificates, which are signed using the corresponding private keys. The content certificates include the hash of the firmware image, ensuring that only verified and untampered binaries are loaded and executed.
CoT description form STM32MP25x is defined in the BL2 device tree
(stm32mp2-cot-descriptors.dtsi
) as follow:
+-------+
| ROTPK |
+---+---+
|
+-------------+-------------+
| |
+------+------+ +------+------+
| STM32MP CFG | | Trusted Key |
| Certificate | | Certificate |
+-------------+ +------+------+
|
+------------+-------------+
| |
+-------+--------+ +--------+-------+
| Trusted OS Key | | Non-Trusted OS |
| certificate | | Key certificate|
+-------+--------+ +--------+-------+
| |
+--------+---------+ +-----------+----------+
|Trusted OS Content| |Non-Trusted OS Content|
| certificate | | certificate |
+------------------+ +----------------------+
In the Chain of Trust, the Root of Trust Public Key must be the same key used to authenticate BL2. This PKI structure is established within the FIP by incorporating the necessary certificates using the following options:
+-------------------------------+--------------------+
| Certificate | Command line |
+-------------------------------+--------------------+
| Root of trust key certificate | --trusted-key-cert |
+-------------------------------+--------------------+
| BL31 key certificate | --soc-fw-key-cert |
+-------------------------------+--------------------+
| BL31 content certificate | --soc-fw-cert |
+-------------------------------+--------------------+
| BL32 key certificate | --tos-fw-key-cert |
+-------------------------------+--------------------+
| BL32 content certificate | --tos-fw-cert |
+-------------------------------+--------------------+
| BL33 key certificate | --nt-fw-key-cert |
+-------------------------------+--------------------+
| BL33 content certificate | --nt-fw-cert |
+-------------------------------+--------------------+
| STM32MP config certificate | --stm32mp-cfg-cert |
+-------------------------------+--------------------+
These certificates can be generated manually using
TF-A's cert_create
tool (with the ST version), which
will always be verified by the ROTPK. In this case, the private
keys associated with the certificates are not kept,
and they are used only once for each FIP.
See Offline signing of BL2 and FIP for
more details on how to use cert_create
and fiptool
.
Secure boot stages¶
The secure boot process involves multiple stages of verification. It begins with the ROM code and continues through the loading and execution of all bootloader firmware components.
Throughout all authentication and signature processes, we
use ECDSA
key pairs (256-bits) based on the NIST P-256
curve
algorithm and SHA-256
for hash computation.
-
TF-A BL2 Authentication:
-
Assets contained in the TF-A BL2:
- ROTPK (Public key)
- Public key index (0..7)
- PKH: table of the 8 ECDSA public key Hashes.
- Image Signature
-
Authentication:
- The ROM loads the BL2 on-chip SRAM.
- The ROM Code authenticates the PKH table using the PKHTH stored in the OTP fuses.
- The ROM Code authenticates ROTPK by comparing its SHA256 to the hash contained in the PKHTH using the Public Key Index.
- The ROM Code authenticates the BL2 using the Public Key to verify the signature stored in the BL2 binary.
-
-
The ROM code starts the BL2 firmware
- BL2 identifies and load
metadata
that contains required information to identify the FIP.
- BL2 identifies and load
-
FIP Authentication
-
Assets contained in the FIP:
- BL31 Firmware, DTB and their certificates
- BL32 Firmware and its certificates
- BL33 Firmware and its certificates
- BL33 DTB, DDR firmware, FCONF and their certificate
-
Authentication:
- BL2 authenticates FCONF, DDR firmware and BL33 config file (U-Boot dtb) using STM32MP Config Certificate
- BL2 initializes the DDR PHY and reads FCONF to load next boot stages
- BL2 authenticates BL31 using SoC key and content certificates
- BL2 authenticates BL32 using trusted OS key and content certificates
- BL2 authenticates BL33 using non-trusted Firmware key and content certificates
-
-
BL2 starts BL31
-
BL31 starts BL32 (OP-TEE) and BL33 (U-Boot)
Setting up your Secure Boot¶
This section will guide you through the process of building and running an image with secure boot.
It is assumed the following context:
- STM32MP25 machine (eg: stm32mp25-disco-welma)
- Default Welma partition layout
- Default Welma development keys used in the Yocto build
- Production keys owned by a separate entity (other than the development team)
Building your Image¶
Welma requirements:
-
machine.conf:
- Set
BOOT_SIGNING_MECHANISM = "stm32mp2"
- Set
-
In
local.conf
- Activate secure boot by defining
WELMA_SECURE_BOOT = "1"
(this is the default) - Adjust or keep the default values for
WELMA_KEY_SWK1_PUB
andWELMA_KEY_SWK1_PRIV
- Activate secure boot by defining
-
Other variables:
PRIVATE_KEYS_PREFIX
: Prefix used in private key files:<prefix><index>.pem
PUBLIC_KEYS_PREFIX
: Prefix used in public key files:<prefix><index>.pem
PRIVATE_KEY_INDEX
: Index of the private key to be used, which must be between 0 and 7.FORCE_FLAG
: Must always be unset, except in the case of key revocation by choosing a private key index greater than 0, where it must be set toFORCE_FLAG = "1"
.WELMA_ROT_SIGN_KEY
: Path to the private key to be used. Built fromPRIVATE_KEYS_PREFIX
andPRIVATE_KEY_INDEX
variables.
-
TF-A BL2:
- Have TF-A BL2 compiled with TBB support (
TRUSTED_BOARD_BOOT=1
) and signed with the development keys (executestm32mp2-sign
) - For development devices only, compile TF-A with
DYN_DISABLE_AUTH=1
option - Have
WELMA_KEY_SWK1_PUB
injected (executeinject-pubkey-uboot-dtb
) - Have FIP file embed all necessary boot stages and certificates (execute
cert_create
andfiptool
)
- Have TF-A BL2 compiled with TBB support (
Warning
DYN_DISABLE_AUTH=1
option should only be enabled for development
platforms.
-
u-boot:
- Activate FIT signature (
CONFIG_FIT_SIGNATURE
) - Disable the U-Boot command line or restrict its access by a password (not done in Welma), because it would allow an attacker to bypass the secure boot mechanism.
- Activate FIT signature (
-
In SYSRO and APPRO: have your programs not start other programs located in SYSRW, as this filesystem is not covered by secure boot. Keep in mind that
/home
is located in SYSRW and make sure that files such as~/.profile
,~/.bashrc
, etc. do not get executed automatically if they were created by an attacker.
Signing your Image with Production Keys¶
Input:
-
Generated by the build:
- BL2 Firmware
- FIP archive
- fitImage (BOOT)
- .verity images (SYSRO, APPRO)
-
Production Keys: ROT keys, SWK1.priv, SWK1.crt
Ouput (signed images provisioned with necessary public keys and certificates):
- BL2 Firmware
- FIP archive
- BOOT vfat partition
- SYSRO and APPRO verity partitions
Steps:
- Inject SWK1.crt into U-Boot DTB
- Extract
u-boot.dtb
from FIP archive usingfiptool
(with ST support): - Inject SWK1.crt into
u-boot.dtb
: - Replace
u-boot.dtb
in the FIP archive
- Extract
- Sign TF-A BL2
-
Sign fitImage:
- Create the BOOT partition (vfat) populated with the signed fitImage, using
mkdosfs
&mcopy
- Create the BOOT partition (vfat) populated with the signed fitImage, using
-
Sign .verity images:
Fusing your Products¶
-
Prepare the PKHTH table to be fused: Sign TF-A BL2
-
Disable JTAG
Offline signing of BL2 and FIP¶
BL2 signing¶
In order to sign BL2 with other keys, after a Yocto build (and out of the Yocto build environment), two scripts can to be used:
stm32mp2-pkhth-gen
: will create the PKHTH table for the new public keysstm32mp2-sign
: will sign the binary file with the new private keys and insert the PKHTH table
These two scripts are Python implementations of the STM32MP_KeyGen_CLI
and
STM32MP_SigningTool_CLI
precompiled tools provided by ST. This Python implementation
offers more flexibility and easier integration into the Yocto environment.
However, stm32mp2-sign
only supports signing BL2 binary files with private keys passed
as arguments. For PKCS#11
support, please use STM32MP_SigningTool_CLI
.
Alongside these two scripts, the stm32mp2-sigcheck
tool can be used to verify the
signature of a binary before deploying it to the board. This tool replicates the
signature verification process performed by the ROM code on the BL2 binary.
Pre-requisites:
- python3
- pycryptodome module, v3.21.0 or later
Signing example:
$ stm32mp2-pkhth-gen --keys /path/to/publicKey*.pem \
-o publicKeysHasheTableHash.bin
$ stm32mp2-sign --binary-image <TF-A BL2> \
--output tf-a-bl2-signed.stm32 \
--public-keys path/to/publicKey*.pem \
--private-key path/to/privateKey0.pem
To check the binary's signature, stm32mp2-sigcheck
can be used as follow:
stm32mp2-sigcheck
using the -p
option.
FIP signing¶
To authenticate a FIP, the key and content certificates of its elements must be added, two tools can to be used (with ST support version):
cert_create
: will generate all required certificatesfiptool
: will create the FIP containing the generated certificates
Warning
The tools typically included in Linux distributions do not natively support ST-specific options. The ST-modified version of these tools should be used instead. These modified tools can be found in the TF-A build artifacts.
Example:
cert_create -n \
--tfw-nvctr 0 \
--ntfw-nvctr 0 \
--key-alg ecdsa \
--hash-alg sha256 \
--rot-key /path/to/privateKey.pem \
--fw-config /path/to/<TF-A FCONF>.dtb \
--soc-fw /path/to/<BL31 Firmware> \
--soc-fw-config /path/to/<BL31 DTB> \
--ddr-fw /path/to/<DDR Firmware> \
--tos-fw /path/to/<BL32 Firmware> \
--tos-fw-extra1 /path/to/<BL32 Firmware EXTRA 1> \
--tos-fw-extra2 /path/to/<BL32 Firmware EXTRA 2> \
--nt-fw /path/to/<BL33 Firmware> \
--hw-config /path/to/<BL33 DTB> \
--trusted-key-cert /path/to/<Output Trusted key certificate> \
--nt-fw-cert /path/to/<Output BL33 content certificate> \
--nt-fw-key-cert /path/to/<Output BL33 key certificate> \
--tos-fw-cert /path/to/<Output BL32 content certificate> \
--tos-fw-key-cert /path/to/<Output BL32 key certificate> \
--stm32mp-cfg-cert /path/to/<Output SMT32MP CFG certificate> \
--soc-fw-cert /path/to/<Output BL31 content certificate> \
--soc-fw-key-cert /path/to/<Output BL31 key certificate> \
fiptool create \
--fw-config /path/to/<FCONF DTB> \
--soc-fw /path/to/<BL31 Firmware> \
--soc-fw-config /path/to/<BL31 DTB> \
--ddr-fw /path/to/<DDR Firmware> \
--tos-fw /path/to/<BL32 Firmware> \
--tos-fw-extra1 /path/to/<BL32 EXTRA 1> \
--tos-fw-extra2 /path/to/<BL32 EXTRA 2> \
--nt-fw /path/to/<BL33 Firmware> \
--hw-config /path/to/<BL33 DTB> \
--soc-fw-cert /path/to/<BL31 Content Certificate> \
--soc-fw-key-cert /path/to/<BL31 Key Certificate> \
--trusted-key-cert /path/to/<Trusted Key Certificate> \
--nt-fw-cert /path/to/<BL33 Content Certificate> \
--nt-fw-key-cert /path/to/<BL33 Key Certificate> \
--tos-fw-cert /path/to/<BL32 Content Certificate> \
--tos-fw-key-cert /path/to/<BL32 Key Certificate> \
--stm32mp-cfg-cert /path/to/<STM32MP CFG Certificate> \
<Output FIP Archive>
Burning the eFuses¶
The PKHTH generated by stm32mp2-pkhth-gen
can be used
in u-boot command line interpreter to burn the eFuses.
Warning
These commands are writing to One-Time Programmable (OTP) eFuses. Be absolutely certain that you want to write to the OTP before running these commands. Once written, the data cannot be changed or erased. Before closing the device, ensure there are no authentication error when loading BL2.
PKHTH provisioning¶
Example:
STM32MP> setenv ipaddr 169.254.142.1 && setenv serverip 169.254.142.224
STM32MP> tftp publicKeysHasheTableHash.bin
Using ethernet@30bf0000 device
TFTP from server 169.254.142.224; our IP address is 169.254.142.1
Filename 'publicKeysHasheTableHash.bin'.
Load address: 0x84000000
Loading: #
67.4 KiB/s
done
Bytes transferred = 32 (20 hex)
STM32MP> stm32key read ${loadaddr} # Read the downloaded PKHTH
Read OEM-KEY1 at 0x84000000
OEM-KEY1 OTP 144: [84000000] 0ad86eb8
OEM-KEY1 OTP 145: [84000004] de5f9ad1
OEM-KEY1 OTP 146: [84000008] 4fc7850e
OEM-KEY1 OTP 147: [8400000c] 6c3592f4
OEM-KEY1 OTP 148: [84000010] 073dcc7b
OEM-KEY1 OTP 149: [84000014] cea61272
OEM-KEY1 OTP 150: [84000018] c59462c0
OEM-KEY1 OTP 151: [8400001c] a37f9be9
STM32MP> stm32key select OEM-KEY1 # Select PKHTH OTP
OEM-KEY1 selected
STM32MP> stm32key read # Read the current PKHTH OTP
OEM-KEY1 OTP 144: 00000000 lock : 00000000
OEM-KEY1 OTP 145: 00000000 lock : 00000000
OEM-KEY1 OTP 146: 00000000 lock : 00000000
OEM-KEY1 OTP 147: 00000000 lock : 00000000
OEM-KEY1 OTP 148: 00000000 lock : 00000000
OEM-KEY1 OTP 149: 00000000 lock : 00000000
OEM-KEY1 OTP 150: 00000000 lock : 00000000
OEM-KEY1 OTP 151: 00000000 lock : 00000000
OEM-KEY1 is not locked!
OEM-KEY1 is free!
STM32MP> stm32key fuse ${loadaddr} # Burning the eFuses
OEM-KEY1 OTP 144: 00000000 lock : 00000000
OEM-KEY1 OTP 145: 00000000 lock : 00000000
OEM-KEY1 OTP 146: 00000000 lock : 00000000
OEM-KEY1 OTP 147: 00000000 lock : 00000000
OEM-KEY1 OTP 148: 00000000 lock : 00000000
OEM-KEY1 OTP 149: 00000000 lock : 00000000
OEM-KEY1 OTP 150: 00000000 lock : 00000000
OEM-KEY1 OTP 151: 00000000 lock : 00000000
OEM-KEY1 is not locked!
OEM-KEY1 is free!
Writing OEM-KEY1 with
OEM-KEY1 OTP 144: [84000000] 0ad86eb8
OEM-KEY1 OTP 145: [84000004] de5f9ad1
OEM-KEY1 OTP 146: [84000008] 4fc7850e
OEM-KEY1 OTP 147: [8400000c] 6c3592f4
OEM-KEY1 OTP 148: [84000010] 073dcc7b
OEM-KEY1 OTP 149: [84000014] cea61272
OEM-KEY1 OTP 150: [84000018] c59462c0
OEM-KEY1 OTP 151: [8400001c] a37f9be9
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> y
Fuse OEM-KEY1 OTP 144 : 0ad86eb8
Fuse OEM-KEY1 OTP 145 : de5f9ad1
Fuse OEM-KEY1 OTP 146 : 4fc7850e
Fuse OEM-KEY1 OTP 147 : 6c3592f4
Fuse OEM-KEY1 OTP 148 : 073dcc7b
Fuse OEM-KEY1 OTP 149 : cea61272
Fuse OEM-KEY1 OTP 150 : c59462c0
Fuse OEM-KEY1 OTP 151 : a37f9be9
OEM-KEY1 updated !
Check the values written in the fuses with stm32key read
in U-Boot:
STM32MP> stm32key read
OEM-KEY1 OTP 144: 0ad86eb8 lock : 40000000
OEM-KEY1 OTP 145: de5f9ad1 lock : 40000000
OEM-KEY1 OTP 146: 4fc7850e lock : 40000000
OEM-KEY1 OTP 147: 6c3592f4 lock : 40000000
OEM-KEY1 OTP 148: 073dcc7b lock : 40000000
OEM-KEY1 OTP 149: cea61272 lock : 40000000
OEM-KEY1 OTP 150: c59462c0 lock : 40000000
OEM-KEY1 OTP 151: a37f9be9 lock : 40000000
Closing the device¶
Before closing the device, verify that the authentication process is properly
implemented in both the ROM code and TF-A. To close the device, stm32key
is
used as follow:
Test cases¶
The following test cases are designed to verify the secure boot process. The main objective is to ensure that there are no authentication error in BL2 or FIP that might indicate a security breach or a failure in the secure boot process.
BL2 and FIP signed with matching keys¶
When BL2 and FIP are signed with the keys corresponding to the PKHTH fused,
a notice message is displayed when BL2 is compiled with DYN_DISABLE_AUTH=1
:
Corrupted BL2 signature or content¶
If an installed BL2 has a corrupted signature or content but the public key contained in its header is correct, the following Boot ROM error message appears and the boot continues because the FIP will be authenticated with the matching key:
Corrupted FIP or signed with a wrong key¶
When a wrong key is used to sign the FIP, the authentication of the FIP elements
by BL2 will fail and an -EAUTH
(-80) error message is displayed:
The image identifier depends on the FIP element whose authentication failed. You
can find the list of image ids in TF-A source code tbbr_img_def_exp.h
.