Skip to content

Commit 16cfc43

Browse files
committed
port/armv8m-tz: NSC bridge transport for ARMv8-M TrustZone
Rename port/stmicro/stm32-tz to port/armv8m-tz to reflect that the transport is target-agnostic across ARMv8-M parts (Cortex-M23/M33/ M35P/M55/M85). The target-specific NSC veneer is provided by the host; the only ARM-flavored thing in the transport is the documented expectation that the extern wcs_wolfhsm_transmit symbol is a cmse_nonsecure_entry on the secure side. Config define renamed WOLFHSM_CFG_PORT_STM32_TZ_NSC -> WOLFHSM_CFG_PORT_ARMV8M_TZ_NSC and make flag STM32_TZ_NSC=1 -> ARMV8M_TZ_NSC=1. wh_settings.h doc, chapter08 port docs, and the CI step name all updated to drop STM32-specific wording. Review fixes folded in: - _NscServerRecv clears ctx->rsp_size up-front so error paths leave no stale response state behind. - _NscClientRecv rejects too-small caller buffers with WH_ERROR_BADARGS instead of WH_ERROR_ABORTED; cached response is preserved for retry. - _NscClientSend returns WH_ERROR_NOTREADY if a prior response has not been consumed; propagates known WH_ERROR_* codes from the veneer. - _NscServerCleanup zeroes the context so stale NS pointers cannot survive a reinit. - Reorder whTransportNscServerContext fields to satisfy -Wpadded. - Cover the new behaviors in wh_test_transport_nsc and add the NSC contexts to the struct padding check.
1 parent 0aeb181 commit 16cfc43

9 files changed

Lines changed: 88 additions & 36 deletions

File tree

.github/workflows/build-and-test.yml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -36,9 +36,9 @@ jobs:
3636
- name: Build and test
3737
run: cd test && make clean && make -j WOLFSSL_DIR=../wolfssl && make run
3838

39-
# Build and test STM32 TrustZone NSC bridge transport (port/stmicro/stm32-tz)
40-
- name: Build and test STM32_TZ_NSC ASAN
41-
run: cd test && make clean && make -j STM32_TZ_NSC=1 ASAN=1 WOLFSSL_DIR=../wolfssl && make run
39+
# Build and test ARMv8-M TrustZone NSC bridge transport (port/armv8m-tz)
40+
- name: Build and test ARMV8M_TZ_NSC ASAN
41+
run: cd test && make clean && make -j ARMV8M_TZ_NSC=1 ASAN=1 WOLFSSL_DIR=../wolfssl && make run
4242

4343
# Build and test standard build, with DMA and ASAN enabled
4444
- name: Build and test DMA ASAN

docs/src/chapter08.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -46,15 +46,15 @@ The distribution of this port is restricted by the vendor. Please contact suppo
4646
- 1x 100MHz e200z0 PowerPC HSM core with NVM
4747
- Crypto offload: TRNG, AES128
4848

49-
### STM32 TrustZone (STM32H5 / NSC bridge)
49+
### ARMv8-M TrustZone (NSC bridge)
5050

51-
The `port/stmicro/stm32-tz` port provides a synchronous TrustZone non-secure-callable bridge transport for ARMv8-M Cortex-M targets. It is designed for the wolfBoot deployment in which the secure-side wolfBoot image hosts a wolfHSM server and exposes it to the non-secure application through a single `cmse_nonsecure_entry` veneer (`wcs_wolfhsm_transmit`); see `wolfBoot/docs/wolfHSM.md` for the build, flash, and test recipe on STM32H5.
51+
The `port/armv8m-tz` port provides a synchronous TrustZone non-secure-callable bridge transport for any ARMv8-M Cortex-M target (Cortex-M23 / M33 / M35P / M55 / M85). It is designed for deployments in which a secure-side image hosts a wolfHSM server and exposes it to the non-secure application through a single `cmse_nonsecure_entry` veneer (`wcs_wolfhsm_transmit`). The first integration is wolfBoot on STM32H5; see `wolfBoot/docs/wolfHSM.md` for the build, flash, and test recipe.
5252

5353
The port provides:
5454
- Single-call NSC transport (no polling, no shared-memory ring): client `Send` invokes the host-supplied veneer inline and caches the response; client `Recv` consumes the cached response on the first call (subsequent calls return `WH_ERROR_NOTREADY` until the next `Send`).
5555
- Server-side callbacks that consume the request the host's veneer parked in a static context and write the response back to the non-secure caller's buffer.
5656

57-
The transport itself is target-agnostic; the STM32H5-specific glue (NSC veneer, `whFlashCb` flash adapter, secure-side server init, NS test exerciser) lives in the wolfBoot port.
57+
The transport is target-agnostic. Bringing it up on a new ARMv8-M part is a porting exercise on the host side only: provide the `cmse_nonsecure_entry` veneer that fronts `wcs_wolfhsm_transmit`, plus whatever flash/NVM adapter and server init the deployment needs.
5858

5959
### POSIX
6060

Lines changed: 23 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* port/stmicro/stm32-tz/wh_transport_nsc.c
2+
* port/armv8m-tz/wh_transport_nsc.c
33
*
44
* Copyright (C) 2026 wolfSSL Inc.
55
*
@@ -16,13 +16,12 @@
1616
* GNU General Public License for more details.
1717
*
1818
* You should have received a copy of the GNU General Public License
19-
* along with this program; if not, write to the Free Software
20-
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
19+
* along with wolfHSM. If not, see <http://www.gnu.org/licenses/>.
2120
*/
2221

2322
#include "wolfhsm/wh_settings.h"
2423

25-
#ifdef WOLFHSM_CFG_PORT_STM32_TZ_NSC
24+
#ifdef WOLFHSM_CFG_PORT_ARMV8M_TZ_NSC
2625

2726
#include <stdint.h>
2827
#include <string.h>
@@ -79,12 +78,21 @@ static int _NscClientSend(void* context, uint16_t size, const void* data)
7978
if (size == 0U || size > WH_TRANSPORT_NSC_BUFFER_SIZE) {
8079
return WH_ERROR_BADARGS;
8180
}
81+
/* prior response must be consumed before next Send */
82+
if (ctx->last_rsp_size != 0U) {
83+
return WH_ERROR_NOTREADY;
84+
}
8285

8386
rspSz = (uint32_t)WH_TRANSPORT_NSC_BUFFER_SIZE;
8487
rc = wcs_wolfhsm_transmit((const uint8_t*)data, (uint32_t)size,
8588
ctx->rsp_buf, &rspSz);
8689
if (rc != 0) {
8790
ctx->last_rsp_size = 0;
91+
/* propagate known wolfHSM error codes, collapse unknowns */
92+
if (rc == WH_ERROR_BADARGS || rc == WH_ERROR_NOTREADY ||
93+
rc == WH_ERROR_ABORTED) {
94+
return rc;
95+
}
8896
return WH_ERROR_ABORTED;
8997
}
9098
if (rspSz == 0U || rspSz > (uint32_t)WH_TRANSPORT_NSC_BUFFER_SIZE) {
@@ -107,6 +115,10 @@ static int _NscClientRecv(void* context, uint16_t* out_size, void* data)
107115
if (ctx->last_rsp_size == 0U) {
108116
return WH_ERROR_NOTREADY;
109117
}
118+
/* out_size is in/out capacity; reject truncation, keep cached response */
119+
if (*out_size < ctx->last_rsp_size) {
120+
return WH_ERROR_BADARGS;
121+
}
110122

111123
memcpy(data, ctx->rsp_buf, ctx->last_rsp_size);
112124
*out_size = ctx->last_rsp_size;
@@ -170,15 +182,14 @@ static int _NscServerRecv(void* context, uint16_t* inout_size, void* data)
170182
if (!ctx->request_pending || ctx->req_buf == NULL || ctx->req_size == 0U) {
171183
return WH_ERROR_NOTREADY;
172184
}
185+
/* clear stale rsp_size up-front so every exit path leaves a clean state */
186+
ctx->rsp_size = 0;
187+
173188
if (ctx->req_size > *inout_size) {
174189
ctx->request_pending = 0;
175190
return WH_ERROR_ABORTED;
176191
}
177192

178-
/* Stale value from the previous call must not leak through error paths
179-
* that skip Send. */
180-
ctx->rsp_size = 0;
181-
182193
memcpy(data, ctx->req_buf, ctx->req_size);
183194
*inout_size = ctx->req_size;
184195
ctx->request_pending = 0;
@@ -187,6 +198,7 @@ static int _NscServerRecv(void* context, uint16_t* inout_size, void* data)
187198

188199
static int _NscServerSend(void* context, uint16_t size, const void* data)
189200
{
201+
/* veneer is responsible for Recv/Send pairing; Send does not enforce it */
190202
whTransportNscServerContext* ctx = (whTransportNscServerContext*)context;
191203

192204
if (ctx == NULL || data == NULL) {
@@ -210,6 +222,8 @@ static int _NscServerCleanup(void* context)
210222
if (ctx == NULL) {
211223
return WH_ERROR_BADARGS;
212224
}
225+
/* clear stale NS pointers so they cannot survive reinit */
226+
memset(ctx, 0, sizeof(*ctx));
213227
return WH_ERROR_OK;
214228
}
215229

@@ -220,4 +234,4 @@ const whTransportServerCb whTransportNscServer_Cb = {
220234
.Cleanup = _NscServerCleanup,
221235
};
222236

223-
#endif /* WOLFHSM_CFG_PORT_STM32_TZ_NSC */
237+
#endif /* WOLFHSM_CFG_PORT_ARMV8M_TZ_NSC */
Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* port/stmicro/stm32-tz/wh_transport_nsc.h
2+
* port/armv8m-tz/wh_transport_nsc.h
33
*
44
* Copyright (C) 2026 wolfSSL Inc.
55
*
@@ -16,8 +16,7 @@
1616
* GNU General Public License for more details.
1717
*
1818
* You should have received a copy of the GNU General Public License
19-
* along with this program; if not, write to the Free Software
20-
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
19+
* along with wolfHSM. If not, see <http://www.gnu.org/licenses/>.
2120
*/
2221

2322
/*
@@ -31,16 +30,16 @@
3130
* notify counter, or async producer/consumer — Send delivers the
3231
* response, Recv just hands it back.
3332
*
34-
* The transport is generic to any ARMv8-M TrustZone target; the
35-
* STM32-specific dependencies live in the host (wolfBoot).
33+
* The transport is target-agnostic across ARMv8-M TrustZone parts;
34+
* the target-specific NSC veneer is provided by the host.
3635
*/
3736

3837
#ifndef WH_TRANSPORT_NSC_H_
3938
#define WH_TRANSPORT_NSC_H_
4039

4140
#include "wolfhsm/wh_settings.h"
4241

43-
#ifdef WOLFHSM_CFG_PORT_STM32_TZ_NSC
42+
#ifdef WOLFHSM_CFG_PORT_ARMV8M_TZ_NSC
4443

4544
#include <stdint.h>
4645
#include "wolfhsm/wh_comm.h"
@@ -55,10 +54,10 @@ typedef struct {
5554
uint8_t rsp_buf[WH_TRANSPORT_NSC_BUFFER_SIZE];
5655
uint16_t last_rsp_size;
5756
uint8_t initialized;
58-
uint8_t WH_PAD[5]; /* Pad to 8-byte alignment */
57+
uint8_t WH_PAD[5]; /* trailing slack */
5958
} whTransportNscClientContext;
6059

61-
/* Empty config struct - kept for ABI symmetry with other transports */
60+
/* Empty config; Init accepts NULL since there is nothing to read. */
6261
typedef struct {
6362
uint8_t WH_PAD[1];
6463
} whTransportNscClientConfig;
@@ -71,8 +70,8 @@ typedef struct {
7170
*/
7271
typedef struct {
7372
const uint8_t* req_buf;
74-
uint16_t req_size;
7573
uint8_t* rsp_buf;
74+
uint16_t req_size;
7675
uint16_t rsp_capacity;
7776
uint16_t rsp_size; /* set by Send, read by veneer */
7877
uint8_t request_pending; /* set by veneer, cleared by Recv */
@@ -83,9 +82,10 @@ typedef struct {
8382
uint8_t WH_PAD[1];
8483
} whTransportNscServerConfig;
8584

85+
/* Pre-populated tables; callbacks are file-local in wh_transport_nsc.c */
8686
extern const whTransportClientCb whTransportNscClient_Cb;
8787
extern const whTransportServerCb whTransportNscServer_Cb;
8888

89-
#endif /* WOLFHSM_CFG_PORT_STM32_TZ_NSC */
89+
#endif /* WOLFHSM_CFG_PORT_ARMV8M_TZ_NSC */
9090

9191
#endif /* WH_TRANSPORT_NSC_H_ */

test/Makefile

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -165,12 +165,12 @@ ifeq ($(AUTH),1)
165165
DEF += -DWOLFHSM_CFG_ENABLE_AUTHENTICATION
166166
endif
167167

168-
# Build the STM32 TZ NSC bridge transport plus its host unit test
169-
ifeq ($(STM32_TZ_NSC),1)
170-
DEF += -DWOLFHSM_CFG_PORT_STM32_TZ_NSC
171-
WOLFHSM_STM32_TZ_DIR := $(WOLFHSM_DIR)/port/stmicro/stm32-tz
172-
INC += -I$(WOLFHSM_STM32_TZ_DIR)
173-
SRC_C += $(wildcard $(WOLFHSM_STM32_TZ_DIR)/*.c)
168+
# Build the ARMv8-M TrustZone NSC bridge transport plus its host unit test
169+
ifeq ($(ARMV8M_TZ_NSC),1)
170+
DEF += -DWOLFHSM_CFG_PORT_ARMV8M_TZ_NSC
171+
WOLFHSM_ARMV8M_TZ_DIR := $(WOLFHSM_DIR)/port/armv8m-tz
172+
INC += -I$(WOLFHSM_ARMV8M_TZ_DIR)
173+
SRC_C += $(wildcard $(WOLFHSM_ARMV8M_TZ_DIR)/*.c)
174174
endif
175175

176176
## Project defines

test/wh_test.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@
4646
#include "wh_test_timeout.h"
4747
#include "wh_test_dma.h"
4848
#include "wh_test_keystore_reqsize.h"
49-
#ifdef WOLFHSM_CFG_PORT_STM32_TZ_NSC
49+
#ifdef WOLFHSM_CFG_PORT_ARMV8M_TZ_NSC
5050
#include "wh_test_transport_nsc.h"
5151
#endif
5252
#ifdef WOLFHSM_CFG_ENABLE_AUTHENTICATION
@@ -108,7 +108,7 @@ int whTest_Unit(void)
108108
WH_TEST_ASSERT(0 == whTest_Comm());
109109
WH_TEST_ASSERT(0 == whTest_ClientServer());
110110

111-
#ifdef WOLFHSM_CFG_PORT_STM32_TZ_NSC
111+
#ifdef WOLFHSM_CFG_PORT_ARMV8M_TZ_NSC
112112
WH_TEST_ASSERT(0 == whTest_TransportNsc());
113113
#endif
114114

test/wh_test_check_struct_padding.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -203,4 +203,10 @@ whMessageCert_VerifyAcertRequest whMessageCert_VerifyAcertRequest_test;
203203
#endif /* WOLFHSM_CFG_CERTIFICATE_MANAGER_ACERT */
204204
#endif /* WOLFHSM_CFG_CERTIFICATE_MANAGER */
205205

206+
#ifdef WOLFHSM_CFG_PORT_ARMV8M_TZ_NSC
207+
#include "wh_transport_nsc.h"
208+
whTransportNscClientContext whTransportNscClientContext_test;
209+
whTransportNscServerContext whTransportNscServerContext_test;
210+
#endif /* WOLFHSM_CFG_PORT_ARMV8M_TZ_NSC */
211+
206212
#endif /* WH_TEST_CHECK_STRUCT_PADDING_C_ */

test/wh_test_transport_nsc.c

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121

2222
#include "wolfhsm/wh_settings.h"
2323

24-
#ifdef WOLFHSM_CFG_PORT_STM32_TZ_NSC
24+
#ifdef WOLFHSM_CFG_PORT_ARMV8M_TZ_NSC
2525

2626
#include <stdint.h>
2727
#include <string.h>
@@ -100,11 +100,34 @@ static int test_client_callbacks(void)
100100
WH_TEST_ASSERT_RETURN(WH_ERROR_NOTREADY ==
101101
whTransportNscClient_Cb.Recv(&ctx, &sz, data_out));
102102

103+
/* too-small buffer returns BADARGS, cached response preserved */
104+
rc = whTransportNscClient_Cb.Send(&ctx, sizeof(data_in), data_in);
105+
WH_TEST_ASSERT_RETURN(rc == WH_ERROR_OK);
106+
sz = (uint16_t)(sizeof(data_in));
107+
WH_TEST_ASSERT_RETURN(WH_ERROR_BADARGS ==
108+
whTransportNscClient_Cb.Recv(&ctx, &sz, data_out));
109+
/* second Send before Recv consumes prior reply is NOTREADY */
110+
WH_TEST_ASSERT_RETURN(WH_ERROR_NOTREADY ==
111+
whTransportNscClient_Cb.Send(&ctx, sizeof(data_in), data_in));
112+
sz = sizeof(data_out);
113+
rc = whTransportNscClient_Cb.Recv(&ctx, &sz, data_out);
114+
WH_TEST_ASSERT_RETURN(rc == WH_ERROR_OK);
115+
WH_TEST_ASSERT_RETURN(sz == sizeof(data_in) + 1U);
116+
103117
g_stub_force_rc = -42;
104118
rc = whTransportNscClient_Cb.Send(&ctx, sizeof(data_in), data_in);
105119
WH_TEST_ASSERT_RETURN(rc == WH_ERROR_ABORTED);
106120
g_stub_force_rc = 0;
107121

122+
/* WH_ERROR_* return values from the veneer are propagated unchanged. */
123+
g_stub_force_rc = WH_ERROR_BADARGS;
124+
rc = whTransportNscClient_Cb.Send(&ctx, sizeof(data_in), data_in);
125+
WH_TEST_ASSERT_RETURN(rc == WH_ERROR_BADARGS);
126+
g_stub_force_rc = WH_ERROR_NOTREADY;
127+
rc = whTransportNscClient_Cb.Send(&ctx, sizeof(data_in), data_in);
128+
WH_TEST_ASSERT_RETURN(rc == WH_ERROR_NOTREADY);
129+
g_stub_force_rc = 0;
130+
108131
g_stub_force_rspSz = (uint32_t)WH_TRANSPORT_NSC_BUFFER_SIZE + 1U;
109132
rc = whTransportNscClient_Cb.Send(&ctx, sizeof(data_in),
110133
data_in);
@@ -157,11 +180,12 @@ static int test_server_callbacks(void)
157180
ctx.rsp_size = 0xBEEF;
158181
ctx.request_pending = 1;
159182

160-
/* Oversize: must clear request_pending. */
183+
/* oversize must clear request_pending and rsp_size */
161184
sz = (uint16_t)(sizeof(req) - 1U);
162185
rc = whTransportNscServer_Cb.Recv(&ctx, &sz, data_buf);
163186
WH_TEST_ASSERT_RETURN(rc == WH_ERROR_ABORTED);
164187
WH_TEST_ASSERT_RETURN(ctx.request_pending == 0U);
188+
WH_TEST_ASSERT_RETURN(ctx.rsp_size == 0U);
165189

166190
ctx.req_buf = req;
167191
ctx.req_size = (uint16_t)sizeof(req);
@@ -209,4 +233,4 @@ int whTest_TransportNsc(void)
209233
return WH_TEST_SUCCESS;
210234
}
211235

212-
#endif /* WOLFHSM_CFG_PORT_STM32_TZ_NSC */
236+
#endif /* WOLFHSM_CFG_PORT_ARMV8M_TZ_NSC */

wolfhsm/wh_settings.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,14 @@
129129
* WOLFHSM_CFG_PORT_GETTIME - Function-like macro returning the current system
130130
* time in microseconds as a uint64_t. Must be defined in wolfhsm_cfg.h for
131131
* the active port UNLESS WOLFHSM_CFG_NO_SYS_TIME is defined
132+
*
133+
* WOLFHSM_CFG_PORT_ARMV8M_TZ_NSC - If defined, build the ARMv8-M TrustZone
134+
* non-secure-callable (NSC) bridge transport in
135+
* port/armv8m-tz/wh_transport_nsc.{c,h}. Target-agnostic across
136+
* ARMv8-M Cortex-M parts; the non-secure client calls into the
137+
* secure-side server through a single cmse_nonsecure_entry veneer
138+
* provided by the host (e.g. wolfBoot's WOLFCRYPT_TZ_WOLFHSM engine).
139+
* Default: Not defined
132140
133141
* Overridable porting functions:
134142
*

0 commit comments

Comments
 (0)