From ddf990a4c9ed9cde88d307641f4d32a141ea2dd4 Mon Sep 17 00:00:00 2001 From: Aidan Garske Date: Wed, 25 Mar 2026 18:59:32 +0000 Subject: [PATCH] Address review feedback - Renamed spdm_demo to spdm_ctrl: file, binary, internal demo_* functions to ctrl_*, all references in include.am, spdm_test.sh, .gitignore, CLAUDE.md, both READMEs - README mentions Nations: title updated to Nuvoton NPCT75x and Nations NS350 TPMs, added Nations build section - README section header renamed from Demo Commands to Setup/Control Commands - README added reset pin control section: documents GPIO reset requirement, Pi-specific example, custom hardware design guidance - Moved spdm_tcg.c to common build section, no longer conditional on Nuvoton/Nations in src/spdm/include.am - Removed redundant wolfSSL options include from spdm_internal.h since tpm2_types.h handles this - Added WOLFTPM_SPDM_TCG generic guard as auto-define in spdm_types.h, replaced ~30 occurrences of #if defined(WOLFSPDM_NUVOTON) || defined(WOLFSPDM_NATIONS) across all files --- .gitignore | 2 +- examples/spdm/README.md | 71 ++++++++++++++++------ examples/spdm/include.am | 14 ++--- examples/spdm/{spdm_demo.c => spdm_ctrl.c} | 70 ++++++++++----------- examples/spdm/spdm_test.sh | 4 +- src/spdm/README.md | 48 +++++++-------- src/spdm/include.am | 8 +-- src/spdm/spdm_context.c | 12 ++-- src/spdm/spdm_internal.h | 11 +--- src/spdm/spdm_msg.c | 4 +- src/spdm/spdm_secured.c | 6 +- src/spdm/spdm_tcg.c | 4 +- src/spdm/unit_test.c | 6 +- src/tpm2_spdm.c | 10 +-- src/tpm2_wrap.c | 4 +- wolftpm/spdm/spdm.h | 4 +- wolftpm/spdm/spdm_tcg.h | 4 +- wolftpm/spdm/spdm_types.h | 8 +++ wolftpm/tpm2_spdm.h | 4 +- wolftpm/tpm2_wrap.h | 4 +- 20 files changed, 167 insertions(+), 131 deletions(-) rename examples/spdm/{spdm_demo.c => spdm_ctrl.c} (92%) diff --git a/.gitignore b/.gitignore index 222f771e..83f99344 100644 --- a/.gitignore +++ b/.gitignore @@ -92,7 +92,7 @@ examples/firmware/ifx_fw_update examples/firmware/st33_fw_update examples/endorsement/get_ek_certs examples/endorsement/verify_ek_cert -examples/spdm/spdm_demo +examples/spdm/spdm_ctrl # Generated Cert Files certs/ca-*.pem diff --git a/examples/spdm/README.md b/examples/spdm/README.md index 377cd485..9c939c3e 100644 --- a/examples/spdm/README.md +++ b/examples/spdm/README.md @@ -1,12 +1,17 @@ -# TPM SPDM Examples +# TPM SPDM Setup/Control -This directory contains the SPDM demo for Nuvoton NPCT75x TPMs with wolfTPM. +This directory contains the SPDM setup and control tool for Nuvoton NPCT75x +and Nations NS350 TPMs with wolfTPM. ## Overview -The `spdm_demo` establishes an SPDM secure session between the host and a -Nuvoton TPM over SPI, enabling AES-256-GCM encrypted bus communication. Once -active, all TPM commands are automatically encrypted with no application changes. +The `spdm_ctrl` tool establishes SPDM secure sessions between the host and a +TPM over SPI, enabling AES-256-GCM encrypted bus communication. Once active, +all TPM commands are automatically encrypted with no application changes. + +Supported hardware: +- **Nuvoton NPCT75x** — Identity key mode (ECDHE P-384) +- **Nations NS350** — Identity key mode + PSK mode For standard SPDM protocol support (spdm-emu, measurements, challenge, etc.), see the [wolfSPDM](https://github.com/aidangarske/wolfSPDM) standalone library. @@ -33,7 +38,16 @@ cd wolfTPM make ``` -## Demo Commands +### wolfTPM with Nations SPDM + +```bash +cd wolfTPM +./autogen.sh +./configure --enable-spdm --enable-nations +make +``` + +## Setup/Control Commands | Option | Description | |--------|-------------| @@ -48,39 +62,60 @@ make ## Usage Examples ```bash -# One-time setup: enable SPDM + GPIO reset -./examples/spdm/spdm_demo --enable -gpioset gpiochip0 4=0 && sleep 0.1 && gpioset gpiochip0 4=1 && sleep 2 +# One-time setup: enable SPDM + reset TPM +./examples/spdm/spdm_ctrl --enable +# Reset the TPM (see "TPM Reset Pin Control" below) # Query SPDM status -./examples/spdm/spdm_demo --status +./examples/spdm/spdm_ctrl --status # Get TPM identity key -./examples/spdm/spdm_demo --get-pubkey +./examples/spdm/spdm_ctrl --get-pubkey # Establish SPDM session -./examples/spdm/spdm_demo --connect +./examples/spdm/spdm_ctrl --connect # Lock SPDM-only mode (connect + lock in one session) -./examples/spdm/spdm_demo --connect --lock -gpioset gpiochip0 4=0 && sleep 0.1 && gpioset gpiochip0 4=1 && sleep 2 +./examples/spdm/spdm_ctrl --connect --lock +# Reset the TPM # All commands now auto-encrypt: ./examples/wrap/caps # auto-SPDM, AES-256-GCM encrypted ./tests/unit.test # full test suite over encrypted bus # Unlock SPDM-only mode -gpioset gpiochip0 4=0 && sleep 0.1 && gpioset gpiochip0 4=1 && sleep 2 -./examples/spdm/spdm_demo --connect --unlock +# Reset the TPM +./examples/spdm/spdm_ctrl --connect --unlock +# Reset the TPM +``` + +## TPM Reset Pin Control + +SPDM enable/disable and SPDM-only mode changes require a TPM reset to take +effect. The reset pin must be connected and controllable by the host. + +**Important for custom hardware designs:** Ensure the TPM reset pin is routed +to a host-controllable GPIO. Without reset pin control, SPDM mode changes +cannot be applied and recovery from SPDM-only mode is not possible. + +### Raspberry Pi Example (GPIO 4) + +```bash +# Assert reset low, wait, release high, wait for TPM startup gpioset gpiochip0 4=0 && sleep 0.1 && gpioset gpiochip0 4=1 && sleep 2 ``` +Other platforms will use their own GPIO control mechanism. The key requirement +is toggling the TPM reset line (active low) with sufficient hold time. + ## Automated Test Suite -Runs 6 tests: status, connect, lock, unit test over SPDM, unlock, cleartext caps setup lifecycle on hardware. +Runs the full SPDM setup lifecycle on hardware: ```bash -./examples/spdm/spdm_test.sh +./examples/spdm/spdm_test.sh ./examples/spdm/spdm_ctrl nuvoton +./examples/spdm/spdm_test.sh ./examples/spdm/spdm_ctrl nations +./examples/spdm/spdm_test.sh ./examples/spdm/spdm_ctrl nations-psk ``` ## Support diff --git a/examples/spdm/include.am b/examples/spdm/include.am index 54980203..deb6283d 100644 --- a/examples/spdm/include.am +++ b/examples/spdm/include.am @@ -3,16 +3,16 @@ if BUILD_EXAMPLES if BUILD_SPDM -noinst_PROGRAMS += examples/spdm/spdm_demo +noinst_PROGRAMS += examples/spdm/spdm_ctrl -examples_spdm_spdm_demo_SOURCES = examples/spdm/spdm_demo.c -examples_spdm_spdm_demo_LDADD = src/libwolftpm.la $(LIB_STATIC_ADD) -examples_spdm_spdm_demo_DEPENDENCIES = src/libwolftpm.la -examples_spdm_spdm_demo_CFLAGS = $(AM_CFLAGS) +examples_spdm_spdm_ctrl_SOURCES = examples/spdm/spdm_ctrl.c +examples_spdm_spdm_ctrl_LDADD = src/libwolftpm.la $(LIB_STATIC_ADD) +examples_spdm_spdm_ctrl_DEPENDENCIES = src/libwolftpm.la +examples_spdm_spdm_ctrl_CFLAGS = $(AM_CFLAGS) endif endif example_spdmdir = $(exampledir)/spdm -dist_example_spdm_DATA = examples/spdm/spdm_demo.c +dist_example_spdm_DATA = examples/spdm/spdm_ctrl.c -DISTCLEANFILES+= examples/spdm/.libs/spdm_demo +DISTCLEANFILES+= examples/spdm/.libs/spdm_ctrl diff --git a/examples/spdm/spdm_demo.c b/examples/spdm/spdm_ctrl.c similarity index 92% rename from examples/spdm/spdm_demo.c rename to examples/spdm/spdm_ctrl.c index e543b9d5..453921d3 100644 --- a/examples/spdm/spdm_demo.c +++ b/examples/spdm/spdm_ctrl.c @@ -1,4 +1,4 @@ -/* spdm_demo.c +/* spdm_ctrl.c * * Copyright (C) 2006-2025 wolfSSL Inc. * @@ -40,12 +40,12 @@ #include #include -int TPM2_SPDM_Demo(void* userCtx, int argc, char *argv[]); +int TPM2_SPDM_Ctrl(void* userCtx, int argc, char *argv[]); static void usage(void) { printf("SPDM Demo - TPM secure session\n\n" - "Usage: spdm_demo [options]\n" + "Usage: spdm_ctrl [options]\n" #ifdef WOLFSPDM_NUVOTON " --enable Enable SPDM via NTC2_PreConfig\n" " --disable Disable SPDM via NTC2_PreConfig\n" @@ -76,7 +76,7 @@ static void usage(void) } #ifdef WOLFSPDM_NUVOTON -static int demo_enable(WOLFTPM2_DEV* dev) +static int ctrl_enable(WOLFTPM2_DEV* dev) { int rc; printf("\n=== Enable SPDM ===\n"); @@ -95,7 +95,7 @@ static int demo_enable(WOLFTPM2_DEV* dev) return rc; } -static int demo_disable(WOLFTPM2_DEV* dev) +static int ctrl_disable(WOLFTPM2_DEV* dev) { int rc; printf("\n=== Disable SPDM ===\n"); @@ -113,7 +113,7 @@ static int demo_disable(WOLFTPM2_DEV* dev) return rc; } -static int demo_status(WOLFTPM2_DEV* dev) +static int ctrl_status(WOLFTPM2_DEV* dev) { int rc; WOLFSPDM_NUVOTON_STATUS status; @@ -143,7 +143,7 @@ static int demo_status(WOLFTPM2_DEV* dev) return rc; } -static int demo_get_pubkey(WOLFTPM2_DEV* dev) +static int ctrl_get_pubkey(WOLFTPM2_DEV* dev) { int rc; byte pubKey[128]; @@ -163,7 +163,7 @@ static int demo_get_pubkey(WOLFTPM2_DEV* dev) return rc; } -static int demo_connect(WOLFTPM2_DEV* dev) +static int ctrl_connect(WOLFTPM2_DEV* dev) { int rc; @@ -186,7 +186,7 @@ static int demo_connect(WOLFTPM2_DEV* dev) return rc; } -static int demo_lock(WOLFTPM2_DEV* dev, int lock) +static int ctrl_lock(WOLFTPM2_DEV* dev, int lock) { int rc; printf("\n=== SPDM-Only: %s ===\n", lock ? "LOCK" : "UNLOCK"); @@ -220,7 +220,7 @@ static int hex2bin(const char* hex, byte* bin, word32* binSz) return 0; } -static int demo_nations_status(WOLFTPM2_DEV* dev) +static int ctrl_nations_status(WOLFTPM2_DEV* dev) { int rc; int isConn; @@ -277,7 +277,7 @@ static int demo_nations_status(WOLFTPM2_DEV* dev) return 0; /* status is informational, don't fail */ } -static int demo_nations_psk_connect(WOLFTPM2_DEV* dev, const char* pskHex) +static int ctrl_nations_psk_connect(WOLFTPM2_DEV* dev, const char* pskHex) { int rc; byte psk[128]; @@ -301,7 +301,7 @@ static int demo_nations_psk_connect(WOLFTPM2_DEV* dev, const char* pskHex) return rc; } -static int demo_nations_psk_set(WOLFTPM2_DEV* dev, +static int ctrl_nations_psk_set(WOLFTPM2_DEV* dev, const char* pskHex, const char* clearAuthHex) { int rc; @@ -357,7 +357,7 @@ static int demo_nations_psk_set(WOLFTPM2_DEV* dev, return rc; } -static int demo_nations_psk_clear(WOLFTPM2_DEV* dev, const char* authHex) +static int ctrl_nations_psk_clear(WOLFTPM2_DEV* dev, const char* authHex) { int rc; byte clearAuth[256]; @@ -387,7 +387,7 @@ static int demo_nations_psk_clear(WOLFTPM2_DEV* dev, const char* authHex) return rc; } -static int demo_nations_identity_key_set(WOLFTPM2_DEV* dev, int set) +static int ctrl_nations_identity_key_set(WOLFTPM2_DEV* dev, int set) { int rc; printf("\n=== Nations Identity Key %s ===\n", set ? "Set" : "Unset"); @@ -400,7 +400,7 @@ static int demo_nations_identity_key_set(WOLFTPM2_DEV* dev, int set) return rc; } -static int demo_nations_get_pubkey(WOLFTPM2_DEV* dev) +static int ctrl_nations_get_pubkey(WOLFTPM2_DEV* dev) { int rc; byte pubKey[128]; @@ -428,7 +428,7 @@ static int demo_nations_get_pubkey(WOLFTPM2_DEV* dev) return rc; } -static int demo_nations_caps184(WOLFTPM2_DEV* dev) +static int ctrl_nations_caps184(WOLFTPM2_DEV* dev) { int rc; GetCapability_In capIn; @@ -505,7 +505,7 @@ static int demo_nations_caps184(WOLFTPM2_DEV* dev) return 0; } -static int demo_nations_connect(WOLFTPM2_DEV* dev) +static int ctrl_nations_connect(WOLFTPM2_DEV* dev) { int rc; @@ -529,7 +529,7 @@ static int demo_nations_connect(WOLFTPM2_DEV* dev) } #endif /* WOLFSPDM_NATIONS */ -int TPM2_SPDM_Demo(void* userCtx, int argc, char *argv[]) +int TPM2_SPDM_Ctrl(void* userCtx, int argc, char *argv[]) { int rc, i; WOLFTPM2_DEV dev; @@ -568,42 +568,42 @@ int TPM2_SPDM_Demo(void* userCtx, int argc, char *argv[]) for (i = 1; i < argc; i++) { #ifdef WOLFSPDM_NUVOTON if (XSTRCMP(argv[i], "--enable") == 0) - rc = demo_enable(&dev); + rc = ctrl_enable(&dev); else if (XSTRCMP(argv[i], "--disable") == 0) - rc = demo_disable(&dev); + rc = ctrl_disable(&dev); else if (XSTRCMP(argv[i], "--status") == 0) - rc = demo_status(&dev); + rc = ctrl_status(&dev); else if (XSTRCMP(argv[i], "--get-pubkey") == 0) - rc = demo_get_pubkey(&dev); + rc = ctrl_get_pubkey(&dev); else if (XSTRCMP(argv[i], "--connect") == 0) - rc = demo_connect(&dev); + rc = ctrl_connect(&dev); else if (XSTRCMP(argv[i], "--lock") == 0) - rc = demo_lock(&dev, 1); + rc = ctrl_lock(&dev, 1); else if (XSTRCMP(argv[i], "--unlock") == 0) - rc = demo_lock(&dev, 0); + rc = ctrl_lock(&dev, 0); else #endif #ifdef WOLFSPDM_NATIONS if (XSTRCMP(argv[i], "--identity-key-set") == 0) - rc = demo_nations_identity_key_set(&dev, 1); + rc = ctrl_nations_identity_key_set(&dev, 1); else if (XSTRCMP(argv[i], "--identity-key-unset") == 0) - rc = demo_nations_identity_key_set(&dev, 0); + rc = ctrl_nations_identity_key_set(&dev, 0); else if (XSTRCMP(argv[i], "--get-pubkey") == 0) - rc = demo_nations_get_pubkey(&dev); + rc = ctrl_nations_get_pubkey(&dev); else if (XSTRCMP(argv[i], "--connect") == 0) - rc = demo_nations_connect(&dev); + rc = ctrl_nations_connect(&dev); else if (XSTRCMP(argv[i], "--status") == 0) - rc = demo_nations_status(&dev); + rc = ctrl_nations_status(&dev); else if (XSTRCMP(argv[i], "--psk") == 0 && i + 1 < argc) - rc = demo_nations_psk_connect(&dev, argv[++i]); + rc = ctrl_nations_psk_connect(&dev, argv[++i]); else if (XSTRCMP(argv[i], "--psk-set") == 0 && i + 2 < argc) { const char* pskArg = argv[++i]; const char* authArg = argv[++i]; - rc = demo_nations_psk_set(&dev, pskArg, authArg); + rc = ctrl_nations_psk_set(&dev, pskArg, authArg); } else if (XSTRCMP(argv[i], "--psk-clear") == 0 && i + 1 < argc) - rc = demo_nations_psk_clear(&dev, argv[++i]); + rc = ctrl_nations_psk_clear(&dev, argv[++i]); else if (XSTRCMP(argv[i], "--lock") == 0) rc = wolfTPM2_SpdmNationsSetOnlyMode(&dev, 1); else if (XSTRCMP(argv[i], "--unlock") == 0) @@ -614,7 +614,7 @@ int TPM2_SPDM_Demo(void* userCtx, int argc, char *argv[]) printf(" %s (rc=0x%x)\n", rc == 0 ? "Success" : "FAILED", rc); } else if (XSTRCMP(argv[i], "--caps184") == 0) - rc = demo_nations_caps184(&dev); + rc = ctrl_nations_caps184(&dev); else #endif { printf("Unknown option: %s\n", argv[i]); usage(); rc = BAD_FUNC_ARG; } @@ -631,7 +631,7 @@ int main(int argc, char *argv[]) { int rc = -1; #ifndef WOLFTPM2_NO_WRAPPER - rc = TPM2_SPDM_Demo(NULL, argc, argv); + rc = TPM2_SPDM_Ctrl(NULL, argc, argv); #else printf("Wrapper code not compiled in\n"); (void)argc; (void)argv; diff --git a/examples/spdm/spdm_test.sh b/examples/spdm/spdm_test.sh index b72825bc..1237c311 100755 --- a/examples/spdm/spdm_test.sh +++ b/examples/spdm/spdm_test.sh @@ -19,7 +19,7 @@ # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA -SPDM_DEMO="${1:-./examples/spdm/spdm_demo}" +SPDM_DEMO="${1:-./examples/spdm/spdm_ctrl}" CAPS_DEMO="./examples/wrap/caps" UNIT_TEST="./tests/unit.test" GPIO_CHIP="gpiochip0" @@ -102,7 +102,7 @@ run_test_no_reset() { if [ ! -x "$SPDM_DEMO" ]; then echo "Error: $SPDM_DEMO not found." - echo "Usage: $0 [path-to-spdm_demo] [nuvoton|nations|nations-psk]" + echo "Usage: $0 [path-to-spdm_ctrl] [nuvoton|nations|nations-psk]" exit 1 fi diff --git a/src/spdm/README.md b/src/spdm/README.md index 0f6e01a0..da546b66 100644 --- a/src/spdm/README.md +++ b/src/spdm/README.md @@ -24,9 +24,9 @@ make && sudo make install && sudo ldconfig && popd ./autogen.sh && ./configure --enable-spdm --enable-nuvoton && make # Enable SPDM (one-time), reset, connect -./examples/spdm/spdm_demo --enable +./examples/spdm/spdm_ctrl --enable gpioset gpiochip0 4=0 && sleep 0.1 && gpioset gpiochip0 4=1 && sleep 2 -./examples/spdm/spdm_demo --connect +./examples/spdm/spdm_ctrl --connect ``` See [Building](#building) and [Nuvoton NPCT75x Details](#nuvoton-npct75x) for @@ -44,7 +44,7 @@ make && sudo make install && sudo ldconfig && popd ./autogen.sh && ./configure --enable-spdm --enable-nations && make # Connect (identity key is factory default) -./examples/spdm/spdm_demo --connect +./examples/spdm/spdm_ctrl --connect ``` See [Building](#building) and [Nations NS350 Details](#nations-ns350) for full @@ -194,13 +194,13 @@ make ```bash # Enable SPDM on the TPM (persists across resets) -./examples/spdm/spdm_demo --enable +./examples/spdm/spdm_ctrl --enable # GPIO reset gpioset gpiochip0 4=0 && sleep 0.1 && gpioset gpiochip0 4=1 && sleep 2 # Verify SPDM is enabled -./examples/spdm/spdm_demo --status +./examples/spdm/spdm_ctrl --status ``` #### Nations @@ -209,7 +209,7 @@ Identity key mode is the factory default — no setup required. If previously unset, restore with: ```bash -./examples/spdm/spdm_demo --identity-key-set +./examples/spdm/spdm_ctrl --identity-key-set ``` ### Establishing a Session @@ -218,10 +218,10 @@ unset, restore with: ```bash # Establish SPDM session (VERSION → GET_PUBK → KEY_EXCHANGE → GIVE_PUB → FINISH) -./examples/spdm/spdm_demo --connect +./examples/spdm/spdm_ctrl --connect # Query SPDM status -./examples/spdm/spdm_demo --status +./examples/spdm/spdm_ctrl --status ``` **Note:** `--get-pubkey` retrieves the TPM's identity key as part of the full @@ -234,7 +234,7 @@ Requires PSK to be provisioned first. See ```bash # Establish PSK session (VERSION → CAPS → ALGO → PSK_EXCHANGE → PSK_FINISH) -./examples/spdm/spdm_demo --psk +./examples/spdm/spdm_ctrl --psk ``` ### Lock/Unlock SPDM-Only Mode @@ -245,7 +245,7 @@ enforcement to take effect. **Nuvoton (identity key):** ```bash -./examples/spdm/spdm_demo --connect --lock +./examples/spdm/spdm_ctrl --connect --lock gpioset gpiochip0 4=0 && sleep 0.1 && gpioset gpiochip0 4=1 && sleep 2 # TPM now requires SPDM — all commands auto-encrypted: @@ -253,27 +253,27 @@ gpioset gpiochip0 4=0 && sleep 0.1 && gpioset gpiochip0 4=1 && sleep 2 ./tests/unit.test # full test suite over encrypted bus # Unlock -./examples/spdm/spdm_demo --connect --unlock +./examples/spdm/spdm_ctrl --connect --unlock gpioset gpiochip0 4=0 && sleep 0.1 && gpioset gpiochip0 4=1 && sleep 2 ``` **Nations (identity key):** ```bash -./examples/spdm/spdm_demo --connect --lock +./examples/spdm/spdm_ctrl --connect --lock # Power cycle required (unplug and re-plug Raspberry Pi) -./examples/spdm/spdm_demo --connect --unlock +./examples/spdm/spdm_ctrl --connect --unlock # Power cycle again ``` **Nations (PSK mode):** ```bash -./examples/spdm/spdm_demo --psk --lock +./examples/spdm/spdm_ctrl --psk --lock # Power cycle required -./examples/spdm/spdm_demo --psk --unlock +./examples/spdm/spdm_ctrl --psk --unlock # Power cycle again ``` @@ -284,20 +284,20 @@ is provisioned by default; it must be unset before PSK can be used. ```bash # 1. Unset identity key (enables PSK mode) -./examples/spdm/spdm_demo --identity-key-unset +./examples/spdm/spdm_ctrl --identity-key-unset # 2. Provision PSK (64-byte PSK + 32-byte ClearAuth) # The demo computes SHA-384(ClearAuth) and sends PSK(64)+Digest(48) = 112 bytes -./examples/spdm/spdm_demo --psk-set +./examples/spdm/spdm_ctrl --psk-set # 3. Establish PSK session -./examples/spdm/spdm_demo --psk +./examples/spdm/spdm_ctrl --psk # 4. Clear PSK (sends raw 32-byte ClearAuth; TPM verifies SHA-384 internally) -./examples/spdm/spdm_demo --psk-clear +./examples/spdm/spdm_ctrl --psk-clear # 5. Restore identity key (factory default) -./examples/spdm/spdm_demo --identity-key-set +./examples/spdm/spdm_ctrl --identity-key-set ``` **Important:** The ClearAuth must be exactly 32 bytes. PSK_SET stores its SHA-384 @@ -308,13 +308,13 @@ to verify. Using the wrong size makes PSK_CLEAR impossible. ```bash # Nuvoton (identity key — includes GPIO resets between tests) -./examples/spdm/spdm_test.sh ./examples/spdm/spdm_demo nuvoton +./examples/spdm/spdm_test.sh ./examples/spdm/spdm_ctrl nuvoton # Nations (identity key — no GPIO resets) -./examples/spdm/spdm_test.sh ./examples/spdm/spdm_demo nations +./examples/spdm/spdm_test.sh ./examples/spdm/spdm_ctrl nations # Nations (PSK — full lifecycle: provision → connect → clear → restore) -./examples/spdm/spdm_test.sh ./examples/spdm/spdm_demo nations-psk +./examples/spdm/spdm_test.sh ./examples/spdm/spdm_ctrl nations-psk ``` ## TCG SPDM Vendor Commands @@ -335,7 +335,7 @@ SPDM `VENDOR_DEFINED_REQUEST` messages with `StandardID=0x0001` (TCG). ## Command Reference -All `spdm_demo` options in one table: +All `spdm_ctrl` options in one table: | Option | Vendor | Description | |-------------------------------|---------|-------------| diff --git a/src/spdm/include.am b/src/spdm/include.am index 196691c6..31e3e45a 100644 --- a/src/spdm/include.am +++ b/src/spdm/include.am @@ -11,17 +11,15 @@ src_libwolftpm_la_SOURCES += \ src/spdm/spdm_msg.c \ src/spdm/spdm_secured.c \ src/spdm/spdm_session.c \ + src/spdm/spdm_tcg.c \ src/spdm/spdm_transcript.c -# spdm_tcg.c: shared TCG SPDM code (Nuvoton + Nations) +# Vendor-specific SPDM code if BUILD_NUVOTON -src_libwolftpm_la_SOURCES += src/spdm/spdm_tcg.c src/spdm/spdm_nuvoton.c +src_libwolftpm_la_SOURCES += src/spdm/spdm_nuvoton.c endif if BUILD_NATIONS -if !BUILD_NUVOTON -src_libwolftpm_la_SOURCES += src/spdm/spdm_tcg.c -endif src_libwolftpm_la_SOURCES += src/spdm/spdm_nations.c src_libwolftpm_la_SOURCES += src/spdm/spdm_psk.c endif diff --git a/src/spdm/spdm_context.c b/src/spdm/spdm_context.c index d0ae493b..16ea6044 100644 --- a/src/spdm/spdm_context.c +++ b/src/spdm/spdm_context.c @@ -183,7 +183,7 @@ int wolfSPDM_SetRequesterKeyPair(WOLFSPDM_CTX* ctx, return WOLFSPDM_SUCCESS; } -#if defined(WOLFSPDM_NUVOTON) || defined(WOLFSPDM_NATIONS) +#ifdef WOLFTPM_SPDM_TCG int wolfSPDM_SetRequesterKeyTPMT(WOLFSPDM_CTX* ctx, const byte* tpmtPub, word32 tpmtPubSz) { @@ -197,7 +197,7 @@ int wolfSPDM_SetRequesterKeyTPMT(WOLFSPDM_CTX* ctx, ctx->reqPubKeyTPMTLen = tpmtPubSz; return WOLFSPDM_SUCCESS; } -#endif /* WOLFSPDM_NUVOTON || WOLFSPDM_NATIONS */ +#endif /* WOLFTPM_SPDM_TCG */ /* wolfSPDM_SetPSK moved to spdm_psk.c */ @@ -275,7 +275,7 @@ byte wolfSPDM_GetNegotiatedVersion(WOLFSPDM_CTX* ctx) return ctx->spdmVersion; } -#if defined(WOLFSPDM_NUVOTON) || defined(WOLFSPDM_NATIONS) +#ifdef WOLFTPM_SPDM_TCG word32 wolfSPDM_GetConnectionHandle(WOLFSPDM_CTX* ctx) { if (ctx == NULL) { @@ -309,7 +309,7 @@ int wolfSPDM_Connect(WOLFSPDM_CTX* ctx) return WOLFSPDM_E_IO_FAIL; } -#if defined(WOLFSPDM_NUVOTON) || defined(WOLFSPDM_NATIONS) +#ifdef WOLFTPM_SPDM_TCG if (ctx->mode == WOLFSPDM_MODE_NUVOTON || ctx->mode == WOLFSPDM_MODE_NATIONS) { return wolfSPDM_ConnectTCG(ctx); @@ -389,7 +389,7 @@ int wolfSPDM_SendReceive(WOLFSPDM_CTX* ctx, return WOLFSPDM_E_IO_FAIL; } -#if defined(WOLFSPDM_NUVOTON) || defined(WOLFSPDM_NATIONS) +#ifdef WOLFTPM_SPDM_TCG if (ctx->mode == WOLFSPDM_MODE_NUVOTON || ctx->mode == WOLFSPDM_MODE_NATIONS || ctx->mode == WOLFSPDM_MODE_NATIONS_PSK) { @@ -480,7 +480,7 @@ int wolfSPDM_SendReceive(WOLFSPDM_CTX* ctx, return WOLFSPDM_SUCCESS; } -#endif /* WOLFSPDM_NUVOTON || WOLFSPDM_NATIONS */ +#endif /* WOLFTPM_SPDM_TCG */ rc = ctx->ioCb(ctx, txBuf, txSz, rxBuf, rxSz, ctx->ioUserCtx); if (rc != 0) { diff --git a/src/spdm/spdm_internal.h b/src/spdm/spdm_internal.h index 90aec887..364d6841 100644 --- a/src/spdm/spdm_internal.h +++ b/src/spdm/spdm_internal.h @@ -27,12 +27,7 @@ #include #endif -/* wolfSSL options MUST be included first */ -#ifndef WOLFSSL_USER_SETTINGS - #include -#endif -#include - +/* spdm_types.h pulls in wolfSSL options via tpm2_types.h */ #include #include #include @@ -79,7 +74,7 @@ struct WOLFSPDM_CTX { WOLFSPDM_IO_CB ioCb; void* ioUserCtx; -#if defined(WOLFSPDM_NUVOTON) || defined(WOLFSPDM_NATIONS) +#ifdef WOLFTPM_SPDM_TCG /* TCG binding fields (shared by Nuvoton + Nations) */ word32 connectionHandle; /* Connection handle (usually 0) */ word16 fipsIndicator; /* FIPS service indicator */ @@ -213,7 +208,7 @@ static WC_INLINE word64 SPDM_Get64LE(const byte* buf) { /* ----- Write TCG SPDM Binding header ----- */ /* tag(2/BE) + size(4/BE) + * connHandle(4/BE) + fips(2/BE) + reserved(4) */ -#if defined(WOLFSPDM_NUVOTON) || defined(WOLFSPDM_NATIONS) +#ifdef WOLFTPM_SPDM_TCG static WC_INLINE void wolfSPDM_WriteTcgHeader(byte* buf, word16 tag, word32 totalSz, word32 connHandle, word16 fips) { diff --git a/src/spdm/spdm_msg.c b/src/spdm/spdm_msg.c index ee02fccb..39fc08a4 100644 --- a/src/spdm/spdm_msg.c +++ b/src/spdm/spdm_msg.c @@ -78,7 +78,7 @@ int wolfSPDM_BuildKeyExchange(WOLFSPDM_CTX* ctx, byte* buf, word32* bufSz) buf[offset++] = ctx->spdmVersion; buf[offset++] = SPDM_KEY_EXCHANGE; buf[offset++] = 0x00; /* MeasurementSummaryHashType = None */ -#if defined(WOLFSPDM_NUVOTON) || defined(WOLFSPDM_NATIONS) +#ifdef WOLFTPM_SPDM_TCG buf[offset++] = 0xFF; /* SlotID = 0xFF (no cert, use provisioned public key) */ #else buf[offset++] = 0x00; /* SlotID = 0 (certificate slot 0) */ @@ -254,7 +254,7 @@ int wolfSPDM_BuildFinish(WOLFSPDM_CTX* ctx, byte* buf, word32* bufSz) * and FINISH header. For PUB_KEY_ID mode, Cm = SHA-384(TPMT_PUBLIC) * of the requester's public key (matching how Ct is computed for * responder per TCG SPDM binding). */ -#if defined(WOLFSPDM_NUVOTON) || defined(WOLFSPDM_NATIONS) +#ifdef WOLFTPM_SPDM_TCG if (rc == WOLFSPDM_SUCCESS && mutualAuth && ctx->reqPubKeyTPMTLen > 0) { byte cmHash[WOLFSPDM_HASH_SIZE]; rc = wolfSPDM_Sha384Hash(cmHash, ctx->reqPubKeyTPMT, diff --git a/src/spdm/spdm_secured.c b/src/spdm/spdm_secured.c index 9de0866a..08209d96 100644 --- a/src/spdm/spdm_secured.c +++ b/src/spdm/spdm_secured.c @@ -65,7 +65,7 @@ int wolfSPDM_EncryptInternal(WOLFSPDM_CTX* ctx, return WOLFSPDM_E_BUFFER_SMALL; } -#if defined(WOLFSPDM_NUVOTON) || defined(WOLFSPDM_NATIONS) +#ifdef WOLFTPM_SPDM_TCG if (ctx->mode == WOLFSPDM_MODE_NUVOTON || ctx->mode == WOLFSPDM_MODE_NATIONS || ctx->mode == WOLFSPDM_MODE_NATIONS_PSK) { @@ -194,7 +194,7 @@ int wolfSPDM_DecryptInternal(WOLFSPDM_CTX* ctx, /* ----- Transport-specific header parsing ----- */ -#if defined(WOLFSPDM_NUVOTON) || defined(WOLFSPDM_NATIONS) +#ifdef WOLFTPM_SPDM_TCG if (ctx->mode == WOLFSPDM_MODE_NUVOTON || ctx->mode == WOLFSPDM_MODE_NATIONS || ctx->mode == WOLFSPDM_MODE_NATIONS_PSK) { @@ -296,7 +296,7 @@ int wolfSPDM_DecryptInternal(WOLFSPDM_CTX* ctx, if (rc == 0) { appDataLen = SPDM_Get16LE(decrypted); -#if defined(WOLFSPDM_NUVOTON) || defined(WOLFSPDM_NATIONS) +#ifdef WOLFTPM_SPDM_TCG if (ctx->mode == WOLFSPDM_MODE_NUVOTON || ctx->mode == WOLFSPDM_MODE_NATIONS || ctx->mode == WOLFSPDM_MODE_NATIONS_PSK) { diff --git a/src/spdm/spdm_tcg.c b/src/spdm/spdm_tcg.c index 34acffdd..03e21955 100644 --- a/src/spdm/spdm_tcg.c +++ b/src/spdm/spdm_tcg.c @@ -29,7 +29,7 @@ #include "spdm_internal.h" -#if defined(WOLFSPDM_NUVOTON) || defined(WOLFSPDM_NATIONS) +#ifdef WOLFTPM_SPDM_TCG #include @@ -575,6 +575,6 @@ int wolfSPDM_ConnectTCG(WOLFSPDM_CTX* ctx) return WOLFSPDM_SUCCESS; } -#endif /* WOLFSPDM_NUVOTON || WOLFSPDM_NATIONS */ +#endif /* WOLFTPM_SPDM_TCG */ #endif /* WOLFTPM_SPDM */ diff --git a/src/spdm/unit_test.c b/src/spdm/unit_test.c index 1e21e0fb..d344a5f5 100644 --- a/src/spdm/unit_test.c +++ b/src/spdm/unit_test.c @@ -574,7 +574,7 @@ static int test_invalid_curve_point(void) TEST_PASS(); } -#if defined(WOLFSPDM_NUVOTON) || defined(WOLFSPDM_NATIONS) +#ifdef WOLFTPM_SPDM_TCG /* I/O callback that returns a TCG response with msgSize < TCG_HEADER_SIZE */ static int tcg_underflow_io_cb(WOLFSPDM_CTX* ctx, const byte* txBuf, word32 txSz, byte* rxBuf, word32* rxSz, void* userCtx) @@ -618,7 +618,7 @@ static int test_tcg_underflow(void) TEST_CTX_FREE(); TEST_PASS(); } -#endif /* WOLFSPDM_NUVOTON || WOLFSPDM_NATIONS */ +#endif /* WOLFTPM_SPDM_TCG */ #ifdef WOLFSPDM_NATIONS static int test_nations_mode(void) @@ -975,7 +975,7 @@ int main(void) /* Security tests */ test_mitm_signature_rejected(); test_invalid_curve_point(); -#if defined(WOLFSPDM_NUVOTON) || defined(WOLFSPDM_NATIONS) +#ifdef WOLFTPM_SPDM_TCG test_tcg_underflow(); #endif #ifdef WOLFSPDM_NATIONS diff --git a/src/tpm2_spdm.c b/src/tpm2_spdm.c index a79d1751..56dcfc22 100644 --- a/src/tpm2_spdm.c +++ b/src/tpm2_spdm.c @@ -42,7 +42,7 @@ #include /* TIS functions for SPI/I2C TPM transport */ -#if (defined(WOLFSPDM_NUVOTON) || defined(WOLFSPDM_NATIONS)) && \ +#if defined(WOLFTPM_SPDM_TCG) && \ !defined(WOLFTPM_LINUX_DEV) && !defined(WOLFTPM_SWTPM) && \ !defined(WOLFTPM_WINAPI) #include @@ -205,7 +205,7 @@ int wolfTPM2_SPDM_SecuredExchange( return BAD_FUNC_ARG; } -#if defined(WOLFSPDM_NUVOTON) || defined(WOLFSPDM_NATIONS) +#ifdef WOLFTPM_SPDM_TCG /* In SPDM-only mode, TPM commands must be wrapped in SPDM VENDOR_DEFINED * messages with the TPM2_CMD vendor code. The TPM's SPDM layer only * accepts SPDM messages (starting with version byte 0x13), not raw TPM @@ -247,7 +247,7 @@ int wolfTPM2_SPDM_SecuredExchange( return TPM_RC_SUCCESS; } -#endif /* WOLFSPDM_NUVOTON || WOLFSPDM_NATIONS */ +#endif /* WOLFTPM_SPDM_TCG */ /* Standard SPDM mode: send TPM command as raw app data */ return wolfSPDM_SecuredExchange(ctx->spdmCtx, @@ -258,7 +258,7 @@ int wolfTPM2_SPDM_SecuredExchange( /* Nuvoton-Specific Functions */ /* -------------------------------------------------------------------------- */ -#if defined(WOLFSPDM_NUVOTON) || defined(WOLFSPDM_NATIONS) +#ifdef WOLFTPM_SPDM_TCG /* Set built-in TIS I/O callback for routing SPDM through TPM SPI/I2C. * Must be called after wolfTPM2_SPDM_InitCtx() and SetTPMCtx(). */ @@ -381,6 +381,6 @@ int wolfTPM2_SPDM_Disable(WOLFTPM2_SPDM_CTX* ctx) #endif /* WOLFSPDM_NUVOTON */ -#endif /* WOLFSPDM_NUVOTON || WOLFSPDM_NATIONS */ +#endif /* WOLFTPM_SPDM_TCG */ #endif /* WOLFTPM_SPDM */ diff --git a/src/tpm2_wrap.c b/src/tpm2_wrap.c index 2b550b73..2a455568 100644 --- a/src/tpm2_wrap.c +++ b/src/tpm2_wrap.c @@ -1116,7 +1116,7 @@ int wolfTPM2_SpdmCleanup(WOLFTPM2_DEV* dev) return TPM_RC_SUCCESS; } -#if defined(WOLFSPDM_NUVOTON) || defined(WOLFSPDM_NATIONS) +#ifdef WOLFTPM_SPDM_TCG /* Shared TCG SPDM functions */ int wolfTPM2_SpdmGetPubKey(WOLFTPM2_DEV* dev, byte* pubKey, word32* pubKeySz) @@ -1124,7 +1124,7 @@ int wolfTPM2_SpdmGetPubKey(WOLFTPM2_DEV* dev, byte* pubKey, word32* pubKeySz) WOLFTPM2_SPDM_CHECK_CTX(dev); return wolfSPDM_Nuvoton_GetPubKey(dev->spdmCtx->spdmCtx, pubKey, pubKeySz); } -#endif /* WOLFSPDM_NUVOTON || WOLFSPDM_NATIONS */ +#endif /* WOLFTPM_SPDM_TCG */ #ifdef WOLFSPDM_NUVOTON /* Nuvoton-specific SPDM functions */ diff --git a/wolftpm/spdm/spdm.h b/wolftpm/spdm/spdm.h index 177b6744..dc6d9416 100644 --- a/wolftpm/spdm/spdm.h +++ b/wolftpm/spdm/spdm.h @@ -67,7 +67,7 @@ typedef enum { struct WOLFSPDM_CTX; typedef struct WOLFSPDM_CTX WOLFSPDM_CTX; -#if defined(WOLFSPDM_NUVOTON) || defined(WOLFSPDM_NATIONS) +#ifdef WOLFTPM_SPDM_TCG #include #endif #ifdef WOLFSPDM_NUVOTON @@ -130,7 +130,7 @@ WOLFTPM_API int wolfSPDM_SecuredExchange(WOLFSPDM_CTX* ctx, /* Session info */ WOLFTPM_API word32 wolfSPDM_GetSessionId(WOLFSPDM_CTX* ctx); WOLFTPM_API byte wolfSPDM_GetNegotiatedVersion(WOLFSPDM_CTX* ctx); -#if defined(WOLFSPDM_NUVOTON) || defined(WOLFSPDM_NATIONS) +#ifdef WOLFTPM_SPDM_TCG WOLFTPM_API word32 wolfSPDM_GetConnectionHandle(WOLFSPDM_CTX* ctx); WOLFTPM_API word16 wolfSPDM_GetFipsIndicator(WOLFSPDM_CTX* ctx); #endif diff --git a/wolftpm/spdm/spdm_tcg.h b/wolftpm/spdm/spdm_tcg.h index 5a5d9e4d..c982fc32 100644 --- a/wolftpm/spdm/spdm_tcg.h +++ b/wolftpm/spdm/spdm_tcg.h @@ -35,7 +35,7 @@ #include -#if defined(WOLFSPDM_NUVOTON) || defined(WOLFSPDM_NATIONS) +#ifdef WOLFTPM_SPDM_TCG #ifdef __cplusplus extern "C" { @@ -159,6 +159,6 @@ WOLFTPM_API int wolfSPDM_ConnectTCG(WOLFSPDM_CTX* ctx); } #endif -#endif /* WOLFSPDM_NUVOTON || WOLFSPDM_NATIONS */ +#endif /* WOLFTPM_SPDM_TCG */ #endif /* WOLFSPDM_TCG_H */ diff --git a/wolftpm/spdm/spdm_types.h b/wolftpm/spdm/spdm_types.h index 0fb29cf7..ddb83730 100644 --- a/wolftpm/spdm/spdm_types.h +++ b/wolftpm/spdm/spdm_types.h @@ -137,6 +137,14 @@ extern "C" { #define WOLFSPDM_PUBKEY_BUF_SZ 256 /* Public key buffer */ #endif +/* ----- TCG Build Option ----- */ + +/* Nuvoton or Nations enables TCG SPDM binding; future chips can set directly */ +#if (defined(WOLFSPDM_NUVOTON) || defined(WOLFSPDM_NATIONS)) && \ + !defined(WOLFTPM_SPDM_TCG) + #define WOLFTPM_SPDM_TCG +#endif + /* ----- PSK Build Option ----- */ /* Nations build enables PSK by default; can also be set independently */ diff --git a/wolftpm/tpm2_spdm.h b/wolftpm/tpm2_spdm.h index ba2c28a0..1aa961ec 100644 --- a/wolftpm/tpm2_spdm.h +++ b/wolftpm/tpm2_spdm.h @@ -176,7 +176,7 @@ WOLFTPM_API void wolfTPM2_SPDM_FreeCtx( /* Nuvoton-Specific Functions (requires wolfSPDM with --enable-nuvoton) * -------------------------------------------------------------------------- */ -#if defined(WOLFSPDM_NUVOTON) || defined(WOLFSPDM_NATIONS) +#ifdef WOLFTPM_SPDM_TCG /** * Set the built-in TIS I/O callback for routing SPDM through TPM SPI/I2C. @@ -193,7 +193,7 @@ WOLFTPM_API int wolfTPM2_SPDM_SetTisIO( WOLFTPM2_SPDM_CTX* ctx ); -#endif /* WOLFSPDM_NUVOTON || WOLFSPDM_NATIONS */ +#endif /* WOLFTPM_SPDM_TCG */ #ifdef __cplusplus } /* extern "C" */ diff --git a/wolftpm/tpm2_wrap.h b/wolftpm/tpm2_wrap.h index 678a6578..8ffa7e42 100644 --- a/wolftpm/tpm2_wrap.h +++ b/wolftpm/tpm2_wrap.h @@ -498,7 +498,7 @@ WOLFTPM_API int wolfTPM2_SpdmDisconnect(WOLFTPM2_DEV* dev); */ WOLFTPM_API int wolfTPM2_SpdmCleanup(WOLFTPM2_DEV* dev); -#if defined(WOLFSPDM_NUVOTON) || defined(WOLFSPDM_NATIONS) +#ifdef WOLFTPM_SPDM_TCG /*! \ingroup wolfTPM2_Wrappers \brief Get the TPM's SPDM-Identity public key (shared TCG function). @@ -512,7 +512,7 @@ WOLFTPM_API int wolfTPM2_SpdmCleanup(WOLFTPM2_DEV* dev); */ WOLFTPM_API int wolfTPM2_SpdmGetPubKey(WOLFTPM2_DEV* dev, byte* pubKey, word32* pubKeySz); -#endif /* WOLFSPDM_NUVOTON || WOLFSPDM_NATIONS */ +#endif /* WOLFTPM_SPDM_TCG */ #ifdef WOLFSPDM_NUVOTON /* Nuvoton-specific SPDM functions (requires wolfSPDM with --enable-nuvoton) */