Each vendor now has a dedicated Pi:
- wolftpm-nuvoton: NPCT75x on SPI CS 0 (existing runner, relabeled)
- wolftpm-nations: NS350 on SPI CS 0 (new runner rpi-ns350)
Changes:
- runs-on uses matrix.runner_label so each matrix entry routes to
the correct physical runner.
- Concurrency moved from workflow-level to job-level with group
hw-spdm-runner-${{ matrix.vendor }} so nuvoton and nations run in
parallel rather than serializing on a shared hw-spdm-runner group.
- Dropped the pre-test caps detect step and its GPIO 4 reset pulse.
The detect step was unreliable (auto-SPDM in wolfTPM2_Init only
fires on TPM_RC_DISABLED from Startup, not TPM_RC_FAILURE, so a
locked chip couldn't self-recover) and pointless now that each
runner is dedicated to a known chip. spdm_test.sh already handles
its own vendor-specific reset: gpio_reset for nuvoton, no-reset
for nations (GPIO 4 isn't routed to NS350 RST on the daughter
board, per spdm_test.sh:135,159).
- Nations spi_cs flipped from 1 to 0 since the new Pi has NS350 on
its own CS 0 rather than sharing a bus with NPCT75x.
- Restore userWithAuth attribute in seal example (intentional for
password-based unsealing)
- Restore chained if (rc == TPM_RC_SUCCESS) pattern and the
release-build authSz mismatch check in TPM2_CommandProcess
- Restore TPM2_Packet_AppendSymmetric call in TPM2_Duplicate
- Update ParamEncDec_Dispatch test to use fwtpm raw-pointer
TPM2_ParamEnc_AESCFB signature
Add portable firmware TPM 2.0 implementation (fwTPM) built on wolfCrypt.
Implements 105/113 TPM 2.0 v1.38 commands (93%) as a standalone server
with socket and TIS transports, NV storage, and full CI/fuzz coverage.
- src/tpm2_wrap.c: wolfTPM2_Init auto-SPDM path now calls vendor-specific
wolfTPM2_SpdmConnectNuvoton/Nations (which sets TIS I/O, mode, and the
host ephemeral key pair for mutual auth). Previous refactor to the
generic wolfTPM2_SpdmConnect dropped that setup, so FINISH failed with
WOLFSPDM_E_PEER_ERROR whenever the TPM was in SPDM-only-locked mode.
- src/tpm2_spdm.c: wolfSPDM_ParseVendorDefined returns payload dataLen
(>=0) on success per spdm_tcg.c:72 convention. wolfTPM2_SPDM_SecuredExchange
was treating any non-zero return as an error, so the first TPM command
over SPDM (10-byte Startup response) bubbled up as rc=0xa.
- tests/unit_tests.c: Add test_tpm_alg_supported() helper that queries
TPM_CAP_ALGS and skip test_wolfTPM2_EccSignVerifyDig iterations when the
hash isn't supported. Nuvoton NPCT75x lacks SHA512 and returns
TPM_RC_SIZE parameter 1 (not TPM_RC_HASH), so the prior post-hoc skip
couldn't catch it.
- .github/workflows/hw-spdm-test.yml: New workflow targeting a self-hosted
Raspberry Pi runner. Runs examples/spdm/spdm_test.sh against real Nuvoton
hardware. Fork-PR gated. Health check soft-fails with a warning if the
Pi is unhealthy so merging isn't blocked on a flaky runner. Nations
matrix entry scaffolded (commented) for when the NS350 is wired.
- scripts/hw-runner-health-check.sh: Pre-flight that verifies /dev/spidev,
/dev/gpiochip, and gpiod are present+accessible before the build.