Skip to content

wolfTPM SPDM support (Nuvoton NPCT75x and NSING NS350)#458

Open
aidangarske wants to merge 10 commits intowolfSSL:masterfrom
aidangarske:add-full-spdm-support
Open

wolfTPM SPDM support (Nuvoton NPCT75x and NSING NS350)#458
aidangarske wants to merge 10 commits intowolfSSL:masterfrom
aidangarske:add-full-spdm-support

Conversation

@aidangarske
Copy link
Member

@aidangarske aidangarske commented Feb 20, 2026

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/)

  • SPDM 1.3 (DSP0274) with Algorithm Set B (P-384, SHA-384, AES-256-GCM, HKDF)
  • Standard mode: works with libspdm spdm-emu responder for testing
  • TCG SPDM Binding: vendor-defined commands (GET_PUBK, GIVE_PUB, SPDMONLY,
    GET_STS_, TPM2_CMD, PSK_SET_, PSK_CLR_)
  • Identity key session: GET_VERSION, GET_CAPABILITIES, NEGOTIATE_ALGORITHMS,
    GET_PUBK, KEY_EXCHANGE, GIVE_PUB, FINISH
  • PSK session: GET_VERSION, GET_CAPABILITIES, NEGOTIATE_ALGORITHMS,
    PSK_EXCHANGE, PSK_FINISH
  • Secured messaging: AES-256-GCM AEAD with sequence number tracking
  • Static memory mode (zero-malloc) and dynamic mode (--enable-spdm-dynamic-mem)
  • Unit test suite (spdm/test/unit_test.c)

Nuvoton NPCT75x Support

  • NTC2_PreConfig vendor commands for SPDM enable/disable
  • SPDM-only mode: lock/unlock enforcement over identity key sessions
  • Auto-SPDM: transparent session establishment when TPM is in SPDM-only mode
  • Tested: 6/6 hardware tests (status, connect, lock, unit test, unlock, caps)

Nations NS350 Support

PSK Mode

  • PSK_SET/PSK_CLEAR vendor commands with 32-byte ClearAuth (TCG PC Client spec)
  • PSK_EXCHANGE/PSK_FINISH session establishment (Salt_0 = 0xFF for PSK mode)
  • GET_STATUS with response parsing (PSKSet, SPDMOnly, spec version)
  • SPDM_ONLY lock/unlock for PSK mode
  • Tested: 10/10 PSK lifecycle tests (provision, connect, clear, re-provision)

Identity Key Mode

  • Shared TCG SPDM binding protocol with Nuvoton
  • TPM2_VendorSpdmIdentityKeySet for identity key provisioning
  • TODO: Re-test on firmware 0.1.0.15 (digest changed to SHA-384(TPMT_PUBLIC))

wolfTPM Integration

  • 13+ new wolfTPM2_Spdm*() wrapper API functions in tpm2_wrap.h
  • Transparent SPDM transport in TPM2_SendCommand() — all TPM commands
    automatically encrypted when SPDM session is active
  • TIS I/O callback for routing SPDM through SPI/I2C TPM FIFO
  • Auto-generated ephemeral P-384 key pair for mutual authentication

SPDM Demo (examples/spdm/)

  • spdm_demo.c: Nuvoton and Nations hardware modes
  • spdm_test.sh: Automated tests for nuvoton, nations, and nations-psk modes

TCG SPDM Vendor Commands

VdCode Command Nuvoton Nations
GET_PUBK Get Public Key Yes Yes
GIVE_PUB Give Public Key Yes Yes
TPM2_CMD TPM Command Yes Yes
GET_STS_ Get Status Yes Yes
SPDMONLY SPDM-Only Mode Yes Yes
PSK_SET_ PSK Set N/A Yes
PSK_CLR_ PSK Clear N/A Yes

Test Plan

  • Build with --enable-spdm --enable-nuvoton
  • Build with --enable-spdm --enable-nations
  • Build without --enable-spdm (no breakage)
  • 26/26 unit tests PASS
  • 6/6 Nuvoton hardware tests PASS
  • 10/12 Nations PSK hardware tests PASS. (two still need testing)
  • Nations identity key mode on firmware 0.1.0.15
  • Copilot review
  • fenrir
  • update fenrir to scan wolftpm/spdm

This comment was marked as outdated.

This comment was marked as outdated.

This comment was marked as outdated.

@aidangarske aidangarske requested a review from dgarske February 20, 2026 21:58
@dgarske dgarske assigned dgarske and wolfSSL-Bot and unassigned aidangarske Feb 21, 2026
Copilot AI review requested due to automatic review settings February 24, 2026 16:26

This comment was marked as off-topic.

This comment was marked as outdated.

@dgarske dgarske removed their assignment Feb 24, 2026
Copilot AI review requested due to automatic review settings February 26, 2026 18:20

This comment was marked as outdated.

wolfSSL-Fenrir-bot

This comment was marked as duplicate.

wolfSSL-Fenrir-bot

This comment was marked as duplicate.

aidangarske and others added 6 commits March 23, 2026 13:21
  - 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
… 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)
  - 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
  - Ct hash changed from SHA-384(X||Y) to SHA-384(TPMT_PUBLIC) for both
    responder (KEY_EXCHANGE) and requester (FINISH mutual auth), matching
    Vision's updated firmware and Nuvoton's implementation
  - wolfSSL requires --enable-ecccustcurves=all for Nations (HAVE_ECC_CDH)
  - spdm_test.sh: use run_test_no_reset for Nations (GPIO 4 not wired to
    TPM_RST on NS350 daughter board, requires full power cycle)
  - spdm_test.sh nations: full lifecycle (unset, set, connect, status, caps)
  - spdm/README.md: separate wolfSSL build sections for Nuvoton vs Nations,
    removed status columns from command tables, updated troubleshooting for
    NS350 power cycle requirement
  - CLAUDE.md: updated build instructions with correct minimal flags

  Tested: 5/5 Nations identity key tests PASS, 12/12 Nations PSK tests PAS
Copilot AI review requested due to automatic review settings March 23, 2026 21:44
@dgarske dgarske force-pushed the add-full-spdm-support branch from a938208 to 30065f1 Compare March 23, 2026 21:44
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

  - Create spdm_tcg.c/spdm_tcg.h for shared TCG binding code (Nuvoton + Nations)
  - Consolidate duplicate VendorCmdClear/VendorCmdSecured helpers
  - Extract shared GetCapabilities/NegotiateAlgorithms functions
  - Rename Nuvoton_GetPubKey/GivePubKey to TCG_ prefix (with compat aliases)
  - Unify vendor constants (GET_STS_, SPDMONLY, lock/unlock)
  - Add overridable buffer size macros (WOLFSPDM_KEY_EX_TX_SZ, etc.)
  - Use ECC_MAX_SIG_SIZE from wolfCrypt for DER signature buffers
  - Add SPDM_VERSION_10 macro for GET_VERSION
  - Add HAVE_ECC/WOLFSSL_SHA384 compile-time checks
  - Add WOLFTPM_SPDM_PSK generic build option (replaces WOLFSPDM_NATIONS for PSK protocol code)
  - Fix spdm_test.sh caps exit code check (caps returns handle count, not 0)
  - Slim spdm_nuvoton.c to Nuvoton-only (112 lines), spdm_nations.c to Nations-only (294 lines)
  - 6/6 Nuvoton hardware tests pass
Copy link

@wolfSSL-Fenrir-bot wolfSSL-Fenrir-bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fenrir Automated Review — PR #458

Scan targets checked: wolftpm-bugs, wolftpm-src

No new issues found in the changed files. ✅

This comment was marked as outdated.

The shared TCG SPDM source and header files were referenced by
include.am/Makefile.in but not committed, causing CI build failures.
  - Create spdm_psk.c with shared SPDM PSK protocol code (vendor-independent)
    - wolfSPDM_SetPSK() moved from spdm_context.c
    - wolfSPDM_BuildPskExchange/ParsePskExchangeRsp moved from spdm_msg.c
    - wolfSPDM_BuildPskFinish/ParsePskFinishRsp moved from spdm_msg.c
    - wolfSPDM_DeriveHandshakeKeysPsk() moved from spdm_kdf.c
    - wolfSPDM_ConnectPsk() moved from spdm_nations.c (renamed from ConnectNationsPsk)
  - Create spdm_psk.h with shared PSK declarations and backward-compat alias
  - Make wolfSPDM_DeriveFromHandshakeSecret() non-static for cross-file use
  - Vendor files now contain only vendor-specific commands:
    - spdm_nations.c: GetStatus, SetOnlyMode, PskSet, PskClear, PskClearWithVCA
    - spdm_nuvoton.c: GetStatus, SetOnlyMode
  - 12/12 Nations PSK hardware tests pass
  - Enables future Infineon PSK support without touching vendor-specific code
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 45 out of 46 changed files in this pull request and generated 1 comment.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +973 to +978
/* Initialize device */
rc = wolfTPM2_Init(&dev, TPM2_IoCb, NULL);
if (rc != 0) {
printf("Failed (Init failed: 0x%x)\n", rc);
return;
}
Copy link

Copilot AI Mar 24, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This unit test returns early if wolfTPM2_Init() fails, which can silently skip the SPDM wrapper assertions and still print "Passed" later in the suite. Other unit tests in this file use Assert*() so failures are reported consistently. Consider converting this to AssertIntEQ(rc, 0) (or an explicit skip mechanism that increments the fail count) rather than returning.

Copilot uses AI. Check for mistakes.
Copy link

@wolfSSL-Fenrir-bot wolfSSL-Fenrir-bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fenrir Automated Review — PR #458

Scan targets checked: wolftpm-bugs, wolftpm-src

No new issues found in the changed files. ✅

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants