DHCOM STM32MP15 Secure Boot

From Wiki-DB
Jump to navigation Jump to search



Abbreviation Description
BSI Bundesamt für Sicherheit in der Informationstechnik
CoM Computer on module
FIT Flattened Image Tree
FSBL Fist Stage Bootloader (TF-A or U-Boot SPL)
OTP One Time Programmable (eFuses)
OP-TEE Open Portable Trusted Execution Environment
PKH Public Key Hash
ROM Read-Only Memory
RSA Rivest, Shamir und Adleman (asynchronous encryption)
SHA Secure Hash Algorithm
SoC System on chip
SoM System on module
SSBL Second Stage Bootloader (U-Boot)
TF-A Trusted Firmware A

Secure Boot

The term Secure Boot originally comes from the UEFI specification[1] and describes a secure boot process in which only signed software is loaded and executed during the boot process.

Secure Boot is a necessary cornerstone for enforcing security mechanisms in a trusted computing environment. Enforcing the execution of signed software only during the boot process, as long as the chain of trust is secure, can guarantee that said software is free from tampering, as any manipulation will invalidate the software's signature and prevent the software from being executed.

Secure Boot Generic

The figure Secure Boot Generic shows an example of a secure boot process that leads to a reset in the event of an error in the signature check. Each stage uses the certificate and signature to check the origin and integrity of the next stage. On success, the next stage is executed, and in the event of an error, this always leads to a defined error state. In the simplest case, the certificates are integrated into the binary image of the previous stage.

Program code and certificate need to be trustworthy and therefore protected against tampering in each stage, otherwise the secure boot chain can be compromised. Except for the first stage, all binary images are protected against third-party tampering by the signature. As this is practically impossible for the first stage, manipulation protection has to be enforced by hardware measures to make said stage immutable, with the first stage's program code and the verification certificate for the second stage being stored in read-only memory (ROM).

Basic and trusted boot in the context of Secure Boot

When booting Linux on the STM32MP1 SoC with U-Boot SPL and U-Boot only, STM speaks of "Basic Boot"[2]. However, if Linux is booted with a combination of TF-A, U-Boot and OP-TEE, STM refers to this as "Trusted Boot"[3].

Boot chain Description
Basic boot BootROM -> U-Boot SPL -> U-Boot -> Linux
Trusted boot BootROM -> TF-A -> U-Boot + OP-TEE -> Linux

Secure Boot in Basic Boot with BootROM authentication and Verified Boot

This Secure Boot implementation does use the the BootROM integrated image authentication to authenticate the U-Boot SPL as FSBL. Authentication of U-Boot as SSBL by the U-Boot SPL and authentication of the Linux kernel, Device Tree and ramdisk by U-Boot is done using the open source implementation Verified Boot. This also means that everything from U-Boot SPL onwards is platform independent, as we do not rely on hardware specific implementations.

Verified Boot

Developers of Google's Chromium project worked out a concept for the Verified Boot called Secure Boot mechanism on the basis of the boot loader "Das U-Boot". They use the existing infrastructure of the FIT images and for the system configuration at runtime via a Device Tree. The description language for the FIT images was extended by an additional signature node and the Device Tree of the platform was used to store the certificate(s) for the authentication of the images. The signature node can be used to sign individual subimages as well as combinations of individual subimages in the FIT image. The tool mkimage takes care the signature creation for the FIT images and the addition of the certificate in a Device Tree.

With Verified Boot, the Device Tree with included public key is integrated into the program image of the stage, which accomplishes the authentication and is thus very similar to the general procedure shown in figure Secure Boot Generic. The number of public keys that can be integrated is theoretically unlimited, but they must be distinguishable by name.

Technical details of Verified Boot

Name Verified Boot
Implementierung Software (Open Source)
Hash algorithms
  • SHA1 (deprecated)[4]
  • SHA256
  • SHA384
  • SHA512
Crypto algorithms
  • RSA2048 (deprecated as of 2024)[4]
  • RSA4096
  • ECDSA256 (currently limited to U-Boot SPL)
Number of key pairs unlimited

In-depth references for Verified Boot

Flatten Image Tree
Verified Boot
ECDSA signature verification
TODO: Mention ECDSA limitations

Note: This has currently some limitations!

Tutorial: Secure boot from BootROM to Linux with basic boot

System requirements and needed tools

The following table lists all requirements to create the key pairs and build the signed images with embedded public keys.

Category Description
Host operating system
  • Linux (Debian 9, Ubuntu 18.04 or higher prefered)
Debian packages
  • bison
  • device-tree-compiler
  • flex
  • gcc-arm-linux-gnueabihf (>= gcc 6)
  • git
  • make
  • openssl
  • swig
STM32 Tools
TODO: Should we give host setup instructions?

Add STM32CubeProrammer binaries to user environment

export PATH=${PATH}:~/STMicroelectronics/STM32Cube/STM32CubeProgrammer/bin

Intended use of the four generated key pairs

We've decided to create and use as few certificates as reasonable to ensure a high level of security. Therefore, we chose a separate key pair for each boot stage and also a separate key pair for image and configuration nodes. If you're confused about the difference between image and configuration nodes, head over to Flatten Image Tree to refresh your knowledge. The exact purpose of the four key pairs generated for Verified Boot is described in the following table.

File name Intended use
fsbl-img Authenticate image nodes of FIT images loaded by U-Boot SPL (U-Boot, Device Tree, firmware)
fsbl-cfg Authenticate config nodes of FIT images loaded by U-Boot SPL (U-Boot + Device Tree + firmware)
ssbl-img Authenticate image nodes of FIT images loaded by U-Boot (Kernel, Device Tree, InitRamFS)
ssbl-cfg Authenticate config nodes of FIT images loaded by U-Boot (Kernel + Device Tree + InitRamFS)

Created/Modified files in the U-Boot source for Verified Boot

The created or modified files to build U-Boot with Verified Boot on STM32MP15 are described in the following table.

File Description
build_signed_uboot.sh Shell script that automates the creation of key pairs, the modification of FIT source files and Device Tree's and building of U-Boot SPL and U-Boot.
board/dhelectronics/dh_stm32mp1/u-boot-dhco?.its FIT source files with defined U-Boot image and Device Tree's for DHSOM platforms.
board/dhelectronics/dh_stm32mp1/linux-dhcom.its Dummy FIT source file with defined dummy kernel image and dummy Device Tree for DHSOM platforms.
To avoid relying on a built kernel image on a fixed path, we created this dummy, since adding the public keys with mkimage requires a valid FIT source file.
configs/stm32mp15_dhco?_secure_defconfig Example U-Boot defconfig's with enabled CONFIG_FIT_SIGNATURE and CONFIG_SPL_FIT_SIGNATURE.

Build Verified Boot enabled U-Boot SPL and U-Boot

To build the U-Boot SPL and U-Boot images, you need to check out the source code and run a build script that automates everything from key generation to image creation and signing.

Checkout source code for Verified Boot

Checkout the branch v2022.01_dhcom_secure_boot from DH electronics GitHub repository with:

git clone https://github.com/dh-electronics/u-boot-stm32mp1.git -b v2022.01_dhcom_secure_boot

If you already have a cloned U-Boot source code, you can also fetch it into your existing repository with:

cd /path/to/u-boot
git remote add u-boot-stm32mp1 https://github.com/dh-electronics/u-boot-stm32mp1.git
git fetch u-boot-stm32mp1
git checkout v2022.01_dhcom_secure_boot
Run the build script build_signed_uboot.sh

The shell script build_signed_uboot.sh included in the U-Boot source performs the following steps.

  1. Prebuild U-Boat SPL and U-Boat to build the required tools and Device Tree's
  2. Generate the four key pairs if not already created
  3. Generate/Modify FIT image source files for Linux (dummy) and U-Boot
  4. Add public keys to the built Device Tree's used by U-Boot SPL and U-Boot
  5. Rebuild U-Boot SPL and U-Boot with new Device Tree's containing the public keys

The script supports the following environment variables to configure the target architecture, the cross compiler, the defconfig, the key algorithm, the key directory, and a key postfix:

Name Description Default
ARCH Target architecture for the U-Boot build arm
CROSS_COMPILE Used cross compiler to build U-Boot arm-linux-gnueabihf-
DEFCONFIG Used defconfig for the U-Boot build stm32mp15_dhcom_secure_defconfig
KEY_ALGO Signature algorithm used for Verified Boot rsa
KEY_DIR Directory where the key pairs are stored ../keys
KEY_POSTFIX Postfix which is appended to the key names -$(date +%F)

To perform the steps mentioned above, you just need to run the shell script build_signed_uboot.sh like below. In this example, we override the default value for KEY_POSTFIX with -testing to append this string to the four key file names. The script has debug output enabled by default, which should output all the statements in the script itself and the output of the commands used in the script. If you have any problems with the script, feel free to get in touch with us and attach a logfile.

cd /path/to/u-boot
KEY_POSTFIX="-testing" ./build_signed_uboot.sh | tee build_signed_uboot.log

If this process completes without errors, there are two boot loader images in the root directory of the U-Boot source.

File name Stage Description
u-boot-spl.stm32 FSBL U-Boot SPL binary with appended Device Tree and prepended STM32 image header[5].
u-boot-spl-signed.stm32 FSBL Same as above but as signed STM32 image. Is created in Sign U-Boot SPL with STM32MP_SigningTool_CLI.
u-boot.itb SSBL U-Boot and Device Tree's contained in a FIT image.
u-boot-signed.itb SSBL Same as above but with signed configs and images.

Generate key pair and sign U-Boot SPL for BootROM authentication

To sign the U-Boot SPL as SSBL image for authentication with the BootROM we have to use the STM32 tools STM32MP_KeyGen_CLI and STM32MP_SigningTool_CLI.

Generate key pair with STM32MP_KeyGen_CLI

All STM32MP15 SoCs only support one key pair for authenticating images through the BootROM. To generate a ECDSA key pair for the STM32MP Secure Boot use the tool STM32MP_KeyGen_CLI[6]:

STM32MP_KeyGen_CLI --absolute-path "$(pwd)" --password <a secure password>
                       STM32MP Key Generator v2.9.0                              

 Prime256v1 curve is selected. 
 AES_256_cbc algorithm is selected for private key encryption
 Generating Prime256v1 keys... 
 Private key PEM file created 
 Public key PEM file created 
 public key hash file created 
 Keys generated successfully.
 + public key:       publicKey.pem
 + private key:      privateKey.pem
 + public hash key:  publicKeyhash.bin
Sign U-Boot SPL with STM32MP_SigningTool_CLI

To add the public key and the image signature to our built U-Boot SPL binary with STM32 image header, we are using the tool STM32MP_SigningTool_CLI[7] to update the existing STM32 image header of u-boot-spl.stm32 with the required details.

STM32MP_SigningTool_CLI --binary-image /path/to/u-boot/u-boot-spl.stm32 --public-key publicKey.pem --private-key privateKey.pem --password <a secure password> --output /path/to/u-boot/u-boot-spl-signed.stm32
                       STM32MP Signing Tool v2.9.0                     

 Prime256v1 curve is selected. 
 Header version 1 preparation ... 
 Reading Private Key File... 
 ECDSA signature generated.
 Signature verification:  SUCCESS 
 The Signed image file generated successfully:  /path/to/u-boot/u-boot-spl-signed.stm32

You can check the STM32 image header details with:

STM32MP_SigningTool_CLI --dump-header /path/to/u-boot/u-boot-spl-signed.stm32
                       STM32MP Signing Tool v2.9.0                     

Header description:

    Magic: 0x53544d32
    Signature: c8 30 a0 62 2d 6d 4e 1b b9 f7 fe 38 27 65 e0 44 f0 f5 9d e6 8a a6 02 cb 74 52 26 9c 1e e9 07 17 
               1a c7 da 8e 96 fa 82 d3 b1 dc d5 3a 05 0e 87 83 94 4d 47 ad 17 07 88 0d b5 ae 2e 38 1d 90 22 ad 
    Checksum: 0xa8ca85
    Header version: 0x10000
    Size: 0x22dec
    Load address: 0x2ffc2500
    Entry point: 0x2ffc2500
    Image version: 0x0
    Option flags: 0x0
    ECDSA Algo: 0x1
    ECDSA pub key: 3b 71 8e 59 f1 ee 4c a8 4b 72 5f 4a 1c 63 8b 6e b8 01 ec 1a 3f 8c 98 2f d2 1d 77 f9 09 10 8f 04 
                   30 da 5c 3a 24 53 0d 71 93 f0 a5 d9 c9 a7 27 b4 5f a5 c4 4d 55 8b 7a 25 e3 03 ef ca 87 ff 04 25 
    Binary type: 0x0

The difference to an unsigned STM32 image header is that the values for "Signature" and "ECDSA pub key" are not all zeros and that "Option flags" is 0x0 for enabled signature verification instead of 0x1 for disabled signature verification.

Write U-Boot SPL and U-Boot to your boot media

The first step to verify that the built U-Boot SPL and U-Boot works as expected is to program both images to your boot media. Depending on the boot configuration, your DHSOM will boot from the module's SPI-NOR flash, from the module's or baseboard's eMMC or from an SD card. The boot configuration is always defined by the boot pins by default, because the boot pins have no alternative function on the STM32MP15 SoCs.

TODO: How can a user determine the used boot media?
TODO: How to enforce boot media on Secure Boot enabled devices?
Write U-Boot SPL and U-Boot to the SPI-NOR flash of the SoM

The following commands for the U-Boot Shell calculate some addresses based on the image offsets expected by the BootROM, load the required images from SD card or via TFTP into memory and finally write the prepared memory into the SPI-NOR flash on the SoM.

Prepare for loading u-boot-spl-signed.stm32 and u-boot-signed.itb into memory:

mw.b ${loadaddr} 0xff 0x200000
setexpr fsbl1addr ${loadaddr} + 0x0
setexpr fsbl2addr ${loadaddr} + 0x40000
setexpr ssbl1addr ${loadaddr} + 0x80000

Load u-boot-spl-signed.stm32 and u-boot-signed.itb from SD card:

load mmc 0:4 ${fsbl1addr} u-boot-spl-signed.stm32
load mmc 0:4 ${fsbl2addr} u-boot-spl-signed.stm32
load mmc 0:4 ${ssbl1addr} u-boot-signed.itb

Load u-boot-spl-signed.stm32 and u-boot-signed.itb from tftp server:

setenv serverip
setenv ipaddr
setenv netmask
tftp ${fsbl1addr} ${serverip}:u-boot-spl-signed.stm32
tftp ${fsbl2addr} ${serverip}:u-boot-spl-signed.stm32
tftp ${ssbl1addr} ${serverip}:u-boot-signed.itb

Check for magic numbers of expected image headers and conditionally program the SPI-NOR flash:

if itest *${fsbl1addr} == 0x324d5453 && itest *${fsbl2addr} == 0x324d5453 && itest *${ssbl1addr} == 0xedfe0dd0; then
  sf probe && sf update ${loadaddr} 0 0x200000
Write U-Boot SPL and U-Boot to an SD card
Write U-Boot SPL and U-Boot to the eMMC

Enroll, test and enforce BootROM image authentication

To enroll, test and enforce image authentication by the BootROM you need to program the PKH into the OTP of the STM32MP15 SoC. The publicKeyhash.bin file that you created in the Generate key pair with STM32MP_KeyGen_CLI step contains the PKH in binary format for use with the stm32key U-Boot command. If the stm32key command does fail or is not available on the target U-Boot, you can also write the PKH manually with the more generic fuse command into the OTP.

Program public key hash to eFuses

The following commands for the U-Boot Shell load the file publicKeyhash.bin into memory and program the contained PKH to the OTP of the STM32MP15 SoC. The used command stm32key writes and locks the words of the OTP automatically without knowing anything about the OTP layout/addresses. If this fails or the stm32key command is not available, you can also write and lock the OTP with the fuse command

Program publicKeyhash.bin into OTP with stm32key command

Load publicKeyhash.bin from SD card:

load mmc 0:4 ${loadaddr} publicKeyhash.bin

Or load publicKeyhash.bin per TFTP:

setenv serverip
setenv ipaddr
setenv netmask
tftp ${loadaddr} ${serverip}:publicKeyhash.bin

Show the contents of publicKeyhash.bin:

stm32key read ${loadaddr}
Read KEY at 0xc2000000
OTP value 24: 4e31bbcd
OTP value 25: 51e827dd
OTP value 26: 3511f521
OTP value 27: fd9c11a2
OTP value 28: 5b997b82
OTP value 29: 8150adc5
OTP value 30: a9c68fa9
OTP value 31: 72a3ba74

Write the contents of publicKeyhash.bin to OTP with the stm32key command:

stm32key fuse ${loadaddr}
TODO: Add output
Program PKH manually into OTP with fuse command

Generate fuse command with hexdump from file publicKeyhash.bin on linux host:

Warning: Do not use the example output! Only use your unique values for programming the PKH in the OTP!
echo fuse prog -y 0 0x18 $(hexdump -e '/4 "0x"' -e '/1 "%x"' -e '" "' /path/to/publicKeyhash.bin)
fuse prog -y 0 0x18 0x4e31bbcd 0x51e827dd 0x3511f521 0xfd9c11a2 0x5b997b82 0x8150adc5 0xa9c68fa9 0x72a3ba74

Write the PKH into OTP manually with the fuse command:

Warning: Do not use the example command! Only use your unique values for programming the PKH in the OTP!
fuse prog -y 0 0x18 0x4e31bbcd 0x51e827dd 0x3511f521 0xfd9c11a2 0x5b997b82 0x8150adc5 0xa9c68fa9 0x72a3ba74

Lock the related OTP words manually with the fuse command:

fuse prog -y 0 0x10000018 1 1 1 1 1 1 1 1
Test BootROM image authentication

To verify the image authentication by the BootROM with the programmed PKH and the programmed signed images, you must reboot your device.

On the third line of the U-Boot SPL output, check the BootROM authentication status. The status output should look like this: Bootrom authentication: succeeded. Note the succeeded status for successful authentication of the U-Boot SPL image by the BootROM.

The following output shows successful authentication of the U-Boot-SPL image in line 3, as well as successful authentication of the used configuration in line 7 and the U-Boot and Device Tree subimages in lines 8 and 9 of the U-Boot-FIT image.

U-Boot SPL 2022.01-00012-g6c5892c90c28 (Feb 16 2022 - 11:11:16 +0100)
Model: STMicroelectronics STM32MP15xx DHCOM Premium Developer Kit (2)
Bootrom authentication: succeeded
Code:  SoM:rev=1,ddr3=3 Board:rev=0
RAM: DDR3L 32bits 2x4Gb 533MHz
Trying to boot from SPI
## Checking hash(es) for config config-2 ... sha256,rsa4096:fsbl-cfg-2022-02-16+ OK
## Checking hash(es) for Image uboot ... sha256,rsa4096:fsbl-img-2022-02-16+ sha256+ OK
## Checking hash(es) for Image fdt-1 ... sha256,rsa4096:fsbl-img-2022-02-16+ sha256+ OK
Enforce BootROM image authentication

Without any further changes, the BootROM is able to perform authentication of the FSBL image, but unauthenticated images can still be used and executed. The device is still open, let's see this as a kind of test mode to check if the PKH is set correctly.

Once the authentication process is confirmed, the device can be closed and the user is forced to use signed images.

The 6th bit in the 1st word of the OTP is responsible that the BootROM only accepts signed images. Burning this bit enforces authentication of images by the BootROM and unsigned binaries are no longer supported on the target device.

To program this bit, the U-Boot Shell can be used with the stm32key command or with the more general fuse command.

With usage of the stm32key command:

Warning: After running the following command, your device will only be able to boot signed images!
stm32key close

Or with usage of the fuse command:

Warning: After running the following command, your device will only be able to boot signed images!
fuse prog 0 0x0 0x40

Secure Boot in Trusted Boot with BootROM authentication, TF-A and OP-TEE

  1. Add support for STM32MP15 DHCOM in [8]
  2. Add support for STM32MP15 DHCOM in [9]
  3. Create stm32mp15_dhcom_trusted_defconfig???
  4. Integrate STM32MP15 DHCOM into [10]