wolfTPM SPDM support (tested with Nuvoton NPCT75x)#458
wolfTPM SPDM support (tested with Nuvoton NPCT75x)#458aidangarske wants to merge 4 commits intowolfSSL:masterfrom
Conversation
b684e06 to
e56719c
Compare
dgarske
left a comment
There was a problem hiding this comment.
This is very nice and almost ready for merge. I provided you some feedback directly and I know you are out Monday, so no rush.
- 18/18 emulator tests PASS (6 tests x 3 versions: 1.2, 1.3, 1.4) 1. Removed OpaqueDataLength(2) from CHALLENGE request for SPDM 1.3+ — spec says only RequesterContext(8), no OpaqueDataLength in request 2. Removed OpaqueDataLength(2) from signed GET_MEASUREMENTS request for SPDM 1.3+ — same issue - spdm/README.md: Added supported versions table (spdm-emu: 1.2/1.3/1.4, Nuvoton: 1.3), updated protocol flow diagram, added --ver flag to demo options, added wolfSPDM_SetMaxVersion() to API table, updated emulator section to mention 18-test multi-version coverage - Addressed PR review feedback
dgarske
left a comment
There was a problem hiding this comment.
Please work on code size reduction (possibly moving the spdm-emu stuff to another report). Also please work on the TPM SPDM PSK use case.
f43ecbb to
57c6e83
Compare
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 38 out of 39 changed files in this pull request and generated 4 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
… lines)
Security fixes:
- Mandatory responder signature verification in KEY_EXCHANGE_RSP (was conditional skip)
- Sensitive stack buffer zeroing (wc_ForceZero) in BuildFinish, ParseKeyExchangeRsp,
wolfSPDM_Finish for keys, HMAC, and signature data
- TCG integer underflow guard in ParseTcgClearMessage (msgSize < header check)
- BuildIV: removed dead code duplicate branches, collapsed to single 8-byte XOR path
Code quality:
- Cascade error handling (rc == WOLFSPDM_SUCCESS pattern) across spdm_msg.c,
spdm_session.c, spdm_secured.c for single-cleanup-path safety
- wolfSPDM_BuildVendorDefined: added spdmVersion parameter (was hardcoded 0x13)
- spdm_error.h: added spdm_types.h include for standalone WOLFSPDM_API definition
- spdm.h: added stack usage documentation (~22KB context, ~20KB call chain)
Codebase reduction (-4,301 net lines):
- Condensed spdm_demo.c (382->256 lines), spdm_test.sh (143->70 lines)
- Removed verbose banner comments and redundant section headers across all files
- Consolidated unit tests with shared helpers, removed duplicate test patterns
- Removed spdm-emu-test.yml CI workflow (moved to standalone wolfSPDM repo)
- Streamlined README documentation
Test results:
- 26/26 unit tests PASS
- 6/6 Nuvoton hardware tests PASS (spdm_test.sh)
57c6e83 to
d58702e
Compare
- Nations NS350 PSK mode: PSK_SET, PSK_CLEAR, PSK_EXCHANGE, PSK_FINISH,
GET_STATUS, SPDM_ONLY with 32-byte ClearAuth per TCG PC Client spec
- Salt_0 = 0xFF for PSK mode HKDF-Extract (vs 0x00 for identity key mode)
- NATIONS_PSK mode checks in spdm_secured.c encrypt/decrypt paths
- GET_STATUS response parsing fix (PSKSet byte was not being read)
- Demo cleanup order: TPM2_Shutdown before SPDM disconnect
- 32-byte ClearAuth enforcement on PSK_SET and PSK_CLEAR
- spdm_test.sh nations-psk: 12-step PSK lifecycle test with NSING reference data
- spdm/README.md: TCG commands section, Nations PSK docs, validation status
- Removed unused inline PSK_SET, SetPskSetPayload, ConnectNationsPskProvision
- SPDM 1.3+ OpaqueDataLength fix for CHALLENGE and GET_MEASUREMENTS requests
Tested: 10/10 Nations PSK tests PASS, 6/6 Nuvoton tests PASS
wolfSSL-Fenrir-bot
left a comment
There was a problem hiding this comment.
Fenrir Automated Review — PR #458
Scan targets checked: wolftpm-bugs, wolftpm-src
Findings: 1
Info (1)
Incomplete review: src/*.c diffs truncated
File: hal/tpm_io_linux.c:85-87
Function: N/A
Category: HAL implementation flaws
The diff provided was truncated before reaching the in-scope src/tpm2.c, src/tpm2_packet.c, src/tpm2_spdm.c, src/tpm2_swtpm.c, and src/tpm2_wrap.c changes. The only visible in-scope change is in hal/tpm_io_linux.c which adds a compile-time SPI chip-select constant TPM2_SPI_DEV_CS "0" for WOLFTPM_NATIONS, identical to the existing Nuvoton configuration. This change is benign. The out-of-scope spdm/src/ library code (visible in the diff) demonstrates good security practices: wc_ForceZero for key material, wc_ecc_check_key for peer key validation, proper buffer bounds checking, and state machine enforcement. A complete review of src/tpm2_spdm.c and src/tpm2_wrap.c is recommended as these files contain the integration layer between wolfTPM and the SPDM subsystem.
#elif defined(WOLFTPM_NATIONS)
/* Nations Technology NS350 uses CE0 */
#define TPM2_SPI_DEV_CS "0"Recommendation: Re-run this security review with the complete diff (including src/tpm2.c, src/tpm2_packet.c, src/tpm2_spdm.c, src/tpm2_swtpm.c, and src/tpm2_wrap.c) to ensure full coverage of the in-scope files.
This review was generated automatically by Fenrir. Findings are non-blocking.
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 41 out of 42 changed files in this pull request and generated 2 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| if (rc < 0) /* SPDM not active, use normal transport */ | ||
| #endif | ||
| { | ||
| rc = (TPM_RC)INTERNAL_SEND_COMMAND(ctx, packet); | ||
| } |
There was a problem hiding this comment.
In TPM2_SendCommandAuth(), the SPDM fallback condition uses if (rc < 0) to decide that SPDM is inactive. However, wolfTPM2_SPDM_SecuredExchange/wolfSPDM return negative error codes on real failures (e.g., decrypt/HMAC/IO errors), so this will incorrectly fall back to sending the same command over the clear transport after an SPDM failure. Use a dedicated sentinel for "SPDM not active" (e.g., return -1 only for that case and check rc == -1 here), and treat any other non-zero as a hard error (no cleartext retry).
| if (rc < 0) /* SPDM not active, use normal transport */ | |
| #endif | |
| { | |
| rc = (TPM_RC)INTERNAL_SEND_COMMAND(ctx, packet); | |
| } | |
| if (rc == -1) { /* SPDM not active, use normal transport */ | |
| rc = (TPM_RC)INTERNAL_SEND_COMMAND(ctx, packet); | |
| } | |
| else if (rc != 0) { | |
| /* SPDM is active but the secured exchange failed: do not retry in clear */ | |
| return rc; | |
| } | |
| #else | |
| rc = (TPM_RC)INTERNAL_SEND_COMMAND(ctx, packet); | |
| #endif |
| #ifdef WOLFTPM_SPDM | ||
| rc = TPM2_SPDM_SendCommand(ctx, packet); | ||
| if (rc == TPM_RC_SUCCESS) | ||
| return TPM2_Packet_Parse(rc, packet); | ||
| /* rc < 0 means SPDM not active, fall through to normal transport */ | ||
| #endif | ||
|
|
||
| /* submit command and wait for response */ | ||
| rc = (TPM_RC)INTERNAL_SEND_COMMAND(ctx, packet); |
There was a problem hiding this comment.
In TPM2_SendCommand(), if TPM2_SPDM_SendCommand() returns an SPDM error (non-zero), the code currently falls through to INTERNAL_SEND_COMMAND and will resend the command in cleartext. This can leak commands/authorization after an SPDM failure and can also cause duplicate execution. Handle SPDM outcomes explicitly: return immediately on any error that is not the "SPDM not active" sentinel, and only fall back to INTERNAL_SEND_COMMAND when SPDM is not configured/connected.
Description
Migrates the standalone wolfSPDM library into wolfTPM as an in-tree spdm/
subdirectory and adds full SPDM support for both Nuvoton NPCT75x and
Nations NS350 TPMs. Eliminates the external dependency — a single
--enable-spdm configure flag builds everything.
wolfSPDM Library (spdm/)
GET_STS_, TPM2_CMD, PSK_SET_, PSK_CLR_)
GET_PUBK, KEY_EXCHANGE, GIVE_PUB, FINISH
PSK_EXCHANGE, PSK_FINISH
Nuvoton NPCT75x Support
Nations NS350 Support
PSK Mode
Identity Key Mode
wolfTPM Integration
automatically encrypted when SPDM session is active
SPDM Demo (examples/spdm/)
TCG SPDM Vendor Commands
Test Plan