How to protect the coprocessor firmware

Revision as of 14:38, 22 October 2020 by Registered User (→‎Firmware star and stop)
Under construction.png Registered User (-) 11:42, 24 September 2020 (CEST)
Page under construction

1. Article purpose[edit source]

This article explains how to protect the software loaded by main processor in the coprocessor. It will ensure integrity of the loaded firmware.

2. Introduction[edit source]

The Linux OS through the remoteproc framework allows to load firmware and control remote processors. Thanks to Arm@ Trustzone and resource isolation, it is possible to authenticate a firmware before loading it. It is required to ensure integrity of the running firmware. It could be required for a complete secure platform.

3. Principle[edit source]

The protection of the coprocessor firmware is relying on the signature of the firmware using hash computation and encryption key, but also the isolation of the execution memories.

  • The firmware is signed using a OP-TEE signature script
  • The Firmware is read from the file system by the remoteproc framework and the image is sent to the Arm@ Trustzone.
  • The firmware is authenticated and managed by OP-TEE in the Arm@ Trustzone.

Authenticate rproc fw.png

3.1. Firmware signature[edit source]

A basic strategy to sign a firmware consists in adding an header that will contains the signature required for authentication. The signature is generated by computing a hash of the binary with the header and to encrypt this hash using a key.
On the STM32MP1, the signature procedure is similar but optimized to minimize the memory and accelerate the authentication process. The principle is to compute the hash of the segments to load instead of computing the hash of the full image.

The signature consists in:

  1. Parse the program table in the ELF file to identify the segments to Load.
  2. Compute the hash of each segment and save result in the hash table chunk of the header.
  3. Compute the hash of the header and sign the hash with the private key.

3.2. Authentication[edit source]

The Authentication is executed in the secure context by an OP-TEE trusted application.

  1. The Header is copied in a secure memory to prevent hacking
  2. The Header is verified using the signature and the public key embedded in OP-TEE
  3. The Elf segments are loaded in the MCU RAMs (assigned to secure context). Upon segment load, a hash is computed and compared to the hash stored in the header hash table during the firmware signature.
  4. The execution RAMs are isolated for the Cortex-M4 usage.

3.2.1. Memory Management[edit source]

The MCU SRAM and the RETRAM memories can be dedicated to Cortex-M4 usage (isolated), shared with the the Cortex-A7 non secure context or protected for Cortex-A7 secure access only.
Using the TZC400 mechanism:

  • During the load and authentication phase: The memories can be locked for secure access only.
  • During the execution phase: The memories can be isolated for MCU usage (e.g execution code and data) or shared with the Cortex-A7 non secure context.

Developer has to pay attention for Cortex-M4 firmware build to pack in a same memory bank data shared with the Cortex-A7. This allows to isolate the rest of the memories banks for the Cortex-M4 context.
As the default implementation in OP-TEE respected mapping described in memory mapping section. Descriptions provided in this article respect this mapping too.
The following mapping is considered:

  • The RETRAM, MCU SRAM1 and MCU SRAM2 are used for execution code and data. They are accessible by the Cortex-A secure only when no firmware is running and isolated to Cortex-M4 context during authenticated firmware execution.
  • The MCU SRAM3 (IPC Buffers) is shared between the Cortex-A7 non secure context and the Cortex-M. No protection is applied on this memory bank.
  • The MCU SRAM4 is reserved for the Cortex-A non secure context so not used.

Of course this mapping can be customized by developer depending on project need. In this case the code update as to de done in a synchronized manner in stm32cube firmware, Linux Kernel device-tree and the Op-TEE rproc PTA code.

4. Firmware signature[edit source]

STM32CubeMP1 firmware generationKeys generationSign the STM32CubeMP1_firmwarebuild OPTEE with public KeySignature procedure

4.1. STM32CubeMP1 firmware generation[edit source]

Most of the Stm32CUbeMP1 firmware can be isolated. Develloper has to pay attention to the memories shared with the Cortex-A7 non secure context:

  • the resource table,
  • the log buffer shared through the resource table,
  • the shared buffers for RPMsg communication,
  • other shared buffers defined by the develloper for its project.

4.1.1. The resource table[edit source]

The resource table is linked by default with other firmware data. A specific memory region has to be defined in the linker script to define a new region. In following example we reserve 512 bytes at the begining of the MCU_SRAM3 for the resource table:

/* Memories definition */
MEMORY
{
 m_interrupts (RX)  : ORIGIN = 0x00000000, LENGTH = 0x00000298
 m_text       (RX)  : ORIGIN = 0x10000000, LENGTH = 0x00020000
 m_data       (RW)  : ORIGIN = 0x10020000, LENGTH = 0x00020000
 m_rsc_table  (RW)  : ORIGIN = 0x10040000, LENGTH = 0x00000200
 m_ipc_shm    (RW)  : ORIGIN = 0x10040200, LENGTH = 0x0000FE00
}
.resource_table :
{
  . = ALIGN(4);
  KEEP (*(.resource_table*))
  . = ALIGN(4);
} > m_rsc_table

4.1.2. log buffer[edit source]

The log buffer can be enable in the resource table to get Cortex-M4 log from the Cortex-A7 non secure context. To define it

  • an attribute has to be added to the system_log_buf buffer:
#if defined(__GNUC__) 
#define __section_t(S)          __attribute__((__section__(#S)))
#define __resource              __section_t(.sys_logs)
#endif

char  __resource __attribute__((used)); system_log_buf[SYSTEM_TRACE_BUF_SZ];
  • Update the linker script to extend the m_rsc_table memory region and add to it the log buffer
MEMORY
{
 m_interrupts (RX)  : ORIGIN = 0x00000000, LENGTH = 0x00000298
 m_text       (RX)  : ORIGIN = 0x10000000, LENGTH = 0x00020000
 m_data       (RW)  : ORIGIN = 0x10020000, LENGTH = 0x00020000
 m_rsc_table  (RW)  : ORIGIN = 0x10040000, LENGTH = 0x00001000
 m_ipc_shm    (RW)  : ORIGIN = 0x10041000, LENGTH = 0x0000F000
}

.sys_logs :
{
  . = ALIGN(4);
  KEEP (*(.sys_logs*))
  . = ALIGN(4);
} > m_rsc_table

4.1.3. RPMsg shared buffer[edit source]

The memory region for these buffers are already reserved tnaks to the m_ipc_shm memory region defined in the linker script.

4.2. Generate private and public key[edit source]

To sign and authenticate the coprocessor firmware a RSA key as to be generated. For instance the ssh-keygen command can be used.

 ssh-keygen

Two files are created:

  • id_rsa: the private key to sign the firmware.
  • id_rsa.pub: the public key to authenticate the firmware.

4.3. Sign STM32CubeMP1 firmware[edit source]

The OP-TEE ST-Microelectronics distribution integrates the sign_rproc_fw.py than allows to sign the firmware binary ELF file. This script:

  • Add an header on top of the ELF binary
  • compute the hash of the program segments that will be loaded in the Cortex-M4 memories and fill the hash table included in the header
  • Compute the hash of the header and sign it using the private key.

To sign the firmware :

  • Use the default key available in the optee repository : keys/default_rproc.pem
in this case the default key can be updated by is own generated RSA private key:
 ./scripts/sign_rproc_fw.py sign --in <firmware name>
  • Or specify the key to use as parameter:
 ./scripts/sign_rproc_fw.py sign --in <firmware name> --key <id_rsa private key>
  • For more script options:
 ./scripts/sign_rproc_fw.py sign --help

The signed firmware is available in the ELF file directory with a .sign extension.

4.4. OP-TEE remoteproc TA generation[edit source]

The OPTEE OS firmware has to be re-generated to include:

  • the remote processor Trusted Application(TA)
  • the remote processor platform Pseudo trusted application(PTA)
  • the public key


4.4.1. Configuration[edit source]

Enable the CFG_RPROC_PTA in core/arch/arm/plat-stm32mp1/conf.mk

CFG_RPROC_PTA ?= y

4.4.2. Build the OP-TEE OS[edit source]

As prerequisite the OP-TEE OS build environment has to be installed.
Additional directives to build OP-TEE OS:

  • CFG_IN_TREE_EARLY_TAS=remoteproc/80a4c275-0a47-4905-8285-1486a9771a08 : add remoteproc early TA.
  • CFG_RPROC_SIGN_KEY= <key file path name>: specify the public key file to authenticate the remote processor firmware. This directive is optional. If not defined the keys/default_rproc.pem default key will be used.

Example of buil command for the STM32MP157x-DK2 board:

  • Using the default key available in the OP-TEE repository to build the OP-TEE OS: keys/default_rproc.pem
in this case the default key can be updated by is own generated RSA private key:
 make PLATFORM=stm32mp1 CFG_EMBED_DTB_SOURCE_FILE=stm32mp157c-dk2.dts CFG_SECURE_DT=stm32mp157c-dk2 O=out all  comp-cflagscore=--sysroot=$SDKTARGETSYSROOT CFG_IN_TREE_EARLY_TAS=remoteproc/80a4c275-0a47-4905-8285-1486a9771a08
  • Or specify the key to use by defining CFG_RPROC_SIGN_KEY:
 make PLATFORM=stm32mp1 CFG_EMBED_DTB_SOURCE_FILE=stm32mp157c-dk2.dts CFG_SECURE_DT=stm32mp157c-dk2 O=out all  comp-cflagscore=--sysroot=$SDKTARGETSYSROOT CFG_IN_TREE_EARLY_TAS=remoteproc/80a4c275-0a47-4905-8285-1486a9771a08 CFG_RPROC_SIGN_KEY=my_public_key.pem

4.4.3. Update the software on board[edit source]

Refer to update OP-TEE software on board for details.

5. Autneticated Firmware livecycle[edit source]

Authentication software overview.png

The management of the firmware live cycle does not change from user point of view and is described in the remoteproc article.

The main difference with an autheticated firmware is that the remote processor framework delegate the coprocessor management to the OP-TEE. The load of an Authenticated firmware by U-boot is also supported.

5.1. Firmware load and authentication[edit source]

Authentication Fw load phase1.png

1. The firmware in copied by the Linux Kernel Or U-boot in a non secure DDR memory.
2. The firmware iheader is copied in a secure memory to garanty is integrity during the authentication.
3. The Header hash is computed.
4. The signature is decrypted using the public key. the result is the hash of the header computed by the signing tools. Both hashes are compared to authentified the firmware header.
5. At this step the firmware header is valid. the next step can start: loaad the the firmware in MCU memories:

Authentication Fw load phase2.png

For each segment to load:
6. the segment is copied in the MCU RAm which is accessible only by the secure context to ensure it integrity.
7. the hash of the copied segment is computes and compare to the hash stored in the firmware header.
8. At this step all segments have been copied and Authentified, the firmware is loaded.

5.2. Firmware start and stop[edit source]

The firmware is started and stopped by OP-TEE. The reset and RAMs access right are only accessible by the secure context.

  • Before starting the firmware the MCU rams access rignt are updated to isolate execution RAMs for the Cortex-M4.
  • After stopping the firmware the MCU SRAM are cleaned and acces right are updated to secure context.

5.3. RPMsg management[edit source]

As the resource tables and RPMsg vrings and buffers are in a shared memory it is possible to communicate with the Authenticated firmware.

5.4. Firmware core dump[edit source]

As the Memories are protected it is not possible to dump the firmware on crash.

6. Firmware signature[edit source]

The coprocessor firmware can be signed in the same way as the bootloader using Signing Tool. It will add a complete header that will contains the public key and the signature required for authentication. Using this tool is compliant with the authentication processing that is already done for bootloader authentication. This authentication is ECDSA based.

./STM32AP_SigningTool_CLI -bin /home/User/Folder1/BinaryFile.bin –pubk /home/user/publicKey.pem –prvk /home/user/privateKey.pem –iv 0 –pwd azerty –s –la 0x20000000 –ep 0x08000000 –a 2 –o /home/user/Folder2/Folder3/signedFile.bin -type copro