Skip to content

Commit 6f034bb

Browse files
committed
STM32 wolfIP: share wolfssl.mk + tls_client across ports, docs, cppcheck fix
1 parent fbb17d2 commit 6f034bb

20 files changed

Lines changed: 571 additions & 1098 deletions

Makefile

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,8 @@ CPPCHECK_FLAGS=--enable=warning,performance,portability,missingInclude \
133133
--suppress=constParameterCallback \
134134
--suppress=toomanyconfigs \
135135
--suppress=unmatchedSuppression --inconclusive \
136+
--suppress=comparePointers:src/port/stm32c5a3/startup.c \
137+
--suppress=comparePointers:src/port/stm32c5a3/syscalls.c \
136138
--suppress=comparePointers:src/port/stm32h563/startup.c \
137139
--suppress=comparePointers:src/port/stm32h563/syscalls.c \
138140
--suppress=comparePointers:src/port/stm32h753/startup.c \
@@ -149,6 +151,7 @@ CPPCHECK_FLAGS=--enable=warning,performance,portability,missingInclude \
149151
--suppress=comparePointers:src/port/rp2350_cyw43439/startup_hazard3.c \
150152
--suppress=comparePointers:src/port/rp2350_cyw43439/syscalls.c \
151153
--suppress=unknownMacro:src/port/stm32h563/dot1x_client.c \
154+
--suppress=unknownMacro:src/port/stm32c5a3/startup.c \
152155
--suppress=preprocessorErrorDirective:src/supplicant/supplicant_features.h \
153156
--disable=style \
154157
--std=c99 --language=c \

src/port/stm32/PORTING.md

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
# Porting wolfIP to a new STM32
2+
3+
This tree is layered so a new STM32 wolfIP port is a small set of per-chip
4+
files plus shared infrastructure. Existing ports: `stm32c5a3` (M33, TLS 1.3 +
5+
DHUK), `stm32h753` (M7, TLS + HTTPS), `stm32h563` (M33, TLS + SSH + MQTT +
6+
dot1x + FreeRTOS), `stm32f439` (M4, network only), `stm32n6` (M55, network
7+
only).
8+
9+
## Shared -- reuse as-is
10+
11+
| File | What it gives you |
12+
|------|-------------------|
13+
| `src/port/stm32/stm32_eth.c` / `.h` | Synopsys DWC GMAC MAC+DMA+PHY driver for H5/H7/N6 (and C5, via a one-line `STM32C5 -> STM32H5` alias). ETH1 at `0x40028000` on H5/C5. |
14+
| `src/port/stm32/wolfssl.mk` | `WOLFSSL_ROOT`/`WOLFMQTT_ROOT` defaults, the `WOLFSSL_SRCS` TLS-1.3 source list, the optional `WOLFSSL_LOG_SRCS` (logging/error/wc_encrypt) group, and the `$(WOLFSSL_ROOT)/%.o` relaxed-warning rule. `include` it from a port Makefile. |
15+
| `src/port/wolfssl_io.c` | wolfIP <-> wolfSSL I/O callbacks (EAGAIN -> WANT_READ/WRITE, `-1` -> CONN_CLOSE). |
16+
| `src/port/tls_client.c` / `.h` | Shared TLS 1.3 client state machine. Build knobs (per-port `-D`): `TLS_CLIENT_MUTUAL_AUTH` (present a client cert from the port's `tls_certs.h`), `ENABLE_DHUK_KEY` (sign CertificateVerify via the DHUK PK callback), `TLS_CLIENT_CIPHER` (force one suite), `TLS_CLIENT_SETTLE_POLLS` (post-connect settle, default 10). Without `MUTUAL_AUTH` it is a plain one-way client (SNI via `tls_client_set_sni()`). |
17+
| `src/port/certs.h` | Embedded test certificates (for the HTTPS/server ports). |
18+
| `src/wolfip.c` | The stack itself. |
19+
20+
## Per-chip -- supply these
21+
22+
| File | Notes |
23+
|------|-------|
24+
| `startup.c` (+ `ivt.c`) | Vendor vector table + reset. Genuinely per-silicon (different peripheral IRQ set). C5A3 folds the full M33 vector table into `startup.c` (no separate `ivt.c`). |
25+
| `target.ld` | Memory map (flash/RAM addresses + sizes). Add an `.eth_buffers` output section in RAM for the GMAC descriptors + RX/TX buffers. |
26+
| `main.c` | The per-chip register sequences: `clock_init`, `uart_init`, `eth_gpio_init` (RMII pinmux + SYSCFG/SBS PHY-interface select + RCC ETH gates), `rng_init`. Plus the wolfIP init + poll loop (mostly copyable between ports). |
27+
| `config.h` | wolfIP sizing (sockets, buffers, static IP). |
28+
| `user_settings.h` | wolfSSL config: the shared TLS-1.3 base + a per-chip HW-crypto arm (`STM32_HASH` / `STM32_CRYPTO` / `WOLFSSL_STM32_PKA` / RNG, gated on the chip define). |
29+
| `Makefile` | Thin: CPU flags, device `-D`, includes, `include ../stm32/wolfssl.mk`, board sources, feature source lists, flash command. |
30+
31+
## Makefile pattern
32+
33+
```make
34+
CFLAGS := -mcpu=cortex-mXX ... -D<CHIP>
35+
CFLAGS_WOLFSSL := $(filter-out -Werror,$(CFLAGS)) -Wno-unused-variable -Wno-unused-function
36+
include $(ROOT)/src/port/stm32/wolfssl.mk # WOLFSSL_SRCS + %.o rule + defaults
37+
...
38+
ifeq ($(ENABLE_TLS),1)
39+
WOLFSSL_SRCS += $(WOLFSSL_LOG_SRCS) # unless you strip logging/error to save flash
40+
SRCS += $(WOLFSSL_SRCS)
41+
endif
42+
```
43+
44+
- A port that needs feature defines on the wolfSSL objects (e.g. SSH/dot1x) sets `WOLFSSL_EXTRA_DEFS` -- the shared `%.o` rule appends it (see `stm32h563/Makefile`).
45+
- Keep `all:`/`clean:`/`size:`/`flash:` in the port; `wolfssl.mk` intentionally defines only variables and the `%.o` pattern rule so it never hijacks the default goal.
46+
47+
## New-port checklist (things that bite)
48+
49+
- **`_sbrk` must use the linker `.heap` region**, not `_ebss.._estack`. On a port whose linker places `.eth_buffers` after `.bss`, an `_ebss`-based heap hands out malloc memory that overlaps the Ethernet DMA buffers, and packet DMA silently corrupts heap objects (seen on C5A3: garbage `WOLFSSL_CTX->method` -> bus fault deep in TLS).
50+
- **Add the port to the root `Makefile` cppcheck suppression list** (`comparePointers` for `startup.c`/`syscalls.c`, and `unknownMacro` for a CMSIS vendor `startup.c`). A cleaner alternative for new code: cast the `_sbrk` bounds compare to `uintptr_t` so no `comparePointers` suppression is needed.
51+
- **RMII alternate-function numbers are not uniform** -- check each pin against the CubeMX/HAL board example (on C5A3, RXD0/RXD1 are AF12/AF13 while the rest are AF10). A wrong AF on an RX pin leaves the link up (MDIO works) but drops all RX.
52+
- **DMA buffers must be in DMA-reachable RAM** (not DTCM on H7); place them via the `.eth_buffers` section.
53+
- **Wire MSPLIM** to the linker's real stack-limit symbol (`PROVIDE(__STACK_LIMIT = __StackLimit)` if the CMSIS startup uses `__STACK_LIMIT`) so a stack overflow faults cleanly instead of corrupting the heap.
54+
- The `../wolfssl` object tree is shared: ports at different FP ABIs (hard vs soft float) clobber each other's `.o` files. `make clean` (or delete `$(WOLFSSL_ROOT)/**/*.o`) between such builds.
55+
56+
## Shared TLS client
57+
58+
`tls_client.c`/`.h` moved to `src/port/` (see the shared table above). The three
59+
TLS ports now compile the single `$(ROOT)/src/port/tls_client.c` and select
60+
behavior with `-D` knobs: `stm32c5a3` sets `TLS_CLIENT_MUTUAL_AUTH` +
61+
`TLS_CLIENT_CIPHER` (+ `ENABLE_DHUK_KEY`) for its mutual-auth DHUK demo, while
62+
`stm32h753`/`stm32h563` build it as a plain one-way client (H753 keeps its
63+
historical `TLS_CLIENT_SETTLE_POLLS=100`). C5A3's mutual-auth + DHUK build is
64+
verified on hardware; H753/H563 are build-verified (boards not testable here --
65+
no H753 on the bench, H563 is provisioned TZEN=1).

src/port/stm32/wolfssl.mk

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
# wolfssl.mk -- shared wolfSSL/wolfCrypt build plumbing for the STM32 bare-metal
2+
# wolfIP ports (stm32c5a3, stm32h753, stm32h563, ...).
3+
#
4+
# Copyright (C) 2026 wolfSSL Inc.
5+
#
6+
# `include $(ROOT)/src/port/stm32/wolfssl.mk` from a port Makefile. Provides:
7+
# - WOLFSSL_ROOT / WOLFMQTT_ROOT sibling defaults (a port may set WOLFSSL_ROOT
8+
# earlier with ?= to point at a worktree; that still wins).
9+
# - WOLFSSL_SRCS: the minimal wolfSSL/wolfCrypt source set for a TLS 1.3 client
10+
# (ECC + AES-GCM) plus the ChaCha20-Poly1305 / RSA-verify / logging groups
11+
# the ports share. Add to SRCS from inside the port's ENABLE_TLS block.
12+
# - the $(WOLFSSL_ROOT)/%.o relaxed-warning compile rule (uses the port's
13+
# CFLAGS_WOLFSSL, which the port defines and appends its own -D flags to).
14+
#
15+
# Only variables and a pattern rule live here -- no explicit targets -- so the
16+
# including Makefile keeps ownership of the default goal and of all/clean/size/
17+
# flash. Include it AFTER the port has set CFLAGS (and, if used, its own
18+
# WOLFSSL_ROOT ?= override); the port defines CFLAGS_WOLFSSL itself.
19+
20+
WOLFSSL_ROOT ?= $(ROOT)/../wolfssl
21+
WOLFMQTT_ROOT ?= $(ROOT)/../wolfmqtt
22+
23+
# Minimal wolfSSL/wolfCrypt source set for a TLS 1.3 client with ECC + AES-GCM.
24+
WOLFSSL_SRCS := \
25+
$(WOLFSSL_ROOT)/wolfcrypt/src/aes.c \
26+
$(WOLFSSL_ROOT)/wolfcrypt/src/sha.c \
27+
$(WOLFSSL_ROOT)/wolfcrypt/src/sha256.c \
28+
$(WOLFSSL_ROOT)/wolfcrypt/src/sha512.c \
29+
$(WOLFSSL_ROOT)/wolfcrypt/src/hmac.c \
30+
$(WOLFSSL_ROOT)/wolfcrypt/src/hash.c \
31+
$(WOLFSSL_ROOT)/wolfcrypt/src/kdf.c \
32+
$(WOLFSSL_ROOT)/wolfcrypt/src/random.c \
33+
$(WOLFSSL_ROOT)/wolfcrypt/src/ecc.c \
34+
$(WOLFSSL_ROOT)/wolfcrypt/src/asn.c \
35+
$(WOLFSSL_ROOT)/wolfcrypt/src/coding.c \
36+
$(WOLFSSL_ROOT)/wolfcrypt/src/wc_port.c \
37+
$(WOLFSSL_ROOT)/wolfcrypt/src/memory.c \
38+
$(WOLFSSL_ROOT)/wolfcrypt/src/wolfmath.c \
39+
$(WOLFSSL_ROOT)/wolfcrypt/src/sp_int.c \
40+
$(WOLFSSL_ROOT)/wolfcrypt/src/sp_c32.c \
41+
$(WOLFSSL_ROOT)/wolfcrypt/src/sp_cortexm.c \
42+
$(WOLFSSL_ROOT)/src/ssl.c \
43+
$(WOLFSSL_ROOT)/src/tls.c \
44+
$(WOLFSSL_ROOT)/src/tls13.c \
45+
$(WOLFSSL_ROOT)/src/internal.c \
46+
$(WOLFSSL_ROOT)/src/keys.c \
47+
$(WOLFSSL_ROOT)/src/wolfio.c
48+
49+
# ChaCha20-Poly1305 (fallback suite).
50+
WOLFSSL_SRCS += \
51+
$(WOLFSSL_ROOT)/wolfcrypt/src/chacha.c \
52+
$(WOLFSSL_ROOT)/wolfcrypt/src/chacha20_poly1305.c \
53+
$(WOLFSSL_ROOT)/wolfcrypt/src/poly1305.c
54+
55+
# RSA for peer certificate verification.
56+
WOLFSSL_SRCS += \
57+
$(WOLFSSL_ROOT)/wolfcrypt/src/rsa.c \
58+
$(WOLFSSL_ROOT)/wolfcrypt/src/signature.c
59+
60+
# Logging / error-strings / encrypt-helpers group. Kept separate because a
61+
# size-tight port may omit it (e.g. with NO_ERROR_STRINGS + logging off). Ports
62+
# that want it do: WOLFSSL_SRCS += $(WOLFSSL_LOG_SRCS)
63+
WOLFSSL_LOG_SRCS := \
64+
$(WOLFSSL_ROOT)/wolfcrypt/src/logging.c \
65+
$(WOLFSSL_ROOT)/wolfcrypt/src/error.c \
66+
$(WOLFSSL_ROOT)/wolfcrypt/src/wc_encrypt.c
67+
68+
# wolfSSL objects build with relaxed warnings (third-party, heavily #ifdef'd).
69+
# CFLAGS_WOLFSSL is defined by the including port Makefile. WOLFSSL_EXTRA_DEFS
70+
# lets a port add feature defines that the wolfSSL objects need (e.g. H563's
71+
# -DWOLFSSL_WOLFSSH / -DHAVE_PBKDF2 for its SSH / dot1x builds); it is empty by
72+
# default.
73+
$(WOLFSSL_ROOT)/%.o: $(WOLFSSL_ROOT)/%.c
74+
$(CC) $(CFLAGS_WOLFSSL) -DWOLFSSL_USER_SETTINGS $(WOLFSSL_EXTRA_DEFS) -I$(WOLFSSL_ROOT) -c $< -o $@

src/port/stm32c5a3/.gitignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,7 @@
22
*.o
33
app.elf
44
app.bin
5+
6+
# Generated TLS test host material (contains a throwaway test private key).
7+
# Regenerate with: python3 gen_certs.py (also rewrites tls_certs.h)
8+
tls-certs/

src/port/stm32c5a3/Makefile

Lines changed: 14 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -50,8 +50,8 @@ endif
5050
ifeq ($(ENABLE_TLS_CLIENT),1)
5151
WOLFSSL_ROOT ?= $(ROOT)/../wolfssl-c5tls
5252
endif
53-
WOLFSSL_ROOT ?= $(ROOT)/../wolfssl
54-
WOLFMQTT_ROOT ?= $(ROOT)/../wolfmqtt
53+
# Sibling WOLFSSL_ROOT/WOLFMQTT_ROOT fallbacks + the shared wolfSSL source list
54+
# and $(WOLFSSL_ROOT)/%.o rule come from the shared fragment (included below).
5555

5656
# -----------------------------------------------------------------------------
5757
# Device headers / CMSIS
@@ -77,6 +77,10 @@ CFLAGS_WOLFSSL := $(CFLAGS)
7777
CFLAGS_WOLFSSL := $(filter-out -Werror,$(CFLAGS_WOLFSSL))
7878
CFLAGS_WOLFSSL += -Wno-unused-variable -Wno-unused-function
7979

80+
# Shared wolfSSL build plumbing: WOLFSSL_ROOT/WOLFMQTT_ROOT defaults, the base
81+
# WOLFSSL_SRCS list, and the $(WOLFSSL_ROOT)/%.o relaxed-warning rule.
82+
include $(ROOT)/src/port/stm32/wolfssl.mk
83+
8084
LDSCRIPT := target.ld
8185
# The vendor startup (startup.c) uses the CMSIS __PROGRAM_START flow:
8286
# __cmsis_start runs the .copy.table/.zero.table init then calls newlib's
@@ -118,7 +122,7 @@ SRCS += $(ROOT)/src/port/wolfssl_io.c
118122
# TLS client (3A.0 mutual-auth against openssl s_server)
119123
ifeq ($(ENABLE_TLS_CLIENT),1)
120124
CFLAGS += -DENABLE_TLS_CLIENT
121-
SRCS += tls_client.c
125+
SRCS += $(ROOT)/src/port/tls_client.c
122126

123127
# Milestone 3A.1: set ENABLE_DHUK_KEY=1 to sign CertificateVerify with the
124128
# DHUK-wrapped identity key via a PK callback (identity scalar never in SW).
@@ -145,49 +149,9 @@ endif
145149
# rules here (before "all:") would hijack the default goal.
146150
CFLAGS_WOLFSSL += $(TLS_WOLFSSL_DEFS)
147151

148-
# wolfSSL source files (minimal set for TLS 1.3 client with ECC)
149-
WOLFSSL_SRCS := \
150-
$(WOLFSSL_ROOT)/wolfcrypt/src/aes.c \
151-
$(WOLFSSL_ROOT)/wolfcrypt/src/sha.c \
152-
$(WOLFSSL_ROOT)/wolfcrypt/src/sha256.c \
153-
$(WOLFSSL_ROOT)/wolfcrypt/src/sha512.c \
154-
$(WOLFSSL_ROOT)/wolfcrypt/src/hmac.c \
155-
$(WOLFSSL_ROOT)/wolfcrypt/src/hash.c \
156-
$(WOLFSSL_ROOT)/wolfcrypt/src/kdf.c \
157-
$(WOLFSSL_ROOT)/wolfcrypt/src/random.c \
158-
$(WOLFSSL_ROOT)/wolfcrypt/src/ecc.c \
159-
$(WOLFSSL_ROOT)/wolfcrypt/src/asn.c \
160-
$(WOLFSSL_ROOT)/wolfcrypt/src/coding.c \
161-
$(WOLFSSL_ROOT)/wolfcrypt/src/wc_port.c \
162-
$(WOLFSSL_ROOT)/wolfcrypt/src/memory.c \
163-
$(WOLFSSL_ROOT)/wolfcrypt/src/wolfmath.c \
164-
$(WOLFSSL_ROOT)/wolfcrypt/src/sp_int.c \
165-
$(WOLFSSL_ROOT)/wolfcrypt/src/sp_c32.c \
166-
$(WOLFSSL_ROOT)/wolfcrypt/src/sp_cortexm.c \
167-
$(WOLFSSL_ROOT)/src/ssl.c \
168-
$(WOLFSSL_ROOT)/src/tls.c \
169-
$(WOLFSSL_ROOT)/src/tls13.c \
170-
$(WOLFSSL_ROOT)/src/internal.c \
171-
$(WOLFSSL_ROOT)/src/keys.c \
172-
$(WOLFSSL_ROOT)/src/wolfio.c
173-
174-
# ChaCha20-Poly1305 (optional)
175-
WOLFSSL_SRCS += \
176-
$(WOLFSSL_ROOT)/wolfcrypt/src/chacha.c \
177-
$(WOLFSSL_ROOT)/wolfcrypt/src/chacha20_poly1305.c \
178-
$(WOLFSSL_ROOT)/wolfcrypt/src/poly1305.c
179-
180-
# RSA for certificate verification
181-
WOLFSSL_SRCS += \
182-
$(WOLFSSL_ROOT)/wolfcrypt/src/rsa.c \
183-
$(WOLFSSL_ROOT)/wolfcrypt/src/signature.c
184-
185-
# Support sources (logging, error strings, encrypt helpers)
186-
WOLFSSL_SRCS += \
187-
$(WOLFSSL_ROOT)/wolfcrypt/src/logging.c \
188-
$(WOLFSSL_ROOT)/wolfcrypt/src/error.c \
189-
$(WOLFSSL_ROOT)/wolfcrypt/src/wc_encrypt.c
190-
152+
# wolfSSL/wolfCrypt source set comes from the shared wolfssl.mk (included above),
153+
# plus the logging/error/encrypt group.
154+
WOLFSSL_SRCS += $(WOLFSSL_LOG_SRCS)
191155
SRCS += $(WOLFSSL_SRCS)
192156

193157
endif # ENABLE_TLS
@@ -322,18 +286,17 @@ app.bin: app.elf
322286
%.o: %.c
323287
$(CC) $(CFLAGS) -c $< -o $@
324288

325-
# wolfSSL objects use relaxed warnings
326-
$(WOLFSSL_ROOT)/%.o: $(WOLFSSL_ROOT)/%.c
327-
$(CC) $(CFLAGS_WOLFSSL) -DWOLFSSL_USER_SETTINGS -I$(WOLFSSL_ROOT) -c $< -o $@
289+
# The $(WOLFSSL_ROOT)/%.o relaxed-warning rule comes from wolfssl.mk.
328290

329291
# The two wolfIP<->wolfSSL glue files live in the app/port tree but include
330292
# wolfssl/ssl.h, so they need the wolfSSL-facing defines (WOLFSSL_WOLFIP /
331293
# WOLFSSL_STM32C5 / -I$(WOLFSSL_ROOT)). Keep -Werror (our code). These are
332294
# defined only when ENABLE_TLS is on, and sit after "all:" so they do not
333295
# hijack the default goal.
334296
ifeq ($(ENABLE_TLS),1)
335-
tls_client.o: tls_client.c
336-
$(CC) $(CFLAGS) $(TLS_WOLFSSL_DEFS) -c $< -o $@
297+
# Shared TLS client: mutual auth (client cert from tls_certs.h) + forced suite.
298+
$(ROOT)/src/port/tls_client.o: $(ROOT)/src/port/tls_client.c
299+
$(CC) $(CFLAGS) $(TLS_WOLFSSL_DEFS) -DTLS_CLIENT_MUTUAL_AUTH -DTLS_CLIENT_CIPHER='"TLS_AES_128_GCM_SHA256"' -c $< -o $@
337300

338301
$(ROOT)/src/port/wolfssl_io.o: $(ROOT)/src/port/wolfssl_io.c
339302
$(CC) $(CFLAGS) $(TLS_WOLFSSL_DEFS) -c $< -o $@

src/port/stm32c5a3/README.md

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
# wolfIP on STM32C5A3ZG (NUCLEO-C5A3ZG)
2+
3+
Bare-metal wolfIP TCP/IP port for the STMicro STM32C5A3ZG (Cortex-M33F, no
4+
TrustZone), with a TLS 1.3 mutual-auth client whose long-term ECDSA identity
5+
key is protected by the STM32 DHUK (Device Hardware Unique Key) crypto
6+
callback: the private scalar is unwrapped inside the SAES block and signed on
7+
the hardware PKA, so it never appears in software.
8+
9+
## Status
10+
11+
All configurations validated on hardware (NUCLEO-C5A3ZG):
12+
13+
- Network: DHCP + ICMP ping + TCP echo on port 7.
14+
- DHUK crypto-callback self-test: ECDSA sign (HW PKA), AES-GCM (SAES), HMAC-SHA256 (HASH), TRNG.
15+
- TLS 1.3 mutual-auth client: `TLS_AES_128_GCM_SHA256`, peer verifies the device client certificate.
16+
- DHUK identity key in TLS: CertificateVerify signed through the callback (SAES unwrap -> HW PKA).
17+
18+
## Hardware
19+
20+
- MCU: Cortex-M33F @ 144 MHz (HSE 48 MHz -> PSI -> PSIS), 1 MB flash, 256 KB SRAM. No TrustZone (single image).
21+
- Ethernet: on-chip Synopsys DWC GMAC (RMII), shared driver `../stm32/stm32_eth.c`.
22+
- Crypto: SAES, PKA (V2, sign-only), HASH, RNG.
23+
24+
RMII pin map (all AF10 unless noted):
25+
26+
| Signal | Pin | Note |
27+
|-----------|------|------------------------------|
28+
| REF_CLK | PA1 | |
29+
| MDC | PC1 | |
30+
| MDIO | PE12 | not PA2 (PA2 = USART2 TX) |
31+
| CRS_DV | PD1 | |
32+
| RXD0 | PC4 | **AF12** (not AF10) |
33+
| RXD1 | PC5 | **AF13** (not AF10) |
34+
| TX_EN | PG11 | |
35+
| TXD0 | PG13 | |
36+
| TXD1 | PG12 | |
37+
38+
Console: USART2 PA2(TX)/PA3(RX) AF7, 115200 8N1 over the ST-LINK VCP.
39+
40+
## Build
41+
42+
```
43+
make # network only (DHCP + ping + TCP echo)
44+
make ENABLE_CB_SELFTEST=1 # + wolfCrypt DHUK self-test (no TLS)
45+
make ENABLE_TLS_CLIENT=1 # + TLS 1.3 mutual-auth client (software identity key)
46+
make ENABLE_TLS_CLIENT=1 ENABLE_DHUK_KEY=1 # + identity key signed via the DHUK callback
47+
```
48+
49+
The TLS / self-test builds need the wolfSSL branch that carries the STM32C5
50+
bare-crypto + DHUK port; point `WOLFSSL_ROOT` at it (defaults to the sibling
51+
`../wolfssl-c5tls` for those builds). The wolfSSL/wolfCrypt source list and
52+
build rules are shared from `../stm32/wolfssl.mk`.
53+
54+
If your shell presets `CC` to the host compiler, pass `CC=arm-none-eabi-gcc`.
55+
56+
Approx flash usage (1 MB): network 3.0%, self-test 6.8%, TLS 21.2%, TLS+DHUK 21.9%.
57+
58+
## Flash
59+
60+
STM32CubeProgrammer over SWD (pyocd / st-flash do not support C5; the debug AP
61+
is AP2, so use under-reset connect):
62+
63+
```
64+
make flash
65+
# = STM32_Programmer_CLI -c port=swd sn=<ST-LINK-SN> mode=UR -e all -d app.bin 0x08000000 -v -rst
66+
```
67+
68+
## TLS test
69+
70+
The device is the client; run an OpenSSL server on the host that requires and
71+
verifies the client certificate:
72+
73+
```
74+
cd tls-certs
75+
openssl s_server -accept 11111 -tls1_3 -cert server.pem -key server.key.pem \
76+
-Verify 1 -CAfile ca.pem -www
77+
```
78+
79+
Set the target in `config.h` (`TLS_SERVER_IP` / `TLS_SERVER_PORT`). On success
80+
the device logs `TLS Client: Passed!` and the server logs `verify return:1` for
81+
`CN = stm32c5a3-client`.
82+
83+
## Test certificates
84+
85+
`tls_certs.h` (embedded in the firmware, all public material) is committed; the
86+
host server material `tls-certs/` is git-ignored (it holds a throwaway test
87+
key). Both come from `gen_certs.py`. The client identity keypair is the public
88+
NIST P-256 CAVP vector in `st_p256_vec.h`; the CA and server are fixed-scalar
89+
test keys. To (re)generate before running the TLS test:
90+
91+
```
92+
python3 gen_certs.py # writes tls_certs.h AND tls-certs/{ca,server,server.key}.pem
93+
make ENABLE_TLS_CLIENT=1 ENABLE_DHUK_KEY=1 && make flash
94+
```
95+
96+
ECDSA cert DER is not byte-reproducible, so regenerating rewrites `tls_certs.h`
97+
too -- rebuild + reflash so the device cert matches the fresh host CA.
98+
99+
## Hardware gotchas (see the inline comments)
100+
101+
- RXD0/RXD1 use AF12/AF13, not AF10 -- AF10 there silently kills RX (link stays up via MDIO, no frames received).
102+
- The RNG clock-error detector (`CR.CED`) false-trips on the 48 MHz CK48 clock; it is disabled (`WC_STM32_RNG_CED_DISABLE`).
103+
- `_sbrk` uses the linker `.heap` region -- an `_ebss.._estack` heap would overlap the Ethernet DMA buffers and be corrupted by packet DMA.
104+
- C5 PKA is sign-only: ECDSA verify and ephemeral ECDHE run in software (Config A).
105+
106+
## Out of scope
107+
108+
- Config B (`WOLF_CRYPTO_CB_ONLY_ECC`, route ECDHE through the callback to strip software ECC) -- needs wolfSSL-side ECDH callback work.
109+
- wolfBoot secure-boot chainload (this board is supported by wolfBoot `config/examples/stm32c5.config`).

0 commit comments

Comments
 (0)