Skip to content
Open
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
165 changes: 165 additions & 0 deletions .github/workflows/wolfboot-tz-integration.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,165 @@
# Nightly integration: build wolfBoot's STM32H5 TrustZone demo against
# the latest wolfHSM main and run it under the m33mu emulator. This
# catches drift between wolfHSM and wolfBoot main (in either direction)
# that the pinned-submodule per-PR builds do not. The full client suite
# runs software RSA and ECC, which is slow under the emulator, so this
# is a nightly job rather than a per-PR gate.
#
# On failure it opens (or updates) a tracking issue assigned to
# wolfSSL-Bot.

name: wolfBoot TrustZone integration nightly (m33mu)

on:
schedule:
# 07:00 UTC daily
- cron: '0 7 * * *'
workflow_dispatch:

permissions:
contents: read
issues: write

jobs:
wolfboot-stm32h5-tz-wolfhsm:
runs-on: ubuntu-latest
timeout-minutes: 60
container:
image: ghcr.io/wolfssl/wolfboot-ci-m33mu:latest

steps:
- name: Checkout wolfHSM (this repo, main)
uses: actions/checkout@v4
with:
path: wolfHSM

- name: Checkout wolfBoot master
# Switch `ref` to `master` once wolfBoot PR #769 lands; until
# then the STM32H5 demo only exists on that PR.
uses: actions/checkout@v4
with:
repository: wolfSSL/wolfBoot
ref: refs/pull/769/head
path: wolfBoot
# Skip lib/wolfHSM submodule init - we replace it with this
# checkout. Other submodules still need to come down.
submodules: false

- name: Initialise wolfBoot submodules (except lib/wolfHSM)
working-directory: wolfBoot
run: |
git config -f .gitmodules submodule.lib/wolfHSM.update none
git submodule update --init --recursive

- name: Point lib/wolfHSM at this checkout
working-directory: wolfBoot
run: |
rm -rf lib/wolfHSM
ln -s "$GITHUB_WORKSPACE/wolfHSM" lib/wolfHSM
ls -l lib/wolfHSM

- name: Build wolfBoot STM32H5 TZ demo
working-directory: wolfBoot/port/stmicro/stm32h5-tz-wolfhsm
run: make

- name: Run wolfHSM whTest_ClientConfig under m33mu
working-directory: wolfBoot/port/stmicro/stm32h5-tz-wolfhsm
run: |
set -o pipefail
mkdir -p /tmp/m33mu-wolfhsm-persist
cp out/wolfboot.bin out/image_v1_signed.bin /tmp/m33mu-wolfhsm-persist/
cd /tmp/m33mu-wolfhsm-persist
# m33mu timeout below the 60 min job timeout so a hung run
# still produces a log. Software RSA keygen dominates.
m33mu wolfboot.bin image_v1_signed.bin:0x60000 \
--persist --uart-stdout --timeout 3000 \
--expect-bkpt 0x7d --quit-on-faults \
2>&1 | tee /tmp/m33mu-wolfhsm.log

- name: Verify wolfHSM whTest_ClientConfig
run: |
grep -q "wolfHSM whTest_ClientConfig PASSED" /tmp/m33mu-wolfhsm.log
grep -q "RNG DEVID=0x5748534D SUCCESS" /tmp/m33mu-wolfhsm.log
grep -q "AES GCM DEVID=0x5748534D SUCCESS" /tmp/m33mu-wolfhsm.log
grep -q "RSA SUCCESS" /tmp/m33mu-wolfhsm.log
grep -q "ECC ephemeral ECDH SUCCESS" /tmp/m33mu-wolfhsm.log
grep -q "SHA256 DEVID=0x5748534D SUCCESS" /tmp/m33mu-wolfhsm.log
grep -q "HKDF SUCCESS" /tmp/m33mu-wolfhsm.log
grep -q "\\[BKPT\\] imm=0x7d" /tmp/m33mu-wolfhsm.log
grep -q "\\[EXPECT BKPT\\] Success" /tmp/m33mu-wolfhsm.log

- name: Archive emulator log on failure
if: failure()
uses: actions/upload-artifact@v4
with:
name: m33mu-wolfhsm.log
path: /tmp/m33mu-wolfhsm.log

- name: Open or update tracking issue on failure
if: failure()
uses: actions/github-script@v7
with:
script: |
const runUrl = `${context.serverUrl}/${context.repo.owner}/${context.repo.repo}/actions/runs/${context.runId}`;
const marker = 'nightly-tz-integration';
const title = 'Nightly wolfBoot TrustZone (m33mu) integration failed';
const body = [
'The nightly wolfBoot STM32H5 TrustZone integration run failed.',
'',
`Run: ${runUrl}`,
'',
'This builds wolfBoot main against wolfHSM main and runs the',
'STM32H5 demo under m33mu. A failure usually means a regression',
'in the NSC transport, the wolfBoot port, or a wolfHSM/wolfBoot',
'API drift. The emulator log is attached to the run as an artifact.',
].join('\n');

// Reuse one open tracking issue instead of opening a new one
// every night.
const existing = await github.rest.issues.listForRepo({
owner: context.repo.owner,
repo: context.repo.repo,
state: 'open',
labels: marker,
});

if (existing.data.length > 0) {
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: existing.data[0].number,
body: `Still failing as of ${runUrl}`,
});
return;
}

// Best-effort label create (ignore if it already exists).
try {
await github.rest.issues.createLabel({
owner: context.repo.owner,
repo: context.repo.repo,
name: marker,
color: 'b60205',
});
} catch (e) { /* label exists */ }

try {
await github.rest.issues.create({
owner: context.repo.owner,
repo: context.repo.repo,
title,
body,
labels: [marker],
assignees: ['wolfSSL-Bot'],
});
} catch (e) {
// Assignee may not be assignable; retry without it so the
// issue still gets filed.
await github.rest.issues.create({
owner: context.repo.owner,
repo: context.repo.repo,
title,
body,
labels: [marker],
});
}
1 change: 1 addition & 0 deletions docs/src/5-Features.md
Original file line number Diff line number Diff line change
Expand Up @@ -469,6 +469,7 @@ wolfHSM ships with several reference transports that between them cover the most
- **POSIX TCP transport** (`port/posix/posix_transport_tcp.h`): carries the packet exchange over a length-prefixed TCP stream. The server listens on a configured port and the client connects to it. This is the default transport for the POSIX server example and the recommended development transport, because the client and server can live in separate host processes — or on separate machines — without any additional platform integration.
- **POSIX shared memory transport** (`port/posix/posix_transport_shm.h`): hosts the same request/response buffer layout used by the memory buffer transport in a named POSIX shared memory object, with optional space for DMA-style buffers alongside it. This lets the client and server run as independent processes on the same host while exercising the shared-memory code paths a multi-core SoC would use in production.
- **TLS-over-TCP transport** (`port/posix/posix_transport_tls.h`): wraps the POSIX TCP transport in a wolfSSL-secured channel, with support for certificate-based authentication and PSK. It is intended for deployments where the client and server are physically separated and the link between them cannot be trusted. The packet framing above the TLS session is identical to the plain TCP transport, so higher-level code does not change between the two.
- **ARMv8-M TrustZone NSC bridge transport** (`port/armv8m-tz/wh_transport_nsc.h`): a synchronous transport for ARMv8-M Cortex-M parts where the server runs in the secure world and clients run in the non-secure world. The non-secure client `Send` calls a single `cmse_nonsecure_entry` veneer (`wcs_wolfhsm_transmit`) the integrator provides; that veneer hands the request to the secure-side server inline and returns the response in the same call, which `Recv` then yields. There is no polling or shared-memory ring. The transport is target-agnostic across ARMv8-M parts; the veneer, flash/NVM adapter, and server init are supplied by the secure-side integration. The reference integration is the wolfBoot STM32H5 port.

Beyond the reference transports, platform ports for embedded targets typically supply hardware-specific transports — silicon mailboxes, interrupt-driven inter-core channels, vendor IPC blocks — by implementing the same callback interface. The comm-layer contract is purely "deliver one packet, in order," so a transport need only marshal bytes between the two sides.

Expand Down
44 changes: 44 additions & 0 deletions port/armv8m-tz/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
# ARMv8-M TrustZone NSC bridge transport

A synchronous wolfHSM transport for ARMv8-M TrustZone targets that
bridges a non-secure client to a secure-world server through a single
Non-Secure Callable (NSC) veneer. See `wh_transport_nsc.h` for the C
API and `docs/src/chapter08.md` for the narrative description.

## How it works

Client and server share a single secure-callable function. The
non-secure side packs a wolfHSM request into a buffer, calls the
veneer, and waits for the veneer to return with the response written
into a second buffer. The secure side runs the wolfHSM server in the
same process; there is no separate task, no IRQ, and no shared-memory
ring — just a function call across the security boundary.

## Host-side veneer contract

The integrator provides one function with this exact shape:

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

declared `cmse_nonsecure_entry` from the secure side. On entry,
`cmd[0..cmdSz)` holds the request and `*rspSz` is the maximum response
size the client can accept; on return the function writes the
response into `rsp[0..*rspSz)` and updates `*rspSz` to the actual
size. Return value follows wolfHSM's `WH_ERROR_*` convention.

The veneer must not block on anything outside the secure server; the
non-secure side treats it as a synchronous call.

## Known integrations

- **wolfBoot STM32H5 demo app** at
[`port/stmicro/stm32h5-tz-wolfhsm/`](https://github.com/wolfSSL/wolfBoot/tree/main/port/stmicro/stm32h5-tz-wolfhsm)
in wolfBoot. Reference integration on a NUCLEO-H563ZI;
verified end-to-end on real silicon and on the m33mu emulator.

To add a new integration, copy the veneer skeleton from wolfBoot's
demo, wire `wh_transport_nsc.h` into the non-secure client init, and
write a `whServerCb` table for the secure server.
Loading
Loading