Secure boot on STM32MP¶
Overview¶
This page explains the bootloader authentication on Welma, for machines with STM32MP25 and STM32MP13 processors.
References:
Acronyms:
- BL2: Boot Loader stage 2
- CoT: Chain Of Trust
- FIP: Firmware Image Package, packaging format used by TF-A to package firmware images in a single binary
- PKH: Public Key Hash
- PKHTH: Public Key Hash Table Hash
- ROT: Root Of Trust
- ROTPK: Root Of Trust Public Key
- TBBR: Trusted Board Boot Requirements
- TF-A: Trusted Firmware-A
Runtime architecture¶
The bootloader is made of 2 parts:
- BL2, which gets authenticated by the ROM code
- FIP, which contains BL3 firmware images and gets authenticated by BL2
BL2 structure¶
The BL2 image is structured as follows:
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 possible extensions: authentication, decryption, and padding. By default in Welma, the decryption extension is not used.
The base header primarily includes the signature and option flags that enable each of the three extensions. The signature is computed differently on STM32MP13 and STM32MP25. See STM32 header for binary files.
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.
FIP structure¶
The FIP consolidates all BL3 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 | (N/A on STM32MP13)
+----------------------------+-----------------+
| BL31 Device Tree | --soc-fw-config | (N/A on STM32MP13)
+----------------------------+-----------------+
| 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 | (N/A on STM32MP13)
+----------------------------+-----------------+
To guarantee the authenticity of the binaries within the FIP, TF-A employs a chain of certificates 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:
+-------+
| 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 |
+------------------+ +----------------------+
Ref: TF-A BL2 Trusted Board Boot, STM32 MPU implementation
In the Chain of Trust, the Root of Trust Public Key must be the same key used to authenticate BL2. This 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 | (N/A on STM32MP13)
+-------------------------------+--------------------+
| BL31 content certificate | --soc-fw-cert | (N/A on STM32MP13)
+-------------------------------+--------------------+
| 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 using
TF-A's cert_create tool (see FIP signing below).
In this case, the private keys associated with the certificates are generated
on the fly and not kept: new keys are generated each time a FIP is signed
(except for the ROT key).
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, the algorithms used are
ECDSA (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 BL2 into its 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
metadatathat contains required information to identify the FIP.
- BL2 identifies and load
-
FIP Authentication
-
Assets contained in the FIP:
- BL31 Firmware, DTB and their certificates (N/A on STM32MP13)
- 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 (N/A on STM32MP13)
- BL2 authenticates BL32 using trusted OS key and content certificates
- BL2 authenticates BL33 using non-trusted Firmware key and content certificates
-
-
BL2 starts BL31 (N/A on STM32MP13), BL32 (OP-TEE) and BL33 (U-Boot)
Yocto configuration¶
This section explains how Welma configures secure boot in Yocto and points out the key variables that you should check.
-
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_PUBandWELMA_KEY_SWK1_PRIV
- Activate secure boot by defining
-
Other variables:
PRIVATE_KEYS_PREFIX: Prefix used in private key files:<prefix><index>.pemPUBLIC_KEYS_PREFIX: Prefix used in public key files:<prefix><index>.pemPRIVATE_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_PREFIXandPRIVATE_KEY_INDEXvariables.
-
TF-A BL2:
- Have TF-A BL2 compiled with TBB support (
TRUSTED_BOARD_BOOT=1) and signed with the development keys (executestm32mp-sign) - Have
WELMA_KEY_SWK1_PUBinjected (executeinject-pubkey-uboot-dtb) - Have FIP file embed all necessary boot stages and certificates (execute
cert_createandfiptool)
- Have TF-A BL2 compiled with TBB support (
Warning
In Welma, two images of tf-a get built: one for production and one for
development (with "-dev" in the name). The latter is compiled with
DISABLE_IMAGE_AUTH=1 (which does not prevent booting when the FIP
authentication fails) and with DYN_DISABLE_AUTH=1 (for logging and testing
purpose). The development image should not be used in production.
-
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
/homeis 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.
Sign images with production keys¶
The images resulting from the Yocto build are signed with development keys that should not be used for production, as they are publicly disclosed.
This section explains how to sign images with other keys, out of the Yocto build environment.
The following keys should be defined:
- Root Of Trust key pair, using ECC algorithm, for signing BL2 and FIP
- SWK1, using RSA algorithm, for signing the kernel image and the filesystems
BL2 signing¶
In order to sign BL2, two scripts can to be used:
stm32mp-pkhth-gen: will create the PKHTH table for the new public keysstm32mp-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, stm32mp-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 stm32mp-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:
$ stm32mp-pkhth-gen --keys /path/to/publicKey*.pem \
-o publicKeysHasheTableHash.bin
$ stm32mp-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, stm32mp-sigcheck can be used as follow:
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 (STM32MP25):
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>
Global signing process¶
Input:
-
Generated by the Yocto build:
- BL2 image
- FIP image
- fitImage (BOOT)
- .verity images (SYSRO, APPRO)
-
Production Keys: ROT key pair, SWK1.priv, SWK1.crt
Output:
-
Signed images provisioned with necessary public keys and certificates):
- BL2 Firmware
- FIP archive
- BOOT vfat partition
- SYSRO and APPRO verity partitions
-
PKHTH
Steps:
- Inject SWK1.crt into U-Boot DTB
- Extract
u-boot.dtbfrom FIP archive usingfiptool(with ST support): - Inject SWK1.crt into
u-boot.dtb: - Replace
u-boot.dtbin the FIP archive
- Extract
-
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:
Secure products (manufacturing)¶
In manufacturing, each product has to be secured with the following steps:
- Burn (fuse) the PKHTH into the chip (see below)
- Close the chip (see Closing the device)
- Disable JTAG
Burning the eFuses¶
The PKHTH is generated by stm32mp-pkhth-gen (see BL2 signing).
It can be burnt into the eFuses by u-boot commands.
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.
The commands to burn the PKHTH are:
- on STM32MP13:
- on STM32MP25:
Detailed example (STM32MP25):
STM32MP> setenv ipaddr 169.254.142.1 && setenv serverip 169.254.142.224
STM32MP> tftp publicKeysHashTableHash.bin
Using ethernet@30bf0000 device
TFTP from server 169.254.142.224; our IP address is 169.254.142.1
Filename 'publicKeysHashTableHash.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 PKHTH is correctly fused
- the ROM code properly authenticates BL2
- BL2 properly authenticates FIP
To close the device, execute:
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 signed with matching keys¶
When BL2 is signed with keys matching the fused PKHTH, a notice message is displayed by BL2:
(on STM32MP25, BL2 needs to be compiled withDYN_DISABLE_AUTH=1, for this message
to be displayed)
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, BL2 displays this message:
(on STM32MP25, BL2 needs to be compiled withDYN_DISABLE_AUTH=1, for this message
to be displayed)
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.