Literature
- RM0487 STM32U3 Reference Manual
- UM2237 STM32CubeProgrammer software description
- AN5054 Secure programming using STM32CubeProgrammer
- AN2606 STM32 microcontroller system memory boot mode
- AN6205 Introduction to the use of PKA Key wrapping
- PSA API PSA Cryptography API 1.0
- Start by reading the article Initial Attestation STM32U3 How to Introduction
Target description
This application describes how to use the PSA Crypto driver to sign an entity attestation token (EAT) for initial attestation using the DUA (device unique authentication Key).
The provided example is using the STM32U385 Nucleo board, device embedding hardware cryptographic accelerators (STM32 RSSe KW only runs on crypto parts).
Introduction
Through this practical example, the user will learn how to:
- Export Wrapped DUA private Key using RSSe KW
- Generate a challenge and fill the attestation token
- Sign the attestation token using the STM32 Key Wrap Engine and the device user key (DUA_USER or DUA_USLU)
- Generate the EAT (Entity Attestation Token)
- Retrieve DUA certificate from the system flash memory using STM32 software utilities.
Hardware
- U385RG-Q Nucleo board (MB1841)
Required tools
- STM32CubeProgrammer[1] Software programming tool for STM32 (v2.20.0 min)
- IAR Embedded Workbench rev 9.20.1 + patch STM32U37x-38x
- The patch is available in the STM32CubeFW: STM32Cube_FW_U3_Vx.x.x\Utilities\PC_Software
- STM32Cube_FW_U3_V1.1.0 [2] or upper
- Download the STM32CubeU3 package and install
A directory NUCLEO-STM32U385RG-Q is included in the CubeFW Projects directory.
The Applications\MbedTLS_HW_KWE directory contains the example using initial attestation.
- X-CUBE-RSSe [2] Root security System binaries extensions and configuration files package
- Download the X-CUBE-RSSe package
- Unzip and place it in STMicroelectronics/STM32CubeProgrammer/X-CUBE-RSSe:
Once the new package is unzipped, you can use RSSe functionalities with the STM32CubeProgrammer.
1. Execution of the Initial_Attestation_KWE application example
The application retrieves the DUA certificate from the system flash memory using STM32 software utilities.
The DUA certificate contains the DUA's public key and a signature. The public key is used to verify the authenticity of the attestation token.
The coupling and chaining bridge (CCB) and the use of a wrapped DUA private key provide side-channel protected operations to ensure the security of the attestation token creation process.
The user application initiates an attestation request to the initial attestation service.
The attestation token must be filled with claims (for example: device identity, firmware version) and random data (see Step1: Generate a challenge and collect informations to fill the attestation token).
The data items in the token are used to verify the device integrity and assess its trustworthiness.
Attestation key provisioning is out of scope for the attestation service and is expected to take part during manufacturing of the device.
The initial attestation service interacts with the STM32 Hardware Key Wrapping Engine (KWE) through the PSA (Platform Security Architecture) API. The PSA API provides functions for key management, hashing, signing, and exporting public keys.
The following example is shown for IAR Embedded Workbench. But it is applicable for the other supported tool chains.
1.1. Use X-CUBE-RSSe to get the Wrapped DUA Private key
Select which key to use between DUA_USER or DUA_USLU for the initial attestation signature computation.
To understand the differences between the two DUA keys, start by reading the article Initial Attestation STM32U3 How to Introduction.
The Certificate Authority certificate, used to authenticate the DUA_USER chip certificate is public.
The Certificate Authority certificate, used to authenticate the DUA_USLU chip certificate is provided to the customer only if needed.
- Use STM32CubeProgrammer and the RSSe_KW library to export the chosen device unique authentication private key (DUA_USER or DUA_USLU) in wrapped form.
From the repository ...\STM32Cube\STM32CubeProgrammer\bin, execute this command line:
STM32_Programmer_CLI -c port=SWD -rssekw C:\Program Files\STMicroelectronics\STM32Cube\STM32CubeProgrammer\x-cube-rsse-v1-1-0\STM32CubeExpansion_RSSe_V1.1.0\RSSe\STM32U3/RSSe_KW_U375_U385_v1.0.0.bin C:\stm32cubeu3-1-2-0\STM32Cube_FW_U3_V1.2.0\Projects\NUCLEO-U385RG-Q\Applications\MbedTLS_HW_KWE\Initial_Attestation_KWE\Wrapped_Keys/DUA_USLU_DHUK_Sign_NS_Priv.bin KeyType=eccchiplu ExportPublicKey=No WrappingKeySelect=DHUK KeyUsage=ECDSA_USAGE_SIGN SecAttr=NON_SECURE PrivAttr=PRIVILEGE
Here is the success message:
The wrapped key is now copied in a binary format in the folder Wrapped_keys located in Projects\NUCLEO-U385RG-Q\Applications\MbedTLS_HW_KWE\Initial_Attestation_KWE\Wrapped_Keys\DUA_USLU_DHUK_Sign_NS_Priv.bin
1.2. Flash and execute Initial_Attestation_KWE
- Reset the board options bytes using the STM32CubeProgrammer:
The command line previously launched to get the wrapped DUA private key activates the TrustZone and sets the RDP level to 0.5 to protect the RSSe_KW execution environment.
To flash the Initial attestation example a TrustZone and RDP regression shall be performed.
From the repository ...\STM32Cube\STM32CubeProgrammer\bin, execute these command lines:
- Set RDP level to 1:
STM32_Programmer_CLI -c port=SWD mode=HOTPLUG -ob RDP=0xDC
- Once MCU in RDP level 1, TrustZone can be deactivated: Set RDP=0, TZEN=0 and reset MCU to factory settings:
STM32_Programmer_CLI -c port=SWD mode=HOTPLUG -ob RDP=0xAA TZEN=0 SWAP_BANK=0 nBOOT0=1 nSWBOOT0=1 NSBOOTADD0=0x100000 NSBOOTADD1=0x17f1e0 WRP1A_PSTRT=0x7f WRP1A_PEND=0x0 UNLOCK_1A=1 WRP1B_PSTRT=0x7f WRP1B_PEND=0x0 UNLOCK_1B=1 WRP2A_PSTRT=0x7f WRP2A_PEND=0x0 UNLOCK_2A=1 WRP2B_PSTRT=0x7f WRP2B_PEND=0x0 UNLOCK_2B=1 -e all -rst -ob displ
- Open the Initial_Attestation_KWE example.
- The firmware is available at: STM32Cube_FW_U3_Vx.x.x\Projects\NUCLEO-U385RG-Q\Applications\MbedTLS_HW_KWE\Initial_Attestation_KWE
- STM32U385RG should be automatically selected in the product option (see figure below)
- For IAR: menu: Project -> Option -> General Option
- If it's not the case, check if your IDE version is supporting this product or if the STM32U3 patch is correctly installed (see prerequisites at the beginning of this article)
- Edit the command line options to link to the wrapped key obtained X-CUBE-RSSe:
From IAR: menu: Project -> Option -> Linker, adapt the command line options in the window to the path / name where the wrapped key has been generated:
--image_input $PROJ_DIR$\..\Wrapped_Keys\DUA_USLU_DHUK_Sign_NS_Priv.bin,__wrapped_keys_start__,wrapped_keys,4
--keep __wrapped_keys_start__
- Compile the project: Project -> Rebuild All
- Load the code: Project -> Download -> Download active application
- Set the board in RDP level 1 to execute the code: From the repository ...\STM32Cube\STM32CubeProgrammer\bin, execute this command line:
STM32_Programmer_CLI -c port=SWD mode=HOTPLUG -ob RDP=0xDC
- Unplug and plug the board
- The green led will be turned on
- The global variable glob_status will be set to PASSED
2. Application example Steps by steps:
- To be able to perform step by step the RDP level must be set to 0: From the repository ...\STM32Cube\STM32CubeProgrammer\bin, execute these command lines:
- Set RDP level to 1:
STM32_Programmer_CLI -c port=SWD mode=HOTPLUG -ob RDP=0xDC
- Once MCU in RDP level 1, TrustZone can be deactivated: Set RDP=0, TZEN=0 and reset MCU to factory settings:
STM32_Programmer_CLI -c port=SWD mode=HOTPLUG -ob RDP=0xAA TZEN=0 SWAP_BANK=0 nBOOT0=1 nSWBOOT0=1 NSBOOTADD0=0x100000 NSBOOTADD1=0x17f1e0 WRP1A_PSTRT=0x7f WRP1A_PEND=0x0 UNLOCK_1A=1 WRP1B_PSTRT=0x7f WRP1B_PEND=0x0 UNLOCK_1B=1 WRP2A_PSTRT=0x7f WRP2A_PEND=0x0 UNLOCK_2A=1 WRP2B_PSTRT=0x7f WRP2B_PEND=0x0 UNLOCK_2B=1 -e all -rst -ob displ
- Set RDP level to 1:
- Open the Initial_Attestation_KWE example from IAR
- Connect the Nucleo and start the debug session.
- Do a step by step execution to follow the explanations below.
Here are the detailed steps of the example in STM32CubeFW:
The user application initiates an attestation request to the initial attestation service. This service generates an attestation token, which includes claims (e.g., device identity, firmware version) and random data for ensuring freshness.
The initial attestation service interacts with the STM32 Hardware Key Wrapping Engine (KWE) through the PSA (Platform Security Architecture) API. The PSA API provides functions for key management, hashing, signing, and exporting public keys.
2.1. Step1: Generate a challenge and collect informations to fill the attestation token
Generate a challenge and fill the attestation token
- Generate a challenge and fill the attestation token: The chip asks for a random number, also called challenge.
- In a real use case, the challenge must be replaced by one from the server.
- Add to watch: "token"
- At this point, the token is not completely filled:
- This first function will generate a challenge --> the token is completed with this value.Collect device information and fill the attestation token. The user must update information depending on their application.
psa_generate_random(token.challenge, sizeof(token.challenge));
memcpy(token.device_id, (void *)UID_BASE , sizeof(token.device_id)); token.firmware_version = 0x0000001234; token.security_lifecycle = 0x01;
- At this point, the token is not completely filled.
Compute measurements by hashing the firmware data and fill the attestation token.
psa_hash_compute(PSA_ALG_SHA_256,
Firmware_Data, /* Firmware Data to digest */
sizeof(Firmware_Data),
Computed_Hash, /* Data buffer to receive digest data */
sizeof(Computed_Hash), /* Size of hash buffer */
&computed_size); /* Size of computed digest */
- When the digest is completed, it is added to the token field "measurements"
- Right click on Firmware_Data and select Add to Watch
- Do the same for sizeof(Firmware_Data ), Computed_Hash and sizeof(Computed_Hash)
- In the watch window the input message is displayed as written in the constant declaration. The message size is 128 bits (16 x 8)
- "Computed_Hash" in the watch window shows the Hash generated from the Message. The Hash size is 256 bits (32 x 8). It is this value that is added to the token field "measurements".
- Note: Using SHA-256, the Hash length will always be 256-bit long, this for any input message length (also for message lengths smaller than 224 bits)
2.2. Step2: Compute the hash of the attestation token
A hash of the attestation token is generated using psa_hash_compute function.
Compute the hash of the token, excluding the signature field
A hash of the attestation token is generated using psa_hash_compute function.
psa_hash_compute(PSA_ALG_SHA_256,
(uint8_t*)&token, /* Token Data to digest */
sizeof(attestation_token_t) - sizeof(token.signature),
Computed_Hash, /* Data buffer to receive digest data */
sizeof(Computed_Hash), /* Size of hash buffer */
&computed_size); /* Size of computed digest */
2.3. Step3: Import the device user key (DUA_USER or DUA_USLU) to sign the token
The DUA user key is already wrapped using the RSSe_KW library. The Wrapped DUA private key is imported into the STM32 Key Wrap Engine using psa_import_key function and the driver location of STM32 Key Wrap Engine.
DUA user key is already wrapped using the Root Security Services
The wrapped key is available in the Wrapped_keys folder.
The application copied this key at address 0x080FF000 via a compilation linker.
You can watch the memory at this address:
- ECDSA configuration
After initialization of the HAL, the clocks and the BSP, the configuration of the ECDSA is done through the key_attributes structure.
ECDSA configuration
/* Init the key attributes */
key_attributes = psa_key_attributes_init();
/* Setup the key policy for the private key */
psa_set_key_usage_flags(&key_attributes, PSA_KEY_USAGE_SIGN_HASH);
psa_set_key_algorithm(&key_attributes, PSA_ALG_ECDSA(PSA_ALG_SHA_256));
psa_set_key_type(&key_attributes, PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1));
/* Set up key bits using PSA_KWE_ECC_KEY_DUA_USER_BITS */
psa_set_key_bits(&key_attributes, PSA_KWE_ECC_KEY_DUA_USER_BITS);
- The digital signature is done through signing the generated Hash of the input message; selected with attribute: PSA_KEY_USAGE_SIGN_HASH.
- ECDSA signature is selected with attribute: PSA_ALG_ECDSA(PSA_ALG_SHA_256)
- Different possible Hashing algorithms are supported, for this example SHA2-256 is chosen, generating a fixed length 256 bits hash.
- In this example a pair of keys is used, one private (to sign) and one public (to verify the signature), selected with attribute: PSA_KEY_TYPE_ECC_KEY_PAIR
- The argument PSA_ECC_FAMILY_SECP_R1 defines the family of the chosen elliptic curve.
The size of the private key is defining which curve of this family is selected (256 bits for this example, see main.c, Private_Key declaration).
- Resulting in elliptic curve secp256r1.
Wrapped DUA private key import
The Wrapped DUA private key is imported into the STM32 Key Wrap Engine using psa_import_key function and the driver location of STM32 Key Wrap Engine.
This function will add a header to the wrapped key and save it at address 0x080FC000.
/* Set up the key location using PSA_CRYPTO_KWE_DRIVER_LOCATION to import the DUA User key using STM32 Key Wrap Engine (KWE) */
psa_set_key_lifetime(&key_attributes, PSA_KEY_LIFETIME_FROM_PERSISTENCE_AND_LOCATION(PSA_KEY_PERSISTENCE_DEFAULT, PSA_CRYPTO_KWE_DRIVER_LOCATION));
/* Set up DUA user certificate key ID */
psa_set_key_id(&key_attributes, PSA_KWE_ECC_KEY_ID_DUA_USER_LU);
/* Import the DUA user */
retval = psa_import_key(&key_attributes, Private_Key_Blob, (PSA_KWE_ECC_KEY_DUA_USER_BITS/8U), &key_handle_private);
psa_set_key_id: this function sets the lifetime attribute to PSA_KEY_LIFETIME_PERSISTENT. This function does not access storage, it merely stores the given value in the attribute object.
psa_import_key: The key is written to storage and a header is added. you can visualize this at address 0x080FC000.
Add a breakpoint after the psa_import_key function and watch the memory:
2.4. Step4: Token signature generation
Sign the token using the STM32 Key Wrap Engine and the device user key (DUA_USER or DUA_USLU). The hash is signed using the imported Wrapped DUA private key to create a digital signature.
Sign the token using the STM32 Key Wrap Engine and the device user key
The hash is signed using the imported Wrapped DUA private key to create a digital signature.
From this step, the RDP level must be set to 1.
The wrapped key must be unwrapped to do the signature. For this unwrap process, CCB Hardware IP is called to check if the key is OK (with DHUK).
The RDP level must be set to 1 to do this check and the execution step by step is not possible anymore.
psa_sign_hash(key_handle_private,
PSA_ALG_ECDSA(PSA_ALG_SHA_256), /* Algorithm type */
Computed_Hash, sizeof(Computed_Hash), /* Token to sign */
token.signature, sizeof(token.signature), /* Data buf to receive signature*/
&computed_size); /* Size of computed signature */
2.5. Step5: Entity Attestation Token Generation
The signed attestation token, now known as the Entity Attestation Token, is generated.
This token includes the signature and the claims, providing proof of the device identity and integrity.
It can be converted to PEM format
2.6. Step6: Certificate Retrieval
The application retrieves the DUA certificate from the system flash memory using STM32 software utilities. The DUA certificate contains the DUA public key and a signature, which can be used to verify the authenticity of the attestation token.
The coupling and chaining bridge (CCB) and the DUA private key provide side-channel protected operations to ensure the security of the attestation token creation process.
cert_status = UTIL_CERT_GetCertificate(DUA_USER_LU, chip_certificate);
2.7. Destroy the keys to free up resources.
PSA_KEY_PERSISTENCE_DEFAULT: defines that the wrapped private key is stored in the embedded flash and under which condition the key can be destroyed.
3. References
