Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 46 additions & 0 deletions .github/workflows/trustzone-emulator-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,52 @@ jobs:
grep -q "\\[BKPT\\] imm=0x7f" /tmp/m33mu-fwtpm.log
grep -q "\\[EXPECT BKPT\\] Success" /tmp/m33mu-fwtpm.log

- name: Clean and build test with wolfHSM (stm32h5)
run: |
make clean distclean
cp config/examples/stm32h5-tz-wolfhsm.config .config
make

- name: Prepare wolfHSM persistence directory
run: |
rm -rf /tmp/m33mu-wolfhsm-persist
mkdir -p /tmp/m33mu-wolfhsm-persist
rm -f /tmp/m33mu-wolfhsm-first.log /tmp/m33mu-wolfhsm-second.log

- name: Run wolfHSM first boot (stm32h5)
run: |
cd /tmp/m33mu-wolfhsm-persist
m33mu "$GITHUB_WORKSPACE/wolfboot.bin" \
"$GITHUB_WORKSPACE/test-app/image_v1_signed.bin:0x60000" \
--persist --uart-stdout --timeout 120 --expect-bkpt 0x7d \
| tee /tmp/m33mu-wolfhsm-first.log

- name: Verify wolfHSM first boot (stm32h5)
run: |
grep -q "wolfHSM CommInit ok" /tmp/m33mu-wolfhsm-first.log
grep -q "wolfHSM RNG ok:" /tmp/m33mu-wolfhsm-first.log
grep -q "wolfHSM SHA256 ok" /tmp/m33mu-wolfhsm-first.log
grep -q "wolfHSM AES ok" /tmp/m33mu-wolfhsm-first.log
grep -q "wolfHSM first boot path, committing key to NVM" /tmp/m33mu-wolfhsm-first.log
grep -q "wolfHSM NSC tests passed" /tmp/m33mu-wolfhsm-first.log
grep -q "\\[BKPT\\] imm=0x7d" /tmp/m33mu-wolfhsm-first.log
grep -q "\\[EXPECT BKPT\\] Success" /tmp/m33mu-wolfhsm-first.log

- name: Run wolfHSM second boot (stm32h5)
run: |
cd /tmp/m33mu-wolfhsm-persist
m33mu "$GITHUB_WORKSPACE/wolfboot.bin" \
"$GITHUB_WORKSPACE/test-app/image_v1_signed.bin:0x60000" \
--persist --uart-stdout --timeout 120 --expect-bkpt 0x7f \
| tee /tmp/m33mu-wolfhsm-second.log

- name: Verify wolfHSM second boot (stm32h5)
run: |
grep -q "wolfHSM second boot path, restored persisted key" /tmp/m33mu-wolfhsm-second.log
grep -q "wolfHSM NSC tests passed" /tmp/m33mu-wolfhsm-second.log
grep -q "\\[BKPT\\] imm=0x7f" /tmp/m33mu-wolfhsm-second.log
grep -q "\\[EXPECT BKPT\\] Success" /tmp/m33mu-wolfhsm-second.log

- name: Clean and build test with DICE attestation + OTP (stm32h5)
run: |
make clean distclean
Expand Down
35 changes: 35 additions & 0 deletions config/examples/stm32h5-tz-wolfhsm.config
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
ARCH?=ARM
TZEN?=1
TARGET?=stm32h5
SIGN?=ECC256
HASH?=SHA256
DEBUG?=0
VTOR?=1
CORTEX_M0?=0
CORTEX_M33?=1
NO_ASM?=0
NO_MPU=1
EXT_FLASH?=0
SPI_FLASH?=0
ALLOW_DOWNGRADE?=0
NVM_FLASH_WRITEONCE?=1
WOLFBOOT_VERSION?=1
V?=0
SPMATH?=1
RAM_CODE?=1
DUALBANK_SWAP?=0
WOLFBOOT_PARTITION_SIZE?=0xA0000
WOLFBOOT_SECTOR_SIZE?=0x2000
WOLFBOOT_KEYVAULT_ADDRESS?=0x0C040000
WOLFBOOT_KEYVAULT_SIZE?=0x1C000
WOLFBOOT_NSC_ADDRESS?=0x0C05C000
WOLFBOOT_NSC_SIZE?=0x4000
WOLFBOOT_PARTITION_BOOT_ADDRESS?=0x08060000
WOLFBOOT_PARTITION_UPDATE_ADDRESS?=0x0C100000
WOLFBOOT_PARTITION_SWAP_ADDRESS?=0x0C1A0000
FLAGS_HOME=0
DISABLE_BACKUP=0
WOLFCRYPT_TZ=1
WOLFCRYPT_TZ_WOLFHSM=1
IMAGE_HEADER_SIZE?=1024
ARMORED=1
13 changes: 13 additions & 0 deletions docs/STM32-TZ.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,19 @@ The `WOLFCRYPT_TZ_PSA` option provides a standard PSA Crypto interface using
wolfPSA in the secure domain. The key storage uses the same secure flash
keystore backend as PKCS11, exposed through the wolfPSA store API.

### wolfHSM API in non-secure world

The `WOLFCRYPT_TZ_WOLFHSM` option hosts a wolfHSM server inside the secure
domain and exposes it to non-secure applications through a single non-secure
callable veneer. Non-secure code uses the standard wolfCrypt API with the
wolfHSM client cryptocb registered under `WH_DEV_ID`; key material, the
keystore, and crypto operations stay in the secure domain. Persistent keys
live in the same secure flash keystore region used by PKCS11 and PSA, with
two-partition journaling for power-fail safety.

See [wolfHSM](wolfHSM.md) for the full configuration, build, flash, and
test recipe on STM32H5.

### PSA Initial Attestation (DICE)

When `WOLFCRYPT_TZ_PSA=1` is enabled, wolfBoot exposes the PSA Initial
Expand Down
49 changes: 49 additions & 0 deletions docs/wolfHSM.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ wolfBoot supports using wolfHSM on the following platforms:

- wolfBoot simulator (using wolfHSM POSIX TCP transport)
- AURIX TC3xx (shared memory transport)
- STM32H5 TrustZone (the secure-side wolfBoot hosts a wolfHSM server and exposes it to the non-secure application through a single NSC veneer; see [STM32H5 TrustZone Engine](#stm32h5-trustzone-engine) below)

Details on configuring wolfBoot to use wolfHSM on each of these platforms can be found in the wolfBoot (and wolfHSM) documentation specific to that target, with the exception of the simulator, which is documented here. The remainder of this document focuses on the generic wolfHSM-related configuration options.

Expand Down Expand Up @@ -238,3 +239,51 @@ When using wolfHSM server mode, no external server is required. wolfBoot include
```

The embedded wolfHSM server will automatically handle all cryptographic operations and key management using the file-based NVM storage(`wolfBoot_wolfHSM_NVM.bin`) that was generated above.

## STM32H5 TrustZone Engine

On STM32H5, wolfBoot can host a wolfHSM server in the secure TrustZone image and expose it to the non-secure application through a single non-secure-callable veneer (`wcs_wolfhsm_transmit`). The non-secure side runs the standard wolfHSM client API, which auto-registers a wolfCrypt cryptocb under `WH_DEV_ID`, so application-level wolfCrypt calls that pass that device ID transparently round-trip to the secure server.

This is a separate deployment shape from the wolfHSM client/server modes documented above; it does not use `WOLFBOOT_ENABLE_WOLFHSM_CLIENT/SERVER` or the `hsmClientCtx`/`hsmServerCtx` HAL hooks, and is mutually exclusive with the other STM32H5 TrustZone engines (`WOLFCRYPT_TZ_PKCS11`, `WOLFCRYPT_TZ_PSA`, `WOLFCRYPT_TZ_FWTPM`).

### Build

```sh
cp config/examples/stm32h5-tz-wolfhsm.config .config
make
```

For on-board hardware testing, add `WOLFBOOT_TZ_TEST_NO_BKPT=1` so the auto-test prints a UART pass/fail line and idles in `while (1)` instead of issuing `bkpt #0x7f` (which HardFaults on real silicon without a debugger):

```sh
make WOLFBOOT_TZ_TEST_NO_BKPT=1
```

### Flash

The wolfBoot helper programs the option bytes the secure boot path requires (`TZEN`, `SECBOOTADD`, `SECWM1`/`SECWM2`); see [STM32-TZ.md](STM32-TZ.md) for the option-byte details:

```sh
./tools/scripts/set-stm32-tz-option-bytes.sh
STM32_Programmer_CLI -c port=swd -d wolfboot.bin 0x0C000000
STM32_Programmer_CLI -c port=swd -d test-app/image_v1_signed.bin 0x08060000
```

### Test

The non-secure test application runs the wolfHSM auto-test at startup. A successful first boot ends with:

```text
wolfHSM CommInit ok (client=1 server=...)
wolfHSM RNG ok: <16 random bytes>
wolfHSM SHA256 ok
wolfHSM AES ok
wolfHSM first boot path, committing key to NVM
wolfHSM NSC tests passed
```

The default build raises `bkpt #0x7d` on first-boot success and `bkpt #0x7f` on second-boot success (after the persisted key is reloaded from flash on reset). The `WOLFBOOT_TZ_TEST_NO_BKPT=1` build prints a final `WOLFHSM_TZ_TEST_PASS` UART line instead. Reset the board (no re-flash) to verify persistence; the second boot prints `wolfHSM second boot path, restored persisted key`.

### Notes

The wolfHSM NVM lives in the existing `FLASH_KEYVAULT` region (112 KiB at `0x0C040000`) shared with the other STM32H5 TrustZone engines. The flash adapter (`src/wolfhsm_flash_hal.c`) caches the affected sector, modifies it, and rewrites the whole 8 KiB sector in one erase + program cycle, mirroring `psa_store.c` / `pkcs11_store.c`. This satisfies the H5 quad-word ECC rule that each 16-byte unit may be programmed exactly once between erases, which wolfHSM's 8-byte-unit writes would otherwise violate.
6 changes: 4 additions & 2 deletions include/user_settings.h
Original file line number Diff line number Diff line change
Expand Up @@ -756,12 +756,14 @@ extern int tolower(int c);
#endif

#if defined(WOLFBOOT_ENABLE_WOLFHSM_CLIENT) || \
defined(WOLFBOOT_ENABLE_WOLFHSM_SERVER)
defined(WOLFBOOT_ENABLE_WOLFHSM_SERVER) || \
defined(WOLFCRYPT_TZ_WOLFHSM)
# define WOLF_CRYPTO_CB
# undef HAVE_ANONYMOUS_INLINE_AGGREGATES
# define HAVE_ANONYMOUS_INLINE_AGGREGATES 1
# define WOLFSSL_KEY_GEN
#endif /* WOLFBOOT_ENABLE_WOLFHSM_CLIENT || WOLFBOOT_ENABLE_WOLFHSM_SERVER */
#endif /* WOLFBOOT_ENABLE_WOLFHSM_CLIENT || WOLFBOOT_ENABLE_WOLFHSM_SERVER ||
WOLFCRYPT_TZ_WOLFHSM */

#if defined(WOLFBOOT_ENABLE_WOLFHSM_SERVER) && \
defined(WOLFBOOT_CERT_CHAIN_VERIFY)
Expand Down
23 changes: 23 additions & 0 deletions include/wolfboot/wcs_wolfhsm.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
/* wcs_wolfhsm.h
*
* Copyright (C) 2026 wolfSSL Inc.
*
* This file is part of wolfBoot.
*/

#ifndef WOLFBOOT_WCS_WOLFHSM_H
#define WOLFBOOT_WCS_WOLFHSM_H

#include <stdint.h>
#include "wolfboot/wc_secure.h"

#ifdef WOLFCRYPT_TZ_WOLFHSM

int CSME_NSE_API wcs_wolfhsm_transmit(const uint8_t *cmd, uint32_t cmdSz,
uint8_t *rsp, uint32_t *rspSz);

void wcs_wolfhsm_init(void);

#endif /* WOLFCRYPT_TZ_WOLFHSM */

#endif /* WOLFBOOT_WCS_WOLFHSM_H */
30 changes: 30 additions & 0 deletions include/wolfboot/wolfhsm_flash_hal.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
/* wolfhsm_flash_hal.h
*
* Copyright (C) 2026 wolfSSL Inc.
*
* This file is part of wolfBoot.
*/

#ifndef WOLFBOOT_WOLFHSM_FLASH_HAL_H
#define WOLFBOOT_WOLFHSM_FLASH_HAL_H

#ifdef WOLFCRYPT_TZ_WOLFHSM

#include <stdint.h>

#include "wolfhsm/wh_flash.h"

/* Per-call config / context for the adapter. base/size/partition_size are
* the only client-visible fields; the cache lives inside the static
* implementation in wolfhsm_flash_hal.c (mirroring psa_store.c). */
typedef struct {
uint32_t base;
uint32_t size;
uint32_t partition_size;
} whFlashH5Ctx;

extern const whFlashCb whFlashH5_Cb;

#endif /* WOLFCRYPT_TZ_WOLFHSM */

#endif /* WOLFBOOT_WOLFHSM_FLASH_HAL_H */
Loading
Loading