STMicroelectronics delivers a TFM application to test and understand its implementation of the Trusted Firmware. Let’s see what the first run of the Trusted Firmware application provides.
The second article of the series on Trusted Firmware shows how to import the TFM application of STMicroelectronics and the first run of the application on a STM32L562E-DK.
The other articles of the series are:
The TFM application is available for STM32CubeIDE, Keil and IAR. In this example STM32CubeIDE is going to be used as it is provided for free, does not require any license and integrates STM32CubeMX and STM32CubeProgrammer which facilitates the configuration of the micro-controller and its programming.
STMicroelectronics provides, through its STM32Cube ecosystem, every tool necessary to compile the TFM application and to program a development kit.
To avoid any path issue, it is recommended to install these tools (at least the IDE) in a path not containing spaces, i.e. «C:\ST\». The installation steps are:
The TFM source code example contains three subprojects:
These subprojects can be imported in STM32CubeIDE after having installed the STM32Cube MCU & MPU Package for the STM32L5 (v1.4.0). To do so in STM32CubeIDE, open «Help > Manage Embedded Software Packages», scroll down until «STM32L5» and select version 1.4.0. Finally, click on «Install Now».
The import procedure of the code examples must be repeated for all three subprojects. In STM32CubeIDE:
Repeat the same process for TFM_SBSFU_Boot and TFM_Loader. After importing the three subprojects, the Project Explorer of STM32CubeIDE should look like the following image.
The STM32L562E-DK must be initialized first before being able to load the TFM applications.
Connect the STM32L562E-DK via USB to the computer. Use the micro-USB port named “STLK USB” on the right side of the board. STMicroelectronics suggests using a script to do this automatically, which is a good idea to avoid any wrong configuration [UM2671, §10.1]. Simply drag and drop the script
C:\Users\…\STM32Cube\Repository\STM32Cube_FW_L5_V1.4.0\Projects\STM32L562E-DK\Applications\TFM\TFM_SBSFU_Boot\STM32CubeIDE\regression.sh
in STM32CubeIDE and verify that the script has been correctly executed!
The configuration can be manually verified by connecting the STM32CubeProgrammer. Select the Hot Plug Mode and click Connect. The programmer should show the following target information.
The configuration is present in the OB (Option Bytes) tabulation. The table below summarises the configuration present in [UM2671, §10.1] and that should now be applied to your board.
Category | Option | Value |
Read Out Protection | RDP | AA |
User Configuration | SWAP_BANK | Unchecked |
DBANK | Checked | |
SRAM2_RST | Unchecked | |
TZEN | Checked | |
HDP1EN | Unchecked | |
HDP1_PEND | Value 0x00, Address 0x08000000 | |
HDP2EN | Unchecked | |
HDP2_PEND | Value 0x00, Address 0x08000000 | |
SECBOOTADD0 | Value 0x180052, Address 0x0c002900 | |
Secure Area 1 | SECWM1_PSTRT | Value 0x00, Address 0x08000000 |
SECWM1_PEND | Value 0x7f, Address 0x0803f800 | |
Write Protection 1 | WRP1A_PSTRT | Value 0x7f, Address 0x0803f800 |
WRP1A_PEND | Value 0x00, Address 0x08000000 | |
WRP1B_PSTRT | Value 0x7f, Address 0x0803f800 | |
WRP1B_PEND | Value 0x00, Address 0x08000000 | |
Secure Area 2 | SECWM2_PSTRT | Value 0x00, Address 0x08040000 |
SECWM2_PEND | Value 0x7f, Address 0x0807f800 | |
Write Protection 2 | WRP2A_PSTRT | Value 0x7f, Address 0x0807f800 |
WRP2A_PEND | Value 0x00, Address 0x08040000 | |
WRP2B_PSTRT | Value 0x7f, Address 0x0807f800 | |
WRP2B_PEND | Value 0x00, Address 0x08040000 |
The compilation procedure requires 4 sub steps [UM2671, §10.2] as depicted in Figure 24.
The file boot_hal_cfg.h contains the configuration of the TFM_SBSFU_Boot application. However, when importing the project using STM32CubeIDE as we did earlier in this article, the configuration file is not added to the workspace. This can fortunately be fixed easily:
Once done, open the configuration file. According to [UM2671, §10.1], the user should verify its content and adapt it based on his/her needs:
In addition, make sure that flag TFM_DEV_MODE is present in the «Paths and Symbols»; this makes the software compile in development mode, allowing some automatic configurations of the static protections and logging of TFM_SBSFU_Boot on the terminal emulation. To do so, open the properties of the project and then «C/C++ General > Paths and Symbols > Symbols» as shown in figure below.
Of course, this configuration does not ensure a secured device, but let’s keep in mind that this is a first attempt to use and understand the trusted firmware. The configuration will be hardened later. The diff of the modifications is:
diff --git a/TFM_SBSFU_Boot/Inc/boot_hal_cfg.h b/TFM_SBSFU_Boot/Inc/boot_hal_cfg.h index c3e1ce2c5e26453330583333876737d20aa4eca0..720d97e458b3293c16049822530542fcc669190d 100644 --- a/TFM_SBSFU_Boot/Inc/boot_hal_cfg.h +++ b/TFM_SBSFU_Boot/Inc/boot_hal_cfg.h @@ -39,7 +39,7 @@ /* Static protection checking Flag */ #define TFM_WRP_PROTECT_ENABLE /*!< Write Protection */ #define TFM_HDP_PROTECT_ENABLE /*!< HDP protection */ -#define TFM_OB_RDP_LEVEL_VALUE OB_RDP_LEVEL_1 /*!< RDP level */ +#define TFM_OB_RDP_LEVEL_VALUE OB_RDP_LEVEL_0 /*!< RDP level */ #define TFM_SECURE_USER_SRAM2_ERASE_AT_RESET /*!< SRAM2 clear at Reset */ #ifdef TFM_DEV_MODE #define TFM_OB_BOOT_LOCK 0 /*!< BOOT Lock expected value */
An additional modification is still required because the postbuild script (postbuild.sh) contains some errors that must be corrected. Edit the file according to these changes:
diff --git a/TFM_SBSFU_Boot/STM32CubeIDE/postbuild.sh b/TFM_SBSFU_Boot/STM32CubeIDE/postbuild.sh index 58145eb8abe309eadff1d201579daa6385dc29ca..da3b5ba0bbb30c5074274d2633413da7cfe9448f 100644 --- a/TFM_SBSFU_Boot/STM32CubeIDE/postbuild.sh +++ b/TFM_SBSFU_Boot/STM32CubeIDE/postbuild.sh @@ -11,7 +11,7 @@ postbuild=$projectdir/../../TFM_Appli/STM32CubeIDE/postbuild.sh current_directory=`pwd` echo $current_directory -cd $projectdir"/../../Middlewares/Third_Party/mcuboot" +cd $projectdir"/../Middlewares/Third_Party/mcuboot" mcuboot=`pwd` cd $current_directory @@ -196,7 +196,6 @@ if [ $ret != 0 ]; then echo "postbuild.sh failed" exit 1 fi -echo $hardeningbat" updated" echo $hardening" updated" echo $postbuild" updated" exit 0
Finally, build the project by clicking on «Project > Build Project»:
The release folder should contain a binary file named TFM_SBSFU_Boot.bin.
The build of the TFM_Appli Secure and Non-Secure applications do not require any specific configuration. The Secure application must be built first and the Non-Secure application second (click on «Project > Build Project», for each project, as shown in the previous section).
At the end of the build, the respective release folder should contain a binary file; TFM_Appli_Secure.bin for the Secure application and TFM_Appli_NonSecure.bin for the Non-Secure application. In addition, the postbuild script creates two new binaries per application, thus four in total: the first is a signed binary and the second is a signed and encrypted binary. The script saves them in a folder named «Binary» in the root directory of TFM_Appli. The script currently uses default signature and encryption keys. Let’s keep them to ease the test of TFM and change them on a second stage.
Similar to the build of TFM_Appli applications, the build of TFM_Loader is quite easy; just click on «Project > Build Project». The release folder should contain the binary file TFM_Loader.bin. Another similarity is that a postbuild script creates a derived binary (the loader image) and saves it in a folder named «Binary» in the root directory of TFM_Loader.
The project provides a script (TFM_UPDATE.sh) that programs all binaries generated during the build process [UM2671, §10.3]. The script is updated during the postbuild of TFM_SBSFU_Boot application to ensure that binaries are programmed at the correct memory locations.
If you installed the tools in the non-default path, two little changes to the script are necessary as it contains the full path to STM32CubeProgrammer. Modify the value of PATH and external_loader as suggested in the patch below.
diff --git a/TFM_SBSFU_Boot/STM32CubeIDE/TFM_UPDATE.sh b/TFM_SBSFU_Boot/STM32CubeIDE/TFM_UPDATE.sh index fe5d7cbaef08284da59f010c188c14356a13223b..c58e9e0e86effddb2e307b14a0587e1a877da2f4 100644 --- a/TFM_SBSFU_Boot/STM32CubeIDE/TFM_UPDATE.sh +++ b/TFM_SBSFU_Boot/STM32CubeIDE/TFM_UPDATE.sh @@ -4,9 +4,9 @@ echo "TFM_UPDATE started" SCRIPT=$(readlink -f $0) # Absolute path this script SCRIPTPATH=`dirname $SCRIPT` -PATH="/C/Program Files/STMicroelectronics/STM32Cube/STM32CubeProgrammer/bin/":$PATH +PATH="/C/ST/STM32CubeProgrammer/bin/":$PATH stm32programmercli="STM32_Programmer_CLI" -external_loader="C:\PROGRA~1\STMicroelectronics\STM32Cube\STM32CubeProgrammer\bin\ExternalLoader\MX25LM51245G_STM32L562E-DK.stldr" +external_loader="C:\ST\STM32CubeProgrammer\bin\ExternalLoader\MX25LM51245G_STM32L562E-DK.stldr" connect_no_reset="-c port=SWD mode=UR -el $external_loader" connect="-c port=SWD mode=UR --hardRst -el $external_loader" slot0=0xc017000
Finally, connect the STM32F562E-DK and execute TFM_UPDATE.sh. Verify that the script was correctly executed, it must display:
[…] TFM_Appli Secure Written […] TFM_Appli NonSecure Written […] TFM_Loader Written […] TFM_SBSFU_Boot Written […] TFM_UPDATE script Done, press a key
Open Tera Term and configure the new connection [UM2671, §10.5] with:
Then, click on menu «Setup», choose «Serial port…» and configure the serial port with:
Click on «New setting» to validate.
Press the reset button on the board. As the security mechanisms have been configured on purpose to the lowest level, the board shouldn’t have any problem to boot because the RDP (read protection option bytes) was set to level 0. The TFM_SBSFU_Boot application starts, verifies the configuration, and corrects it if necessary as we set the flag TFM_DEV_MODE. The first boot should look like
[INF] BANK 1 secure flash [0, 117] : OB [0, 127] [ERR] Unexpected value for secure flash protection: set wmsec1 [INF] BANK 2 secure flash [127, 0] : OB [0, 127] [INF] BANK 1 flash write protection [4, 35] : OB [127, 0] [ERR] Unexpected value for write protection : set wrp1 [INF] BANK 2 flash write protection [116, 127] : OB [127, 0] [ERR] Unexpected value for write protection : set wrp2 [INF] BANK 1 secure user flash [0, 34] : OB [0, 0] [ERR] Unexpected value for secure user flash protection : set hdp1 [INF] Starting bootloader [INF] Initializing BL2 NV area : Power down/reset not supported... [INF] Init BL2 NV Header area: Done [INF] Initializing BL2 NV Counters [INF] Init BL2 NV counters to 0 : Done [INF] BL2 NV Area Initialized : Power Down/reset supported [INF] Checking BL2 NV area [INF] Checking BL2 NV area header [INF] Checking BL2 NV Counter consistency [INF] Consistent BL2 NV Counter 3 = 0x0 [INF] Consistent BL2 NV Counter 4 = 0x0 [INF] Swap type: none [INF] Swap type: none [INF] verify counter 0 1000000 0 [INF] counter 0 : ok [INF] verify sig key id 0 [INF] signature OK [INF] Counter 3 set to 0x1000000 [INF] verify counter 1 1000000 0 [INF] counter 1 : ok [INF] verify sig key id 1 [INF] signature OK [INF] 2f, fd, 66, 8e, b6, 87 , af ,8c, [INF] 62, e6, e3, f5, d1, b9 , f3 ,a3, [INF] Counter 4 set to 0x1000000 [INF] Bootloader chainload address offset: 0x17000 [INF] Jumping to the first image slot set to BL2 SHARED DATA2XX_HUK_CUSTOMIZATION_ [INF] Code c002900 c011bee [INF] hash TFM_SBSFU_Boot f27557 .. e8fc7444 [INF] otfdec key … [INF] otfdec key … [Sec Thread] Secure image initializing!
Then the non-secure application should take over and display
====================================================================== = (C) COPYRIGHT 2019 STMicroelectronics = = = = User App #A = ====================================================================== =================== Main Menu ============================ Test Protections -------------------------------------- 1 Test TFM ---------------------------------------------- 2 Selection :
Two options are available:
TFM has a very complex source code. Therefore, it is not the goal to understand it in this article. However, it may be interesting after this set up to understand some steps that TFM takes.
The short example below follows the execution of PSA_CONNECT()
for the test of AES-GCM:
main()
calls tfm_app_menu()
to enter «Test TFM» after key 2 is pressedtfm_app_menu()
calls psa_aead_test()
to enter «AES GCM Test» after key 0 is pressedpsa_aead_test()
calls psa_allocate_key()
to allocate a transient keypsa_allocate_key()
calls PSA_CONNECT(TFM_CRYPTO)
to connect to PSAPSA_CONNECT()
calls psa_connect(TFM_CRYPTO_SID, TFM_CRYPTO_VERSION)
psa_connect()
calls tfm_ns_interface_dispatch(tfm_psa_connect_veneer)
tfm_ns_interface_dispatch()
calls tfm_psa_connect_veneer(…)
tfm_psa_connect_veneer()
calls TFM_CORE_NS_IPC_REQUEST_VENEER(tfm_svcall_psa_connect)
TFM_CORE_NS_IPC_REQUEST_VENEER
calls tfm_core_ns_ipc_request(tfm_svcall_psa_connect)
tfm_core_ns_ipc_request()
calls tfm_core_ipc_request(tfm_svcall_psa_connect)
tfm_core_ipc_request()
calls
ASM SVC TFM_SVC_IPC_REQUEST()
which is the Supervisor call: the «argument» is ignored by the processor but can be retrieved by the exception handler to determine which service is being calledASM BX LR
which is a branch and exchange instruction set operation: the address to jump to is held in register LR (Link Register) which is used to store the return address when a subroutine call is madeThe Secure Application retrieves the supervisor call with:
tfm_core_svc_handler()
calls tfm_psa_ipc_request_handler(svc_args)
which handles IPC requeststfm_psa_ipc_request_handler()
handles the request and calls function from SVC contextThis article presented the set up of the STM32L562E-DK with the TFM application.
The set up itself was quite easy as it followed the steps given by the user manual. The good configuration and the use of TFM are, however, more difficult to master, and the code itself is quite complex to understand.
In the next article we will try to take advantage of TFM by using some secure services.
[…] First run of the Trusted Firmware (TFM) application presents the first run of the TFM application […]