diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md index 8569aa68e..e48246458 100644 --- a/.github/copilot-instructions.md +++ b/.github/copilot-instructions.md @@ -70,7 +70,7 @@ noise rather than safety. - Raw libc calls (`memcpy`, `memset`, `strlen`, ...) in the core library: these are caught deterministically by the Semgrep gate and should use the `XMEMCPY`/`XMEMSET`/`XSTRLEN` wrappers. Do not duplicate that as a review - comment. (The vendored `src/spdm/` and `src/fwtpm/` trees are exempt.) + comment. (The vendored `lib/wolfSPDM/`, `src/spdm/` and `src/fwtpm/` trees are exempt.) - C++ idioms or constructs outside C89/C99. wolfTPM targets C89/C99 and must compile across its many feature configurations. - `TPM2_ForceZero` replaced by `memset`/`XMEMSET` (the project deliberately uses diff --git a/.github/semgrep-rules.yml b/.github/semgrep-rules.yml index 67306e845..8c63992d3 100644 --- a/.github/semgrep-rules.yml +++ b/.github/semgrep-rules.yml @@ -6,7 +6,7 @@ # # Style/maintainability is intentionally out of scope (owned by codespell, # Coverity, and the CodeQL security suite). These rules only enforce security -# invariants. The vendored src/spdm/ and src/fwtpm/ trees, the HAL platform +# invariants. The vendored lib/wolfSPDM/, src/spdm/ and src/fwtpm/ trees, the HAL platform # drivers, and the swtpm socket transport carry their own platform libc usage # and are excluded where noted. @@ -24,6 +24,7 @@ rules: - src/ - hal/ - wolftpm/ + - lib/wolfSPDM/src/ pattern-either: - pattern: gets(...) - pattern: strcpy(...) @@ -43,6 +44,7 @@ rules: - src/ - hal/ - wolftpm/ + - lib/wolfSPDM/src/ pattern-either: - pattern: system(...) - pattern: popen(...) @@ -72,6 +74,7 @@ rules: - src/ exclude: - src/spdm/ + - lib/wolfSPDM/ - src/fwtpm/ - src/tpm2_swtpm.c pattern-either: diff --git a/.github/workflows/cmake-build.yml b/.github/workflows/cmake-build.yml index 9a7a2ee39..890f947a8 100644 --- a/.github/workflows/cmake-build.yml +++ b/.github/workflows/cmake-build.yml @@ -138,6 +138,8 @@ jobs: steps: #pull wolfTPM - uses: actions/checkout@master + with: + submodules: true # Install cmake (matrix includes a Windows leg, so this job stays on the host # runner; apt is made resilient instead of moving into the Linux CI image) @@ -227,6 +229,8 @@ jobs: password: ${{ secrets.GITHUB_TOKEN }} steps: - uses: actions/checkout@master + with: + submodules: true # Same wolfSSL config as the matrix build above, so it shares that cache # entry (key includes only OS + commit, not the wolfTPM options). diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 6e91c7875..09f2d2a0a 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -27,6 +27,8 @@ jobs: steps: - name: Checkout wolfTPM uses: actions/checkout@v4 + with: + submodules: true # CodeQL's action is fiddly inside a custom container, so keep this job # on the host runner and just make apt resilient to mirror timeouts. diff --git a/.github/workflows/codespell.yml b/.github/workflows/codespell.yml index d1be82df3..266601c06 100644 --- a/.github/workflows/codespell.yml +++ b/.github/workflows/codespell.yml @@ -22,6 +22,8 @@ jobs: steps: - name: Checkout wolfTPM uses: actions/checkout@v4 + with: + submodules: true - name: Run codespell uses: codespell-project/actions-codespell@v2 diff --git a/.github/workflows/coverity-scan-fixes.yml b/.github/workflows/coverity-scan-fixes.yml index c37ac43b9..6c88d058a 100644 --- a/.github/workflows/coverity-scan-fixes.yml +++ b/.github/workflows/coverity-scan-fixes.yml @@ -13,6 +13,7 @@ jobs: steps: - uses: actions/checkout@v4 with: + submodules: true ref: master # Cache the built wolfSSL tree keyed on the resolved upstream commit so it diff --git a/.github/workflows/freestanding-build.yml b/.github/workflows/freestanding-build.yml index ab940b705..d260e400e 100644 --- a/.github/workflows/freestanding-build.yml +++ b/.github/workflows/freestanding-build.yml @@ -23,6 +23,8 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 + with: + submodules: true - name: Write freestanding user_settings.h (types + mem/str, no libc) run: | diff --git a/.github/workflows/fuzz.yml b/.github/workflows/fuzz.yml index 6c4b6b184..aea3a3d54 100644 --- a/.github/workflows/fuzz.yml +++ b/.github/workflows/fuzz.yml @@ -51,6 +51,8 @@ jobs: steps: - name: Checkout wolfTPM uses: actions/checkout@v4 + with: + submodules: true - name: ASLR workaround run: sudo sysctl vm.mmap_rnd_bits=28 diff --git a/.github/workflows/fwtpm-test.yml b/.github/workflows/fwtpm-test.yml index 460aa6b1d..3f351aea5 100644 --- a/.github/workflows/fwtpm-test.yml +++ b/.github/workflows/fwtpm-test.yml @@ -282,6 +282,8 @@ jobs: steps: - name: Checkout wolfTPM uses: actions/checkout@v4 + with: + submodules: true # Matrix includes a macOS leg, so this job stays on the host runner; # apt is made resilient rather than moving into the Linux CI image. @@ -461,6 +463,8 @@ jobs: steps: - name: Checkout wolfTPM uses: actions/checkout@v4 + with: + submodules: true - name: Setup wolfSSL uses: ./.github/actions/setup-wolfssl @@ -491,6 +495,8 @@ jobs: steps: - name: Checkout wolfTPM uses: actions/checkout@v4 + with: + submodules: true - name: Setup wolfSSL uses: ./.github/actions/setup-wolfssl @@ -528,6 +534,8 @@ jobs: # (where it passes) and just make apt resilient to mirror timeouts. steps: - uses: actions/checkout@master + with: + submodules: true - name: Install tpm2-tools uses: ./.github/actions/apt-retry @@ -565,6 +573,8 @@ jobs: steps: - name: Checkout wolfTPM uses: actions/checkout@v4 + with: + submodules: true - name: Checkout wolfSSL uses: actions/checkout@v4 @@ -663,6 +673,8 @@ jobs: steps: - name: Checkout wolfTPM uses: actions/checkout@v4 + with: + submodules: true - name: Setup wolfSSL uses: ./.github/actions/setup-wolfssl diff --git a/.github/workflows/make-test-swtpm.yml b/.github/workflows/make-test-swtpm.yml index 774029e44..3cc946e8b 100644 --- a/.github/workflows/make-test-swtpm.yml +++ b/.github/workflows/make-test-swtpm.yml @@ -380,6 +380,8 @@ jobs: steps: - name: Checkout wolfTPM uses: actions/checkout@master + with: + submodules: true # Build (or restore from cache) + install wolfSSL. The action caches the # built ./wolfssl tree keyed on the resolved wolfSSL commit + this config, diff --git a/.github/workflows/multi-compiler.yml b/.github/workflows/multi-compiler.yml index 0d0911702..89096123b 100644 --- a/.github/workflows/multi-compiler.yml +++ b/.github/workflows/multi-compiler.yml @@ -94,6 +94,8 @@ jobs: # Checkout first so the local apt-retry composite action is on disk. - name: Checkout wolfTPM uses: actions/checkout@v4 + with: + submodules: true # Version-specific compilers are not baked into the CI image; keep this # job on the host runner and just make apt resilient to mirror timeouts. diff --git a/.github/workflows/pqc-build-matrix.yml b/.github/workflows/pqc-build-matrix.yml index 15411a4f0..54f701640 100644 --- a/.github/workflows/pqc-build-matrix.yml +++ b/.github/workflows/pqc-build-matrix.yml @@ -109,6 +109,8 @@ jobs: steps: - name: Checkout wolfTPM uses: actions/checkout@v4 + with: + submodules: true - name: Setup wolfSSL with PQC uses: ./.github/actions/setup-wolfssl @@ -160,6 +162,8 @@ jobs: steps: - name: Checkout wolfTPM uses: actions/checkout@v4 + with: + submodules: true - name: Build wolfTPM standalone (${{ matrix.name }}) run: | @@ -188,6 +192,8 @@ jobs: steps: - name: Checkout wolfTPM uses: actions/checkout@v4 + with: + submodules: true - name: Setup wolfSSL with PQC uses: ./.github/actions/setup-wolfssl with: diff --git a/.github/workflows/pqc-examples.yml b/.github/workflows/pqc-examples.yml index 14dded6ae..946210538 100644 --- a/.github/workflows/pqc-examples.yml +++ b/.github/workflows/pqc-examples.yml @@ -25,6 +25,8 @@ jobs: steps: - name: Checkout wolfTPM uses: actions/checkout@v4 + with: + submodules: true - name: Install tpm2-tools uses: ./.github/actions/apt-retry @@ -199,6 +201,7 @@ jobs: - name: Checkout wolfTPM uses: actions/checkout@v4 with: + submodules: true persist-credentials: false - name: Setup wolfSSL with PQC TLS diff --git a/.github/workflows/publish-ci-image.yml b/.github/workflows/publish-ci-image.yml index 83487ec16..49fc77d38 100644 --- a/.github/workflows/publish-ci-image.yml +++ b/.github/workflows/publish-ci-image.yml @@ -48,6 +48,7 @@ jobs: steps: - uses: actions/checkout@v4 with: + submodules: true fetch-depth: 1 - name: Compute lowercase owner diff --git a/.github/workflows/release-checks.yml b/.github/workflows/release-checks.yml index 4c8667eb4..81f5850ea 100644 --- a/.github/workflows/release-checks.yml +++ b/.github/workflows/release-checks.yml @@ -78,6 +78,8 @@ jobs: steps: - name: Checkout wolfTPM uses: actions/checkout@v4 + with: + submodules: true - name: Download wolfSSL uses: actions/download-artifact@v4 @@ -122,6 +124,8 @@ jobs: steps: - name: Checkout wolfTPM uses: actions/checkout@v4 + with: + submodules: true - name: Download wolfSSL uses: actions/download-artifact@v4 @@ -165,6 +169,8 @@ jobs: steps: - name: Checkout wolfTPM uses: actions/checkout@v4 + with: + submodules: true # PQC-enabled wolfSSL is a superset of what fwTPM and SPDM need, so one # install covers the maximal rebuild below. diff --git a/.github/workflows/rust-test.yml b/.github/workflows/rust-test.yml index 5fbbc52d5..e41a9d13f 100644 --- a/.github/workflows/rust-test.yml +++ b/.github/workflows/rust-test.yml @@ -37,6 +37,8 @@ jobs: steps: - name: Checkout wolfTPM uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + with: + submodules: true # Build + install wolfSSL with the crypto-callback support the wrapper # (and the TPM-backed TLS bridge) needs; installs to /usr/local so @@ -112,6 +114,8 @@ jobs: steps: - name: Checkout wolfTPM uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + with: + submodules: true - name: Setup wolfSSL uses: ./.github/actions/setup-wolfssl with: diff --git a/.github/workflows/sanitizer.yml b/.github/workflows/sanitizer.yml index 262e09680..50b669bef 100644 --- a/.github/workflows/sanitizer.yml +++ b/.github/workflows/sanitizer.yml @@ -103,6 +103,8 @@ jobs: - name: Checkout wolfTPM uses: actions/checkout@v4 + with: + submodules: true - name: Install tpm2-tools uses: ./.github/actions/apt-retry diff --git a/.github/workflows/sbom.yml b/.github/workflows/sbom.yml index 06e84a339..6fb660453 100644 --- a/.github/workflows/sbom.yml +++ b/.github/workflows/sbom.yml @@ -28,6 +28,7 @@ jobs: - name: Checkout wolftpm uses: actions/checkout@v4 with: + submodules: true path: wolftpm # wolfTPM links wolfSSL/wolfCrypt, so its SBOM records wolfSSL as a @@ -155,6 +156,8 @@ jobs: steps: - uses: actions/checkout@v4 + with: + submodules: true - name: Read the pinned wolfGlass revision id: pin diff --git a/.github/workflows/seal-test.yml b/.github/workflows/seal-test.yml index e3ff63065..497a9bc9b 100644 --- a/.github/workflows/seal-test.yml +++ b/.github/workflows/seal-test.yml @@ -34,6 +34,8 @@ jobs: steps: - name: Checkout wolfTPM uses: actions/checkout@v4 + with: + submodules: true - name: Setup wolfSSL uses: ./.github/actions/setup-wolfssl diff --git a/.github/workflows/semgrep.yml b/.github/workflows/semgrep.yml index ef3708ebe..0fbf5d0c4 100644 --- a/.github/workflows/semgrep.yml +++ b/.github/workflows/semgrep.yml @@ -22,6 +22,8 @@ jobs: timeout-minutes: 10 steps: - uses: actions/checkout@v4 + with: + submodules: true - uses: actions/setup-python@v5 with: diff --git a/.github/workflows/smoke-test.yml b/.github/workflows/smoke-test.yml index 67ca27bb3..e00df5ad2 100644 --- a/.github/workflows/smoke-test.yml +++ b/.github/workflows/smoke-test.yml @@ -31,6 +31,8 @@ jobs: steps: - name: Checkout wolfTPM uses: actions/checkout@v4 + with: + submodules: true - name: Check for bare C scope blocks run: python3 scripts/check-empty-brace-scopes.py @@ -54,6 +56,8 @@ jobs: steps: - name: Checkout wolfTPM uses: actions/checkout@v4 + with: + submodules: true - name: Setup wolfSSL uses: ./.github/actions/setup-wolfssl diff --git a/.github/workflows/spdm-test.yml b/.github/workflows/spdm-test.yml index a9370e7b8..af52a4e4c 100644 --- a/.github/workflows/spdm-test.yml +++ b/.github/workflows/spdm-test.yml @@ -9,6 +9,8 @@ on: branches: [master] paths: - 'src/spdm/**' + - 'lib/wolfSPDM' + - '.gitmodules' - 'wolftpm/spdm/**' - 'src/fwtpm/**' - 'wolftpm/fwtpm/**' @@ -64,6 +66,7 @@ jobs: - name: Checkout wolfTPM uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 with: + submodules: true persist-credentials: false - name: Setup wolfSSL @@ -80,6 +83,20 @@ jobs: --with-wolfcrypt=$HOME/wolfssl-install make -j"$(nproc)" + - name: Compile against the installed headers (${{ matrix.name }}) + run: | + set -e + make install DESTDIR="$PWD/inst" >/dev/null + printf '%s\n' '#include ' \ + '#include ' '#include ' \ + 'int main(void) { return 0; }' > consumer.c + cc -c consumer.c -o consumer.o -I"$PWD/inst/usr/local/include" \ + -I"$HOME/wolfssl-install/include" + printf '%s\n' '#include ' \ + 'int main(void) { return 0; }' > consumer2.c + cc -c consumer2.c -o consumer2.o -I"$PWD/inst/usr/local/include" \ + -I"$HOME/wolfssl-install/include" + - name: Test unavailable vendor rejection (${{ matrix.name }}) if: matrix.name == 'spdm-nuvoton' || matrix.name == 'spdm-nations' run: | @@ -124,6 +141,7 @@ jobs: - name: Checkout wolfTPM uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 with: + submodules: true persist-credentials: false - name: Setup wolfSSL diff --git a/.github/workflows/wolfhal-build.yml b/.github/workflows/wolfhal-build.yml index eabecf339..6ccdfadcf 100644 --- a/.github/workflows/wolfhal-build.yml +++ b/.github/workflows/wolfhal-build.yml @@ -25,6 +25,8 @@ jobs: steps: - name: Checkout wolfTPM uses: actions/checkout@v4 + with: + submodules: true - name: Install ARM toolchain uses: ./.github/actions/apt-retry @@ -125,6 +127,8 @@ jobs: steps: - name: Checkout wolfTPM uses: actions/checkout@v4 + with: + submodules: true - name: Setup wolfSSL uses: ./.github/actions/setup-wolfssl diff --git a/.github/workflows/wolfssl-versions-pqc.yml b/.github/workflows/wolfssl-versions-pqc.yml index adb51986a..fd76005c9 100644 --- a/.github/workflows/wolfssl-versions-pqc.yml +++ b/.github/workflows/wolfssl-versions-pqc.yml @@ -73,6 +73,8 @@ jobs: steps: - name: Checkout wolfTPM uses: actions/checkout@v4 + with: + submodules: true - name: Cache wolfSSL ${{ matrix.wolfssl-version }} if: matrix.wolfssl-version != 'master' diff --git a/.github/workflows/zephyr.yml b/.github/workflows/zephyr.yml index 02562ace6..8049d6dc3 100644 --- a/.github/workflows/zephyr.yml +++ b/.github/workflows/zephyr.yml @@ -29,6 +29,8 @@ jobs: # Checkout first so the local apt-retry composite action is on disk. - name: Checkout wolfTPM uses: actions/checkout@v4 + with: + submodules: true # Large, version-pinned zephyr package set — not baked into the wolfTPM # CI image; just make apt resilient to mirror timeouts. diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 000000000..2f07e7b97 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,5 @@ +[submodule "lib/wolfSPDM"] + path = lib/wolfSPDM + url = https://github.com/wolfSSL/wolfSPDM.git + branch = wolftpm-core + ignore = dirty diff --git a/configure.ac b/configure.ac index f0b9510a5..4438ab14b 100644 --- a/configure.ac +++ b/configure.ac @@ -760,6 +760,10 @@ then AC_MSG_ERROR([--enable-spdm requires the client library (incompatible with --enable-fwtpm-only)]) fi AC_DEFINE([WOLFTPM_SPDM], [1], [Enable SPDM support]) + if test ! -f "$srcdir/lib/wolfSPDM/src/spdm_context.c"; then + AC_MSG_ERROR([--enable-spdm needs the wolfSPDM submodule: run git submodule update --init lib/wolfSPDM]) + fi + AM_CPPFLAGS="$AM_CPPFLAGS -I\$(top_srcdir)/lib/wolfSPDM -I\$(top_srcdir)/lib/wolfSPDM/src" if test "x$ENABLED_TCG" = "xdetect" then diff --git a/lib/wolfSPDM b/lib/wolfSPDM new file mode 160000 index 000000000..c0f0ce274 --- /dev/null +++ b/lib/wolfSPDM @@ -0,0 +1 @@ +Subproject commit c0f0ce27461f4d8f2cb3bff069f8f737d370de71 diff --git a/src/fwtpm/include.am b/src/fwtpm/include.am index f98d9b0ac..a0186ac86 100644 --- a/src/fwtpm/include.am +++ b/src/fwtpm/include.am @@ -31,21 +31,21 @@ endif # -DWOLFTPM_FWTPM), so SPDM sources have to be listed here too. if BUILD_FWTPM_SPDM src_fwtpm_fwtpm_server_SOURCES += \ - src/spdm/spdm_responder.c \ - src/spdm/spdm_context.c \ - src/spdm/spdm_crypto.c \ - src/spdm/spdm_kdf.c \ - src/spdm/spdm_msg.c \ - src/spdm/spdm_secured.c \ - src/spdm/spdm_session.c \ - src/spdm/spdm_transcript.c + lib/wolfSPDM/src/spdm_responder.c \ + lib/wolfSPDM/src/spdm_context.c \ + lib/wolfSPDM/src/spdm_crypto.c \ + lib/wolfSPDM/src/spdm_kdf.c \ + lib/wolfSPDM/src/spdm_msg.c \ + lib/wolfSPDM/src/spdm_secured.c \ + lib/wolfSPDM/src/spdm_session.c \ + lib/wolfSPDM/src/spdm_transcript.c src_fwtpm_fwtpm_server_CFLAGS += -DFWTPM_SPDM_HAVE_RESPONDER src_fwtpm_fwtpm_server_CPPFLAGS += -DFWTPM_SPDM_HAVE_RESPONDER if BUILD_SPDM_TCG -src_fwtpm_fwtpm_server_SOURCES += src/spdm/spdm_tcg.c +src_fwtpm_fwtpm_server_SOURCES += lib/wolfSPDM/src/spdm_tcg.c endif if BUILD_SPDM_PSK -src_fwtpm_fwtpm_server_SOURCES += src/spdm/spdm_psk.c +src_fwtpm_fwtpm_server_SOURCES += lib/wolfSPDM/src/spdm_psk.c endif endif BUILD_FWTPM_SPDM diff --git a/src/spdm/README.md b/src/spdm/README.md index 65d8bd2bd..d3106fe31 100644 --- a/src/spdm/README.md +++ b/src/spdm/README.md @@ -8,8 +8,11 @@ responses are encrypted with AES-256-GCM over the existing SPI/I2C bus. Identity key mode requires the responder's P-384 public key from a trusted provisioning source. -For standard SPDM protocol testing with the DMTF spdm-emu emulator, see the -[wolfSPDM](https://github.com/aidangarske/wolfSPDM) standalone library. +The SPDM code lives in the [wolfSPDM](https://github.com/wolfSSL/wolfSPDM) +library, included as the `lib/wolfSPDM` submodule and compiled into libwolftpm +in its TPM profile. Clone with `git clone --recursive`, or run +`git submodule update --init` in an existing checkout. wolfSPDM also builds +standalone as a DMTF SPDM 1.2-1.4 requester with PQC for spdm-emu testing. ## Quick Start diff --git a/src/spdm/include.am b/src/spdm/include.am index f6838fd83..c3099f4fa 100644 --- a/src/spdm/include.am +++ b/src/spdm/include.am @@ -2,37 +2,37 @@ # included from Top Level Makefile.am # All paths should be given relative to the root +# SPDM comes from the wolfSPDM submodule, built in its wolfTPM profile. if BUILD_SPDM -# Side-agnostic SPDM core: same code feeds requester and responder. src_libwolftpm_la_SOURCES += \ - src/spdm/spdm_context.c \ - src/spdm/spdm_crypto.c \ - src/spdm/spdm_kdf.c \ - src/spdm/spdm_msg.c \ - src/spdm/spdm_secured.c \ - src/spdm/spdm_session.c \ - src/spdm/spdm_transcript.c + lib/wolfSPDM/src/spdm_context.c \ + lib/wolfSPDM/src/spdm_crypto.c \ + lib/wolfSPDM/src/spdm_kdf.c \ + lib/wolfSPDM/src/spdm_msg.c \ + lib/wolfSPDM/src/spdm_secured.c \ + lib/wolfSPDM/src/spdm_session.c \ + lib/wolfSPDM/src/spdm_transcript.c if BUILD_SPDM_TCG -src_libwolftpm_la_SOURCES += src/spdm/spdm_tcg.c +src_libwolftpm_la_SOURCES += lib/wolfSPDM/src/spdm_tcg.c endif # Gated on the mode flag, not on a vendor flag - PSK isn't Nations-specific. if BUILD_SPDM_PSK -src_libwolftpm_la_SOURCES += src/spdm/spdm_psk.c +src_libwolftpm_la_SOURCES += lib/wolfSPDM/src/spdm_psk.c endif if BUILD_NUVOTON -src_libwolftpm_la_SOURCES += src/spdm/spdm_nuvoton.c +src_libwolftpm_la_SOURCES += lib/wolfSPDM/src/vendor/spdm_nuvoton.c endif if BUILD_NATIONS -src_libwolftpm_la_SOURCES += src/spdm/spdm_nations.c +src_libwolftpm_la_SOURCES += lib/wolfSPDM/src/vendor/spdm_nations.c endif if BUILD_FWTPM_SPDM -src_libwolftpm_la_SOURCES += src/spdm/spdm_responder.c +src_libwolftpm_la_SOURCES += lib/wolfSPDM/src/spdm_responder.c endif check_PROGRAMS += src/spdm/unit_test @@ -45,5 +45,6 @@ endif BUILD_SPDM # Ship unconditionally: EXTRA_DIST inside a conditional is dropped from the dist # tarball when packaged without --enable-spdm, breaking later --enable-spdm builds. -EXTRA_DIST += src/spdm/spdm_internal.h +EXTRA_DIST += lib/wolfSPDM/src/spdm_internal.h +EXTRA_DIST += lib/wolfSPDM/LICENSE EXTRA_DIST += src/spdm/README.md diff --git a/src/spdm/spdm_context.c b/src/spdm/spdm_context.c deleted file mode 100644 index 5d2a569eb..000000000 --- a/src/spdm/spdm_context.c +++ /dev/null @@ -1,584 +0,0 @@ -/* spdm_context.c - * - * Copyright (C) 2006-2026 wolfSSL Inc. - * - * This file is part of wolfSPDM. - * - * wolfSPDM is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3 of the License, or - * (at your option) any later version. - * - * wolfSPDM is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA - */ - -#ifdef HAVE_CONFIG_H - #include -#endif - -#ifdef WOLFTPM_SPDM - -#include "spdm_internal.h" -#include -#include - -/* ----- Context Management ----- */ - -int wolfSPDM_Init(WOLFSPDM_CTX* ctx) -{ - int rc; - - if (ctx == NULL) { - return WOLFSPDM_E_INVALID_ARG; - } - - /* Clean slate, dont read fields before this */ - XMEMSET(ctx, 0, sizeof(WOLFSPDM_CTX)); - ctx->state = WOLFSPDM_STATE_INIT; - - /* Initialize RNG */ - rc = wc_InitRng(&ctx->rng); - if (rc != 0) { - return WOLFSPDM_E_CRYPTO_FAIL; - } - ctx->flags.rngInitialized = 1; - - /* Set default session ID (0x0001 is valid; 0x0000/0xFFFF are reserved) */ - ctx->reqSessionId = 0x0001; - - ctx->flags.initialized = 1; - /* isDynamic remains 0, only wolfSPDM_New sets it */ - - return WOLFSPDM_SUCCESS; -} - -#ifdef WOLFTPM_SMALL_STACK -WOLFSPDM_CTX* wolfSPDM_New(void) -{ - WOLFSPDM_CTX* ctx; - - ctx = (WOLFSPDM_CTX*)XMALLOC(sizeof(WOLFSPDM_CTX), NULL, - DYNAMIC_TYPE_TMP_BUFFER); - if (ctx == NULL) { - return NULL; - } - - if (wolfSPDM_Init(ctx) != WOLFSPDM_SUCCESS) { - XFREE(ctx, NULL, DYNAMIC_TYPE_TMP_BUFFER); - return NULL; - } - ctx->flags.isDynamic = 1; /* Tag AFTER Init so it isn't wiped */ - - return ctx; -} -#endif /* WOLFTPM_SMALL_STACK */ - -void wolfSPDM_Free(WOLFSPDM_CTX* ctx) -{ - int wasDynamic; - - if (ctx == NULL) { - return; - } - - wasDynamic = ctx->flags.isDynamic; - - /* Free RNG */ - if (ctx->flags.rngInitialized) { - wc_FreeRng(&ctx->rng); - } - - /* Free ephemeral key */ - if (ctx->flags.ephemeralKeyInit) { - wc_ecc_free(&ctx->ephemeralKey); - } - - /* Zero entire struct (covers all sensitive key material) */ - wc_ForceZero(ctx, sizeof(WOLFSPDM_CTX)); - -#ifdef WOLFTPM_SMALL_STACK - if (wasDynamic) { - XFREE(ctx, NULL, DYNAMIC_TYPE_TMP_BUFFER); - } -#else - (void)wasDynamic; -#endif -} - -int wolfSPDM_GetCtxSize(void) -{ - return (int)sizeof(WOLFSPDM_CTX); -} - -int wolfSPDM_InitStatic(WOLFSPDM_CTX* ctx, int size) -{ - if (ctx == NULL) { - return WOLFSPDM_E_INVALID_ARG; - } - - if (size < (int)sizeof(WOLFSPDM_CTX)) { - return WOLFSPDM_E_BUFFER_SMALL; - } - - return wolfSPDM_Init(ctx); -} - -/* ----- Configuration ----- */ - -int wolfSPDM_SetIO(WOLFSPDM_CTX* ctx, WOLFSPDM_IO_CB ioCb, void* userCtx) -{ - if (ctx == NULL || ioCb == NULL) { - return WOLFSPDM_E_INVALID_ARG; - } - - ctx->ioCb = ioCb; - ctx->ioUserCtx = userCtx; - - return WOLFSPDM_SUCCESS; -} - -int wolfSPDM_SetResponderPubKey(WOLFSPDM_CTX* ctx, - const byte* pubKey, word32 pubKeySz) -{ - if (ctx == NULL || pubKey == NULL) { - return WOLFSPDM_E_INVALID_ARG; - } - - if (pubKeySz != WOLFSPDM_ECC_POINT_SIZE) { - return WOLFSPDM_E_INVALID_ARG; - } - - XMEMCPY(ctx->rspPubKey, pubKey, pubKeySz); - ctx->rspPubKeyLen = pubKeySz; - ctx->flags.hasRspPubKey = 1; - - return WOLFSPDM_SUCCESS; -} - -int wolfSPDM_SetRequesterKeyPair(WOLFSPDM_CTX* ctx, - const byte* privKey, word32 privKeySz, - const byte* pubKey, word32 pubKeySz) -{ - if (ctx == NULL || privKey == NULL || pubKey == NULL) { - return WOLFSPDM_E_INVALID_ARG; - } - - if (privKeySz != WOLFSPDM_ECC_KEY_SIZE || - pubKeySz != WOLFSPDM_ECC_POINT_SIZE) { - return WOLFSPDM_E_INVALID_ARG; - } - - XMEMCPY(ctx->reqPrivKey, privKey, privKeySz); - ctx->reqPrivKeyLen = privKeySz; - XMEMCPY(ctx->reqPubKey, pubKey, pubKeySz); - ctx->flags.hasReqKeyPair = 1; - - return WOLFSPDM_SUCCESS; -} - -#ifdef WOLFTPM_SPDM_TCG -int wolfSPDM_SetRequesterKeyTPMT(WOLFSPDM_CTX* ctx, - const byte* tpmtPub, word32 tpmtPubSz) -{ - if (ctx == NULL || tpmtPub == NULL) { - return WOLFSPDM_E_INVALID_ARG; - } - if (tpmtPubSz > sizeof(ctx->reqPubKeyTPMT)) { - return WOLFSPDM_E_INVALID_ARG; - } - XMEMCPY(ctx->reqPubKeyTPMT, tpmtPub, tpmtPubSz); - ctx->reqPubKeyTPMTLen = tpmtPubSz; - return WOLFSPDM_SUCCESS; -} -#endif /* WOLFTPM_SPDM_TCG */ - -/* wolfSPDM_SetPSK moved to spdm_psk.c */ - -void wolfSPDM_SetDebug(WOLFSPDM_CTX* ctx, int enable) -{ - if (ctx != NULL) { - ctx->flags.debug = (enable != 0); - } -} - -int wolfSPDM_SetMode(WOLFSPDM_CTX* ctx, WOLFSPDM_MODE mode) -{ - if (ctx == NULL) { - return WOLFSPDM_E_INVALID_ARG; - } - -#if !defined(WOLFSPDM_NUVOTON) && !defined(WOLFSPDM_NATIONS) && \ - !defined(WOLFTPM_SPDM_PSK) - (void)mode; -#endif - -#ifdef WOLFSPDM_NUVOTON - if (mode == WOLFSPDM_MODE_NUVOTON) { - ctx->mode = WOLFSPDM_MODE_NUVOTON; - ctx->connectionHandle = WOLFSPDM_NUVOTON_CONN_HANDLE_DEFAULT; - ctx->fipsIndicator = WOLFSPDM_NUVOTON_FIPS_DEFAULT; - return WOLFSPDM_SUCCESS; - } -#endif -#ifdef WOLFSPDM_NATIONS - if (mode == WOLFSPDM_MODE_NATIONS) { - ctx->mode = WOLFSPDM_MODE_NATIONS; - ctx->connectionHandle = 0; - /* Default to NON_FIPS; overridden by auto-detect if FIPS configured */ - ctx->fipsIndicator = WOLFSPDM_FIPS_NON_FIPS; - return WOLFSPDM_SUCCESS; - } -#endif -#ifdef WOLFTPM_SPDM_PSK - /* Spec-pure PSK mode - DSP0274 handshake. Available whenever the PSK - * feature is built, independent of any vendor adapter. */ - if (mode == WOLFSPDM_MODE_NATIONS_PSK) { - ctx->mode = WOLFSPDM_MODE_NATIONS_PSK; - ctx->connectionHandle = 0; - ctx->fipsIndicator = WOLFSPDM_FIPS_NON_FIPS; - return WOLFSPDM_SUCCESS; - } -#endif - - return WOLFSPDM_E_INVALID_ARG; /* Unsupported mode */ -} - -WOLFSPDM_MODE wolfSPDM_GetMode(WOLFSPDM_CTX* ctx) -{ - if (ctx == NULL) { - return WOLFSPDM_MODE_AUTO; - } - return ctx->mode; -} - -/* ----- Session Status ----- */ - -int wolfSPDM_IsConnected(WOLFSPDM_CTX* ctx) -{ - if (ctx == NULL) { - return 0; - } - return (ctx->state == WOLFSPDM_STATE_CONNECTED) ? 1 : 0; -} - -word32 wolfSPDM_GetSessionId(WOLFSPDM_CTX* ctx) -{ - if (ctx == NULL || ctx->state != WOLFSPDM_STATE_CONNECTED) { - return 0; - } - return ctx->sessionId; -} - -byte wolfSPDM_GetNegotiatedVersion(WOLFSPDM_CTX* ctx) -{ - if (ctx == NULL || ctx->state < WOLFSPDM_STATE_VERSION) { - return 0; - } - return ctx->spdmVersion; -} - -#ifdef WOLFTPM_SPDM_TCG -word32 wolfSPDM_GetConnectionHandle(WOLFSPDM_CTX* ctx) -{ - if (ctx == NULL) { - return 0; - } - return ctx->connectionHandle; -} - -word16 wolfSPDM_GetFipsIndicator(WOLFSPDM_CTX* ctx) -{ - if (ctx == NULL) { - return 0; - } - return ctx->fipsIndicator; -} -#endif - -/* ----- Session Establishment - Connect (Full Handshake) ----- */ - -int wolfSPDM_Connect(WOLFSPDM_CTX* ctx) -{ - if (ctx == NULL) { - return WOLFSPDM_E_INVALID_ARG; - } - - if (!ctx->flags.initialized) { - return WOLFSPDM_E_BAD_STATE; - } - - if (ctx->ioCb == NULL) { - return WOLFSPDM_E_IO_FAIL; - } - -#ifdef WOLFTPM_SPDM_TCG - if (ctx->mode == WOLFSPDM_MODE_NUVOTON || - ctx->mode == WOLFSPDM_MODE_NATIONS) { - return wolfSPDM_ConnectTCG(ctx); - } -#endif -#ifdef WOLFTPM_SPDM_PSK - if (ctx->mode == WOLFSPDM_MODE_NATIONS_PSK) { - return wolfSPDM_ConnectPsk(ctx); - } -#endif - - return WOLFSPDM_E_INVALID_ARG; /* Standard mode not available */ -} - -int wolfSPDM_Disconnect(WOLFSPDM_CTX* ctx) -{ - int rc; - byte txBuf[8]; - byte rxBuf[16]; /* END_SESSION_ACK: 4 bytes */ - word32 txSz, rxSz; - - if (ctx == NULL) { - return WOLFSPDM_E_INVALID_ARG; - } - - if (ctx->state != WOLFSPDM_STATE_CONNECTED) { - return WOLFSPDM_E_NOT_CONNECTED; - } - - /* Build END_SESSION */ - txSz = sizeof(txBuf); - rc = wolfSPDM_BuildEndSession(ctx, txBuf, &txSz); - if (rc == WOLFSPDM_SUCCESS) { - rxSz = sizeof(rxBuf); - rc = wolfSPDM_SecuredExchange(ctx, txBuf, txSz, rxBuf, &rxSz); - } - if (rc == WOLFSPDM_SUCCESS) { - if (rxSz < 4) { - rc = WOLFSPDM_E_BUFFER_SMALL; - } - else if (wolfSPDM_CheckError(rxBuf, rxSz, NULL)) { - rc = WOLFSPDM_E_PEER_ERROR; - } - else if (rxSz != 4 || rxBuf[0] != ctx->spdmVersion || - rxBuf[1] != SPDM_END_SESSION_ACK || - rxBuf[2] != 0 || rxBuf[3] != 0) { - rc = WOLFSPDM_E_PEER_ERROR; - } - } - - /* Reset session state and wipe session-scoped keys; configured identity - * keys remain for a later connection */ - ctx->state = WOLFSPDM_STATE_INIT; - ctx->sessionId = 0; - ctx->reqSeqNum = 0; - ctx->rspSeqNum = 0; - /* App data keys */ - wc_ForceZero(ctx->reqDataKey, sizeof(ctx->reqDataKey)); - wc_ForceZero(ctx->rspDataKey, sizeof(ctx->rspDataKey)); - wc_ForceZero(ctx->reqDataIv, sizeof(ctx->reqDataIv)); - wc_ForceZero(ctx->rspDataIv, sizeof(ctx->rspDataIv)); - /* Handshake keys */ - wc_ForceZero(ctx->reqHsSecret, sizeof(ctx->reqHsSecret)); - wc_ForceZero(ctx->rspHsSecret, sizeof(ctx->rspHsSecret)); - wc_ForceZero(ctx->reqFinishedKey, sizeof(ctx->reqFinishedKey)); - wc_ForceZero(ctx->rspFinishedKey, sizeof(ctx->rspFinishedKey)); - /* Secrets and hashes */ - wc_ForceZero(ctx->handshakeSecret, sizeof(ctx->handshakeSecret)); - wc_ForceZero(ctx->sharedSecret, sizeof(ctx->sharedSecret)); - ctx->sharedSecretSz = 0; - wc_ForceZero(ctx->th1, sizeof(ctx->th1)); - wc_ForceZero(ctx->th2, sizeof(ctx->th2)); - /* Free ephemeral ECC key */ - if (ctx->flags.ephemeralKeyInit) { - wc_ecc_free(&ctx->ephemeralKey); - ctx->flags.ephemeralKeyInit = 0; - } - - return rc; -} - -/* ----- I/O Helper ----- */ - -int wolfSPDM_SendReceive(WOLFSPDM_CTX* ctx, - const byte* txBuf, word32 txSz, - byte* rxBuf, word32* rxSz) -{ - int rc; - - if (ctx == NULL || ctx->ioCb == NULL) { - return WOLFSPDM_E_IO_FAIL; - } - -#ifdef WOLFTPM_SPDM_TCG - if (ctx->mode == WOLFSPDM_MODE_NUVOTON || - ctx->mode == WOLFSPDM_MODE_NATIONS || - ctx->mode == WOLFSPDM_MODE_NATIONS_PSK) { - /* Wrap messages with TCG SPDM - * headers; I/O sends TCG-framed messages. */ - byte tcgTx[WOLFSPDM_MAX_MSG_SIZE + WOLFSPDM_AEAD_OVERHEAD + - WOLFSPDM_TCG_HEADER_SIZE]; - byte tcgRx[WOLFSPDM_MAX_MSG_SIZE + WOLFSPDM_AEAD_OVERHEAD + - WOLFSPDM_TCG_HEADER_SIZE]; - word32 tcgRxSz = sizeof(tcgRx); - int tcgTxSz; - word32 msgSize; - word32 payloadSz; - word16 tag; - - /* Detect message type: SPDM version byte 0x10-0x1F = clear message. - * Secured records start with SessionID (LE, typically 0x01 0x00...), - * which is never in the SPDM version range. */ - if (txSz > 0 && txBuf[0] >= 0x10 && txBuf[0] <= 0x1F) { - /* Clear SPDM message - wrap with TCG clear header (0x8101) */ - tcgTxSz = wolfSPDM_BuildTcgClearMessage(ctx, txBuf, txSz, - tcgTx, sizeof(tcgTx)); - } else { - /* Secured record - prepend TCG secured header (0x8201) */ - word32 totalSz; - if (txSz > sizeof(tcgTx) - WOLFSPDM_TCG_HEADER_SIZE) { - return WOLFSPDM_E_BUFFER_SMALL; - } - totalSz = WOLFSPDM_TCG_HEADER_SIZE + txSz; - wolfSPDM_WriteTcgHeader(tcgTx, WOLFSPDM_TCG_TAG_SECURED, - totalSz, ctx->connectionHandle, ctx->fipsIndicator); - XMEMCPY(tcgTx + WOLFSPDM_TCG_HEADER_SIZE, txBuf, txSz); - tcgTxSz = (int)totalSz; - } - - if (tcgTxSz < 0) { - return tcgTxSz; - } - - wolfSPDM_DebugHex(ctx, "TCG TX", tcgTx, (word32)tcgTxSz); - - /* Send/receive via I/O callback (raw transport) */ - rc = ctx->ioCb(ctx, tcgTx, (word32)tcgTxSz, tcgRx, &tcgRxSz, - ctx->ioUserCtx); - if (rc != 0) { - wolfSPDM_DebugPrint(ctx, "TCG I/O failed: %d\n", rc); - return WOLFSPDM_E_IO_FAIL; - } - - wolfSPDM_DebugHex(ctx, "TCG RX", tcgRx, tcgRxSz); - - /* Strip TCG binding header from response */ - if (tcgRxSz < WOLFSPDM_TCG_HEADER_SIZE) { - wolfSPDM_DebugPrint(ctx, "SendReceive: response too short (%u)\n", - tcgRxSz); - return WOLFSPDM_E_BUFFER_SMALL; - } - - tag = SPDM_Get16BE(tcgRx); - if (tag != WOLFSPDM_TCG_TAG_CLEAR && tag != WOLFSPDM_TCG_TAG_SECURED) { - wolfSPDM_DebugPrint(ctx, "SendReceive: unexpected TCG tag " - "0x%04x\n", tag); - return WOLFSPDM_E_PEER_ERROR; - } - - /* Capture FIPS indicator from response if non-zero */ - tag = SPDM_Get16BE(tcgRx + 10); - if (tag != 0) { - ctx->fipsIndicator = tag; - } - - /* Extract payload (everything after 16-byte TCG header) */ - msgSize = SPDM_Get32BE(tcgRx + 2); - - if (msgSize < WOLFSPDM_TCG_HEADER_SIZE || msgSize > tcgRxSz) { - wolfSPDM_DebugPrint(ctx, "SendReceive: TCG size %u invalid " - "(min=%u, received=%u)\n", msgSize, - WOLFSPDM_TCG_HEADER_SIZE, tcgRxSz); - return WOLFSPDM_E_BUFFER_SMALL; - } - - payloadSz = msgSize - WOLFSPDM_TCG_HEADER_SIZE; - if (payloadSz > *rxSz) { - return WOLFSPDM_E_BUFFER_SMALL; - } - - XMEMCPY(rxBuf, tcgRx + WOLFSPDM_TCG_HEADER_SIZE, payloadSz); - *rxSz = payloadSz; - - return WOLFSPDM_SUCCESS; - } -#endif /* WOLFTPM_SPDM_TCG */ - - rc = ctx->ioCb(ctx, txBuf, txSz, rxBuf, rxSz, ctx->ioUserCtx); - if (rc != 0) { - return WOLFSPDM_E_IO_FAIL; - } - - return WOLFSPDM_SUCCESS; -} - -/* ----- Debug Utilities ----- */ -#ifdef DEBUG_WOLFTPM -void wolfSPDM_DebugPrint(WOLFSPDM_CTX* ctx, const char* fmt, ...) -{ - va_list args; - - if (ctx == NULL || !ctx->flags.debug) { - return; - } - - printf("[wolfSPDM] "); - va_start(args, fmt); - vprintf(fmt, args); - va_end(args); - fflush(stdout); -} - -void wolfSPDM_DebugHex(WOLFSPDM_CTX* ctx, const char* label, - const byte* data, word32 len) -{ - word32 i; - - if (ctx == NULL || !ctx->flags.debug || data == NULL) { - return; - } - - printf("[wolfSPDM] %s (%u bytes): ", label, len); - for (i = 0; i < len && i < 32; i++) { - printf("%02x", data[i]); - } - if (len > 32) { - printf("..."); - } - printf("\n"); - fflush(stdout); -} -#endif - -/* ----- Error String ----- */ -const char* wolfSPDM_GetErrorString(int error) -{ - switch (error) { - case WOLFSPDM_SUCCESS: return "Success"; - case WOLFSPDM_E_INVALID_ARG: return "Invalid argument"; - case WOLFSPDM_E_BUFFER_SMALL: return "Buffer too small"; - case WOLFSPDM_E_BAD_STATE: return "Invalid state"; - case WOLFSPDM_E_VERSION_MISMATCH: return "Version mismatch"; - case WOLFSPDM_E_CRYPTO_FAIL: return "Crypto operation failed"; - case WOLFSPDM_E_BAD_SIGNATURE: return "Bad signature"; - case WOLFSPDM_E_BAD_HMAC: return "HMAC verification failed"; - case WOLFSPDM_E_IO_FAIL: return "I/O failure"; - case WOLFSPDM_E_TIMEOUT: return "Timeout"; - case WOLFSPDM_E_PEER_ERROR: return "Peer error response"; - case WOLFSPDM_E_DECRYPT_FAIL: return "Decryption failed"; - case WOLFSPDM_E_SEQUENCE: return "Sequence number error"; - case WOLFSPDM_E_NOT_CONNECTED: return "Not connected"; - case WOLFSPDM_E_ALREADY_INIT: return "Already initialized"; - case WOLFSPDM_E_NO_MEMORY: return "Memory allocation failed"; - case WOLFSPDM_E_SESSION_INVALID: return "Invalid session"; - case WOLFSPDM_E_KEY_EXCHANGE: return "Key exchange failed"; - case WOLFSPDM_E_NOT_AVAILABLE: return "Feature not compiled in"; - case WOLFSPDM_E_FRAMING: return "Framing violation"; - case WOLFSPDM_E_NOT_IMPL: return "Not implemented"; - default: return "Unknown error"; - } -} - -#endif /* WOLFTPM_SPDM */ diff --git a/src/spdm/spdm_crypto.c b/src/spdm/spdm_crypto.c deleted file mode 100644 index 82fc0d675..000000000 --- a/src/spdm/spdm_crypto.c +++ /dev/null @@ -1,386 +0,0 @@ -/* spdm_crypto.c - * - * Copyright (C) 2006-2026 wolfSSL Inc. - * - * This file is part of wolfSPDM. - * - * wolfSPDM is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3 of the License, or - * (at your option) any later version. - * - * wolfSPDM is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA - */ - -#ifdef HAVE_CONFIG_H - #include -#endif - -#ifdef WOLFTPM_SPDM - -#include "spdm_internal.h" - -/* Left-pad a buffer in-place to targetSz with leading zeros */ -static void wolfSPDM_LeftPadToSize(byte* buf, word32 currentSz, word32 targetSz) -{ - if (currentSz < targetSz) { - word32 padLen = targetSz - currentSz; - XMEMMOVE(buf + padLen, buf, currentSz); - XMEMSET(buf, 0, padLen); - } -} - -/* ----- Random Number Generation ----- */ - -int wolfSPDM_GetRandom(WOLFSPDM_CTX* ctx, byte* out, word32 outSz) -{ - int rc; - - if (ctx == NULL || out == NULL || outSz == 0) { - return WOLFSPDM_E_INVALID_ARG; - } - - if (!ctx->flags.rngInitialized) { - return WOLFSPDM_E_BAD_STATE; - } - - rc = wc_RNG_GenerateBlock(&ctx->rng, out, outSz); - if (rc != 0) { - return WOLFSPDM_E_CRYPTO_FAIL; - } - - return WOLFSPDM_SUCCESS; -} - -/* ----- ECDHE Key Generation (P-384) ----- */ - -int wolfSPDM_GenerateEphemeralKey(WOLFSPDM_CTX* ctx) -{ - int rc; - - if (ctx == NULL) { - return WOLFSPDM_E_INVALID_ARG; - } - - if (!ctx->flags.rngInitialized) { - return WOLFSPDM_E_BAD_STATE; - } - - /* Free existing key if any */ - if (ctx->flags.ephemeralKeyInit) { - wc_ecc_free(&ctx->ephemeralKey); - ctx->flags.ephemeralKeyInit = 0; - } - - /* Initialize new key */ - rc = wc_ecc_init(&ctx->ephemeralKey); - if (rc != 0) { - return WOLFSPDM_E_CRYPTO_FAIL; - } - - /* Generate P-384 key pair */ - rc = wc_ecc_make_key(&ctx->rng, WOLFSPDM_ECC_KEY_SIZE, &ctx->ephemeralKey); - if (rc != 0) { - wc_ecc_free(&ctx->ephemeralKey); - return WOLFSPDM_E_CRYPTO_FAIL; - } - - /* Attach RNG so timing-resistant scalar-mul inside wc_ecc_shared_secret - * doesn't fail with MISSING_RNG_E in builds that enable hardening. */ - rc = wc_ecc_set_rng(&ctx->ephemeralKey, &ctx->rng); - if (rc != 0) { - wc_ecc_free(&ctx->ephemeralKey); - return WOLFSPDM_E_CRYPTO_FAIL; - } - - ctx->flags.ephemeralKeyInit = 1; - wolfSPDM_DebugPrint(ctx, "Generated P-384 ephemeral key\n"); - - return WOLFSPDM_SUCCESS; -} - -int wolfSPDM_ExportEphemeralPubKey(WOLFSPDM_CTX* ctx, - byte* pubKeyX, word32* pubKeyXSz, - byte* pubKeyY, word32* pubKeyYSz) -{ - int rc; - - if (ctx == NULL || pubKeyX == NULL || pubKeyXSz == NULL || - pubKeyY == NULL || pubKeyYSz == NULL) { - return WOLFSPDM_E_INVALID_ARG; - } - - if (!ctx->flags.ephemeralKeyInit) { - return WOLFSPDM_E_BAD_STATE; - } - - if (*pubKeyXSz < WOLFSPDM_ECC_KEY_SIZE || - *pubKeyYSz < WOLFSPDM_ECC_KEY_SIZE) { - return WOLFSPDM_E_BUFFER_SMALL; - } - - rc = wc_ecc_export_public_raw(&ctx->ephemeralKey, - pubKeyX, pubKeyXSz, pubKeyY, pubKeyYSz); - if (rc != 0) { - return WOLFSPDM_E_CRYPTO_FAIL; - } - - /* Left-pad coordinates to full size (wolfSSL may strip leading zeros) */ - wolfSPDM_LeftPadToSize(pubKeyX, *pubKeyXSz, WOLFSPDM_ECC_KEY_SIZE); - *pubKeyXSz = WOLFSPDM_ECC_KEY_SIZE; - wolfSPDM_LeftPadToSize(pubKeyY, *pubKeyYSz, WOLFSPDM_ECC_KEY_SIZE); - *pubKeyYSz = WOLFSPDM_ECC_KEY_SIZE; - - return WOLFSPDM_SUCCESS; -} - -/* ----- ECDH Shared Secret Computation ----- */ - -int wolfSPDM_ComputeSharedSecret(WOLFSPDM_CTX* ctx, - const byte* peerPubKeyX, const byte* peerPubKeyY) -{ - ecc_key peerKey; - int rc; - int peerKeyInit = 0; - - if (ctx == NULL || peerPubKeyX == NULL || peerPubKeyY == NULL) { - return WOLFSPDM_E_INVALID_ARG; - } - - if (!ctx->flags.ephemeralKeyInit) { - return WOLFSPDM_E_BAD_STATE; - } - - rc = wc_ecc_init(&peerKey); - if (rc == 0) { - peerKeyInit = 1; - rc = wc_ecc_import_unsigned(&peerKey, peerPubKeyX, peerPubKeyY, - NULL, ECC_SECP384R1); - if (rc != 0) { - wolfSPDM_DebugPrint(ctx, "Failed to import peer public key: %d\n", rc); - } - } - /* Validate peer's public key is on the curve (prevents invalid-curve attacks) */ - if (rc == 0) { - rc = wc_ecc_check_key(&peerKey); - if (rc != 0) { - wolfSPDM_DebugPrint(ctx, "Peer public key invalid (not on curve): %d\n", rc); - } - } - /* Compute ECDH shared secret */ - if (rc == 0) { - ctx->sharedSecretSz = sizeof(ctx->sharedSecret); - rc = wc_ecc_shared_secret(&ctx->ephemeralKey, &peerKey, - ctx->sharedSecret, &ctx->sharedSecretSz); - if (rc != 0) { - wolfSPDM_DebugPrint(ctx, "ECDH shared_secret failed: %d\n", rc); - } - } - if (rc == 0) { - wolfSPDM_LeftPadToSize(ctx->sharedSecret, ctx->sharedSecretSz, - WOLFSPDM_ECC_KEY_SIZE); - ctx->sharedSecretSz = WOLFSPDM_ECC_KEY_SIZE; - wolfSPDM_DebugPrint(ctx, "ECDH shared secret computed (%u bytes)\n", - ctx->sharedSecretSz); - } else { - wc_ForceZero(ctx->sharedSecret, sizeof(ctx->sharedSecret)); - ctx->sharedSecretSz = 0; - } - - if (peerKeyInit) { - wc_ecc_free(&peerKey); - } - - return (rc == 0) ? WOLFSPDM_SUCCESS : WOLFSPDM_E_CRYPTO_FAIL; -} - -/* ----- ECDSA Signature Verification (P-384) ----- */ - -int wolfSPDM_ExtractEccPoint(const byte* pubKey, word32 pubKeySz, - const byte** pubKeyX, const byte** pubKeyY) -{ - word32 pointOffset; - - if (pubKey == NULL || pubKeyX == NULL || pubKeyY == NULL) { - return WOLFSPDM_E_INVALID_ARG; - } - - if (pubKeySz == WOLFSPDM_ECC_POINT_SIZE) { - *pubKeyX = pubKey; - *pubKeyY = pubKey + WOLFSPDM_ECC_KEY_SIZE; - } - else if (pubKeySz >= WOLFSPDM_ECC_POINT_SIZE + 4) { - pointOffset = pubKeySz - (WOLFSPDM_ECC_POINT_SIZE + 4); - if (SPDM_Get16BE(pubKey + pointOffset) != - WOLFSPDM_ECC_KEY_SIZE || - SPDM_Get16BE(pubKey + pointOffset + 2 + - WOLFSPDM_ECC_KEY_SIZE) != WOLFSPDM_ECC_KEY_SIZE) { - return WOLFSPDM_E_INVALID_ARG; - } - *pubKeyX = pubKey + pointOffset + 2; - *pubKeyY = pubKey + pointOffset + 4 + WOLFSPDM_ECC_KEY_SIZE; - } - else { - return WOLFSPDM_E_INVALID_ARG; - } - - return WOLFSPDM_SUCCESS; -} - -int wolfSPDM_VerifySignature(WOLFSPDM_CTX* ctx, const byte* hash, word32 hashSz, - const byte* sig, word32 sigSz) -{ - ecc_key verifyKey; - int rc; - int keyInit = 0; - byte derSig[ECC_MAX_SIG_SIZE]; - word32 derSigSz = sizeof(derSig); - int verified = 0; - const byte* pubKeyX; - const byte* pubKeyY; - - if (ctx == NULL || hash == NULL || sig == NULL) { - return WOLFSPDM_E_INVALID_ARG; - } - - if (!ctx->flags.hasRspPubKey || ctx->rspPubKeyLen < WOLFSPDM_ECC_POINT_SIZE) { - wolfSPDM_DebugPrint(ctx, "No responder public key for verification\n"); - return WOLFSPDM_E_BAD_STATE; - } - - if (sigSz != WOLFSPDM_ECC_SIG_SIZE) { - return WOLFSPDM_E_INVALID_ARG; - } - - rc = wolfSPDM_ExtractEccPoint(ctx->rspPubKey, ctx->rspPubKeyLen, - &pubKeyX, &pubKeyY); - if (rc != WOLFSPDM_SUCCESS) { - return rc; - } - - rc = wc_ecc_init(&verifyKey); - if (rc == 0) { - keyInit = 1; - rc = wc_ecc_import_unsigned(&verifyKey, pubKeyX, pubKeyY, - NULL, ECC_SECP384R1); - if (rc != 0) { - wolfSPDM_DebugPrint(ctx, "Failed to import rsp pub key for verify: %d\n", rc); - } - } - if (rc == 0) { - rc = wc_ecc_check_key(&verifyKey); - if (rc != 0) { - wolfSPDM_DebugPrint(ctx, "Responder pub key invalid (not on curve): %d\n", rc); - } - } - /* Convert raw R||S signature to DER format for wolfCrypt */ - if (rc == 0) { - rc = wc_ecc_rs_raw_to_sig(sig, WOLFSPDM_ECC_KEY_SIZE, - sig + WOLFSPDM_ECC_KEY_SIZE, WOLFSPDM_ECC_KEY_SIZE, - derSig, &derSigSz); - if (rc != 0) { - wolfSPDM_DebugPrint(ctx, "wc_ecc_rs_raw_to_sig failed: %d\n", rc); - } - } - if (rc == 0) { - rc = wc_ecc_verify_hash(derSig, derSigSz, hash, hashSz, - &verified, &verifyKey); - if (rc != 0) { - wolfSPDM_DebugPrint(ctx, "wc_ecc_verify_hash failed: %d\n", rc); - } - } - if (rc == 0 && !verified) { - wolfSPDM_DebugPrint(ctx, "Responder signature verification FAILED\n"); - rc = -1; - } - if (rc == 0) { - wolfSPDM_DebugPrint(ctx, "Responder signature VERIFIED OK\n"); - } - - if (keyInit) { - wc_ecc_free(&verifyKey); - } - - return (rc == 0) ? WOLFSPDM_SUCCESS : WOLFSPDM_E_BAD_SIGNATURE; -} - -/* ----- ECDSA Signing (P-384) ----- */ - -int wolfSPDM_SignHash(WOLFSPDM_CTX* ctx, const byte* hash, word32 hashSz, - byte* sig, word32* sigSz) -{ - ecc_key sigKey; - int rc; - int keyInit = 0; - byte derSig[ECC_MAX_SIG_SIZE]; - word32 derSigSz = sizeof(derSig); - word32 rLen, sLen; - - if (ctx == NULL || hash == NULL || sig == NULL || sigSz == NULL) { - return WOLFSPDM_E_INVALID_ARG; - } - - if (!ctx->flags.hasReqKeyPair || ctx->reqPrivKeyLen == 0) { - wolfSPDM_DebugPrint(ctx, "No requester key pair for signing\n"); - return WOLFSPDM_E_BAD_STATE; - } - - if (*sigSz < WOLFSPDM_ECC_POINT_SIZE) { - return WOLFSPDM_E_BUFFER_SMALL; - } - - rc = wc_ecc_init(&sigKey); - if (rc == 0) { - keyInit = 1; - rc = wc_ecc_import_unsigned(&sigKey, - ctx->reqPubKey, - ctx->reqPubKey + WOLFSPDM_ECC_KEY_SIZE, - ctx->reqPrivKey, - ECC_SECP384R1); - if (rc != 0) { - wolfSPDM_DebugPrint(ctx, "wc_ecc_import_unsigned failed: %d\n", rc); - } - } else { - wolfSPDM_DebugPrint(ctx, "wc_ecc_init failed: %d\n", rc); - } - if (rc == 0) { - rc = wc_ecc_sign_hash(hash, hashSz, derSig, &derSigSz, - &ctx->rng, &sigKey); - if (rc != 0) { - wolfSPDM_DebugPrint(ctx, "wc_ecc_sign_hash failed: %d\n", rc); - } - } - /* Convert DER signature to raw R||S format (96 bytes for P-384) */ - if (rc == 0) { - rLen = WOLFSPDM_ECC_KEY_SIZE; - sLen = WOLFSPDM_ECC_KEY_SIZE; - rc = wc_ecc_sig_to_rs(derSig, derSigSz, sig, &rLen, - sig + WOLFSPDM_ECC_KEY_SIZE, &sLen); - if (rc != 0) { - wolfSPDM_DebugPrint(ctx, "wc_ecc_sig_to_rs failed: %d\n", rc); - } - } - if (rc == 0) { - wolfSPDM_LeftPadToSize(sig, rLen, WOLFSPDM_ECC_KEY_SIZE); - wolfSPDM_LeftPadToSize(sig + WOLFSPDM_ECC_KEY_SIZE, sLen, - WOLFSPDM_ECC_KEY_SIZE); - *sigSz = WOLFSPDM_ECC_POINT_SIZE; - wolfSPDM_DebugPrint(ctx, "Signed hash with P-384 key (sig=%u bytes)\n", - *sigSz); - } - - if (keyInit) { - wc_ecc_free(&sigKey); - } - - return (rc == 0) ? WOLFSPDM_SUCCESS : WOLFSPDM_E_CRYPTO_FAIL; -} - -#endif /* WOLFTPM_SPDM */ diff --git a/src/spdm/spdm_internal.h b/src/spdm/spdm_internal.h deleted file mode 100644 index ba8df3cbf..000000000 --- a/src/spdm/spdm_internal.h +++ /dev/null @@ -1,379 +0,0 @@ -/* spdm_internal.h - * - * Copyright (C) 2006-2026 wolfSSL Inc. - * - * This file is part of wolfSPDM. - * - * wolfSPDM is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3 of the License, or - * (at your option) any later version. - * - * wolfSPDM is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA - */ - -#ifndef WOLFSPDM_INTERNAL_H -#define WOLFSPDM_INTERNAL_H - -/* Include autoconf generated config.h for feature detection */ -#ifdef HAVE_CONFIG_H - #include -#endif - -/* spdm_types.h pulls in wolfSSL options via tpm2_types.h */ -#include -#include -#include - -/* wolfCrypt includes - verify required algorithms */ -#ifndef HAVE_ECC - #error "wolfSPDM requires ECC (--enable-ecc in wolfSSL)" -#endif -#ifndef WOLFSSL_SHA384 - #error "wolfSPDM requires SHA-384 (--enable-sha384 in wolfSSL)" -#endif -#include -#include -#include -#include -#include -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/* ----- State Machine Constants ----- */ - -#define WOLFSPDM_STATE_INIT 0 /* Initial state */ -#define WOLFSPDM_STATE_VERSION 1 /* GET_VERSION complete */ -#define WOLFSPDM_STATE_CERT 2 /* GET_CERTIFICATE / GET_PUB_KEY complete */ -#define WOLFSPDM_STATE_KEY_EX 3 /* KEY_EXCHANGE complete */ -#define WOLFSPDM_STATE_FINISH 4 /* FINISH complete */ -#define WOLFSPDM_STATE_CONNECTED 5 /* Session established */ -#define WOLFSPDM_STATE_ERROR 6 /* Error state */ - -/* ----- Supported SPDM Version Range ----- */ - -/* Maximum SPDM version we support. Supports SPDM 1.2 through 1.4. - * Override with -DWOLFSPDM_MAX_SPDM_VERSION at compile time to cap - * at a lower version. */ -#ifndef WOLFSPDM_MAX_SPDM_VERSION -#define WOLFSPDM_MAX_SPDM_VERSION SPDM_VERSION_14 -#endif - -/* Minimum SPDM version we require. Our key derivation uses BinConcat - * format ("spdm1.2 " prefix) which is a 1.2+ feature. SPDM 1.1 uses - * a different HKDF label format and would require separate key - * derivation code. Override at compile time if 1.1 support is added. */ -#ifndef WOLFSPDM_MIN_SPDM_VERSION -#define WOLFSPDM_MIN_SPDM_VERSION SPDM_VERSION_12 -#endif - -/* ----- Internal Context Structure ----- */ - -struct WOLFSPDM_CTX { - /* State machine */ - int state; - - /* Protocol mode */ - WOLFSPDM_MODE mode; - - /* I/O callback */ - WOLFSPDM_IO_CB ioCb; - void* ioUserCtx; - -#ifdef WOLFTPM_SPDM_TCG - /* TCG binding fields (shared by Nuvoton + Nations) */ - word32 connectionHandle; /* Connection handle (usually 0) */ - word16 fipsIndicator; /* FIPS service indicator */ - - /* Host's public key in TPMT_PUBLIC format */ - byte reqPubKeyTPMT[WOLFSPDM_PUBKEY_BUF_SZ / 2]; /* TPMT_PUBLIC (~120 bytes) */ - word32 reqPubKeyTPMTLen; -#endif - -#ifdef WOLFTPM_SPDM_PSK - /* PSK fields */ - byte psk[WOLFSPDM_PSK_MAX_SIZE]; - word32 pskSz; /* pskSz > 0 means PSK is set */ - byte pskHint[WOLFSPDM_PSK_HINT_MAX]; - word32 pskHintSz; -#endif - - /* Random number generator */ - WC_RNG rng; - - /* Negotiated parameters */ - byte maxVersion; /* Runtime max version cap (0 = use compile-time default) */ - byte spdmVersion; /* Negotiated SPDM version */ - - /* Ephemeral ECDHE key (generated for KEY_EXCHANGE) */ - ecc_key ephemeralKey; - - /* ECDH shared secret (P-384 X-coordinate = 48 bytes) */ - byte sharedSecret[WOLFSPDM_ECC_KEY_SIZE]; - word32 sharedSecretSz; - - /* Transcript hash for TH1/TH2 computation */ - byte transcript[WOLFSPDM_MAX_TRANSCRIPT]; - word32 transcriptLen; - - /* Computed hashes */ - byte certChainHash[WOLFSPDM_HASH_SIZE]; /* Ct = Hash(cert_chain) */ - byte th1[WOLFSPDM_HASH_SIZE]; /* TH1 after KEY_EXCHANGE_RSP */ - byte th2[WOLFSPDM_HASH_SIZE]; /* TH2 after FINISH */ - - /* Derived keys */ - byte handshakeSecret[WOLFSPDM_HASH_SIZE]; - byte reqHsSecret[WOLFSPDM_HASH_SIZE]; - byte rspHsSecret[WOLFSPDM_HASH_SIZE]; - byte reqFinishedKey[WOLFSPDM_HASH_SIZE]; - byte rspFinishedKey[WOLFSPDM_HASH_SIZE]; - - /* Session encryption keys (AES-256-GCM) */ - byte reqDataKey[WOLFSPDM_AEAD_KEY_SIZE]; /* Outgoing encryption key */ - byte rspDataKey[WOLFSPDM_AEAD_KEY_SIZE]; /* Incoming decryption key */ - byte reqDataIv[WOLFSPDM_AEAD_IV_SIZE]; /* Base IV for outgoing */ - byte rspDataIv[WOLFSPDM_AEAD_IV_SIZE]; /* Base IV for incoming */ - - /* Sequence numbers for IV generation */ - word64 reqSeqNum; /* Outgoing message sequence */ - word64 rspSeqNum; /* Incoming message sequence (expected) */ - - /* Session IDs */ - word16 reqSessionId; /* Our session ID (chosen by us) */ - word16 rspSessionId; /* Responder's session ID */ - word32 sessionId; /* Combined: reqSessionId | (rspSessionId << 16) */ - - /* Responder's identity public key (for cert-less mode like Nuvoton) */ - byte rspPubKey[WOLFSPDM_PUBKEY_BUF_SZ / 2]; /* pinned raw X||Y */ - word32 rspPubKeyLen; - - /* Mutual auth fields from KEY_EXCHANGE_RSP */ - byte mutAuthRequested; /* MutAuthRequested from KEY_EXCHANGE_RSP */ - byte reqSlotIdParam; /* ReqSlotIDParam from KEY_EXCHANGE_RSP */ - - /* Requester's identity key pair (for mutual auth) */ - byte reqPrivKey[WOLFSPDM_ECC_KEY_SIZE]; - word32 reqPrivKeyLen; - byte reqPubKey[WOLFSPDM_ECC_POINT_SIZE]; - - /* Boolean flag bit field (at end for better struct packing) */ - struct { - unsigned int debug : 1; - unsigned int initialized : 1; - unsigned int isDynamic : 1; /* Set by wolfSPDM_New(), checked by Free */ - unsigned int rngInitialized : 1; - unsigned int ephemeralKeyInit : 1; - unsigned int hasRspPubKey : 1; - unsigned int hasReqKeyPair : 1; - } flags; -}; - -/* ----- Byte-Order Helpers ----- */ - -static WC_INLINE void SPDM_Set16LE(byte* buf, word16 val) { - buf[0] = (byte)(val & 0xFF); buf[1] = (byte)(val >> 8); -} -static WC_INLINE word16 SPDM_Get16LE(const byte* buf) { - return (word16)(buf[0] | (buf[1] << 8)); -} -static WC_INLINE void SPDM_Set16BE(byte* buf, word16 val) { - buf[0] = (byte)(val >> 8); buf[1] = (byte)(val & 0xFF); -} -static WC_INLINE word16 SPDM_Get16BE(const byte* buf) { - return (word16)((buf[0] << 8) | buf[1]); -} -static WC_INLINE void SPDM_Set32LE(byte* buf, word32 val) { - buf[0] = (byte)(val & 0xFF); buf[1] = (byte)((val >> 8) & 0xFF); - buf[2] = (byte)((val >> 16) & 0xFF); buf[3] = (byte)((val >> 24) & 0xFF); -} -static WC_INLINE word32 SPDM_Get32LE(const byte* buf) { - return (word32)buf[0] | ((word32)buf[1] << 8) | - ((word32)buf[2] << 16) | ((word32)buf[3] << 24); -} -static WC_INLINE void SPDM_Set32BE(byte* buf, word32 val) { - buf[0] = (byte)(val >> 24); buf[1] = (byte)((val >> 16) & 0xFF); - buf[2] = (byte)((val >> 8) & 0xFF); buf[3] = (byte)(val & 0xFF); -} -static WC_INLINE word32 SPDM_Get32BE(const byte* buf) { - return ((word32)buf[0] << 24) | ((word32)buf[1] << 16) | - ((word32)buf[2] << 8) | (word32)buf[3]; -} -static WC_INLINE void SPDM_Set64LE(byte* buf, word64 val) { - buf[0] = (byte)(val & 0xFF); buf[1] = (byte)((val >> 8) & 0xFF); - buf[2] = (byte)((val >> 16) & 0xFF); buf[3] = (byte)((val >> 24) & 0xFF); - buf[4] = (byte)((val >> 32) & 0xFF); buf[5] = (byte)((val >> 40) & 0xFF); - buf[6] = (byte)((val >> 48) & 0xFF); buf[7] = (byte)((val >> 56) & 0xFF); -} -static WC_INLINE word64 SPDM_Get64LE(const byte* buf) { - return (word64)buf[0] | ((word64)buf[1] << 8) | - ((word64)buf[2] << 16) | ((word64)buf[3] << 24) | - ((word64)buf[4] << 32) | ((word64)buf[5] << 40) | - ((word64)buf[6] << 48) | ((word64)buf[7] << 56); -} - -/* ----- Write TCG SPDM Binding header ----- */ -/* tag(2/BE) + size(4/BE) + - * connHandle(4/BE) + fips(2/BE) + reserved(4) */ -#ifdef WOLFTPM_SPDM_TCG -static WC_INLINE void wolfSPDM_WriteTcgHeader(byte* buf, word16 tag, - word32 totalSz, word32 connHandle, word16 fips) -{ - SPDM_Set16BE(buf, tag); - SPDM_Set32BE(buf + 2, totalSz); - SPDM_Set32BE(buf + 6, connHandle); - SPDM_Set16BE(buf + 10, fips); - XMEMSET(buf + 12, 0, 4); /* Reserved */ -} -#endif - -/* ----- Build IV ----- */ -static WC_INLINE void wolfSPDM_BuildIV(byte* iv, const byte* baseIv, - word64 seqNum) -{ - byte seq[8]; int i; - XMEMCPY(iv, baseIv, WOLFSPDM_AEAD_IV_SIZE); - SPDM_Set64LE(seq, seqNum); - for (i = 0; i < 8; i++) iv[i] ^= seq[i]; -} - -/* ----- Connect Step Macro ----- */ - -#define SPDM_CONNECT_STEP(ctx, msg, func) do { \ - wolfSPDM_DebugPrint(ctx, msg); \ - rc = func; \ - if (rc != WOLFSPDM_SUCCESS) { ctx->state = WOLFSPDM_STATE_ERROR; return rc; } \ -} while (0) - -/* ----- Argument Validation Macros ----- */ - -#define SPDM_CHECK_BUILD_ARGS(ctx, buf, bufSz, minSz) \ - do { \ - if ((ctx) == NULL || (buf) == NULL || (bufSz) == NULL) \ - return WOLFSPDM_E_INVALID_ARG; \ - if (*(bufSz) < (minSz)) \ - return WOLFSPDM_E_BUFFER_SMALL; \ - } while(0) - -#define SPDM_CHECK_PARSE_ARGS(ctx, buf, bufSz, minSz) \ - do { \ - if ((ctx) == NULL || (buf) == NULL || (bufSz) < (minSz)) \ - return WOLFSPDM_E_INVALID_ARG; \ - } while(0) - -/* ----- Response Code Check Macro ----- */ - -#define SPDM_CHECK_RESPONSE(ctx, buf, bufSz, expected, fallbackErr) \ - do { \ - if ((buf)[1] != (expected)) { \ - int _ec; \ - if (wolfSPDM_CheckError((buf), (bufSz), &_ec)) { \ - wolfSPDM_DebugPrint((ctx), "SPDM error: 0x%02x\n", _ec); \ - return WOLFSPDM_E_PEER_ERROR; \ - } \ - return (fallbackErr); \ - } \ - } while (0) - -/* ----- Internal Function Declarations - Transcript ----- */ - -WOLFTPM_API void wolfSPDM_TranscriptReset(WOLFSPDM_CTX* ctx); -WOLFTPM_API int wolfSPDM_TranscriptAdd(WOLFSPDM_CTX* ctx, const byte* data, word32 len); -WOLFTPM_API int wolfSPDM_TranscriptHash(WOLFSPDM_CTX* ctx, byte* hash); -WOLFTPM_API int wolfSPDM_Sha384Hash(byte* out, - const byte* d1, word32 d1Sz, - const byte* d2, word32 d2Sz, - const byte* d3, word32 d3Sz); - -/* ----- Internal Function Declarations - Crypto ----- */ - -WOLFTPM_API int wolfSPDM_GenerateEphemeralKey(WOLFSPDM_CTX* ctx); -WOLFTPM_API int wolfSPDM_ExportEphemeralPubKey(WOLFSPDM_CTX* ctx, - byte* pubKeyX, word32* pubKeyXSz, - byte* pubKeyY, word32* pubKeyYSz); -WOLFTPM_API int wolfSPDM_ComputeSharedSecret(WOLFSPDM_CTX* ctx, - const byte* peerPubKeyX, const byte* peerPubKeyY); -WOLFTPM_API int wolfSPDM_GetRandom(WOLFSPDM_CTX* ctx, byte* out, word32 outSz); -WOLFTPM_API int wolfSPDM_SignHash(WOLFSPDM_CTX* ctx, const byte* hash, word32 hashSz, - byte* sig, word32* sigSz); -WOLFTPM_TEST_API int wolfSPDM_ExtractEccPoint(const byte* pubKey, - word32 pubKeySz, const byte** pubKeyX, const byte** pubKeyY); -WOLFTPM_API int wolfSPDM_VerifySignature(WOLFSPDM_CTX* ctx, - const byte* hash, word32 hashSz, - const byte* sig, word32 sigSz); - -/* ----- Internal Function Declarations - Key Derivation ----- */ - -WOLFTPM_API int wolfSPDM_DeriveHandshakeKeys(WOLFSPDM_CTX* ctx, const byte* th1Hash); -WOLFTPM_API int wolfSPDM_DeriveFromHandshakeSecret(WOLFSPDM_CTX* ctx, const byte* th1Hash); -WOLFTPM_API int wolfSPDM_DeriveAppDataKeys(WOLFSPDM_CTX* ctx); -WOLFTPM_API int wolfSPDM_HkdfExpandLabel(byte spdmVersion, const byte* secret, word32 secretSz, - const char* label, const byte* context, word32 contextSz, - byte* out, word32 outSz); -WOLFTPM_API int wolfSPDM_ComputeVerifyData(const byte* finishedKey, const byte* thHash, - byte* verifyData); -/* Cross-TU helper, not a shipped API - WOLFTPM_LOCAL keeps it out of the - * shared-library export table. spdm_internal.h is private to wolfSPDM. */ -WOLFTPM_LOCAL int wolfSPDM_BuildSignedHash(byte spdmVersion, - const char* contextStr, word32 contextStrLen, - const byte* inputDigest, byte* outputDigest); - -/* ----- Internal Function Declarations - Message Building ----- */ - -WOLFTPM_API int wolfSPDM_BuildGetVersion(byte* buf, word32* bufSz); -WOLFTPM_API int wolfSPDM_BuildKeyExchange(WOLFSPDM_CTX* ctx, byte* buf, word32* bufSz); -WOLFTPM_API int wolfSPDM_BuildFinish(WOLFSPDM_CTX* ctx, byte* buf, word32* bufSz); -WOLFTPM_API int wolfSPDM_BuildEndSession(WOLFSPDM_CTX* ctx, byte* buf, word32* bufSz); -/* PSK message builders/parsers declared in spdm_psk.h */ - -/* ----- Internal Function Declarations - Message Parsing ----- */ - -WOLFTPM_API int wolfSPDM_ParseVersion(WOLFSPDM_CTX* ctx, const byte* buf, word32 bufSz); -WOLFTPM_API int wolfSPDM_ParseKeyExchangeRsp(WOLFSPDM_CTX* ctx, const byte* buf, word32 bufSz); -WOLFTPM_API int wolfSPDM_ParseFinishRsp(WOLFSPDM_CTX* ctx, const byte* buf, word32 bufSz); -WOLFTPM_API int wolfSPDM_CheckError(const byte* buf, word32 bufSz, int* errorCode); - -/* ----- Internal Function Declarations - Secured Messaging ----- */ - -WOLFTPM_API int wolfSPDM_EncryptInternal(WOLFSPDM_CTX* ctx, - const byte* plain, word32 plainSz, - byte* enc, word32* encSz); -WOLFTPM_API int wolfSPDM_DecryptInternal(WOLFSPDM_CTX* ctx, - const byte* enc, word32 encSz, - byte* plain, word32* plainSz); - -/* ----- Internal Utility Functions ----- */ - -WOLFTPM_API int wolfSPDM_SendReceive(WOLFSPDM_CTX* ctx, - const byte* txBuf, word32 txSz, - byte* rxBuf, word32* rxSz); - -#ifdef DEBUG_WOLFTPM -WOLFTPM_API void wolfSPDM_DebugPrint(WOLFSPDM_CTX* ctx, const char* fmt, ...) -#ifdef __GNUC__ - __attribute__((format(printf, 2, 3))) -#endif - ; - -WOLFTPM_API void wolfSPDM_DebugHex(WOLFSPDM_CTX* ctx, const char* label, - const byte* data, word32 len); -#else -#define wolfSPDM_DebugPrint(ctx, fmt, ...) do { (void)(ctx); (void)fmt; } while(0) -#define wolfSPDM_DebugHex(ctx, label, data, len) do { (void)(ctx); (void)(label); (void)(data); (void)(len); } while(0) -#endif - -#ifdef __cplusplus -} -#endif - -#endif /* WOLFSPDM_INTERNAL_H */ diff --git a/src/spdm/spdm_kdf.c b/src/spdm/spdm_kdf.c deleted file mode 100644 index e823ed649..000000000 --- a/src/spdm/spdm_kdf.c +++ /dev/null @@ -1,286 +0,0 @@ -/* spdm_kdf.c - * - * Copyright (C) 2006-2026 wolfSSL Inc. - * - * This file is part of wolfSPDM. - * - * wolfSPDM is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3 of the License, or - * (at your option) any later version. - * - * wolfSPDM is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA - */ - -#ifdef HAVE_CONFIG_H - #include -#endif - -#ifdef WOLFTPM_SPDM - -#include "spdm_internal.h" - -/* SPDM key derivation (DSP0277): HKDF with - * info = Length(2,LE) || "spdm1.2 " || Label || Context. */ - -int wolfSPDM_HkdfExpandLabel(byte spdmVersion, const byte* secret, word32 secretSz, - const char* label, const byte* context, word32 contextSz, - byte* out, word32 outSz) -{ - byte info[128]; - word32 infoLen = 0; - word32 labelLen; - const char* prefix; - int rc; - - if (secret == NULL || label == NULL || out == NULL) { - return WOLFSPDM_E_INVALID_ARG; - } - - /* Select version-specific prefix */ - if (spdmVersion >= 0x14) { - prefix = SPDM_BIN_CONCAT_PREFIX_14; /* "spdm1.4 " */ - } else if (spdmVersion >= 0x13) { - prefix = SPDM_BIN_CONCAT_PREFIX_13; /* "spdm1.3 " */ - } else { - prefix = SPDM_BIN_CONCAT_PREFIX_12; /* "spdm1.2 " */ - } - - /* BinConcat format: Length (2 LE) || "spdmX.Y " || Label || Context - * Note: SPDM spec references TLS 1.3 (BE), but Nuvoton uses LE. - * The ResponderVerifyData match proves LE is correct for this TPM. */ - info[infoLen++] = (byte)(outSz & 0xFF); - info[infoLen++] = (byte)((outSz >> 8) & 0xFF); - - labelLen = (word32)XSTRLEN(label); - - /* Bounds check: 2 + prefix(8) + label + context must fit in info[128] */ - if (2 + SPDM_BIN_CONCAT_PREFIX_LEN + labelLen + contextSz > sizeof(info)) { - return WOLFSPDM_E_BUFFER_SMALL; - } - - XMEMCPY(info + infoLen, prefix, SPDM_BIN_CONCAT_PREFIX_LEN); - infoLen += SPDM_BIN_CONCAT_PREFIX_LEN; - - XMEMCPY(info + infoLen, label, labelLen); - infoLen += labelLen; - - if (context != NULL && contextSz > 0) { - XMEMCPY(info + infoLen, context, contextSz); - infoLen += contextSz; - } - - rc = wc_HKDF_Expand(WC_SHA384, secret, secretSz, info, infoLen, out, outSz); - - return (rc == 0) ? WOLFSPDM_SUCCESS : WOLFSPDM_E_CRYPTO_FAIL; -} - -int wolfSPDM_ComputeVerifyData(const byte* finishedKey, const byte* thHash, - byte* verifyData) -{ - Hmac hmac; - int rc; - - if (finishedKey == NULL || thHash == NULL || verifyData == NULL) { - return WOLFSPDM_E_INVALID_ARG; - } - - rc = wc_HmacInit(&hmac, NULL, INVALID_DEVID); - if (rc != 0) { - return WOLFSPDM_E_CRYPTO_FAIL; - } - - rc = wc_HmacSetKey(&hmac, WC_SHA384, finishedKey, WOLFSPDM_HASH_SIZE); - if (rc != 0) { - wc_HmacFree(&hmac); - return WOLFSPDM_E_CRYPTO_FAIL; - } - - rc = wc_HmacUpdate(&hmac, thHash, WOLFSPDM_HASH_SIZE); - if (rc != 0) { - wc_HmacFree(&hmac); - return WOLFSPDM_E_CRYPTO_FAIL; - } - - rc = wc_HmacFinal(&hmac, verifyData); - wc_HmacFree(&hmac); - wc_ForceZero(&hmac, sizeof(hmac)); - - return (rc == 0) ? WOLFSPDM_SUCCESS : WOLFSPDM_E_CRYPTO_FAIL; -} - -/* Derive both data key (AES-256) and IV from a secret using HKDF-Expand */ -static int wolfSPDM_DeriveKeyIvPair(byte spdmVersion, const byte* secret, - byte* key, byte* iv) -{ - int rc; - rc = wolfSPDM_HkdfExpandLabel(spdmVersion, secret, - WOLFSPDM_HASH_SIZE, SPDM_LABEL_KEY, NULL, 0, - key, WOLFSPDM_AEAD_KEY_SIZE); - if (rc != WOLFSPDM_SUCCESS) { - return rc; - } - return wolfSPDM_HkdfExpandLabel(spdmVersion, secret, - WOLFSPDM_HASH_SIZE, SPDM_LABEL_IV, NULL, 0, - iv, WOLFSPDM_AEAD_IV_SIZE); -} - -/* Shared post-Extract: derive HS secrets, finished keys, and data keys from - * ctx->handshakeSecret. Called by both ECDHE and PSK key derivation. */ -int wolfSPDM_DeriveFromHandshakeSecret(WOLFSPDM_CTX* ctx, - const byte* th1Hash) -{ - int rc; - - /* reqHsSecret = HKDF-Expand(HS, "req hs data" || TH1, 48) */ - rc = wolfSPDM_HkdfExpandLabel(ctx->spdmVersion, ctx->handshakeSecret, - WOLFSPDM_HASH_SIZE, SPDM_LABEL_REQ_HS_DATA, th1Hash, WOLFSPDM_HASH_SIZE, - ctx->reqHsSecret, WOLFSPDM_HASH_SIZE); - if (rc == WOLFSPDM_SUCCESS) { - /* rspHsSecret = HKDF-Expand(HS, "rsp hs data" || TH1, 48) */ - rc = wolfSPDM_HkdfExpandLabel(ctx->spdmVersion, ctx->handshakeSecret, - WOLFSPDM_HASH_SIZE, SPDM_LABEL_RSP_HS_DATA, th1Hash, WOLFSPDM_HASH_SIZE, - ctx->rspHsSecret, WOLFSPDM_HASH_SIZE); - } - if (rc == WOLFSPDM_SUCCESS) { - /* Finished keys (used for VerifyData HMAC) */ - rc = wolfSPDM_HkdfExpandLabel(ctx->spdmVersion, ctx->reqHsSecret, - WOLFSPDM_HASH_SIZE, SPDM_LABEL_FINISHED, NULL, 0, - ctx->reqFinishedKey, WOLFSPDM_HASH_SIZE); - } - if (rc == WOLFSPDM_SUCCESS) { - rc = wolfSPDM_HkdfExpandLabel(ctx->spdmVersion, ctx->rspHsSecret, - WOLFSPDM_HASH_SIZE, SPDM_LABEL_FINISHED, NULL, 0, - ctx->rspFinishedKey, WOLFSPDM_HASH_SIZE); - } - if (rc == WOLFSPDM_SUCCESS) { - /* Data encryption keys + IVs (AES-256-GCM) */ - rc = wolfSPDM_DeriveKeyIvPair(ctx->spdmVersion, ctx->reqHsSecret, - ctx->reqDataKey, ctx->reqDataIv); - } - if (rc == WOLFSPDM_SUCCESS) { - rc = wolfSPDM_DeriveKeyIvPair(ctx->spdmVersion, ctx->rspHsSecret, - ctx->rspDataKey, ctx->rspDataIv); - } - - if (rc != WOLFSPDM_SUCCESS) { - /* wipe any partially derived material so it cannot carry into a - * reused ctx */ - wc_ForceZero(ctx->reqHsSecret, sizeof(ctx->reqHsSecret)); - wc_ForceZero(ctx->rspHsSecret, sizeof(ctx->rspHsSecret)); - wc_ForceZero(ctx->reqFinishedKey, sizeof(ctx->reqFinishedKey)); - wc_ForceZero(ctx->rspFinishedKey, sizeof(ctx->rspFinishedKey)); - wc_ForceZero(ctx->reqDataKey, sizeof(ctx->reqDataKey)); - wc_ForceZero(ctx->rspDataKey, sizeof(ctx->rspDataKey)); - wc_ForceZero(ctx->reqDataIv, sizeof(ctx->reqDataIv)); - wc_ForceZero(ctx->rspDataIv, sizeof(ctx->rspDataIv)); - } - - return rc; -} - -int wolfSPDM_DeriveHandshakeKeys(WOLFSPDM_CTX* ctx, const byte* th1Hash) -{ - byte salt[WOLFSPDM_HASH_SIZE]; - int rc; - - if (ctx == NULL || th1Hash == NULL) { - return WOLFSPDM_E_INVALID_ARG; - } - - /* SPDM uses zero salt (unlike TLS 1.3 which uses Hash("")) */ - XMEMSET(salt, 0, sizeof(salt)); - - /* HandshakeSecret = HKDF-Extract(zeros, sharedSecret) */ - rc = wc_HKDF_Extract(WC_SHA384, salt, sizeof(salt), - ctx->sharedSecret, ctx->sharedSecretSz, - ctx->handshakeSecret); - if (rc != 0) { - return WOLFSPDM_E_CRYPTO_FAIL; - } - - return wolfSPDM_DeriveFromHandshakeSecret(ctx, th1Hash); -} - -/* PSK key derivation moved to spdm_psk.c */ - -int wolfSPDM_DeriveAppDataKeys(WOLFSPDM_CTX* ctx) -{ - byte th2Hash[WOLFSPDM_HASH_SIZE]; - byte salt[WOLFSPDM_HASH_SIZE]; - byte masterSecret[WOLFSPDM_HASH_SIZE]; - byte reqAppSecret[WOLFSPDM_HASH_SIZE]; - byte rspAppSecret[WOLFSPDM_HASH_SIZE]; - byte zeroIkm[WOLFSPDM_HASH_SIZE]; - int rc; - - if (ctx == NULL) { - return WOLFSPDM_E_INVALID_ARG; - } - - /* Compute TH2_final = Hash(full transcript including FINISH + FINISH_RSP) */ - rc = wolfSPDM_TranscriptHash(ctx, th2Hash); - if (rc == WOLFSPDM_SUCCESS) { - /* salt = HKDF-Expand(HandshakeSecret, BinConcat("derived"), 48) - * Per DSP0277: "derived" label has NO context (unlike TLS 1.3 which - * uses Hash("")). libspdm confirms: bin_concat("derived", context=NULL) - */ - rc = wolfSPDM_HkdfExpandLabel(ctx->spdmVersion, ctx->handshakeSecret, - WOLFSPDM_HASH_SIZE, "derived", NULL, 0, - salt, WOLFSPDM_HASH_SIZE); - } - if (rc == WOLFSPDM_SUCCESS) { - /* MasterSecret = HKDF-Extract(salt, 0^hashSize) */ - XMEMSET(zeroIkm, 0, sizeof(zeroIkm)); - rc = wc_HKDF_Extract(WC_SHA384, salt, WOLFSPDM_HASH_SIZE, - zeroIkm, WOLFSPDM_HASH_SIZE, masterSecret); - if (rc != 0) { - rc = WOLFSPDM_E_CRYPTO_FAIL; - } - } - if (rc == WOLFSPDM_SUCCESS) { - /* reqAppSecret = HKDF-Expand(MasterSecret, "req app data" || TH2, 48) */ - rc = wolfSPDM_HkdfExpandLabel(ctx->spdmVersion, masterSecret, - WOLFSPDM_HASH_SIZE, SPDM_LABEL_REQ_DATA, th2Hash, - WOLFSPDM_HASH_SIZE, reqAppSecret, WOLFSPDM_HASH_SIZE); - } - if (rc == WOLFSPDM_SUCCESS) { - /* rspAppSecret = HKDF-Expand(MasterSecret, "rsp app data" || TH2, 48) */ - rc = wolfSPDM_HkdfExpandLabel(ctx->spdmVersion, masterSecret, - WOLFSPDM_HASH_SIZE, SPDM_LABEL_RSP_DATA, th2Hash, - WOLFSPDM_HASH_SIZE, rspAppSecret, WOLFSPDM_HASH_SIZE); - } - if (rc == WOLFSPDM_SUCCESS) { - /* Derive new encryption keys + IVs from app data secrets */ - rc = wolfSPDM_DeriveKeyIvPair(ctx->spdmVersion, reqAppSecret, - ctx->reqDataKey, ctx->reqDataIv); - } - if (rc == WOLFSPDM_SUCCESS) { - rc = wolfSPDM_DeriveKeyIvPair(ctx->spdmVersion, rspAppSecret, - ctx->rspDataKey, ctx->rspDataIv); - } - if (rc == WOLFSPDM_SUCCESS) { - /* Reset sequence numbers for application phase */ - ctx->reqSeqNum = 0; - ctx->rspSeqNum = 0; - wolfSPDM_DebugPrint(ctx, "App data keys derived, seq nums reset to 0\n"); - } - - /* Always zero sensitive intermediate key material */ - wc_ForceZero(masterSecret, sizeof(masterSecret)); - wc_ForceZero(reqAppSecret, sizeof(reqAppSecret)); - wc_ForceZero(rspAppSecret, sizeof(rspAppSecret)); - wc_ForceZero(salt, sizeof(salt)); - wc_ForceZero(th2Hash, sizeof(th2Hash)); - - return rc; -} - -#endif /* WOLFTPM_SPDM */ diff --git a/src/spdm/spdm_msg.c b/src/spdm/spdm_msg.c deleted file mode 100644 index 388ec4032..000000000 --- a/src/spdm/spdm_msg.c +++ /dev/null @@ -1,547 +0,0 @@ -/* spdm_msg.c - * - * Copyright (C) 2006-2026 wolfSSL Inc. - * - * This file is part of wolfSPDM. - * - * wolfSPDM is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3 of the License, or - * (at your option) any later version. - * - * wolfSPDM is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA - */ - -#ifdef HAVE_CONFIG_H - #include -#endif - -#ifdef WOLFTPM_SPDM - -#include "spdm_internal.h" - -int wolfSPDM_BuildGetVersion(byte* buf, word32* bufSz) -{ - /* Note: ctx is not used for GET_VERSION, check buf/bufSz directly */ - if (buf == NULL || bufSz == NULL || *bufSz < 4) - return WOLFSPDM_E_BUFFER_SMALL; - - /* Per SPDM spec, GET_VERSION always uses version 1.0 */ - buf[0] = SPDM_VERSION_10; - buf[1] = SPDM_GET_VERSION; - buf[2] = 0x00; - buf[3] = 0x00; - *bufSz = 4; - - return WOLFSPDM_SUCCESS; -} - -static int wolfSPDM_BuildSimpleMsg(WOLFSPDM_CTX* ctx, byte msgCode, - byte* buf, word32* bufSz) -{ - SPDM_CHECK_BUILD_ARGS(ctx, buf, bufSz, 4); - buf[0] = ctx->spdmVersion; - buf[1] = msgCode; - buf[2] = 0x00; - buf[3] = 0x00; - *bufSz = 4; - return WOLFSPDM_SUCCESS; -} - -/* KEY_EXCHANGE request size: 8-byte header, 32-byte RandomData, and two ECC - * coordinates, plus a config-specific OpaqueData block. Keep - * WOLFSPDM_KEYEX_OPAQUE_SZ in sync with the OpaqueData written below. */ -#define WOLFSPDM_KEYEX_FIXED_SZ (40 + 2 * WOLFSPDM_ECC_KEY_SIZE) -#ifdef WOLFSPDM_NUVOTON - #define WOLFSPDM_KEYEX_OPAQUE_SZ 14 -#elif defined(WOLFSPDM_NATIONS) - #define WOLFSPDM_KEYEX_OPAQUE_SZ 2 -#else - #define WOLFSPDM_KEYEX_OPAQUE_SZ 22 -#endif - -int wolfSPDM_BuildKeyExchange(WOLFSPDM_CTX* ctx, byte* buf, word32* bufSz) -{ - word32 offset = 0; - byte pubKeyX[WOLFSPDM_ECC_KEY_SIZE]; - byte pubKeyY[WOLFSPDM_ECC_KEY_SIZE]; - word32 pubKeyXSz = sizeof(pubKeyX); - word32 pubKeyYSz = sizeof(pubKeyY); - int rc; - - /* Require exactly the encoded request size */ - SPDM_CHECK_BUILD_ARGS(ctx, buf, bufSz, - WOLFSPDM_KEYEX_FIXED_SZ + WOLFSPDM_KEYEX_OPAQUE_SZ); - - rc = wolfSPDM_GenerateEphemeralKey(ctx); - if (rc == WOLFSPDM_SUCCESS) - rc = wolfSPDM_ExportEphemeralPubKey(ctx, pubKeyX, &pubKeyXSz, - pubKeyY, &pubKeyYSz); - - if (rc == WOLFSPDM_SUCCESS) { - XMEMSET(buf, 0, *bufSz); - - /* Use negotiated SPDM version (not hardcoded 1.2) */ - buf[offset++] = ctx->spdmVersion; - buf[offset++] = SPDM_KEY_EXCHANGE; - buf[offset++] = 0x00; /* MeasurementSummaryHashType = None */ -#ifdef WOLFTPM_SPDM_TCG - buf[offset++] = 0xFF; /* SlotID = 0xFF (no cert, use provisioned public key) */ -#else - buf[offset++] = 0x00; /* SlotID = 0 (certificate slot 0) */ -#endif - - /* ReqSessionID (2 LE) */ - buf[offset++] = (byte)(ctx->reqSessionId & 0xFF); - buf[offset++] = (byte)((ctx->reqSessionId >> 8) & 0xFF); - - buf[offset++] = 0x00; /* SessionPolicy */ - buf[offset++] = 0x00; /* Reserved */ - - /* RandomData (32 bytes) */ - rc = wolfSPDM_GetRandom(ctx, &buf[offset], WOLFSPDM_RANDOM_SIZE); - if (rc == WOLFSPDM_SUCCESS) { - offset += WOLFSPDM_RANDOM_SIZE; - - /* ExchangeData: X || Y */ - XMEMCPY(&buf[offset], pubKeyX, WOLFSPDM_ECC_KEY_SIZE); - offset += WOLFSPDM_ECC_KEY_SIZE; - XMEMCPY(&buf[offset], pubKeyY, WOLFSPDM_ECC_KEY_SIZE); - offset += WOLFSPDM_ECC_KEY_SIZE; - - /* OpaqueData for secured message version negotiation */ -#ifdef WOLFSPDM_NUVOTON - /* Nuvoton vendor format: 12 bytes */ - buf[offset++] = 0x0c; buf[offset++] = 0x00; - buf[offset++] = 0x00; buf[offset++] = 0x00; - buf[offset++] = 0x05; buf[offset++] = 0x00; - buf[offset++] = 0x01; buf[offset++] = 0x01; - buf[offset++] = 0x01; buf[offset++] = 0x00; - buf[offset++] = 0x10; buf[offset++] = 0x00; - buf[offset++] = 0x00; buf[offset++] = 0x00; -#elif defined(WOLFSPDM_NATIONS) - /* Empty OpaqueData — Nations only accepts OpaqueLength=0 */ - buf[offset++] = 0x00; buf[offset++] = 0x00; -#else - /* Standard SPDM 1.2+ OpaqueData format: 20 bytes */ - buf[offset++] = 0x14; /* OpaqueLength = 20 */ - buf[offset++] = 0x00; - buf[offset++] = 0x01; buf[offset++] = 0x00; /* TotalElements */ - buf[offset++] = 0x00; buf[offset++] = 0x00; /* Reserved */ - buf[offset++] = 0x00; buf[offset++] = 0x00; - buf[offset++] = 0x09; buf[offset++] = 0x00; /* DataSize */ - buf[offset++] = 0x01; /* Registry ID */ - buf[offset++] = 0x01; /* VendorLen */ - buf[offset++] = 0x03; buf[offset++] = 0x00; /* VersionCount */ - buf[offset++] = 0x10; buf[offset++] = 0x00; /* 1.0 */ - buf[offset++] = 0x11; buf[offset++] = 0x00; /* 1.1 */ - buf[offset++] = 0x12; buf[offset++] = 0x00; /* 1.2 */ - buf[offset++] = 0x00; buf[offset++] = 0x00; /* Padding */ -#endif - - *bufSz = offset; - } - } - - return rc; -} - -/* ----- Shared Signing Helpers ----- */ - -/* Build SPDM 1.2+ signed hash per DSP0274: - * M = combined_spdm_prefix || zero_pad || context_str || inputDigest - * outputDigest = Hash(M) - * - * combined_spdm_prefix = "dmtf-spdm-v1.X.*" x4 = 64 bytes - * zero_pad = (36 - contextStrLen) bytes of 0x00 - * context_str = signing context string (variable length, max 36) */ -int wolfSPDM_BuildSignedHash(byte spdmVersion, - const char* contextStr, word32 contextStrLen, - const byte* inputDigest, byte* outputDigest) -{ - byte signMsg[200]; /* 64 + 36 + 48 = 148 bytes max */ - word32 signMsgLen = 0; - word32 zeroPadLen; - byte majorVer, minorVer; - int i, rc; - - majorVer = (byte)('0' + ((spdmVersion >> 4) & 0xF)); - minorVer = (byte)('0' + (spdmVersion & 0xF)); - - /* combined_spdm_prefix: "dmtf-spdm-v1.X.*" x4 = 64 bytes */ - for (i = 0; i < 4; i++) { - XMEMCPY(&signMsg[signMsgLen], "dmtf-spdm-v1.2.*", 16); - signMsg[signMsgLen + 11] = majorVer; - signMsg[signMsgLen + 13] = minorVer; - signMsg[signMsgLen + 15] = '*'; - signMsgLen += 16; - } - - /* Zero padding: 36 - contextStrLen bytes */ - if (contextStrLen > 36) { - return WOLFSPDM_E_INVALID_ARG; - } - zeroPadLen = 36 - contextStrLen; - XMEMSET(&signMsg[signMsgLen], 0x00, zeroPadLen); - signMsgLen += zeroPadLen; - - /* Signing context string */ - XMEMCPY(&signMsg[signMsgLen], contextStr, contextStrLen); - signMsgLen += contextStrLen; - - /* Input digest */ - XMEMCPY(&signMsg[signMsgLen], inputDigest, WOLFSPDM_HASH_SIZE); - signMsgLen += WOLFSPDM_HASH_SIZE; - - /* Hash M */ - rc = wolfSPDM_Sha384Hash(outputDigest, signMsg, signMsgLen, - NULL, 0, NULL, 0); - if (rc != WOLFSPDM_SUCCESS) return rc; - - return WOLFSPDM_SUCCESS; -} - -int wolfSPDM_BuildFinish(WOLFSPDM_CTX* ctx, byte* buf, word32* bufSz) -{ - byte th2Hash[WOLFSPDM_HASH_SIZE]; - byte verifyData[WOLFSPDM_HASH_SIZE]; - byte signature[WOLFSPDM_ECC_POINT_SIZE]; /* 96 bytes for P-384 */ - word32 sigSz = sizeof(signature); - word32 offset = 4; /* Start after header */ - word32 minSz; - int mutualAuth = 0; - int rc; - - /* Check arguments first before any ctx dereference */ - if (ctx == NULL || buf == NULL || bufSz == NULL) { - return WOLFSPDM_E_INVALID_ARG; - } - - /* Mutual auth is enabled when the responder requested it (MutAuthRequested - * bit 0) AND we have a requester key pair to sign with */ - if ((ctx->mutAuthRequested & 0x01) && ctx->flags.hasReqKeyPair) { - mutualAuth = 1; - wolfSPDM_DebugPrint(ctx, "FINISH: Mutual auth ENABLED " - "(MutAuth=0x%02x ReqSlot=0x%02x)\n", - ctx->mutAuthRequested, ctx->reqSlotIdParam); - } - - /* Check buffer size: header(4) + [OpaqueLength(2) for 1.4+] + - * [signature(96) for mutual auth] + HMAC(48) */ - minSz = 4 + WOLFSPDM_HASH_SIZE; /* header + HMAC */ - if (ctx->spdmVersion >= SPDM_VERSION_14) - minSz += 2; /* OpaqueLength */ - if (mutualAuth) - minSz += WOLFSPDM_ECC_POINT_SIZE; /* Signature */ - if (*bufSz < minSz) - return WOLFSPDM_E_BUFFER_SMALL; - - /* Build FINISH header */ - buf[0] = ctx->spdmVersion; - buf[1] = SPDM_FINISH; - if (mutualAuth) { - buf[2] = 0x01; /* Param1: Signature field is included */ - /* Param2: For PUB_KEY_ID mode, shall be 0xFF per DSP0274 */ - buf[3] = 0xFF; - } else { - buf[2] = 0x00; /* Param1: No signature */ - buf[3] = 0x00; /* Param2: SlotID = 0 when no signature */ - } - - /* SPDM 1.4 adds OpaqueLength(2) + OpaqueData(var) after header */ - if (ctx->spdmVersion >= SPDM_VERSION_14) { - buf[offset++] = 0x00; /* OpaqueLength = 0 (LE) */ - buf[offset++] = 0x00; - } - - rc = WOLFSPDM_SUCCESS; - - /* Mutual auth: add Hash(Cm_requester) to transcript between message_k - * 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). */ -#ifdef WOLFTPM_SPDM_TCG - if (rc == WOLFSPDM_SUCCESS && mutualAuth && ctx->reqPubKeyTPMTLen > 0) { - byte cmHash[WOLFSPDM_HASH_SIZE]; - rc = wolfSPDM_Sha384Hash(cmHash, ctx->reqPubKeyTPMT, - ctx->reqPubKeyTPMTLen, NULL, 0, NULL, 0); - if (rc == WOLFSPDM_SUCCESS) - rc = wolfSPDM_TranscriptAdd(ctx, cmHash, WOLFSPDM_HASH_SIZE); - } -#endif - - /* Add FINISH header to transcript, compute TH2 */ - if (rc == WOLFSPDM_SUCCESS) - rc = wolfSPDM_TranscriptAdd(ctx, buf, offset); - if (rc == WOLFSPDM_SUCCESS) - rc = wolfSPDM_TranscriptHash(ctx, th2Hash); - if (rc == WOLFSPDM_SUCCESS) - XMEMCPY(ctx->th2, th2Hash, WOLFSPDM_HASH_SIZE); - - /* Mutual auth: sign TH2, add signature to transcript, recompute TH2 */ - if (rc == WOLFSPDM_SUCCESS && mutualAuth) { - byte signMsgHash[WOLFSPDM_HASH_SIZE]; - - rc = wolfSPDM_BuildSignedHash(ctx->spdmVersion, - "requester-finish signing", 24, th2Hash, signMsgHash); - if (rc == WOLFSPDM_SUCCESS) - rc = wolfSPDM_SignHash(ctx, signMsgHash, WOLFSPDM_HASH_SIZE, - signature, &sigSz); - if (rc == WOLFSPDM_SUCCESS) { - XMEMCPY(&buf[offset], signature, WOLFSPDM_ECC_POINT_SIZE); - offset += WOLFSPDM_ECC_POINT_SIZE; - rc = wolfSPDM_TranscriptAdd(ctx, signature, - WOLFSPDM_ECC_POINT_SIZE); - } - if (rc == WOLFSPDM_SUCCESS) - rc = wolfSPDM_TranscriptHash(ctx, th2Hash); - } - - /* RequesterVerifyData = HMAC(reqFinishedKey, TH2) */ - if (rc == WOLFSPDM_SUCCESS) - rc = wolfSPDM_ComputeVerifyData(ctx->reqFinishedKey, th2Hash, - verifyData); - if (rc == WOLFSPDM_SUCCESS) { - XMEMCPY(&buf[offset], verifyData, WOLFSPDM_HASH_SIZE); - offset += WOLFSPDM_HASH_SIZE; - rc = wolfSPDM_TranscriptAdd(ctx, verifyData, WOLFSPDM_HASH_SIZE); - } - if (rc == WOLFSPDM_SUCCESS) - *bufSz = offset; - - /* Always zero sensitive stack buffers */ - wc_ForceZero(th2Hash, sizeof(th2Hash)); - wc_ForceZero(verifyData, sizeof(verifyData)); - wc_ForceZero(signature, sizeof(signature)); - return rc; -} - -int wolfSPDM_BuildEndSession(WOLFSPDM_CTX* ctx, byte* buf, word32* bufSz) -{ - return wolfSPDM_BuildSimpleMsg(ctx, SPDM_END_SESSION, buf, bufSz); -} - -int wolfSPDM_CheckError(const byte* buf, word32 bufSz, int* errorCode) -{ - if (buf == NULL || bufSz < 4) { - return 0; - } - - if (buf[1] == SPDM_ERROR) { - if (errorCode != NULL) { - *errorCode = buf[2]; - } - return 1; - } - - return 0; -} - -int wolfSPDM_ParseVersion(WOLFSPDM_CTX* ctx, const byte* buf, word32 bufSz) -{ - word16 entryCount; - word32 i; - byte highestVersion = 0; /* No version found yet */ - byte maxVer; - - SPDM_CHECK_PARSE_ARGS(ctx, buf, bufSz, 6); - SPDM_CHECK_RESPONSE(ctx, buf, bufSz, SPDM_VERSION, WOLFSPDM_E_VERSION_MISMATCH); - - /* VersionNumberEntryCount is the one-byte field at offset 5 (byte 4 - * reserved) per DSP0274; older wolfTPM responders placed it at - * offset 4, so fall back to that when offset 5 is zero. - * Offset 6+: VersionNumberEntry array (2 bytes each, LE) */ - entryCount = buf[5]; - if (entryCount == 0) { - entryCount = buf[4]; - } - - /* Reject a truncated entry list instead of negotiating from a subset */ - if ((word32)6 + (word32)entryCount * 2 > bufSz) { - return WOLFSPDM_E_VERSION_MISMATCH; - } - - /* Find highest mutually supported version. - * Per DSP0274, negotiated version must be the highest version - * that both sides support. We support WOLFSPDM_MIN_SPDM_VERSION - * through WOLFSPDM_MAX_SPDM_VERSION (or ctx->maxVersion if set). */ - maxVer = (ctx->maxVersion != 0) ? ctx->maxVersion - : WOLFSPDM_MAX_SPDM_VERSION; - for (i = 0; i < entryCount; i++) { - /* Each entry is 2 bytes; high byte (offset +1) is Major.Minor */ - byte ver = buf[6 + i * 2 + 1]; - if (ver >= WOLFSPDM_MIN_SPDM_VERSION && - ver <= maxVer && - ver > highestVersion) { - highestVersion = ver; - } - } - - /* If no mutually supported version found, fail */ - if (highestVersion == 0) { - wolfSPDM_DebugPrint(ctx, "No mutually supported SPDM version found " - "(require >= 0x%02x)\n", WOLFSPDM_MIN_SPDM_VERSION); - return WOLFSPDM_E_VERSION_MISMATCH; - } - - ctx->spdmVersion = highestVersion; - ctx->state = WOLFSPDM_STATE_VERSION; - - wolfSPDM_DebugPrint(ctx, "Negotiated SPDM version: 0x%02x\n", ctx->spdmVersion); - return WOLFSPDM_SUCCESS; -} - -int wolfSPDM_ParseKeyExchangeRsp(WOLFSPDM_CTX* ctx, const byte* buf, word32 bufSz) -{ - word16 opaqueLen; - word32 sigOffset; - word32 keRspPartialLen; - byte peerPubKeyX[WOLFSPDM_ECC_KEY_SIZE]; - byte peerPubKeyY[WOLFSPDM_ECC_KEY_SIZE]; - byte th1SigHash[WOLFSPDM_HASH_SIZE]; - byte signMsgHash[WOLFSPDM_HASH_SIZE]; - byte expectedHmac[WOLFSPDM_HASH_SIZE]; - const byte* signature; - const byte* rspVerifyData; - int rc; - - SPDM_CHECK_PARSE_ARGS(ctx, buf, bufSz, 140); - SPDM_CHECK_RESPONSE(ctx, buf, bufSz, SPDM_KEY_EXCHANGE_RSP, WOLFSPDM_E_KEY_EXCHANGE); - - ctx->rspSessionId = SPDM_Get16LE(&buf[4]); - ctx->sessionId = (word32)ctx->reqSessionId | ((word32)ctx->rspSessionId << 16); - - /* Parse MutAuthRequested and ReqSlotIDParam (offsets 6-7) */ - ctx->mutAuthRequested = buf[6]; - ctx->reqSlotIdParam = buf[7]; - wolfSPDM_DebugPrint(ctx, "KEY_EXCHANGE_RSP: MutAuth=0x%02x ReqSlotID=0x%02x\n", - ctx->mutAuthRequested, ctx->reqSlotIdParam); - - /* Extract responder's ephemeral public key (offset 40 = 4+2+1+1+32) */ - XMEMCPY(peerPubKeyX, &buf[40], WOLFSPDM_ECC_KEY_SIZE); - XMEMCPY(peerPubKeyY, &buf[88], WOLFSPDM_ECC_KEY_SIZE); - - /* OpaqueLen at offset 136 */ - opaqueLen = SPDM_Get16LE(&buf[136]); - sigOffset = 138 + opaqueLen; - keRspPartialLen = sigOffset; - - if (bufSz < sigOffset + WOLFSPDM_ECC_SIG_SIZE + WOLFSPDM_HASH_SIZE) { - return WOLFSPDM_E_BUFFER_SMALL; - } - - signature = buf + sigOffset; - rspVerifyData = buf + sigOffset + WOLFSPDM_ECC_SIG_SIZE; - - /* Add KEY_EXCHANGE_RSP partial (without sig/verify) to transcript */ - rc = wolfSPDM_TranscriptAdd(ctx, buf, keRspPartialLen); - - /* Verify responder signature over TH1 (DSP0274). Responder public key - * must be provisioned before KEY_EXCHANGE. */ - if (rc == WOLFSPDM_SUCCESS && !ctx->flags.hasRspPubKey) { - wolfSPDM_DebugPrint(ctx, "No responder public key set\n"); - rc = WOLFSPDM_E_BAD_STATE; - } - if (rc == WOLFSPDM_SUCCESS) { - rc = wolfSPDM_TranscriptHash(ctx, th1SigHash); - } - if (rc == WOLFSPDM_SUCCESS) { - rc = wolfSPDM_BuildSignedHash(ctx->spdmVersion, - "responder-key_exchange_rsp signing", 34, - th1SigHash, signMsgHash); - } - if (rc == WOLFSPDM_SUCCESS) { - rc = wolfSPDM_VerifySignature(ctx, signMsgHash, WOLFSPDM_HASH_SIZE, - signature, WOLFSPDM_ECC_SIG_SIZE); - if (rc != WOLFSPDM_SUCCESS) - wolfSPDM_DebugPrint(ctx, "KEY_EXCHANGE_RSP signature INVALID\n"); - } - if (rc == WOLFSPDM_SUCCESS) { - rc = wolfSPDM_TranscriptAdd(ctx, signature, WOLFSPDM_ECC_SIG_SIZE); - } - if (rc == WOLFSPDM_SUCCESS) { - rc = wolfSPDM_ComputeSharedSecret(ctx, peerPubKeyX, peerPubKeyY); - } - if (rc == WOLFSPDM_SUCCESS) { - rc = wolfSPDM_TranscriptHash(ctx, ctx->th1); - } - if (rc == WOLFSPDM_SUCCESS) { - rc = wolfSPDM_DeriveHandshakeKeys(ctx, ctx->th1); - } - if (rc == WOLFSPDM_SUCCESS) { - rc = wolfSPDM_ComputeVerifyData(ctx->rspFinishedKey, ctx->th1, expectedHmac); - } - if (rc == WOLFSPDM_SUCCESS) { - word32 i; - volatile int diff = 0; - for (i = 0; i < WOLFSPDM_HASH_SIZE; i++) { - diff |= expectedHmac[i] ^ rspVerifyData[i]; - } - if (diff != 0) { - wolfSPDM_DebugPrint(ctx, "ResponderVerifyData MISMATCH\n"); - rc = WOLFSPDM_E_BAD_HMAC; - } - } - if (rc == WOLFSPDM_SUCCESS) { - wolfSPDM_DebugPrint(ctx, "ResponderVerifyData VERIFIED OK\n"); - rc = wolfSPDM_TranscriptAdd(ctx, rspVerifyData, WOLFSPDM_HASH_SIZE); - } - if (rc == WOLFSPDM_SUCCESS) { - ctx->state = WOLFSPDM_STATE_KEY_EX; - } - - wc_ForceZero(expectedHmac, sizeof(expectedHmac)); - wc_ForceZero(th1SigHash, sizeof(th1SigHash)); - wc_ForceZero(signMsgHash, sizeof(signMsgHash)); - return rc; -} - -int wolfSPDM_ParseFinishRsp(WOLFSPDM_CTX* ctx, const byte* buf, word32 bufSz) -{ - SPDM_CHECK_PARSE_ARGS(ctx, buf, bufSz, 4); - - if (buf[1] == SPDM_FINISH_RSP) { - int addRc; - word32 rspMsgLen = 4; - - /* SPDM 1.4 adds OpaqueLength(2) + OpaqueData(var) to FINISH_RSP */ - if (ctx->spdmVersion >= SPDM_VERSION_14) { - word16 opaqueLen; - if (bufSz < 6) { - return WOLFSPDM_E_BUFFER_SMALL; - } - opaqueLen = SPDM_Get16LE(&buf[4]); - rspMsgLen = 4 + 2 + opaqueLen; - if (bufSz < rspMsgLen) { - return WOLFSPDM_E_BUFFER_SMALL; - } - } - - /* Add FINISH_RSP (header + OpaqueData for 1.4) to transcript */ - addRc = wolfSPDM_TranscriptAdd(ctx, buf, rspMsgLen); - if (addRc != WOLFSPDM_SUCCESS) { - return addRc; - } - ctx->state = WOLFSPDM_STATE_FINISH; - wolfSPDM_DebugPrint(ctx, "FINISH_RSP received - session established\n"); - return WOLFSPDM_SUCCESS; - } - - if (buf[1] == SPDM_ERROR) { - wolfSPDM_DebugPrint(ctx, "FINISH error: 0x%02x\n", buf[2]); - return WOLFSPDM_E_PEER_ERROR; - } - - return WOLFSPDM_E_BAD_STATE; -} - -/* PSK message builders/parsers moved to spdm_psk.c */ - -#endif /* WOLFTPM_SPDM */ diff --git a/src/spdm/spdm_nations.c b/src/spdm/spdm_nations.c deleted file mode 100644 index 37d722442..000000000 --- a/src/spdm/spdm_nations.c +++ /dev/null @@ -1,185 +0,0 @@ -/* spdm_nations.c - * - * Copyright (C) 2006-2026 wolfSSL Inc. - * - * This file is part of wolfSPDM. - * - * wolfSPDM is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3 of the License, or - * (at your option) any later version. - * - * wolfSPDM is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA - */ - -#ifdef HAVE_CONFIG_H - #include -#endif - -#ifdef WOLFTPM_SPDM - -/* Nations Technology NS350 SPDM Functions - * - * PSK-mode vendor commands and PSK connection flow. - * Identity key mode uses shared TCG code in spdm_tcg.c. - */ - -#include "spdm_internal.h" - -#ifdef WOLFSPDM_NATIONS - -#include - -/* ----- Nations PSK-Mode Vendor Commands ----- */ - -int wolfSPDM_Nations_GetStatus(WOLFSPDM_CTX* ctx, - WOLFSPDM_NATIONS_STATUS* status) -{ - WOLFSPDM_VENDOR_RSP rsp; - int rc; - - if (ctx == NULL || status == NULL) { - return WOLFSPDM_E_INVALID_ARG; - } - - XMEMSET(status, 0, sizeof(*status)); - - wolfSPDM_DebugPrint(ctx, "Nations: GET_STS_\n"); - - /* NS350 accepts GET_STATUS with no payload (Type field omitted) */ - rc = wolfSPDM_TCG_VendorCmdClear(ctx, WOLFSPDM_VDCODE_GET_STS, - NULL, 0, &rsp); - if (rc != WOLFSPDM_SUCCESS) { - return rc; - } - - wolfSPDM_DebugHex(ctx, "GET_STS_ payload", rsp.payload, rsp.payloadSz); - - /* Per TCG spec Table 15 — GET_STATUS_RSP payload: - * [0] SpecMajorVersion, [1] SpecMinorVersion, - * [2] PSKSet (00=NO, 01=YES), - * [3] SPDMOnly (00=DISABLED, 01=ENABLED, 81=PENDING_DISABLE) */ - if (rsp.payloadSz >= 4) { - status->spdmEnabled = 1; - status->pskProvisioned = (rsp.payload[2] != 0); - status->spdmOnlyLocked = (rsp.payload[3] != 0); - wolfSPDM_DebugPrint(ctx, "GET_STS_: v%u.%u PSK=%s SPDMOnly=0x%02x\n", - rsp.payload[0], rsp.payload[1], - status->pskProvisioned ? "YES" : "NO", - rsp.payload[3]); - } - else { - return WOLFSPDM_E_FRAMING; - } - - return WOLFSPDM_SUCCESS; -} - -int wolfSPDM_Nations_SetOnlyMode(WOLFSPDM_CTX* ctx, int lock) -{ - byte param[1]; - int rc; - - if (ctx == NULL) { - return WOLFSPDM_E_INVALID_ARG; - } - - if (ctx->state != WOLFSPDM_STATE_CONNECTED) { - return WOLFSPDM_E_NOT_CONNECTED; - } - - param[0] = lock ? WOLFSPDM_SPDMONLY_LOCK : WOLFSPDM_SPDMONLY_UNLOCK; - - wolfSPDM_DebugPrint(ctx, "Nations: SPDMONLY %s\n", - lock ? "LOCK" : "UNLOCK"); - - rc = wolfSPDM_TCG_VendorCmdSecured(ctx, WOLFSPDM_VDCODE_SPDMONLY, - param, sizeof(param)); - if (rc != WOLFSPDM_SUCCESS) { - return rc; - } - - wolfSPDM_DebugPrint(ctx, "SPDMONLY: Success (Lock=%u)\n", param[0]); - return WOLFSPDM_SUCCESS; -} - -int wolfSPDM_Nations_PskSet(WOLFSPDM_CTX* ctx, - const byte* psk, word32 pskSz) -{ - int rc; - - if (ctx == NULL || psk == NULL || pskSz == 0) { - return WOLFSPDM_E_INVALID_ARG; - } - - wolfSPDM_DebugPrint(ctx, "Nations: PSK_SET_ (%u bytes)\n", pskSz); - - rc = wolfSPDM_TCG_VendorCmdClear(ctx, WOLFSPDM_NATIONS_VDCODE_PSK_SET, - psk, pskSz, NULL); - if (rc != WOLFSPDM_SUCCESS) { - wolfSPDM_DebugPrint(ctx, "PSK_SET_ failed: %d\n", rc); - return rc; - } - - wolfSPDM_DebugPrint(ctx, "PSK_SET_: Success\n"); - return WOLFSPDM_SUCCESS; -} - -int wolfSPDM_Nations_PskClear(WOLFSPDM_CTX* ctx, - const byte* clearAuth, word32 clearAuthSz) -{ - int rc; - - if (ctx == NULL || clearAuth == NULL || clearAuthSz == 0) { - return WOLFSPDM_E_INVALID_ARG; - } - - wolfSPDM_DebugPrint(ctx, "Nations: PSK_CLR_ (auth=%u bytes)\n", - clearAuthSz); - - rc = wolfSPDM_TCG_VendorCmdClear(ctx, WOLFSPDM_NATIONS_VDCODE_PSK_CLEAR, - clearAuth, clearAuthSz, NULL); - if (rc != WOLFSPDM_SUCCESS) { - wolfSPDM_DebugPrint(ctx, "PSK_CLR_ failed: %d\n", rc); - return rc; - } - - wolfSPDM_DebugPrint(ctx, "PSK_CLR_: Success\n"); - return WOLFSPDM_SUCCESS; -} - -int wolfSPDM_Nations_PskClearWithVCA(WOLFSPDM_CTX* ctx, - const byte* clearAuth, word32 clearAuthSz) -{ - int rc; - - if (ctx == NULL || clearAuth == NULL || clearAuthSz == 0) { - return WOLFSPDM_E_INVALID_ARG; - } - - /* Full VCA: GET_VERSION + GET_CAPABILITIES + NEGOTIATE_ALGORITHMS */ - rc = wolfSPDM_GetVersion(ctx); - if (rc != WOLFSPDM_SUCCESS) return rc; - - rc = wolfSPDM_TCG_GetCapabilities(ctx, WOLFSPDM_TCG_CAPS_FLAGS_PSK); - if (rc != WOLFSPDM_SUCCESS) return rc; - - rc = wolfSPDM_TCG_NegotiateAlgorithms(ctx); - if (rc != WOLFSPDM_SUCCESS) return rc; - - return wolfSPDM_Nations_PskClear(ctx, clearAuth, clearAuthSz); -} - -/* PSK connection flow moved to spdm_psk.c (wolfSPDM_ConnectPsk). - * wolfSPDM_ConnectNationsPsk is a backward-compat alias in spdm_psk.h. */ - -#endif /* WOLFSPDM_NATIONS */ - -#endif /* WOLFTPM_SPDM */ diff --git a/src/spdm/spdm_nuvoton.c b/src/spdm/spdm_nuvoton.c deleted file mode 100644 index 400046db6..000000000 --- a/src/spdm/spdm_nuvoton.c +++ /dev/null @@ -1,123 +0,0 @@ -/* spdm_nuvoton.c - * - * Copyright (C) 2006-2026 wolfSSL Inc. - * - * This file is part of wolfSPDM. - * - * wolfSPDM is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3 of the License, or - * (at your option) any later version. - * - * wolfSPDM is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA - */ - -#ifdef HAVE_CONFIG_H - #include -#endif - -#ifdef WOLFTPM_SPDM - -/* Nuvoton-specific SPDM functions (GetStatus, SetOnlyMode). */ - -#include "spdm_internal.h" - -#ifdef WOLFSPDM_NUVOTON - -#include - -int wolfSPDM_Nuvoton_GetStatus( - WOLFSPDM_CTX* ctx, - WOLFSPDM_NUVOTON_STATUS* status) -{ - WOLFSPDM_VENDOR_RSP rsp; - byte statusType[4] = {0x00, 0x00, 0x00, 0x00}; - int rc; - - if (ctx == NULL || status == NULL) { - return WOLFSPDM_E_INVALID_ARG; - } - - XMEMSET(status, 0, sizeof(*status)); - - wolfSPDM_DebugPrint(ctx, "Nuvoton: GET_STS_\n"); - - rc = wolfSPDM_TCG_VendorCmdClear(ctx, WOLFSPDM_VDCODE_GET_STS, - statusType, sizeof(statusType), &rsp); - if (rc != WOLFSPDM_SUCCESS) { - return rc; - } - - wolfSPDM_DebugPrint(ctx, "GET_STS_: VdCode='%.8s', %u bytes\n", - rsp.vdCode, rsp.payloadSz); - - /* Parse status fields per Nuvoton spec page 9: - * Byte 0: SpecVersionMajor (0 for SPDM 1.x) - * Byte 1: SpecVersionMinor (1 = SPDM 1.1, 3 = SPDM 1.3) - * Byte 2: Reserved - * Byte 3: SPDMOnly lock state (0 = unlocked, 1 = locked) */ - if (rsp.payloadSz >= 4) { - byte specMajor = rsp.payload[0]; - byte specMinor = rsp.payload[1]; - byte spdmOnly = rsp.payload[3]; - - status->specVersionMajor = specMajor; - status->specVersionMinor = specMinor; - status->spdmOnlyLocked = (spdmOnly != 0); - status->spdmEnabled = 1; - status->sessionActive = 0; - - wolfSPDM_DebugPrint(ctx, "GET_STS_: SpecVersion=%u.%u, SPDMOnly=%s\n", - specMajor, specMinor, spdmOnly ? "LOCKED" : "unlocked"); - } else if (rsp.payloadSz >= 1) { - status->spdmOnlyLocked = (rsp.payload[0] != 0); - status->spdmEnabled = 1; - wolfSPDM_DebugPrint(ctx, "GET_STS_: SPDMOnly=%s (minimal response)\n", - status->spdmOnlyLocked ? "LOCKED" : "unlocked"); - } - else { - return WOLFSPDM_E_FRAMING; - } - return WOLFSPDM_SUCCESS; -} - -int wolfSPDM_Nuvoton_SetOnlyMode( - WOLFSPDM_CTX* ctx, - int lock) -{ - byte param[1]; - int rc; - - if (ctx == NULL) { - return WOLFSPDM_E_INVALID_ARG; - } - - if (ctx->state != WOLFSPDM_STATE_CONNECTED) { - return WOLFSPDM_E_NOT_CONNECTED; - } - - param[0] = lock ? WOLFSPDM_SPDMONLY_LOCK : WOLFSPDM_SPDMONLY_UNLOCK; - - wolfSPDM_DebugPrint(ctx, "Nuvoton: SPDMONLY %s\n", - lock ? "LOCK" : "UNLOCK"); - - rc = wolfSPDM_TCG_VendorCmdSecured(ctx, WOLFSPDM_VDCODE_SPDMONLY, - param, sizeof(param)); - if (rc != WOLFSPDM_SUCCESS) { - return rc; - } - - wolfSPDM_DebugPrint(ctx, "SPDMONLY: Success\n"); - return WOLFSPDM_SUCCESS; -} - -#endif /* WOLFSPDM_NUVOTON */ - -#endif /* WOLFTPM_SPDM */ diff --git a/src/spdm/spdm_psk.c b/src/spdm/spdm_psk.c deleted file mode 100644 index c1e0d10ae..000000000 --- a/src/spdm/spdm_psk.c +++ /dev/null @@ -1,433 +0,0 @@ -/* spdm_psk.c - * - * Copyright (C) 2006-2026 wolfSSL Inc. - * - * This file is part of wolfSPDM. - * - * wolfSPDM is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3 of the License, or - * (at your option) any later version. - * - * wolfSPDM is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA - */ - -#ifdef HAVE_CONFIG_H - #include -#endif - -#ifdef WOLFTPM_SPDM - -/* Shared SPDM PSK protocol code used by Nations (and future Infineon). */ - -#include "spdm_internal.h" - -#ifdef WOLFTPM_SPDM_PSK - -#include -#include - -/* ----- PSK Context Setup ----- */ - -int wolfSPDM_SetPSK(WOLFSPDM_CTX* ctx, - const byte* psk, word32 pskSz, - const byte* hint, word32 hintSz) -{ - if (ctx == NULL || psk == NULL || pskSz == 0) { - return WOLFSPDM_E_INVALID_ARG; - } - if (pskSz > WOLFSPDM_PSK_MAX_SIZE) { - return WOLFSPDM_E_INVALID_ARG; - } - if (hint != NULL && hintSz > WOLFSPDM_PSK_HINT_MAX) { - return WOLFSPDM_E_INVALID_ARG; - } - - XMEMCPY(ctx->psk, psk, pskSz); - ctx->pskSz = pskSz; - - if (hint != NULL && hintSz > 0) { - XMEMCPY(ctx->pskHint, hint, hintSz); - ctx->pskHintSz = hintSz; - } else { - XMEMSET(ctx->pskHint, 0, sizeof(ctx->pskHint)); - ctx->pskHintSz = 0; - } - - return WOLFSPDM_SUCCESS; -} - -/* ----- PSK Message Builders/Parsers ----- */ - -int wolfSPDM_BuildPskExchange(WOLFSPDM_CTX* ctx, byte* buf, word32* bufSz) -{ - word32 offset = 0; - int rc; - - SPDM_CHECK_BUILD_ARGS(ctx, buf, bufSz, 48); - - if (ctx->pskSz == 0) { - return WOLFSPDM_E_BAD_STATE; - } - - XMEMSET(buf, 0, *bufSz); - - /* Header */ - buf[offset++] = ctx->spdmVersion; - buf[offset++] = SPDM_PSK_EXCHANGE; - buf[offset++] = 0x00; /* MeasurementSummaryHashType = None */ - buf[offset++] = 0x00; /* Param2 = Reserved */ - - /* ReqSessionID (2 LE) */ - SPDM_Set16LE(&buf[offset], ctx->reqSessionId); - offset += 2; - - /* PSKHintLength (2 LE) */ - SPDM_Set16LE(&buf[offset], (word16)ctx->pskHintSz); - offset += 2; - - /* RequesterContextLength (2 LE) = 32 */ - SPDM_Set16LE(&buf[offset], WOLFSPDM_RANDOM_SIZE); - offset += 2; - - /* OpaqueDataLength (2 LE) = 0 */ - SPDM_Set16LE(&buf[offset], 0); - offset += 2; - - /* PSKHint */ - if (ctx->pskHintSz > 0) { - if (offset + ctx->pskHintSz > *bufSz) { - return WOLFSPDM_E_BUFFER_SMALL; - } - XMEMCPY(&buf[offset], ctx->pskHint, ctx->pskHintSz); - offset += ctx->pskHintSz; - } - - /* RequesterContext (32 random bytes) */ - if (offset + WOLFSPDM_RANDOM_SIZE > *bufSz) { - return WOLFSPDM_E_BUFFER_SMALL; - } - rc = wolfSPDM_GetRandom(ctx, &buf[offset], WOLFSPDM_RANDOM_SIZE); - if (rc != WOLFSPDM_SUCCESS) { - return rc; - } - offset += WOLFSPDM_RANDOM_SIZE; - - /* OpaqueData - none */ - - *bufSz = offset; - return WOLFSPDM_SUCCESS; -} - -int wolfSPDM_ParsePskExchangeRsp(WOLFSPDM_CTX* ctx, const byte* buf, - word32 bufSz) -{ - word16 rspContextLen, opaqueLen; - word32 verifyOffset; - word32 rspPartialLen; - byte th1Hash[WOLFSPDM_HASH_SIZE]; - byte expectedHmac[WOLFSPDM_HASH_SIZE]; - const byte* rspVerifyData; - int rc; - - /* Minimum: header(4) + RspSessionID(2) + Reserved(1) + RspContextLen(2) + - * OpaqueLen(2) + VerifyData(48) = 59 */ - SPDM_CHECK_PARSE_ARGS(ctx, buf, bufSz, 59); - SPDM_CHECK_RESPONSE(ctx, buf, bufSz, SPDM_PSK_EXCHANGE_RSP, - WOLFSPDM_E_KEY_EXCHANGE); - - /* Per SPDM 1.3 DSP0274 Table 65: - * [4-5] RspSessionID, [6] MutAuthRequested, [7] ReqSlotIDParam, - * [8-9] RspContextLength, [10-11] OpaqueDataLength */ - ctx->rspSessionId = SPDM_Get16LE(&buf[4]); - ctx->sessionId = (word32)ctx->reqSessionId | - ((word32)ctx->rspSessionId << 16); - - rspContextLen = SPDM_Get16LE(&buf[8]); - opaqueLen = SPDM_Get16LE(&buf[10]); - - verifyOffset = 12 + rspContextLen + opaqueLen; - rspPartialLen = verifyOffset; - - if (bufSz < verifyOffset + WOLFSPDM_HASH_SIZE) { - return WOLFSPDM_E_BUFFER_SMALL; - } - - rspVerifyData = buf + verifyOffset; - - /* Add PSK_EXCHANGE_RSP (without VerifyData) to transcript */ - rc = wolfSPDM_TranscriptAdd(ctx, buf, rspPartialLen); - - /* Compute TH1 and derive handshake keys from PSK BEFORE verifying */ - if (rc == WOLFSPDM_SUCCESS) { - rc = wolfSPDM_TranscriptHash(ctx, th1Hash); - } - if (rc == WOLFSPDM_SUCCESS) { - XMEMCPY(ctx->th1, th1Hash, WOLFSPDM_HASH_SIZE); - rc = wolfSPDM_DeriveHandshakeKeysPsk(ctx, th1Hash); - } - - /* Verify ResponderVerifyData = HMAC(rspFinishedKey, TH1) */ - if (rc == WOLFSPDM_SUCCESS) { - rc = wolfSPDM_ComputeVerifyData(ctx->rspFinishedKey, th1Hash, - expectedHmac); - } - if (rc == WOLFSPDM_SUCCESS) { - word32 i; - volatile int diff = 0; - wolfSPDM_DebugHex(ctx, "Expected HMAC", expectedHmac, - WOLFSPDM_HASH_SIZE); - wolfSPDM_DebugHex(ctx, "Received HMAC", rspVerifyData, - WOLFSPDM_HASH_SIZE); - for (i = 0; i < WOLFSPDM_HASH_SIZE; i++) { - diff |= expectedHmac[i] ^ rspVerifyData[i]; - } - if (diff != 0) { - wolfSPDM_DebugPrint(ctx, "PSK ResponderVerifyData MISMATCH\n"); - rc = WOLFSPDM_E_BAD_HMAC; - } - } - if (rc == WOLFSPDM_SUCCESS) { - wolfSPDM_DebugPrint(ctx, "PSK ResponderVerifyData VERIFIED OK\n"); - rc = wolfSPDM_TranscriptAdd(ctx, rspVerifyData, WOLFSPDM_HASH_SIZE); - } - if (rc == WOLFSPDM_SUCCESS) { - ctx->state = WOLFSPDM_STATE_KEY_EX; - } - - wc_ForceZero(expectedHmac, sizeof(expectedHmac)); - wc_ForceZero(th1Hash, sizeof(th1Hash)); - return rc; -} - -int wolfSPDM_BuildPskFinish(WOLFSPDM_CTX* ctx, byte* buf, word32* bufSz) -{ - byte th2Hash[WOLFSPDM_HASH_SIZE]; - byte verifyData[WOLFSPDM_HASH_SIZE]; - word32 offset = 0; - int rc; - - if (ctx == NULL || buf == NULL || bufSz == NULL) { - return WOLFSPDM_E_INVALID_ARG; - } - - /* PSK_FINISH = header(4) + VerifyData(48) = 52 bytes */ - if (*bufSz < 4 + WOLFSPDM_HASH_SIZE) { - return WOLFSPDM_E_BUFFER_SMALL; - } - - /* Header */ - buf[offset++] = ctx->spdmVersion; - buf[offset++] = SPDM_PSK_FINISH; - buf[offset++] = 0x00; /* Param1 */ - buf[offset++] = 0x00; /* Param2 */ - - /* Add PSK_FINISH header to transcript, compute TH2 */ - rc = wolfSPDM_TranscriptAdd(ctx, buf, offset); - if (rc == WOLFSPDM_SUCCESS) { - rc = wolfSPDM_TranscriptHash(ctx, th2Hash); - } - if (rc == WOLFSPDM_SUCCESS) { - XMEMCPY(ctx->th2, th2Hash, WOLFSPDM_HASH_SIZE); - } - - /* RequesterVerifyData = HMAC(reqFinishedKey, TH2) */ - if (rc == WOLFSPDM_SUCCESS) { - rc = wolfSPDM_ComputeVerifyData(ctx->reqFinishedKey, th2Hash, - verifyData); - } - if (rc == WOLFSPDM_SUCCESS) { - XMEMCPY(&buf[offset], verifyData, WOLFSPDM_HASH_SIZE); - offset += WOLFSPDM_HASH_SIZE; - rc = wolfSPDM_TranscriptAdd(ctx, verifyData, WOLFSPDM_HASH_SIZE); - } - if (rc == WOLFSPDM_SUCCESS) { - *bufSz = offset; - } - - wc_ForceZero(th2Hash, sizeof(th2Hash)); - wc_ForceZero(verifyData, sizeof(verifyData)); - return rc; -} - -int wolfSPDM_ParsePskFinishRsp(WOLFSPDM_CTX* ctx, const byte* buf, - word32 bufSz) -{ - SPDM_CHECK_PARSE_ARGS(ctx, buf, bufSz, 4); - - if (buf[1] == SPDM_PSK_FINISH_RSP) { - int addRc = wolfSPDM_TranscriptAdd(ctx, buf, 4); - if (addRc != WOLFSPDM_SUCCESS) { - return addRc; - } - ctx->state = WOLFSPDM_STATE_FINISH; - wolfSPDM_DebugPrint(ctx, "PSK_FINISH_RSP received\n"); - return WOLFSPDM_SUCCESS; - } - - if (buf[1] == SPDM_ERROR) { - wolfSPDM_DebugPrint(ctx, "PSK_FINISH error: 0x%02x\n", buf[2]); - return WOLFSPDM_E_PEER_ERROR; - } - - return WOLFSPDM_E_BAD_STATE; -} - -/* ----- PSK Key Derivation ----- */ - -int wolfSPDM_DeriveHandshakeKeysPsk(WOLFSPDM_CTX* ctx, const byte* th1Hash) -{ - byte salt[WOLFSPDM_HASH_SIZE]; - int rc; - - if (ctx == NULL || th1Hash == NULL) { - return WOLFSPDM_E_INVALID_ARG; - } - if (ctx->pskSz == 0) { - return WOLFSPDM_E_BAD_STATE; - } - - /* PSK mode: Salt_0 = 0xFF-filled (per TCG PSK specification). */ - XMEMSET(salt, 0xFF, sizeof(salt)); - - /* HandshakeSecret = HKDF-Extract(0xFF-salt, PSK) */ - rc = wc_HKDF_Extract(WC_SHA384, salt, sizeof(salt), - ctx->psk, ctx->pskSz, ctx->handshakeSecret); - if (rc != 0) { - wc_ForceZero(ctx->psk, sizeof(ctx->psk)); - ctx->pskSz = 0; - return WOLFSPDM_E_CRYPTO_FAIL; - } - - rc = wolfSPDM_DeriveFromHandshakeSecret(ctx, th1Hash); - - /* Zero PSK immediately after key derivation */ - wc_ForceZero(ctx->psk, sizeof(ctx->psk)); - ctx->pskSz = 0; - - return rc; -} - -/* ----- Shared PSK Connection Flow ----- */ - -/* GET_VERSION -> GET_CAPABILITIES -> NEGOTIATE_ALGORITHMS -> - * PSK_EXCHANGE -> PSK_FINISH -> app key derivation */ -int wolfSPDM_ConnectPsk(WOLFSPDM_CTX* ctx) -{ - int rc; - byte txBuf[128]; - byte rxBuf[WOLFSPDM_MAX_MSG_SIZE + WOLFSPDM_AEAD_OVERHEAD]; - byte finBuf[64]; - byte encBuf[WOLFSPDM_MAX_MSG_SIZE + WOLFSPDM_AEAD_OVERHEAD]; - byte decBuf[64]; - word32 txSz; - word32 rxSz; - word32 finSz; - word32 encSz; - word32 decSz; - - if (ctx == NULL) { - return WOLFSPDM_E_INVALID_ARG; - } - - if (!ctx->flags.initialized) { - return WOLFSPDM_E_BAD_STATE; - } - - if (ctx->pskSz == 0) { - wolfSPDM_DebugPrint(ctx, "PSK: No PSK set\n"); - return WOLFSPDM_E_BAD_STATE; - } - - if (ctx->ioCb == NULL) { - return WOLFSPDM_E_IO_FAIL; - } - - wolfSPDM_DebugPrint(ctx, "PSK: Starting SPDM connection\n"); - - ctx->state = WOLFSPDM_STATE_INIT; - wolfSPDM_TranscriptReset(ctx); - - /* Step 1: GET_VERSION */ - wolfSPDM_DebugPrint(ctx, "PSK Step 1: GET_VERSION\n"); - rc = wolfSPDM_GetVersion(ctx); - - /* Steps 2-3: GET_CAPABILITIES + NEGOTIATE_ALGORITHMS - * Not mandatory for PSK mode per TCG PC Client PSK spec. - * NS350 supports direct GET_VERSION -> PSK_EXCHANGE. */ - - /* Step 2: PSK_EXCHANGE / PSK_EXCHANGE_RSP */ - if (rc == WOLFSPDM_SUCCESS) { - txSz = sizeof(txBuf); - rxSz = sizeof(rxBuf); - - wolfSPDM_DebugPrint(ctx, "PSK Step 4: PSK_EXCHANGE\n"); - rc = wolfSPDM_BuildPskExchange(ctx, txBuf, &txSz); - } - if (rc == WOLFSPDM_SUCCESS) { - rc = wolfSPDM_TranscriptAdd(ctx, txBuf, txSz); - } - if (rc == WOLFSPDM_SUCCESS) { - rc = wolfSPDM_SendReceive(ctx, txBuf, txSz, rxBuf, &rxSz); - } - if (rc == WOLFSPDM_SUCCESS) { - rc = wolfSPDM_ParsePskExchangeRsp(ctx, rxBuf, rxSz); - } - - /* Step 5: PSK_FINISH / PSK_FINISH_RSP (encrypted) */ - if (rc == WOLFSPDM_SUCCESS) { - finSz = sizeof(finBuf); - encSz = sizeof(encBuf); - rxSz = sizeof(rxBuf); - decSz = sizeof(decBuf); - - wolfSPDM_DebugPrint(ctx, "PSK Step 5: PSK_FINISH\n"); - rc = wolfSPDM_BuildPskFinish(ctx, finBuf, &finSz); - } - if (rc == WOLFSPDM_SUCCESS) { - rc = wolfSPDM_EncryptInternal(ctx, finBuf, finSz, encBuf, &encSz); - } - if (rc == WOLFSPDM_SUCCESS) { - rc = wolfSPDM_SendReceive(ctx, encBuf, encSz, rxBuf, &rxSz); - } - if (rc == WOLFSPDM_SUCCESS) { - rc = wolfSPDM_DecryptInternal(ctx, rxBuf, rxSz, decBuf, &decSz); - } - if (rc == WOLFSPDM_SUCCESS) { - rc = wolfSPDM_ParsePskFinishRsp(ctx, decBuf, decSz); - } - - /* Derive application data keys */ - if (rc == WOLFSPDM_SUCCESS) { - rc = wolfSPDM_DeriveAppDataKeys(ctx); - } - - if (rc == WOLFSPDM_SUCCESS) { - ctx->state = WOLFSPDM_STATE_CONNECTED; - wolfSPDM_DebugPrint(ctx, "PSK: SPDM Session Established! " - "SessionID=0x%08x\n", ctx->sessionId); - } - else { - ctx->state = WOLFSPDM_STATE_ERROR; - } - - /* Always zero sensitive stack buffers */ - wc_ForceZero(txBuf, sizeof(txBuf)); - wc_ForceZero(rxBuf, sizeof(rxBuf)); - wc_ForceZero(finBuf, sizeof(finBuf)); - wc_ForceZero(encBuf, sizeof(encBuf)); - wc_ForceZero(decBuf, sizeof(decBuf)); - - return rc; -} - -#endif /* WOLFTPM_SPDM_PSK */ - -#endif /* WOLFTPM_SPDM */ diff --git a/src/spdm/spdm_responder.c b/src/spdm/spdm_responder.c deleted file mode 100644 index 22eb40684..000000000 --- a/src/spdm/spdm_responder.c +++ /dev/null @@ -1,1288 +0,0 @@ -/* spdm_responder.c - * - * Copyright (C) 2006-2026 wolfSSL Inc. - * - * This file is part of wolfTPM. - * - * wolfTPM is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3 of the License, or - * (at your option) any later version. - * - * wolfTPM is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA - */ - -#ifdef HAVE_CONFIG_H - #include -#endif - -#ifdef WOLFTPM_SPDM_RESPONDER - -#include "spdm_internal.h" -#include -/* spdm_tcg.h is included unconditionally - the transport framing - * constants (TAG_CLEAR/SECURED, HEADER_SIZE) are needed by the - * responder's frame-discrimination check even in PSK-only builds. */ -#include - -struct WOLFSPDM_RESP_CTX { - WOLFSPDM_CTX ctx; - - struct { - unsigned int useTcg : 1; - unsigned int usePsk : 1; - unsigned int hasIdKey : 1; - unsigned int initialized : 1; - unsigned int spdmOnlyLock : 1; /* SPDMONLY lock: plaintext TPM - * rejected with TPM_RC_DISABLED */ - unsigned int pskProvisioned : 1; /* PSK_SET / PSK_CLR vendor state */ - unsigned int clearAuthSet : 1; /* a ClearAuth digest is stored */ - unsigned int sessionAsym : 1; /* session came from KEY_EXCHANGE */ - unsigned int pendingAsym : 1; /* KEY_EX reached via KEY_EXCHANGE */ - } flags; - - /* SHA-384(ClearAuth) stored on PSK_SET, verified on PSK_CLR. */ - byte clearAuthDigest[WOLFSPDM_HASH_SIZE]; - - byte idPrivKey[WOLFSPDM_ECC_KEY_SIZE]; - word32 idPrivKeyLen; - byte idPubKey[WOLFSPDM_ECC_POINT_SIZE]; - word32 idPubKeyLen; - - /* Persistent PSK store. wolfSPDM_DeriveHandshakeKeysPsk wipes - * ctx->psk after each derivation; we reload from here on every - * PSK_EXCHANGE so the responder can serve multiple sessions. */ - byte pskStore[WOLFSPDM_PSK_MAX_SIZE]; - word32 pskStoreSz; - byte pskHintStore[WOLFSPDM_PSK_HINT_MAX]; - word32 pskHintStoreSz; - - WOLFSPDM_RESP_TPM_CB tpmCb; - void* tpmCbUserCtx; - - /* Per-context working buffers. Previously file-scope `static` - - * moved here so each ctx is independently reentrant. */ - byte secureInPlain[WOLFSPDM_MAX_TPM_MSG_SIZE]; - byte secureOutPlain[WOLFSPDM_MAX_TPM_MSG_SIZE]; - byte vdInPayload[WOLFSPDM_MAX_TPM_MSG_SIZE]; - byte vdOutPayload[WOLFSPDM_MAX_TPM_MSG_SIZE]; -}; - -/* Compile-time guarantee that the public static-size macro is large - * enough for the actual struct. If this fires, raise the +1024 slack - * in WOLFSPDM_RESP_CTX_STATIC_SIZE in spdm_responder.h. */ -typedef char wolfSPDM_resp_ctx_size_check_[ - (sizeof(struct WOLFSPDM_RESP_CTX) <= WOLFSPDM_RESP_CTX_STATIC_SIZE) - ? 1 : -1]; - -int wolfSPDM_RespInit(WOLFSPDM_RESP_CTX* ctx) -{ - int rc; - - if (ctx == NULL) { - return WOLFSPDM_E_INVALID_ARG; - } - - XMEMSET(ctx, 0, sizeof(*ctx)); - - rc = wolfSPDM_Init(&ctx->ctx); - if (rc == WOLFSPDM_SUCCESS) { - ctx->flags.initialized = 1; - } - - return rc; -} - -void wolfSPDM_RespFree(WOLFSPDM_RESP_CTX* ctx) -{ - if (ctx == NULL) { - return; - } - wc_ForceZero(ctx->idPrivKey, sizeof(ctx->idPrivKey)); - wc_ForceZero(ctx->pskStore, sizeof(ctx->pskStore)); - wc_ForceZero(ctx->clearAuthDigest, sizeof(ctx->clearAuthDigest)); - wolfSPDM_Free(&ctx->ctx); - XMEMSET(ctx, 0, sizeof(*ctx)); -} - -int wolfSPDM_RespGetCtxSize(void) -{ - return (int)sizeof(struct WOLFSPDM_RESP_CTX); -} - -int wolfSPDM_RespSetMode(WOLFSPDM_RESP_CTX* ctx, int useTcg, int usePsk) -{ - if (ctx == NULL || !ctx->flags.initialized) { - return WOLFSPDM_E_INVALID_ARG; - } - if (!useTcg && !usePsk) { - return WOLFSPDM_E_INVALID_ARG; - } -#ifndef WOLFTPM_SPDM_TCG - if (useTcg) { - return WOLFSPDM_E_NOT_AVAILABLE; - } -#endif -#ifndef WOLFTPM_SPDM_PSK - if (usePsk) { - return WOLFSPDM_E_NOT_AVAILABLE; - } -#endif - ctx->flags.useTcg = (useTcg != 0); - ctx->flags.usePsk = (usePsk != 0); - /* Pick a mode so encrypt/decrypt use the 14-byte TCG AAD format. */ - ctx->ctx.mode = usePsk ? WOLFSPDM_MODE_NATIONS_PSK : WOLFSPDM_MODE_NUVOTON; - return WOLFSPDM_SUCCESS; -} - -int wolfSPDM_RespSetPSK(WOLFSPDM_RESP_CTX* ctx, - const byte* psk, word32 pskSz, - const byte* hint, word32 hintSz) -{ -#ifndef WOLFTPM_SPDM_PSK - (void)ctx; - (void)psk; - (void)pskSz; - (void)hint; - (void)hintSz; - return WOLFSPDM_E_NOT_AVAILABLE; -#else - int rc; - if (ctx == NULL || !ctx->flags.initialized) { - return WOLFSPDM_E_INVALID_ARG; - } - if (psk == NULL || pskSz == 0 || pskSz > sizeof(ctx->pskStore)) { - return WOLFSPDM_E_INVALID_ARG; - } - /* Commit the inner context first so a rejected PSK leaves no partially - * provisioned responder state */ - rc = wolfSPDM_SetPSK(&ctx->ctx, psk, pskSz, hint, hintSz); - if (rc != WOLFSPDM_SUCCESS) { - return rc; - } - XMEMCPY(ctx->pskStore, psk, pskSz); - ctx->pskStoreSz = pskSz; - if (hint != NULL && hintSz > 0 && hintSz <= sizeof(ctx->pskHintStore)) { - XMEMCPY(ctx->pskHintStore, hint, hintSz); - ctx->pskHintStoreSz = hintSz; - } - else { - ctx->pskHintStoreSz = 0; - } - ctx->flags.pskProvisioned = 1; - return WOLFSPDM_SUCCESS; -#endif -} - -int wolfSPDM_RespSetIdentityKey(WOLFSPDM_RESP_CTX* ctx, - const byte* privKey, word32 privSz, - const byte* pubKey, word32 pubSz) -{ - if (ctx == NULL || !ctx->flags.initialized || - privKey == NULL || pubKey == NULL) { - return WOLFSPDM_E_INVALID_ARG; - } - if (privSz != WOLFSPDM_ECC_KEY_SIZE || - pubSz != WOLFSPDM_ECC_POINT_SIZE) { - return WOLFSPDM_E_INVALID_ARG; - } - /* Rotating the key mid-session would attribute that session to a key it - * never negotiated with. */ - if (ctx->ctx.state != WOLFSPDM_STATE_INIT) { - return WOLFSPDM_E_BAD_STATE; - } - XMEMCPY(ctx->idPrivKey, privKey, privSz); - ctx->idPrivKeyLen = privSz; - XMEMCPY(ctx->idPubKey, pubKey, pubSz); - ctx->idPubKeyLen = pubSz; - ctx->flags.hasIdKey = 1; - return WOLFSPDM_SUCCESS; -} - -int wolfSPDM_RespSetTpmCallback(WOLFSPDM_RESP_CTX* ctx, - WOLFSPDM_RESP_TPM_CB cb, void* userCtx) -{ - if (ctx == NULL || !ctx->flags.initialized) { - return WOLFSPDM_E_INVALID_ARG; - } - ctx->tpmCb = cb; - ctx->tpmCbUserCtx = userCtx; - return WOLFSPDM_SUCCESS; -} - -void wolfSPDM_RespSetDebug(WOLFSPDM_RESP_CTX* ctx, int enable) -{ - if (ctx == NULL) { - return; - } - wolfSPDM_SetDebug(&ctx->ctx, enable); -} - -int wolfSPDM_RespIsLocked(const WOLFSPDM_RESP_CTX* ctx) -{ - return (ctx != NULL && ctx->flags.spdmOnlyLock) ? 1 : 0; -} - -int wolfSPDM_RespIsSessionActive(const WOLFSPDM_RESP_CTX* ctx) -{ - if (ctx == NULL) { - return 0; - } - return (ctx->ctx.state == WOLFSPDM_STATE_CONNECTED && - ctx->ctx.sessionId != 0) ? 1 : 0; -} - -word32 wolfSPDM_RespGetIdentityKey(const WOLFSPDM_RESP_CTX* ctx, - const byte** idPub) -{ - if (ctx == NULL || idPub == NULL || !ctx->flags.hasIdKey || - !ctx->flags.sessionAsym) { - return 0; - } - *idPub = ctx->idPubKey; - return ctx->idPubKeyLen; -} - -void wolfSPDM_RespReset(WOLFSPDM_RESP_CTX* ctx) -{ - if (ctx == NULL) { - return; - } - /* Identity key, PSK, mode flags survive; only session-scoped material - * is wiped. */ - wc_ForceZero(ctx->ctx.reqDataKey, sizeof(ctx->ctx.reqDataKey)); - wc_ForceZero(ctx->ctx.rspDataKey, sizeof(ctx->ctx.rspDataKey)); - wc_ForceZero(ctx->ctx.reqDataIv, sizeof(ctx->ctx.reqDataIv)); - wc_ForceZero(ctx->ctx.rspDataIv, sizeof(ctx->ctx.rspDataIv)); - wc_ForceZero(ctx->ctx.handshakeSecret, - sizeof(ctx->ctx.handshakeSecret)); - wc_ForceZero(ctx->ctx.reqHsSecret, sizeof(ctx->ctx.reqHsSecret)); - wc_ForceZero(ctx->ctx.rspHsSecret, sizeof(ctx->ctx.rspHsSecret)); - wc_ForceZero(ctx->ctx.reqFinishedKey, - sizeof(ctx->ctx.reqFinishedKey)); - wc_ForceZero(ctx->ctx.rspFinishedKey, - sizeof(ctx->ctx.rspFinishedKey)); - wc_ForceZero(ctx->ctx.sharedSecret, sizeof(ctx->ctx.sharedSecret)); - ctx->ctx.sharedSecretSz = 0; - ctx->ctx.reqSeqNum = 0; - ctx->ctx.rspSeqNum = 0; - ctx->ctx.sessionId = 0; - ctx->ctx.state = WOLFSPDM_STATE_INIT; - ctx->flags.sessionAsym = 0; - ctx->flags.pendingAsym = 0; -} - -#ifdef WOLFTPM_SPDM_TCG - -#define WOLFSPDM_GET_CAPABILITIES 0xE1 -#define WOLFSPDM_CAPABILITIES 0x61 -#define WOLFSPDM_NEGOTIATE_ALGORITHMS 0xE3 -#define WOLFSPDM_ALGORITHMS 0x63 - -static int RespHandleVendorDefined(WOLFSPDM_RESP_CTX* rctx, - const byte* in, word32 inSz, byte* out, word32* outSz, int fromSecured, - char* vdCodeOut); -static int RespBuildKeyExchangeRsp(WOLFSPDM_RESP_CTX* rctx, - const byte* in, word32 inSz, byte* out, word32* outSz); -static int RespHandleFinish(WOLFSPDM_RESP_CTX* rctx, - const byte* in, word32 inSz, byte* out, word32* outSz); - -static int RespBuildErrorClear(WOLFSPDM_CTX* ctx, byte errCode, - byte errData, byte* out, word32* outSz) -{ - if (*outSz < 4) { - return WOLFSPDM_E_BUFFER_SMALL; - } - out[0] = (ctx->spdmVersion != 0) ? ctx->spdmVersion : SPDM_VERSION_10; - out[1] = SPDM_ERROR; - out[2] = errCode; - out[3] = errData; - *outSz = 4; - return WOLFSPDM_SUCCESS; -} - -/* Always paired: swap -> call existing req-side helper -> swap-back. */ -static void RespSwapDataDir(WOLFSPDM_CTX* ctx) -{ - byte tmpKey[WOLFSPDM_AEAD_KEY_SIZE]; - byte tmpIv[WOLFSPDM_AEAD_IV_SIZE]; - word64 tmpSeq; - - XMEMCPY(tmpKey, ctx->reqDataKey, sizeof(tmpKey)); - XMEMCPY(ctx->reqDataKey, ctx->rspDataKey, sizeof(tmpKey)); - XMEMCPY(ctx->rspDataKey, tmpKey, sizeof(tmpKey)); - - XMEMCPY(tmpIv, ctx->reqDataIv, sizeof(tmpIv)); - XMEMCPY(ctx->reqDataIv, ctx->rspDataIv, sizeof(tmpIv)); - XMEMCPY(ctx->rspDataIv, tmpIv, sizeof(tmpIv)); - - tmpSeq = ctx->reqSeqNum; - ctx->reqSeqNum = ctx->rspSeqNum; - ctx->rspSeqNum = tmpSeq; - - wc_ForceZero(tmpKey, sizeof(tmpKey)); - wc_ForceZero(tmpIv, sizeof(tmpIv)); -} - -static int RespEncrypt(WOLFSPDM_CTX* ctx, - const byte* plain, word32 plainSz, byte* enc, word32* encSz) -{ - int rc; - RespSwapDataDir(ctx); - rc = wolfSPDM_EncryptInternal(ctx, plain, plainSz, enc, encSz); - RespSwapDataDir(ctx); - return rc; -} - -static int RespDecrypt(WOLFSPDM_CTX* ctx, - const byte* enc, word32 encSz, byte* plain, word32* plainSz) -{ - int rc; - RespSwapDataDir(ctx); - rc = wolfSPDM_DecryptInternal(ctx, enc, encSz, plain, plainSz); - RespSwapDataDir(ctx); - return rc; -} - -/* The responder FINISH path has no 1.4 OpaqueData handling, so it tops out - * at 1.3 even when the requester build allows 1.4. */ -#if WOLFSPDM_MAX_SPDM_VERSION > SPDM_VERSION_13 -#define WOLFSPDM_RESP_MAX_VERSION SPDM_VERSION_13 -#else -#define WOLFSPDM_RESP_MAX_VERSION WOLFSPDM_MAX_SPDM_VERSION -#endif -#if WOLFSPDM_MIN_SPDM_VERSION > WOLFSPDM_RESP_MAX_VERSION -#error "SPDM responder version range is empty" -#endif -#define WOLFSPDM_RESP_VERSION_COUNT \ - (WOLFSPDM_RESP_MAX_VERSION - WOLFSPDM_MIN_SPDM_VERSION + 1) - -static int RespBuildVersion(WOLFSPDM_CTX* ctx, - const byte* req, word32 reqSz, - byte* out, word32* outSz) -{ - word32 off; - byte ver; - - (void)req; - (void)reqSz; - if (*outSz < 6 + 2 * WOLFSPDM_RESP_VERSION_COUNT) { - return WOLFSPDM_E_BUFFER_SMALL; - } - off = 0; - out[off++] = SPDM_VERSION_10; - out[off++] = SPDM_VERSION; - out[off++] = 0x00; - out[off++] = 0x00; - /* VersionNumberEntryCount (LE) at offset 4. */ - out[off++] = WOLFSPDM_RESP_VERSION_COUNT; - out[off++] = 0x00; - /* Entries: 2 bytes each, byte+1 holds the version (Major<<4 | Minor). */ - for (ver = WOLFSPDM_MIN_SPDM_VERSION; ver <= WOLFSPDM_RESP_MAX_VERSION; - ver++) { - out[off++] = 0x00; - out[off++] = ver; - } - *outSz = off; - /* The requester picks from the advertised set; its next request - * carries the selection (see RespSelectVersion). */ - ctx->spdmVersion = 0; - ctx->state = WOLFSPDM_STATE_VERSION; - return WOLFSPDM_SUCCESS; -} - -/* Adopt the version the requester selects on its first request after - * VERSION and pin it for the rest of the connection. Before any VERSION - * exchange only pre-negotiation vendor commands (GET_STS_, PSK_SET_) may - * pass, and they select nothing. */ -static int RespSelectVersion(WOLFSPDM_CTX* ctx, byte reqVer, int isVendor) -{ - if (ctx->spdmVersion != 0) { - return (reqVer == ctx->spdmVersion) ? WOLFSPDM_SUCCESS : - WOLFSPDM_E_VERSION_MISMATCH; - } - if (ctx->state != WOLFSPDM_STATE_VERSION) { - return isVendor ? WOLFSPDM_SUCCESS : WOLFSPDM_E_BAD_STATE; - } - if (reqVer < WOLFSPDM_MIN_SPDM_VERSION || - reqVer > WOLFSPDM_RESP_MAX_VERSION) { - return WOLFSPDM_E_VERSION_MISMATCH; - } - ctx->spdmVersion = reqVer; - return WOLFSPDM_SUCCESS; -} - -/* Flags: ENCRYPT/MAC/KEY_EX_CAP always; PSK_CAP iff pskEnabled. */ -static int RespBuildCapabilities(WOLFSPDM_CTX* ctx, int pskEnabled, - const byte* req, word32 reqSz, - byte* out, word32* outSz) -{ - word32 off; - word32 flags; - - (void)req; - (void)reqSz; - if (*outSz < 20) { - return WOLFSPDM_E_BUFFER_SMALL; - } - flags = 0x000193C0UL; - if (pskEnabled) { - flags |= 0x00000400UL; - } - off = 0; - out[off++] = ctx->spdmVersion; - out[off++] = WOLFSPDM_CAPABILITIES; - out[off++] = 0x00; - out[off++] = 0x00; - out[off++] = 0x00; - out[off++] = 0x1F; - out[off++] = 0x00; - out[off++] = 0x00; - SPDM_Set32LE(out + off, flags); - off += 4; - out[off++] = 0xC0; out[off++] = 0x07; out[off++] = 0x00; out[off++] = 0x00; - out[off++] = 0xC0; out[off++] = 0x07; out[off++] = 0x00; out[off++] = 0x00; - *outSz = off; - return WOLFSPDM_SUCCESS; -} - -/* Algorithm Set B (P-384/SHA-384/AES-256-GCM) is the only set we support. */ -static int RespBuildAlgorithms(WOLFSPDM_CTX* ctx, - const byte* req, word32 reqSz, - byte* out, word32* outSz) -{ - word32 off; - - (void)req; - (void)reqSz; - if (*outSz < 52) { - return WOLFSPDM_E_BUFFER_SMALL; - } - off = 0; - out[off++] = ctx->spdmVersion; - out[off++] = WOLFSPDM_ALGORITHMS; - out[off++] = 0x04; - out[off++] = 0x00; - out[off++] = 0x34; out[off++] = 0x00; - out[off++] = 0x00; out[off++] = 0x02; - XMEMSET(out + off, 0, 4); off += 4; - out[off++] = 0x80; out[off++] = 0x00; out[off++] = 0x00; out[off++] = 0x00; - out[off++] = 0x02; out[off++] = 0x00; out[off++] = 0x00; out[off++] = 0x00; - XMEMSET(out + off, 0, 12); off += 12; - out[off++] = 0x00; out[off++] = 0x00; out[off++] = 0x00; out[off++] = 0x00; - out[off++] = 0x02; out[off++] = 0x20; out[off++] = 0x10; out[off++] = 0x00; - out[off++] = 0x03; out[off++] = 0x20; out[off++] = 0x02; out[off++] = 0x00; - out[off++] = 0x04; out[off++] = 0x20; out[off++] = 0x80; out[off++] = 0x00; - out[off++] = 0x05; out[off++] = 0x20; out[off++] = 0x01; out[off++] = 0x00; - *outSz = off; - return WOLFSPDM_SUCCESS; -} - -#ifdef WOLFTPM_SPDM_PSK -/* Transcript add splits across key derivation, matching the requester. */ -static int RespBuildPskExchangeRsp(WOLFSPDM_RESP_CTX* rctx, - const byte* in, word32 inSz, - byte* out, word32* outSz) -{ - WOLFSPDM_CTX* ctx = &rctx->ctx; - word16 reqContextLen; - word16 reqHintLen; - word16 reqOpaqueLen; - word32 off; - word32 partialLen; - byte th1Hash[WOLFSPDM_HASH_SIZE]; - byte verifyData[WOLFSPDM_HASH_SIZE]; - int rc; - - if (inSz < 12 || rctx->pskStoreSz == 0) { - return WOLFSPDM_E_BAD_STATE; - } - if (*outSz < 12u + 32u + WOLFSPDM_HASH_SIZE) { - return WOLFSPDM_E_BUFFER_SMALL; - } - /* Reload PSK from the persistent store - the requester-side helper - * zeroes ctx->psk after derivation. */ - XMEMCPY(ctx->psk, rctx->pskStore, rctx->pskStoreSz); - ctx->pskSz = rctx->pskStoreSz; - if (rctx->pskHintStoreSz > 0) { - XMEMCPY(ctx->pskHint, rctx->pskHintStore, rctx->pskHintStoreSz); - ctx->pskHintSz = rctx->pskHintStoreSz; - } - - ctx->reqSessionId = SPDM_Get16LE(&in[4]); - reqHintLen = SPDM_Get16LE(&in[6]); - reqContextLen = SPDM_Get16LE(&in[8]); - reqOpaqueLen = SPDM_Get16LE(&in[10]); - /* Every declared variable-length field must fit within the request */ - if ((word32)12 + reqHintLen + reqContextLen + reqOpaqueLen > inSz) { - return WOLFSPDM_E_FRAMING; - } - - ctx->rspSessionId = 0xFFFE; - ctx->sessionId = (word32)ctx->reqSessionId | - ((word32)ctx->rspSessionId << 16); - - off = 0; - out[off++] = ctx->spdmVersion; - out[off++] = SPDM_PSK_EXCHANGE_RSP; - out[off++] = 0x00; - out[off++] = 0x00; - SPDM_Set16LE(&out[off], ctx->rspSessionId); off += 2; - out[off++] = 0x00; - out[off++] = 0x00; - SPDM_Set16LE(&out[off], 32); off += 2; - SPDM_Set16LE(&out[off], 0); off += 2; - rc = wolfSPDM_GetRandom(ctx, &out[off], 32); - if (rc != WOLFSPDM_SUCCESS) { - return rc; - } - off += 32; - partialLen = off; - - rc = wolfSPDM_TranscriptAdd(ctx, out, partialLen); - if (rc == WOLFSPDM_SUCCESS) { - rc = wolfSPDM_TranscriptHash(ctx, th1Hash); - } - if (rc == WOLFSPDM_SUCCESS) { - XMEMCPY(ctx->th1, th1Hash, WOLFSPDM_HASH_SIZE); - rc = wolfSPDM_DeriveHandshakeKeysPsk(ctx, th1Hash); - } - if (rc == WOLFSPDM_SUCCESS) { - rc = wolfSPDM_ComputeVerifyData(ctx->rspFinishedKey, th1Hash, - verifyData); - } - if (rc == WOLFSPDM_SUCCESS) { - XMEMCPY(&out[off], verifyData, WOLFSPDM_HASH_SIZE); - off += WOLFSPDM_HASH_SIZE; - rc = wolfSPDM_TranscriptAdd(ctx, verifyData, WOLFSPDM_HASH_SIZE); - } - if (rc == WOLFSPDM_SUCCESS) { - *outSz = off; - ctx->state = WOLFSPDM_STATE_KEY_EX; - rctx->flags.pendingAsym = 0; - } - - wc_ForceZero(verifyData, sizeof(verifyData)); - wc_ForceZero(th1Hash, sizeof(th1Hash)); - return rc; -} -#endif /* WOLFTPM_SPDM_PSK */ - -static int RespDispatchClear(WOLFSPDM_RESP_CTX* rctx, - const byte* in, word32 inSz, - byte* out, word32* outSz) -{ - WOLFSPDM_CTX* ctx = &rctx->ctx; - byte code; - int rc; - int handlerManagesTranscript = 0; - char vdCode[WOLFSPDM_VDCODE_LEN + 1]; - - if (inSz < 2) { - return WOLFSPDM_E_FRAMING; - } - code = in[1]; - XMEMSET(vdCode, 0, sizeof(vdCode)); - - if (code == SPDM_GET_VERSION) { - wolfSPDM_TranscriptReset(ctx); - wolfSPDM_RespReset(rctx); - } - else { - rc = RespSelectVersion(ctx, in[0], - code == SPDM_VENDOR_DEFINED_REQUEST); - if (rc == WOLFSPDM_E_BAD_STATE) { - return RespBuildErrorClear(ctx, - SPDM_ERROR_UNEXPECTED_REQUEST, 0, out, outSz); - } - if (rc != WOLFSPDM_SUCCESS) { - return RespBuildErrorClear(ctx, - SPDM_ERROR_MAJOR_VERSION_MISMATCH, 0, out, outSz); - } - } - - /* VENDOR_DEFINED bytes don't go into the SPDM transcript - the - * requester's wolfSPDM_TCG_VendorCmdClear doesn't add them, so the - * responder mustn't either. GET_PUBK contributes via Ct = SHA-384 - * of its response payload, added separately below. */ - if (code != SPDM_VENDOR_DEFINED_REQUEST) { - rc = wolfSPDM_TranscriptAdd(ctx, in, inSz); - if (rc != WOLFSPDM_SUCCESS) { - return rc; - } - } - - switch (code) { - case SPDM_GET_VERSION: - rc = RespBuildVersion(ctx, in, inSz, out, outSz); - break; - case WOLFSPDM_GET_CAPABILITIES: - rc = RespBuildCapabilities(ctx, rctx->flags.usePsk, - in, inSz, out, outSz); - break; - case WOLFSPDM_NEGOTIATE_ALGORITHMS: - rc = RespBuildAlgorithms(ctx, in, inSz, out, outSz); - break; -#ifdef WOLFTPM_SPDM_PSK - case SPDM_PSK_EXCHANGE: - rc = RespBuildPskExchangeRsp(rctx, in, inSz, out, outSz); - handlerManagesTranscript = 1; - break; -#endif - case SPDM_KEY_EXCHANGE: - rc = RespBuildKeyExchangeRsp(rctx, in, inSz, out, outSz); - handlerManagesTranscript = 1; - break; - case SPDM_VENDOR_DEFINED_REQUEST: - rc = RespHandleVendorDefined(rctx, in, inSz, out, outSz, 0, - vdCode); - handlerManagesTranscript = 1; - /* For GET_PUBK specifically, mirror what the requester does: - * add Ct = SHA-384(rspPubKey) to the transcript. Keyed on the - * parsed VdCode, whose wire offset varies with vendorIdLen. */ - if (rc == WOLFSPDM_SUCCESS && - XMEMCMP(vdCode, WOLFSPDM_VDCODE_GET_PUBK, - WOLFSPDM_VDCODE_LEN) == 0) { - byte ct[WOLFSPDM_HASH_SIZE]; - int hrc = wolfSPDM_Sha384Hash(ct, - rctx->idPubKey, rctx->idPubKeyLen, NULL, 0, NULL, 0); - if (hrc == WOLFSPDM_SUCCESS) { - hrc = wolfSPDM_TranscriptAdd(ctx, ct, WOLFSPDM_HASH_SIZE); - } - wc_ForceZero(ct, sizeof(ct)); - if (hrc != WOLFSPDM_SUCCESS) { - rc = hrc; - } - } - break; - default: - return RespBuildErrorClear(ctx, - SPDM_ERROR_UNSUPPORTED_REQUEST, code, out, outSz); - } - - if (rc == WOLFSPDM_SUCCESS && !handlerManagesTranscript) { - rc = wolfSPDM_TranscriptAdd(ctx, out, *outSz); - } - return rc; -} - -#define WOLFSPDM_VENDOR_DEFINED_RSP 0x7E - -/* KEY_EXCHANGE (clear) -> KEY_EXCHANGE_RSP (clear). Mirror of - * wolfSPDM_BuildKeyExchange / wolfSPDM_ParseKeyExchangeRsp flipped to the - * responder side: receive requester pubkey, generate own ephemeral key, - * compute shared secret, sign TH1 with the identity key, derive handshake - * keys, emit ResponderVerifyData. */ -static int RespBuildKeyExchangeRsp(WOLFSPDM_RESP_CTX* rctx, - const byte* in, word32 inSz, - byte* out, word32* outSz) -{ - WOLFSPDM_CTX* ctx = &rctx->ctx; - byte peerPubKeyX[WOLFSPDM_ECC_KEY_SIZE]; - byte peerPubKeyY[WOLFSPDM_ECC_KEY_SIZE]; - byte myPubX[WOLFSPDM_ECC_KEY_SIZE]; - byte myPubY[WOLFSPDM_ECC_KEY_SIZE]; - word32 myPubXSz = sizeof(myPubX); - word32 myPubYSz = sizeof(myPubY); - byte th1[WOLFSPDM_HASH_SIZE]; - byte signMsgHash[WOLFSPDM_HASH_SIZE]; - byte verifyData[WOLFSPDM_HASH_SIZE]; - byte savedReqPriv[WOLFSPDM_ECC_KEY_SIZE]; - byte savedReqPub[WOLFSPDM_ECC_POINT_SIZE]; - word32 savedReqPrivLen; - byte savedHasReqKeyPair; - word32 sigSz = WOLFSPDM_ECC_SIG_SIZE; - word32 off; - word32 partialLen; - int rc; - - if (inSz < 136 || !rctx->flags.hasIdKey) { - return WOLFSPDM_E_BAD_STATE; - } - if (*outSz < 138u + WOLFSPDM_ECC_SIG_SIZE + WOLFSPDM_HASH_SIZE) { - return WOLFSPDM_E_BUFFER_SMALL; - } - - ctx->reqSessionId = SPDM_Get16LE(&in[4]); - XMEMCPY(peerPubKeyX, &in[40], WOLFSPDM_ECC_KEY_SIZE); - XMEMCPY(peerPubKeyY, &in[88], WOLFSPDM_ECC_KEY_SIZE); - - ctx->rspSessionId = 0xFFFE; - ctx->sessionId = (word32)ctx->reqSessionId | - ((word32)ctx->rspSessionId << 16); - - off = 0; - out[off++] = ctx->spdmVersion; - out[off++] = SPDM_KEY_EXCHANGE_RSP; - out[off++] = 0x00; - out[off++] = 0x00; - SPDM_Set16LE(&out[off], ctx->rspSessionId); off += 2; - out[off++] = 0x00; /* MutAuthRequested */ - out[off++] = 0x00; /* SlotID */ - - rc = wolfSPDM_GetRandom(ctx, &out[off], WOLFSPDM_RANDOM_SIZE); - if (rc != WOLFSPDM_SUCCESS) { - return rc; - } - off += WOLFSPDM_RANDOM_SIZE; - - rc = wolfSPDM_GenerateEphemeralKey(ctx); - if (rc == WOLFSPDM_SUCCESS) { - rc = wolfSPDM_ExportEphemeralPubKey(ctx, - myPubX, &myPubXSz, myPubY, &myPubYSz); - } - if (rc != WOLFSPDM_SUCCESS) { - return rc; - } - XMEMCPY(&out[off], myPubX, WOLFSPDM_ECC_KEY_SIZE); off += WOLFSPDM_ECC_KEY_SIZE; - XMEMCPY(&out[off], myPubY, WOLFSPDM_ECC_KEY_SIZE); off += WOLFSPDM_ECC_KEY_SIZE; - SPDM_Set16LE(&out[off], 0); off += 2; /* OpaqueLength = 0 */ - - partialLen = off; - - rc = wolfSPDM_TranscriptAdd(ctx, out, partialLen); - if (rc == WOLFSPDM_SUCCESS) { - rc = wolfSPDM_TranscriptHash(ctx, th1); - } - if (rc == WOLFSPDM_SUCCESS) { - rc = wolfSPDM_BuildSignedHash(ctx->spdmVersion, - "responder-key_exchange_rsp signing", 34, th1, signMsgHash); - } - if (rc == WOLFSPDM_SUCCESS) { - /* wolfSPDM_SignHash signs with ctx->reqPrivKey/reqPubKey. Swap the - * identity key in temporarily; restore on exit. */ - XMEMCPY(savedReqPriv, ctx->reqPrivKey, WOLFSPDM_ECC_KEY_SIZE); - XMEMCPY(savedReqPub, ctx->reqPubKey, WOLFSPDM_ECC_POINT_SIZE); - savedReqPrivLen = ctx->reqPrivKeyLen; - savedHasReqKeyPair = ctx->flags.hasReqKeyPair; - XMEMCPY(ctx->reqPrivKey, rctx->idPrivKey, WOLFSPDM_ECC_KEY_SIZE); - XMEMCPY(ctx->reqPubKey, rctx->idPubKey, WOLFSPDM_ECC_POINT_SIZE); - ctx->reqPrivKeyLen = WOLFSPDM_ECC_KEY_SIZE; - ctx->flags.hasReqKeyPair = 1; - rc = wolfSPDM_SignHash(ctx, signMsgHash, WOLFSPDM_HASH_SIZE, - &out[off], &sigSz); - XMEMCPY(ctx->reqPrivKey, savedReqPriv, WOLFSPDM_ECC_KEY_SIZE); - XMEMCPY(ctx->reqPubKey, savedReqPub, WOLFSPDM_ECC_POINT_SIZE); - ctx->reqPrivKeyLen = savedReqPrivLen; - ctx->flags.hasReqKeyPair = savedHasReqKeyPair; - } - if (rc == WOLFSPDM_SUCCESS) { - rc = wolfSPDM_TranscriptAdd(ctx, &out[off], WOLFSPDM_ECC_SIG_SIZE); - off += WOLFSPDM_ECC_SIG_SIZE; - } - if (rc == WOLFSPDM_SUCCESS) { - rc = wolfSPDM_ComputeSharedSecret(ctx, peerPubKeyX, peerPubKeyY); - } - if (rc == WOLFSPDM_SUCCESS) { - rc = wolfSPDM_TranscriptHash(ctx, ctx->th1); - } - if (rc == WOLFSPDM_SUCCESS) { - rc = wolfSPDM_DeriveHandshakeKeys(ctx, ctx->th1); - } - if (rc == WOLFSPDM_SUCCESS) { - rc = wolfSPDM_ComputeVerifyData(ctx->rspFinishedKey, ctx->th1, - verifyData); - } - if (rc == WOLFSPDM_SUCCESS) { - XMEMCPY(&out[off], verifyData, WOLFSPDM_HASH_SIZE); - off += WOLFSPDM_HASH_SIZE; - rc = wolfSPDM_TranscriptAdd(ctx, verifyData, WOLFSPDM_HASH_SIZE); - } - if (rc == WOLFSPDM_SUCCESS) { - *outSz = off; - ctx->state = WOLFSPDM_STATE_KEY_EX; - rctx->flags.pendingAsym = 1; - } - - wc_ForceZero(savedReqPriv, sizeof(savedReqPriv)); - wc_ForceZero(verifyData, sizeof(verifyData)); - wc_ForceZero(signMsgHash, sizeof(signMsgHash)); - wc_ForceZero(th1, sizeof(th1)); - return rc; -} - -/* FINISH (encrypted) -> FINISH_RSP (encrypted). Verifies the requester's - * HMAC over TH2 with reqFinishedKey, then emits a 4-byte FINISH_RSP. App - * keys derive after encryption (handled in the secured dispatcher). */ -static int RespHandleFinish(WOLFSPDM_RESP_CTX* rctx, - const byte* in, word32 inSz, byte* out, word32* outSz) -{ - WOLFSPDM_CTX* ctx = &rctx->ctx; - byte th2[WOLFSPDM_HASH_SIZE]; - byte expectedHmac[WOLFSPDM_HASH_SIZE]; - int rc; - word32 i; - volatile int diff = 0; - - if (inSz < 4u + WOLFSPDM_HASH_SIZE) { - return WOLFSPDM_E_FRAMING; - } - if (*outSz < 4) { - return WOLFSPDM_E_BUFFER_SMALL; - } - - rc = wolfSPDM_TranscriptAdd(ctx, in, 4); - if (rc == WOLFSPDM_SUCCESS) { - rc = wolfSPDM_TranscriptHash(ctx, th2); - } - if (rc == WOLFSPDM_SUCCESS) { - XMEMCPY(ctx->th2, th2, WOLFSPDM_HASH_SIZE); - rc = wolfSPDM_ComputeVerifyData(ctx->reqFinishedKey, th2, - expectedHmac); - } - if (rc == WOLFSPDM_SUCCESS) { - for (i = 0; i < WOLFSPDM_HASH_SIZE; i++) { - diff |= expectedHmac[i] ^ in[4 + i]; - } - if (diff != 0) { - rc = WOLFSPDM_E_BAD_HMAC; - } - } - if (rc == WOLFSPDM_SUCCESS) { - rc = wolfSPDM_TranscriptAdd(ctx, in + 4, WOLFSPDM_HASH_SIZE); - } - if (rc == WOLFSPDM_SUCCESS) { - out[0] = ctx->spdmVersion; - out[1] = SPDM_FINISH_RSP; - out[2] = 0x00; - out[3] = 0x00; - *outSz = 4; - rc = wolfSPDM_TranscriptAdd(ctx, out, 4); - } - if (rc == WOLFSPDM_SUCCESS) { - ctx->state = WOLFSPDM_STATE_CONNECTED; - rctx->flags.sessionAsym = 1; - } - - wc_ForceZero(expectedHmac, sizeof(expectedHmac)); - wc_ForceZero(th2, sizeof(th2)); - return rc; -} - -#ifdef WOLFTPM_SPDM_PSK -static int RespHandlePskFinish(WOLFSPDM_RESP_CTX* rctx, - const byte* in, word32 inSz, byte* out, word32* outSz) -{ - WOLFSPDM_CTX* ctx = &rctx->ctx; - byte th2Hash[WOLFSPDM_HASH_SIZE]; - byte expectedHmac[WOLFSPDM_HASH_SIZE]; - int rc; - word32 i; - volatile int diff = 0; - - if (inSz < 4u + WOLFSPDM_HASH_SIZE) { - return WOLFSPDM_E_FRAMING; - } - if (*outSz < 4) { - return WOLFSPDM_E_BUFFER_SMALL; - } - - rc = wolfSPDM_TranscriptAdd(ctx, in, 4); - if (rc == WOLFSPDM_SUCCESS) { - rc = wolfSPDM_TranscriptHash(ctx, th2Hash); - } - if (rc == WOLFSPDM_SUCCESS) { - XMEMCPY(ctx->th2, th2Hash, WOLFSPDM_HASH_SIZE); - rc = wolfSPDM_ComputeVerifyData(ctx->reqFinishedKey, th2Hash, - expectedHmac); - } - if (rc == WOLFSPDM_SUCCESS) { - for (i = 0; i < WOLFSPDM_HASH_SIZE; i++) { - diff |= expectedHmac[i] ^ in[4 + i]; - } - if (diff != 0) { - rc = WOLFSPDM_E_BAD_HMAC; - } - } - if (rc == WOLFSPDM_SUCCESS) { - rc = wolfSPDM_TranscriptAdd(ctx, in + 4, WOLFSPDM_HASH_SIZE); - } - if (rc == WOLFSPDM_SUCCESS) { - out[0] = ctx->spdmVersion; - out[1] = SPDM_PSK_FINISH_RSP; - out[2] = 0x00; - out[3] = 0x00; - *outSz = 4; - rc = wolfSPDM_TranscriptAdd(ctx, out, 4); - } - /* App-key derivation runs in the caller AFTER PSK_FINISH_RSP is - * encrypted with the still-current handshake keys (otherwise the - * requester decrypts with handshake keys but we wrote with app keys). */ - if (rc == WOLFSPDM_SUCCESS) { - ctx->state = WOLFSPDM_STATE_CONNECTED; - rctx->flags.sessionAsym = 0; - } - - wc_ForceZero(expectedHmac, sizeof(expectedHmac)); - wc_ForceZero(th2Hash, sizeof(th2Hash)); - return rc; -} -#endif /* WOLFTPM_SPDM_PSK */ - -static int RespBuildEndSessionAck(WOLFSPDM_CTX* ctx, - const byte* in, word32 inSz, byte* out, word32* outSz) -{ - (void)in; - (void)inSz; - if (*outSz < 4) { - return WOLFSPDM_E_BUFFER_SMALL; - } - out[0] = ctx->spdmVersion; - out[1] = SPDM_END_SESSION_ACK; - out[2] = 0x00; - out[3] = 0x00; - *outSz = 4; - return WOLFSPDM_SUCCESS; -} - -static int RespHandleVendorDefined(WOLFSPDM_RESP_CTX* rctx, - const byte* in, word32 inSz, byte* out, word32* outSz, int fromSecured, - char* vdCodeOut) -{ - WOLFSPDM_CTX* ctx = &rctx->ctx; - char vdCode[WOLFSPDM_VDCODE_LEN + 1]; - /* TPM2_CMD payloads carry large TPM commands (CreatePrimary RSA ~400 - * bytes), so buffers are sized to MAX_MSG_SIZE. Storage lives in the - * per-context struct so concurrent ctxs don't share working memory. */ - byte* payload = rctx->vdInPayload; - byte* respPayload = rctx->vdOutPayload; - word32 payloadSz; - word32 respPayloadSz = 0; - word32 totalSz; - word32 off; - int rc; - - payloadSz = WOLFSPDM_MAX_TPM_MSG_SIZE; - rc = wolfSPDM_ParseVendorDefined(in, inSz, vdCode, payload, &payloadSz); - if (rc < 0) { - return rc; - } - if (vdCodeOut != NULL) { - XMEMCPY(vdCodeOut, vdCode, WOLFSPDM_VDCODE_LEN + 1); - } - - /* TPM2_CMD, GIVE_PUB and SPDMONLY are only ever sent inside a secured - * message; honouring them from a clear frame would defeat the - * bus-snooping defence. GET_PUBK / GET_STS_ / PSK_* are pre-session by - * design and stay reachable in the clear. */ - if (!fromSecured && - (XSTRCMP(vdCode, WOLFSPDM_VDCODE_TPM2_CMD) == 0 || - XSTRCMP(vdCode, WOLFSPDM_VDCODE_GIVE_PUB) == 0 || - XSTRCMP(vdCode, WOLFSPDM_VDCODE_SPDMONLY) == 0)) { - return WOLFSPDM_E_BAD_STATE; - } - - if (XSTRCMP(vdCode, WOLFSPDM_VDCODE_TPM2_CMD) == 0) { - /* Reserve the VENDOR_DEFINED_RSP wrapper overhead - * (1+1+1+1+2+1+2 = 9 fixed bytes + vdCode) so the TPM callback - * cannot return more data than will fit inside the response - * envelope. Otherwise the wrapper below silently returns - * E_BUFFER_SMALL on the largest TPM responses. */ - word32 tpmRespCap = WOLFSPDM_MAX_TPM_MSG_SIZE - - (9 + WOLFSPDM_VDCODE_LEN); - if (rctx->tpmCb == NULL) { - return WOLFSPDM_E_BAD_STATE; - } - rc = rctx->tpmCb(rctx->tpmCbUserCtx, payload, payloadSz, - respPayload, tpmRespCap, &respPayloadSz); - if (rc != 0) { - return WOLFSPDM_E_IO_FAIL; - } - } -#ifdef WOLFTPM_SPDM_TCG - else if (XSTRCMP(vdCode, WOLFSPDM_VDCODE_GET_PUBK) == 0) { - if (!rctx->flags.hasIdKey) { - return WOLFSPDM_E_BAD_STATE; - } - if (rctx->idPubKeyLen > WOLFSPDM_MAX_MSG_SIZE) { - return WOLFSPDM_E_BUFFER_SMALL; - } - XMEMCPY(respPayload, rctx->idPubKey, rctx->idPubKeyLen); - respPayloadSz = rctx->idPubKeyLen; - } - else if (XSTRCMP(vdCode, WOLFSPDM_VDCODE_GIVE_PUB) == 0) { - if (payloadSz > sizeof(ctx->reqPubKeyTPMT)) { - return WOLFSPDM_E_BUFFER_SMALL; - } - XMEMCPY(ctx->reqPubKeyTPMT, payload, payloadSz); - ctx->reqPubKeyTPMTLen = payloadSz; - respPayloadSz = 0; - } -#if defined(WOLFSPDM_NUVOTON) || defined(WOLFSPDM_NATIONS) - /* GET_STS_ / SPDMONLY are vendor-format adapters. Nuvoton and Nations - * share the same vdcode strings and a compatible 4-byte status layout - * - byte[2] is "Reserved" on Nuvoton and "PSKSet" on Nations (Nuvoton - * never sets PSK, so a zero here is correct in either mode). */ - else if (XSTRCMP(vdCode, WOLFSPDM_VDCODE_GET_STS) == 0) { - respPayload[0] = 0x00; - respPayload[1] = 0x04; - respPayload[2] = rctx->flags.pskProvisioned ? 0x01 : 0x00; - respPayload[3] = rctx->flags.spdmOnlyLock ? 0x01 : 0x00; - respPayloadSz = 4; - } - else if (XSTRCMP(vdCode, WOLFSPDM_VDCODE_SPDMONLY) == 0) { - if (payloadSz >= 1 && payload[0] == WOLFSPDM_SPDMONLY_LOCK) { - rctx->flags.spdmOnlyLock = 1; - } - else { - rctx->flags.spdmOnlyLock = 0; - } - respPayloadSz = 0; - } -#endif /* WOLFSPDM_NUVOTON || WOLFSPDM_NATIONS */ -#ifdef WOLFSPDM_NATIONS - /* PSK_SET_ / PSK_CLR_ are Nations-proprietary PSK provisioning carried - * over SPDM VENDOR_DEFINED. The DSP0274 spec leaves PSK delivery to the - * implementation; we adopt Nations' NSING format here. */ - else if (XSTRCMP(vdCode, "PSK_SET_") == 0) { - /* Payload: PSK + SHA-384(ClearAuth). */ - const word32 pskLen = (word32)sizeof(rctx->pskStore); - if (payloadSz != pskLen + WOLFSPDM_HASH_SIZE) { - return WOLFSPDM_E_INVALID_ARG; - } - /* Once a ClearAuth is registered, replacing the PSK requires - * PSK_CLR_ first, or that check is trivially skipped. A PSK set by - * configuration has no ClearAuth, so it may still be provisioned. */ - if (rctx->flags.clearAuthSet) { - return WOLFSPDM_E_BAD_STATE; - } - XMEMCPY(rctx->pskStore, payload, pskLen); - rctx->pskStoreSz = pskLen; - XMEMCPY(rctx->clearAuthDigest, payload + pskLen, WOLFSPDM_HASH_SIZE); - rctx->flags.pskProvisioned = 1; - rctx->flags.clearAuthSet = 1; - /* Mirror into ctx->psk so the next PSK_EXCHANGE can use it. */ - XMEMCPY(ctx->psk, rctx->pskStore, rctx->pskStoreSz); - ctx->pskSz = rctx->pskStoreSz; - respPayloadSz = 0; - } - else if (XSTRCMP(vdCode, "PSK_CLR_") == 0) { - /* Payload: ClearAuth(32 raw bytes). Verify SHA-384 matches stored. */ - byte digest[WOLFSPDM_HASH_SIZE]; - volatile int diff = 0; - word32 i; - if (payloadSz != 32 || !rctx->flags.pskProvisioned) { - return WOLFSPDM_E_INVALID_ARG; - } - rc = wolfSPDM_Sha384Hash(digest, payload, payloadSz, - NULL, 0, NULL, 0); - if (rc != WOLFSPDM_SUCCESS) { - return rc; - } - /* Constant-time compare, matching the FINISH HMAC paths. */ - for (i = 0; i < WOLFSPDM_HASH_SIZE; i++) { - diff |= digest[i] ^ rctx->clearAuthDigest[i]; - } - wc_ForceZero(digest, sizeof(digest)); - if (diff != 0) { - return WOLFSPDM_E_BAD_HMAC; - } - wc_ForceZero(rctx->pskStore, sizeof(rctx->pskStore)); - wc_ForceZero(rctx->clearAuthDigest, sizeof(rctx->clearAuthDigest)); - rctx->pskStoreSz = 0; - rctx->flags.pskProvisioned = 0; - rctx->flags.clearAuthSet = 0; - wc_ForceZero(ctx->psk, sizeof(ctx->psk)); - ctx->pskSz = 0; - respPayloadSz = 0; - } -#endif /* WOLFSPDM_NATIONS */ -#endif /* WOLFTPM_SPDM_TCG */ - else { - return WOLFSPDM_E_NOT_AVAILABLE; - } - - /* Build VENDOR_DEFINED_RSP frame (response code 0x7E). */ - totalSz = 1 + 1 + 1 + 1 + 2 + 1 + 2 + WOLFSPDM_VDCODE_LEN + respPayloadSz; - if (*outSz < totalSz) { - return WOLFSPDM_E_BUFFER_SMALL; - } - off = 0; - out[off++] = ctx->spdmVersion; - out[off++] = WOLFSPDM_VENDOR_DEFINED_RSP; - out[off++] = 0x00; - out[off++] = 0x00; - SPDM_Set16LE(out + off, 0x0001); off += 2; - out[off++] = 0x00; - SPDM_Set16LE(out + off, (word16)(WOLFSPDM_VDCODE_LEN + respPayloadSz)); - off += 2; - XMEMCPY(out + off, vdCode, WOLFSPDM_VDCODE_LEN); - off += WOLFSPDM_VDCODE_LEN; - if (respPayloadSz > 0) { - XMEMCPY(out + off, respPayload, respPayloadSz); - off += respPayloadSz; - } - *outSz = off; - return WOLFSPDM_SUCCESS; -} - -static int RespDispatchSecured(WOLFSPDM_RESP_CTX* rctx, - const byte* securedIn, word32 securedInSz, - byte* securedOut, word32* securedOutSz) -{ - byte* plain = rctx->secureInPlain; - byte* respPlain = rctx->secureOutPlain; - WOLFSPDM_CTX* ctx = &rctx->ctx; - word32 plainSz; - word32 respPlainSz; - byte code; - int rc; - int sessionEnded = 0; - int derivedAppKeys = 0; - - /* KEY_EX has handshake traffic keys; CONNECTED has application traffic - * keys. In every other state, decryption would use unestablished key - * material (zeroed by initialization and reset). */ - if ((ctx->state != WOLFSPDM_STATE_KEY_EX && - ctx->state != WOLFSPDM_STATE_CONNECTED) || ctx->sessionId == 0) { - return WOLFSPDM_E_BAD_STATE; - } - - plainSz = WOLFSPDM_MAX_MSG_SIZE; - rc = RespDecrypt(ctx, securedIn, securedInSz, plain, &plainSz); - if (rc != WOLFSPDM_SUCCESS) { - return rc; - } - if (plainSz < 2) { - return WOLFSPDM_E_FRAMING; - } - code = plain[1]; - - respPlainSz = WOLFSPDM_MAX_MSG_SIZE; - switch (code) { - /* A finish must match the exchange that opened KEY_EX and cannot run - * again once connected, or a PSK peer could relabel its session as - * identity-key authenticated with a plain FINISH. */ -#ifdef WOLFTPM_SPDM_PSK - case SPDM_PSK_FINISH: - if (ctx->state != WOLFSPDM_STATE_KEY_EX || - rctx->flags.pendingAsym) { - return WOLFSPDM_E_BAD_STATE; - } - rc = RespHandlePskFinish(rctx, plain, plainSz, - respPlain, &respPlainSz); - derivedAppKeys = (rc == WOLFSPDM_SUCCESS) ? 1 : 0; - break; -#endif - case SPDM_FINISH: - if (ctx->state != WOLFSPDM_STATE_KEY_EX || - !rctx->flags.pendingAsym) { - return WOLFSPDM_E_BAD_STATE; - } - rc = RespHandleFinish(rctx, plain, plainSz, - respPlain, &respPlainSz); - derivedAppKeys = (rc == WOLFSPDM_SUCCESS) ? 1 : 0; - break; - case SPDM_END_SESSION: - rc = RespBuildEndSessionAck(ctx, plain, plainSz, - respPlain, &respPlainSz); - sessionEnded = 1; - break; - case SPDM_VENDOR_DEFINED_REQUEST: - rc = RespHandleVendorDefined(rctx, plain, plainSz, - respPlain, &respPlainSz, 1, NULL); - break; - default: - rc = RespBuildErrorClear(ctx, - SPDM_ERROR_UNSUPPORTED_REQUEST, code, - respPlain, &respPlainSz); - break; - } - - if (rc == WOLFSPDM_SUCCESS) { - rc = RespEncrypt(ctx, respPlain, respPlainSz, - securedOut, securedOutSz); - } - if (rc == WOLFSPDM_SUCCESS && derivedAppKeys) { - rc = wolfSPDM_DeriveAppDataKeys(ctx); - } - - if (sessionEnded && rc == WOLFSPDM_SUCCESS) { - wolfSPDM_RespReset(rctx); - } - return rc; -} - -#endif /* WOLFTPM_SPDM_TCG */ - -int wolfSPDM_RespHandleMessage(WOLFSPDM_RESP_CTX* ctx, - const byte* inBuf, word32 inSz, - byte* outBuf, word32* outSz) -{ -#ifdef WOLFTPM_SPDM_TCG - word16 tag; - word32 msgSize; - word32 payloadSz; - word32 spdmOutSz; - word32 totalSz; - int rc; -#endif - - if (ctx == NULL || inBuf == NULL || outBuf == NULL || outSz == NULL) { - return WOLFSPDM_E_INVALID_ARG; - } - if (!ctx->flags.initialized) { - return WOLFSPDM_E_BAD_STATE; - } - if (!ctx->flags.useTcg && !ctx->flags.usePsk) { - return WOLFSPDM_E_BAD_STATE; - } - - /* Bus-snooping defence: only TCG clear (0x8101) or secured (0x8201) - * frames are accepted; anything else is rejected here. */ - if (inSz < WOLFSPDM_TCG_HEADER_SIZE) { - return WOLFSPDM_E_FRAMING; - } - -#ifndef WOLFTPM_SPDM_TCG - (void)inBuf; - return WOLFSPDM_E_NOT_AVAILABLE; -#else - tag = SPDM_Get16BE(inBuf); - if (tag != WOLFSPDM_TCG_TAG_CLEAR && tag != WOLFSPDM_TCG_TAG_SECURED) { - return WOLFSPDM_E_FRAMING; - } - msgSize = SPDM_Get32BE(inBuf + 2); - if (msgSize < WOLFSPDM_TCG_HEADER_SIZE || msgSize > inSz) { - return WOLFSPDM_E_FRAMING; - } - ctx->ctx.connectionHandle = SPDM_Get32BE(inBuf + 6); - ctx->ctx.fipsIndicator = SPDM_Get16BE(inBuf + 10); - payloadSz = msgSize - WOLFSPDM_TCG_HEADER_SIZE; - - if (*outSz < WOLFSPDM_TCG_HEADER_SIZE) { - return WOLFSPDM_E_BUFFER_SMALL; - } - spdmOutSz = *outSz - WOLFSPDM_TCG_HEADER_SIZE; - - if (tag == WOLFSPDM_TCG_TAG_CLEAR) { - rc = RespDispatchClear(ctx, - inBuf + WOLFSPDM_TCG_HEADER_SIZE, payloadSz, - outBuf + WOLFSPDM_TCG_HEADER_SIZE, &spdmOutSz); - } - else { - rc = RespDispatchSecured(ctx, - inBuf + WOLFSPDM_TCG_HEADER_SIZE, payloadSz, - outBuf + WOLFSPDM_TCG_HEADER_SIZE, &spdmOutSz); - } - - if (rc != WOLFSPDM_SUCCESS) { - return rc; - } - - totalSz = WOLFSPDM_TCG_HEADER_SIZE + spdmOutSz; - wolfSPDM_WriteTcgHeader(outBuf, tag, totalSz, - ctx->ctx.connectionHandle, ctx->ctx.fipsIndicator); - *outSz = totalSz; - return WOLFSPDM_SUCCESS; -#endif /* WOLFTPM_SPDM_TCG */ -} - -#endif /* WOLFTPM_SPDM_RESPONDER */ diff --git a/src/spdm/spdm_secured.c b/src/spdm/spdm_secured.c deleted file mode 100644 index 705a757d4..000000000 --- a/src/spdm/spdm_secured.c +++ /dev/null @@ -1,379 +0,0 @@ -/* spdm_secured.c - * - * Copyright (C) 2006-2026 wolfSSL Inc. - * - * This file is part of wolfSPDM. - * - * wolfSPDM is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3 of the License, or - * (at your option) any later version. - * - * wolfSPDM is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA - */ - -#ifdef HAVE_CONFIG_H - #include -#endif - -#ifdef WOLFTPM_SPDM - -#include "spdm_internal.h" - -/* - * SPDM Secured Message Format (DSP0277): - * - * MCTP transport: - * Header/AAD: SessionID(4 LE) + SeqNum(2 LE) + Length(2 LE) = 8 bytes - * IV XOR: Leftmost 2 bytes (bytes 0-1) with 2-byte LE sequence number (DSP0277) - * - * Nuvoton TCG binding (Rev 1.11): - * Header/AAD: SessionID(4 LE) + SeqNum(8 LE) + Length(2 LE) = 14 bytes - * IV XOR: Leftmost 8 bytes (bytes 0-7) with 8-byte LE sequence number (DSP0277 1.2) - * Plaintext: AppDataLength(2 LE) + SPDM msg + RandomData (pad to 16) - * - * Full message: Header || Ciphertext || Tag (16) - */ - -int wolfSPDM_EncryptInternal(WOLFSPDM_CTX* ctx, - const byte* plain, word32 plainSz, - byte* enc, word32* encSz) -{ - Aes aes; - byte iv[WOLFSPDM_AEAD_IV_SIZE]; - byte aad[16]; /* Up to 14 bytes for TCG format */ - byte plainBuf[WOLFSPDM_MAX_MSG_SIZE + 16]; - byte tag[WOLFSPDM_AEAD_TAG_SIZE]; - word32 plainBufSz; - word16 recordLen; - word32 hdrSz; - word32 aadSz; - int aesInit = 0; - int rc; - - if (ctx == NULL || plain == NULL || enc == NULL || encSz == NULL) { - return WOLFSPDM_E_INVALID_ARG; - } - if (plainSz > WOLFSPDM_MAX_MSG_SIZE) { - return WOLFSPDM_E_BUFFER_SMALL; - } - -#ifdef WOLFTPM_SPDM_TCG - if (ctx->mode == WOLFSPDM_MODE_NUVOTON || - ctx->mode == WOLFSPDM_MODE_NATIONS || - ctx->mode == WOLFSPDM_MODE_NATIONS_PSK) { - /* Nuvoton TCG binding format per Rev 1.11 spec page 25: - * Header/AAD: SessionID(4 LE) + SeqNum(8 LE) + Length(2 LE) = 14 bytes - * IV XOR: Leftmost 8 bytes (bytes 0-7) with 8-byte LE sequence number - */ - word16 appDataLen = (word16)plainSz; - - word16 unpadded = (word16)(2 + appDataLen); - word16 padLen = (word16)((16 - (unpadded % 16)) % 16); - word16 encPayloadSz = (word16)(unpadded + padLen); - - plainBufSz = encPayloadSz; - /* Length field = ciphertext + MAC - * (per Nuvoton spec page 25: Length=160=144+16) */ - recordLen = (word16)(encPayloadSz + WOLFSPDM_AEAD_TAG_SIZE); - hdrSz = 14; /* 4 + 8 + 2 (TCG binding format) */ - - if (*encSz < hdrSz + plainBufSz + WOLFSPDM_AEAD_TAG_SIZE) { - return WOLFSPDM_E_BUFFER_SMALL; - } - - /* Build plaintext: AppDataLength(2 LE) || SPDM message || RandomData */ - SPDM_Set16LE(plainBuf, appDataLen); - XMEMCPY(&plainBuf[2], plain, plainSz); - /* Fill RandomData with actual random bytes per Nuvoton spec */ - if (padLen > 0) { - rc = wolfSPDM_GetRandom(ctx, &plainBuf[unpadded], padLen); - if (rc != WOLFSPDM_SUCCESS) { - wc_ForceZero(plainBuf, sizeof(plainBuf)); - return rc; - } - } - - /* Build header/AAD: SessionID(4 LE) + SeqNum(8 LE) + - * Length(2 LE) = 14 bytes */ - SPDM_Set32LE(&enc[0], ctx->sessionId); - SPDM_Set64LE(&enc[4], ctx->reqSeqNum); - SPDM_Set16LE(&enc[12], recordLen); - - aadSz = 14; - XMEMCPY(aad, enc, aadSz); - } else -#endif - { - /* MCTP format (per DSP0277): - * Plaintext: AppDataLen(2 LE) + MCTP header(0x05) + SPDM message - * Header: SessionID(4 LE) + SeqNum(2 LE) + Length(2 LE) = 8 bytes - * AAD = Header - */ - word16 appDataLen = (word16)(1 + plainSz); - word16 encDataLen = (word16)(2 + appDataLen); - - /* MCTP carries a 16-bit sequence number; fail rather than let the wire - * value and the 64-bit IV counter diverge past 0xFFFF */ - if (ctx->reqSeqNum > 0xFFFF) { - return WOLFSPDM_E_BAD_STATE; - } - - plainBufSz = encDataLen; - recordLen = (word16)(encDataLen + WOLFSPDM_AEAD_TAG_SIZE); - hdrSz = 8; /* 4 + 2 + 2 */ - - if (*encSz < hdrSz + recordLen) { - return WOLFSPDM_E_BUFFER_SMALL; - } - - /* Build plaintext: AppDataLen(2 LE) || MCTP header(0x05) || SPDM msg */ - SPDM_Set16LE(plainBuf, appDataLen); - plainBuf[2] = MCTP_MESSAGE_TYPE_SPDM; - XMEMCPY(&plainBuf[3], plain, plainSz); - - /* Build header/AAD: SessionID(4 LE) + SeqNum(2 LE) + Length(2 LE) */ - SPDM_Set32LE(&enc[0], ctx->sessionId); - SPDM_Set16LE(&enc[4], (word16)ctx->reqSeqNum); - SPDM_Set16LE(&enc[6], recordLen); - - aadSz = 8; - XMEMCPY(aad, enc, aadSz); - } - - /* Build IV: BaseIV XOR sequence number (DSP0277) */ - wolfSPDM_BuildIV(iv, ctx->reqDataIv, ctx->reqSeqNum); - - /* AES-GCM encrypt — cascade with single cleanup */ - rc = wc_AesInit(&aes, NULL, INVALID_DEVID); - if (rc == 0) { - aesInit = 1; - rc = wc_AesGcmSetKey(&aes, ctx->reqDataKey, WOLFSPDM_AEAD_KEY_SIZE); - } - if (rc == 0) { - rc = wc_AesGcmEncrypt(&aes, &enc[hdrSz], plainBuf, plainBufSz, - iv, WOLFSPDM_AEAD_IV_SIZE, tag, WOLFSPDM_AEAD_TAG_SIZE, aad, aadSz); - } - if (aesInit) { - wc_AesFree(&aes); - } - - if (rc == 0) { - XMEMCPY(&enc[hdrSz + plainBufSz], tag, WOLFSPDM_AEAD_TAG_SIZE); - *encSz = hdrSz + plainBufSz + WOLFSPDM_AEAD_TAG_SIZE; - ctx->reqSeqNum++; - wolfSPDM_DebugPrint(ctx, "Encrypted %u bytes -> %u bytes (seq=%llu)\n", - plainSz, *encSz, (unsigned long long)(ctx->reqSeqNum - 1)); - } - - wc_ForceZero(plainBuf, sizeof(plainBuf)); - return (rc == 0) ? WOLFSPDM_SUCCESS : WOLFSPDM_E_CRYPTO_FAIL; -} - -int wolfSPDM_DecryptInternal(WOLFSPDM_CTX* ctx, - const byte* enc, word32 encSz, - byte* plain, word32* plainSz) -{ - Aes aes; - byte iv[WOLFSPDM_AEAD_IV_SIZE]; - byte aad[16]; - byte decrypted[WOLFSPDM_MAX_MSG_SIZE + 16]; - const byte* ciphertext; - const byte* tag; - word32 cipherLen; - word16 appDataLen; - word32 hdrSz; - word32 aadSz; - int aesInit = 0; - int ret; - int rc; - - if (ctx == NULL || enc == NULL || plain == NULL || plainSz == NULL) { - return WOLFSPDM_E_INVALID_ARG; - } - - /* ----- Transport-specific header parsing ----- */ - -#ifdef WOLFTPM_SPDM_TCG - if (ctx->mode == WOLFSPDM_MODE_NUVOTON || - ctx->mode == WOLFSPDM_MODE_NATIONS || - ctx->mode == WOLFSPDM_MODE_NATIONS_PSK) { - word64 rspSeqNum64; - word32 rspSessionId; - word16 rspLen; - hdrSz = 14; - aadSz = 14; - - if (encSz < hdrSz + WOLFSPDM_AEAD_TAG_SIZE) - return WOLFSPDM_E_BUFFER_SMALL; - - rspSessionId = SPDM_Get32LE(&enc[0]); - rspSeqNum64 = SPDM_Get64LE(&enc[4]); - rspLen = SPDM_Get16LE(&enc[12]); - - if (rspSessionId != ctx->sessionId) { - wolfSPDM_DebugPrint(ctx, "Session ID mismatch: 0x%08x != 0x%08x\n", - rspSessionId, ctx->sessionId); - return WOLFSPDM_E_SESSION_INVALID; - } - if (rspSeqNum64 != ctx->rspSeqNum) { - wolfSPDM_DebugPrint(ctx, "Seq mismatch: %llu != %llu\n", - (unsigned long long)rspSeqNum64, - (unsigned long long)ctx->rspSeqNum); - return WOLFSPDM_E_SEQUENCE; - } - if (rspLen < WOLFSPDM_AEAD_TAG_SIZE || encSz < hdrSz + rspLen) - return WOLFSPDM_E_BUFFER_SMALL; - - cipherLen = (word32)(rspLen - WOLFSPDM_AEAD_TAG_SIZE); - if (cipherLen > sizeof(decrypted)) - return WOLFSPDM_E_BUFFER_SMALL; - - ciphertext = enc + hdrSz; - tag = enc + hdrSz + cipherLen; - XMEMCPY(aad, enc, aadSz); - wolfSPDM_BuildIV(iv, ctx->rspDataIv, rspSeqNum64); - } else -#endif - { - word32 rspSessionId; - word16 rspSeqNum, rspLen; - hdrSz = 8; - aadSz = 8; - - if (encSz < hdrSz + WOLFSPDM_AEAD_TAG_SIZE) - return WOLFSPDM_E_BUFFER_SMALL; - - rspSessionId = SPDM_Get32LE(&enc[0]); - rspSeqNum = SPDM_Get16LE(&enc[4]); - rspLen = SPDM_Get16LE(&enc[6]); - - if (rspSessionId != ctx->sessionId) { - wolfSPDM_DebugPrint(ctx, "Session ID mismatch: 0x%08x != 0x%08x\n", - rspSessionId, ctx->sessionId); - return WOLFSPDM_E_SESSION_INVALID; - } - if ((word64)rspSeqNum != ctx->rspSeqNum) { - wolfSPDM_DebugPrint(ctx, "Seq mismatch: %u != %llu\n", - rspSeqNum, (unsigned long long)ctx->rspSeqNum); - return WOLFSPDM_E_SEQUENCE; - } - if (rspLen < WOLFSPDM_AEAD_TAG_SIZE || encSz < (word32)(hdrSz + rspLen)) - return WOLFSPDM_E_BUFFER_SMALL; - - cipherLen = (word32)(rspLen - WOLFSPDM_AEAD_TAG_SIZE); - if (cipherLen > sizeof(decrypted)) - return WOLFSPDM_E_BUFFER_SMALL; - - ciphertext = enc + hdrSz; - tag = enc + hdrSz + cipherLen; - XMEMCPY(aad, enc, aadSz); - wolfSPDM_BuildIV(iv, ctx->rspDataIv, (word64)rspSeqNum); - } - - /* ----- AES-GCM decrypt (shared for both transports) ----- */ - - ret = WOLFSPDM_E_CRYPTO_FAIL; - rc = wc_AesInit(&aes, NULL, INVALID_DEVID); - if (rc == 0) { - aesInit = 1; - rc = wc_AesGcmSetKey(&aes, ctx->rspDataKey, WOLFSPDM_AEAD_KEY_SIZE); - } - if (rc == 0) { - rc = wc_AesGcmDecrypt(&aes, decrypted, ciphertext, cipherLen, - iv, WOLFSPDM_AEAD_IV_SIZE, tag, WOLFSPDM_AEAD_TAG_SIZE, - aad, aadSz); - if (rc != 0) { - wolfSPDM_DebugPrint(ctx, "AES-GCM decrypt failed: %d\n", rc); - ret = WOLFSPDM_E_DECRYPT_FAIL; - } - else { - /* Record is authenticated (tag verified) so the peer has advanced; - * advance now. A forged record fails the tag and never reaches - * here, and a later payload parse error stays fatal without - * desyncing the sequence. */ - ctx->rspSeqNum++; - } - } - if (aesInit) { - wc_AesFree(&aes); - } - - /* ----- Parse decrypted payload ----- */ - - if (rc == 0 && cipherLen < 2) { - /* authenticated record too short to hold the application length */ - ret = WOLFSPDM_E_BUFFER_SMALL; - } - else if (rc == 0) { - appDataLen = SPDM_Get16LE(decrypted); -#ifdef WOLFTPM_SPDM_TCG - if (ctx->mode == WOLFSPDM_MODE_NUVOTON || - ctx->mode == WOLFSPDM_MODE_NATIONS || - ctx->mode == WOLFSPDM_MODE_NATIONS_PSK) { - /* TCG binding: AppDataLen(2) || SPDM msg || RandomData */ - if (cipherLen < (word32)(2 + appDataLen) || - *plainSz < appDataLen) { - ret = WOLFSPDM_E_BUFFER_SMALL; - } else { - XMEMCPY(plain, &decrypted[2], appDataLen); - *plainSz = appDataLen; - ret = WOLFSPDM_SUCCESS; - } - } else -#endif - { - /* MCTP: AppDataLen(2) || MCTP(1) || SPDM msg */ - if (appDataLen < 1 || cipherLen < (word32)(2 + appDataLen) || - *plainSz < (word32)(appDataLen - 1)) { - ret = WOLFSPDM_E_BUFFER_SMALL; - } else { - XMEMCPY(plain, &decrypted[3], appDataLen - 1); - *plainSz = appDataLen - 1; - ret = WOLFSPDM_SUCCESS; - } - } - } - - if (ret == WOLFSPDM_SUCCESS) { - wolfSPDM_DebugPrint(ctx, "Decrypted %u bytes -> %u bytes\n", - encSz, *plainSz); - } - - wc_ForceZero(decrypted, sizeof(decrypted)); - return ret; -} - -int wolfSPDM_SecuredExchange(WOLFSPDM_CTX* ctx, - const byte* cmdPlain, word32 cmdSz, - byte* rspPlain, word32* rspSz) -{ - byte encBuf[WOLFSPDM_MAX_MSG_SIZE + WOLFSPDM_AEAD_OVERHEAD]; - byte rxBuf[WOLFSPDM_MAX_MSG_SIZE + WOLFSPDM_AEAD_OVERHEAD]; - word32 encSz = sizeof(encBuf); - word32 rxSz = sizeof(rxBuf); - int rc; - - if (ctx == NULL || cmdPlain == NULL || rspPlain == NULL || rspSz == NULL) { - return WOLFSPDM_E_INVALID_ARG; - } - - rc = wolfSPDM_EncryptInternal(ctx, cmdPlain, cmdSz, encBuf, &encSz); - if (rc == WOLFSPDM_SUCCESS) { - rc = wolfSPDM_SendReceive(ctx, encBuf, encSz, rxBuf, &rxSz); - } - if (rc == WOLFSPDM_SUCCESS) { - rc = wolfSPDM_DecryptInternal(ctx, rxBuf, rxSz, rspPlain, rspSz); - } - - return rc; -} - -#endif /* WOLFTPM_SPDM */ diff --git a/src/spdm/spdm_session.c b/src/spdm/spdm_session.c deleted file mode 100644 index 2467442bb..000000000 --- a/src/spdm/spdm_session.c +++ /dev/null @@ -1,162 +0,0 @@ -/* spdm_session.c - * - * Copyright (C) 2006-2026 wolfSSL Inc. - * - * This file is part of wolfSPDM. - * - * wolfSPDM is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3 of the License, or - * (at your option) any later version. - * - * wolfSPDM is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA - */ - -#ifdef HAVE_CONFIG_H - #include -#endif - -#ifdef WOLFTPM_SPDM - -#include "spdm_internal.h" - -/* Callback types for build/parse functions */ -typedef int (*wolfSPDM_BuildFn)(WOLFSPDM_CTX*, byte*, word32*); -typedef int (*wolfSPDM_ParseFn)(WOLFSPDM_CTX*, const byte*, word32); - -/* Exchange helper: build -> transcript(tx) -> sendrecv -> transcript(rx) -> parse */ -static int wolfSPDM_ExchangeMsg(WOLFSPDM_CTX* ctx, - wolfSPDM_BuildFn buildFn, wolfSPDM_ParseFn parseFn, - byte* txBuf, word32 txBufSz, byte* rxBuf, word32 rxBufSz) -{ - word32 txSz = txBufSz; - word32 rxSz = rxBufSz; - int rc; - - rc = buildFn(ctx, txBuf, &txSz); - if (rc == WOLFSPDM_SUCCESS) { - rc = wolfSPDM_TranscriptAdd(ctx, txBuf, txSz); - } - if (rc == WOLFSPDM_SUCCESS) { - rc = wolfSPDM_SendReceive(ctx, txBuf, txSz, rxBuf, &rxSz); - } - if (rc == WOLFSPDM_SUCCESS) { - rc = wolfSPDM_TranscriptAdd(ctx, rxBuf, rxSz); - } - if (rc == WOLFSPDM_SUCCESS) { - rc = parseFn(ctx, rxBuf, rxSz); - } - - return rc; -} - -/* Adapter: BuildGetVersion doesn't take ctx */ -static int wolfSPDM_BuildGetVersionAdapter(WOLFSPDM_CTX* ctx, byte* buf, - word32* bufSz) -{ - (void)ctx; - return wolfSPDM_BuildGetVersion(buf, bufSz); -} - -int wolfSPDM_GetVersion(WOLFSPDM_CTX* ctx) -{ - byte txBuf[8]; - byte rxBuf[32]; /* VERSION: 4 hdr + 2 count + up to 8 entries * 2 = 22 */ - - return wolfSPDM_ExchangeMsg(ctx, wolfSPDM_BuildGetVersionAdapter, - wolfSPDM_ParseVersion, txBuf, sizeof(txBuf), rxBuf, sizeof(rxBuf)); -} - -int wolfSPDM_KeyExchange(WOLFSPDM_CTX* ctx) -{ - byte txBuf[WOLFSPDM_KEY_EX_TX_SZ]; - byte rxBuf[WOLFSPDM_KEY_EX_RX_SZ]; - word32 txSz = sizeof(txBuf); - word32 rxSz = sizeof(rxBuf); - int rc; - - rc = wolfSPDM_BuildKeyExchange(ctx, txBuf, &txSz); - if (rc == WOLFSPDM_SUCCESS) { - rc = wolfSPDM_TranscriptAdd(ctx, txBuf, txSz); - } - if (rc == WOLFSPDM_SUCCESS) { - rc = wolfSPDM_SendReceive(ctx, txBuf, txSz, rxBuf, &rxSz); - if (rc != WOLFSPDM_SUCCESS) { - wolfSPDM_DebugPrint(ctx, "KEY_EXCHANGE: SendReceive failed: %d\n", rc); - } - } - if (rc == WOLFSPDM_SUCCESS) { - wolfSPDM_DebugPrint(ctx, "KEY_EXCHANGE_RSP: received %u bytes\n", rxSz); - rc = wolfSPDM_ParseKeyExchangeRsp(ctx, rxBuf, rxSz); - } - - return rc; -} - -int wolfSPDM_Finish(WOLFSPDM_CTX* ctx) -{ - byte finishBuf[WOLFSPDM_FINISH_BUF_SZ]; - byte encBuf[WOLFSPDM_VENDOR_BUF_SZ]; - byte rxBuf[128]; /* Encrypted FINISH_RSP: ~94 bytes max */ - byte decBuf[64]; /* Decrypted FINISH_RSP: 4 hdr + 48 verify = 52 */ - word32 finishSz = sizeof(finishBuf); - word32 encSz = sizeof(encBuf); - word32 rxSz = sizeof(rxBuf); - word32 decSz = sizeof(decBuf); - int rc; - - /* FINISH is only valid after a successful KEY_EXCHANGE; otherwise the - * session keys are unestablished (zero-entropy). */ - if (ctx == NULL || ctx->state < WOLFSPDM_STATE_KEY_EX) { - return WOLFSPDM_E_BAD_STATE; - } - - rc = wolfSPDM_BuildFinish(ctx, finishBuf, &finishSz); - - /* FINISH must be sent encrypted (HANDSHAKE_IN_THE_CLEAR not negotiated) */ - if (rc == WOLFSPDM_SUCCESS) { - rc = wolfSPDM_EncryptInternal(ctx, finishBuf, finishSz, encBuf, - &encSz); - } - if (rc == WOLFSPDM_SUCCESS) { - rc = wolfSPDM_SendReceive(ctx, encBuf, encSz, rxBuf, &rxSz); - } - - /* Check for unencrypted SPDM error response */ - if (rc == WOLFSPDM_SUCCESS && - rxSz >= 2 && rxBuf[0] >= 0x10 && rxBuf[0] <= 0x1F) { - #ifdef DEBUG_WOLFTPM - if (rxBuf[1] == 0x7F) { - byte errCode = (rxSz >= 3) ? rxBuf[2] : 0xFF; - wolfSPDM_DebugPrint(ctx, "FINISH: SPDM ERROR 0x%02x\n", errCode); - } - #endif - rc = WOLFSPDM_E_PEER_ERROR; - } - - if (rc == WOLFSPDM_SUCCESS) { - rc = wolfSPDM_DecryptInternal(ctx, rxBuf, rxSz, decBuf, &decSz); - } - if (rc == WOLFSPDM_SUCCESS) { - rc = wolfSPDM_ParseFinishRsp(ctx, decBuf, decSz); - } - - /* Derive application data keys (transition from handshake to app phase) */ - if (rc == WOLFSPDM_SUCCESS) { - rc = wolfSPDM_DeriveAppDataKeys(ctx); - } - - /* Always zero sensitive stack buffers */ - wc_ForceZero(finishBuf, sizeof(finishBuf)); - wc_ForceZero(decBuf, sizeof(decBuf)); - return rc; -} - -#endif /* WOLFTPM_SPDM */ diff --git a/src/spdm/spdm_tcg.c b/src/spdm/spdm_tcg.c deleted file mode 100644 index 936df65a9..000000000 --- a/src/spdm/spdm_tcg.c +++ /dev/null @@ -1,729 +0,0 @@ -/* spdm_tcg.c - * - * Copyright (C) 2006-2026 wolfSSL Inc. - * - * This file is part of wolfSPDM. - * - * wolfSPDM is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3 of the License, or - * (at your option) any later version. - * - * wolfSPDM is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA - */ - -#ifdef HAVE_CONFIG_H - #include -#endif - -#ifdef WOLFTPM_SPDM - -/* Shared TCG SPDM code used by both Nuvoton and Nations Technology TPMs. */ - -#include "spdm_internal.h" - -#ifdef WOLFTPM_SPDM_TCG - -#include - -/* ----- Vendor Command Helpers ----- */ - -int wolfSPDM_TCG_VendorCmdClear(WOLFSPDM_CTX* ctx, const char* vdCode, - const byte* payload, word32 payloadSz, WOLFSPDM_VENDOR_RSP* rsp) -{ - byte spdmMsg[WOLFSPDM_VENDOR_BUF_SZ]; - int spdmMsgSz; - byte rxBuf[WOLFSPDM_VENDOR_RX_SZ]; - word32 rxSz; - int rc; - byte ver; - - ver = ctx->spdmVersion ? ctx->spdmVersion : SPDM_VERSION_13; - spdmMsgSz = wolfSPDM_BuildVendorDefined(ver, vdCode, payload, - payloadSz, spdmMsg, sizeof(spdmMsg)); - if (spdmMsgSz < 0) { - return spdmMsgSz; - } - - rxSz = sizeof(rxBuf); - rc = wolfSPDM_SendReceive(ctx, spdmMsg, (word32)spdmMsgSz, rxBuf, &rxSz); - if (rc != WOLFSPDM_SUCCESS) { - return rc; - } - - if (rxSz >= 4 && rxBuf[1] == SPDM_ERROR) { - wolfSPDM_DebugPrint(ctx, "%s: SPDM ERROR 0x%02x 0x%02x\n", - vdCode, rxBuf[2], rxBuf[3]); - return WOLFSPDM_E_PEER_ERROR; - } - - if (rsp != NULL) { - rsp->payloadSz = sizeof(rsp->payload); - XMEMSET(rsp->vdCode, 0, sizeof(rsp->vdCode)); - rc = wolfSPDM_ParseVendorDefined(rxBuf, rxSz, - rsp->vdCode, rsp->payload, &rsp->payloadSz); - if (rc < 0) { - return rc; - } - /* Validate response VdCode matches the request */ - if (XMEMCMP(rsp->vdCode, vdCode, WOLFSPDM_VDCODE_LEN) != 0) { - wolfSPDM_DebugPrint(ctx, "%s: unexpected VdCode '%.8s'\n", - vdCode, rsp->vdCode); - return WOLFSPDM_E_PEER_ERROR; - } - } - - return WOLFSPDM_SUCCESS; -} - -int wolfSPDM_TCG_VendorCmdSecured(WOLFSPDM_CTX* ctx, const char* vdCode, - const byte* payload, word32 payloadSz) -{ - byte spdmMsg[WOLFSPDM_VENDOR_BUF_SZ]; - int spdmMsgSz; - byte decBuf[WOLFSPDM_VENDOR_BUF_SZ]; - word32 decSz = 0; - int rc; - byte ver; - - ver = ctx->spdmVersion ? ctx->spdmVersion : SPDM_VERSION_13; - spdmMsgSz = wolfSPDM_BuildVendorDefined(ver, vdCode, payload, - payloadSz, spdmMsg, sizeof(spdmMsg)); - if (spdmMsgSz < 0) { - rc = spdmMsgSz; - } - else { - decSz = sizeof(decBuf); - rc = wolfSPDM_SecuredExchange(ctx, spdmMsg, (word32)spdmMsgSz, - decBuf, &decSz); - } - - if (rc == WOLFSPDM_SUCCESS && decSz >= 4 && decBuf[1] == SPDM_ERROR) { - wolfSPDM_DebugPrint(ctx, "%s: SPDM ERROR 0x%02x 0x%02x\n", - vdCode, decBuf[2], decBuf[3]); - rc = WOLFSPDM_E_PEER_ERROR; - } - - /* Always zero sensitive stack buffers */ - wc_ForceZero(spdmMsg, sizeof(spdmMsg)); - wc_ForceZero(decBuf, sizeof(decBuf)); - - return rc; -} - -/* ----- TCG SPDM Binding Message Framing ----- */ - -int wolfSPDM_BuildTcgClearMessage( - WOLFSPDM_CTX* ctx, - const byte* spdmPayload, word32 spdmPayloadSz, - byte* outBuf, word32 outBufSz) -{ - word32 totalSz; - - if (ctx == NULL || spdmPayload == NULL || outBuf == NULL) { - return WOLFSPDM_E_INVALID_ARG; - } - - totalSz = WOLFSPDM_TCG_HEADER_SIZE + spdmPayloadSz; - - if (outBufSz < totalSz) { - return WOLFSPDM_E_BUFFER_SMALL; - } - - wolfSPDM_WriteTcgHeader(outBuf, WOLFSPDM_TCG_TAG_CLEAR, totalSz, - ctx->connectionHandle, ctx->fipsIndicator); - XMEMCPY(outBuf + WOLFSPDM_TCG_HEADER_SIZE, spdmPayload, spdmPayloadSz); - - return (int)totalSz; -} - -int wolfSPDM_ParseTcgClearMessage( - const byte* inBuf, word32 inBufSz, - byte* spdmPayload, word32* spdmPayloadSz, - WOLFSPDM_TCG_CLEAR_HDR* hdr) -{ - word16 tag; - word32 msgSize; - word32 payloadSz; - - if (inBuf == NULL || spdmPayload == NULL || spdmPayloadSz == NULL) { - return WOLFSPDM_E_INVALID_ARG; - } - - if (inBufSz < WOLFSPDM_TCG_HEADER_SIZE) { - return WOLFSPDM_E_BUFFER_SMALL; - } - - tag = SPDM_Get16BE(inBuf); - if (tag != WOLFSPDM_TCG_TAG_CLEAR) { - return WOLFSPDM_E_PEER_ERROR; - } - - msgSize = SPDM_Get32BE(inBuf + 2); - if (msgSize < WOLFSPDM_TCG_HEADER_SIZE || msgSize > inBufSz) { - return WOLFSPDM_E_BUFFER_SMALL; - } - - payloadSz = msgSize - WOLFSPDM_TCG_HEADER_SIZE; - if (*spdmPayloadSz < payloadSz) { - return WOLFSPDM_E_BUFFER_SMALL; - } - - if (hdr != NULL) { - hdr->tag = tag; - hdr->size = msgSize; - hdr->connectionHandle = SPDM_Get32BE(inBuf + 6); - hdr->fipsIndicator = SPDM_Get16BE(inBuf + 10); - hdr->reserved = SPDM_Get32BE(inBuf + 12); - } - - XMEMCPY(spdmPayload, inBuf + WOLFSPDM_TCG_HEADER_SIZE, payloadSz); - *spdmPayloadSz = payloadSz; - - return (int)payloadSz; -} - -/* ----- SPDM Vendor Defined Message Helpers ----- */ - -int wolfSPDM_BuildVendorDefined( - byte spdmVersion, - const char* vdCode, - const byte* payload, word32 payloadSz, - byte* outBuf, word32 outBufSz) -{ - word32 totalSz; - word32 offset = 0; - - if (vdCode == NULL || outBuf == NULL) { - return WOLFSPDM_E_INVALID_ARG; - } - if (payload == NULL && payloadSz != 0) { - return WOLFSPDM_E_INVALID_ARG; - } - - /* Reject a payload that would overflow the 16-bit request-length field */ - if (payloadSz > (word32)(0xFFFF - WOLFSPDM_VDCODE_LEN)) { - return WOLFSPDM_E_INVALID_ARG; - } - - /* SPDM VENDOR_DEFINED_REQUEST format: - * SPDMVersion(1) + reqRspCode(1) + param1(1) + param2(1) + - * standardId(2/LE) + vendorIdLen(1) + reqLength(2/LE) + - * vdCode(8) + payload */ - totalSz = 1 + 1 + 1 + 1 + 2 + 1 + 2 + WOLFSPDM_VDCODE_LEN + payloadSz; - - if (outBufSz < totalSz) { - return WOLFSPDM_E_BUFFER_SMALL; - } - - outBuf[offset++] = spdmVersion; - outBuf[offset++] = SPDM_VENDOR_DEFINED_REQUEST; - outBuf[offset++] = 0x00; - outBuf[offset++] = 0x00; - /* Standard ID (0x0001 = TCG, little-endian) */ - SPDM_Set16LE(outBuf + offset, 0x0001); - offset += 2; - /* Vendor ID Length (0 for TCG) */ - outBuf[offset++] = 0x00; - /* Request Length (vdCode + payload, little-endian) */ - SPDM_Set16LE(outBuf + offset, (word16)(WOLFSPDM_VDCODE_LEN + payloadSz)); - offset += 2; - /* VdCode (8-byte ASCII) */ - XMEMCPY(outBuf + offset, vdCode, WOLFSPDM_VDCODE_LEN); - offset += WOLFSPDM_VDCODE_LEN; - /* Payload */ - if (payload != NULL && payloadSz > 0) { - XMEMCPY(outBuf + offset, payload, payloadSz); - offset += payloadSz; - } - - return (int)offset; -} - -int wolfSPDM_ParseVendorDefined( - const byte* inBuf, word32 inBufSz, - char* vdCode, - byte* payload, word32* payloadSz) -{ - word32 offset = 0; - word16 reqLength; - word32 dataLen; - byte vendorIdLen; - - if (inBuf == NULL || vdCode == NULL || payload == NULL || - payloadSz == NULL) { - return WOLFSPDM_E_INVALID_ARG; - } - - /* Minimum: version(1) + code(1) + param1(1) + param2(1) + stdId(2/LE) + - * vidLen(1) + reqLen(2/LE) + vdCode(8) = 17 */ - if (inBufSz < 17) { - return WOLFSPDM_E_BUFFER_SMALL; - } - - offset += 1; /* SPDM version */ - offset += 3; /* request/response code + params */ - offset += 2; /* standard ID */ - vendorIdLen = inBuf[offset]; - offset += 1 + vendorIdLen; - - if (offset + 2 > inBufSz) { - return WOLFSPDM_E_BUFFER_SMALL; - } - - reqLength = SPDM_Get16LE(inBuf + offset); - offset += 2; - - if (reqLength < WOLFSPDM_VDCODE_LEN) { - return WOLFSPDM_E_BUFFER_SMALL; - } - - if (offset + reqLength > inBufSz) { - return WOLFSPDM_E_BUFFER_SMALL; - } - - XMEMCPY(vdCode, inBuf + offset, WOLFSPDM_VDCODE_LEN); - vdCode[WOLFSPDM_VDCODE_LEN] = '\0'; - offset += WOLFSPDM_VDCODE_LEN; - - dataLen = reqLength - WOLFSPDM_VDCODE_LEN; - if (*payloadSz < dataLen) { - return WOLFSPDM_E_BUFFER_SMALL; - } - - if (dataLen > 0) { - XMEMCPY(payload, inBuf + offset, dataLen); - } - *payloadSz = dataLen; - - return (int)dataLen; -} - -/* ----- Shared TCG SPDM Functions ----- */ - -static int wolfSPDM_TCG_CheckPubKey(WOLFSPDM_CTX* ctx, - const byte* pubKey, word32 pubKeySz) -{ - const byte* pubKeyX; - const byte* pubKeyY; - int rc; - - if (!ctx->flags.hasRspPubKey) { - return WOLFSPDM_SUCCESS; - } - if (ctx->rspPubKeyLen != WOLFSPDM_ECC_POINT_SIZE) { - return WOLFSPDM_E_BAD_STATE; - } - - rc = wolfSPDM_ExtractEccPoint(pubKey, pubKeySz, &pubKeyX, &pubKeyY); - if (rc != WOLFSPDM_SUCCESS) { - return WOLFSPDM_E_PEER_ERROR; - } - - if (XMEMCMP(pubKeyX, ctx->rspPubKey, WOLFSPDM_ECC_KEY_SIZE) != 0 || - XMEMCMP(pubKeyY, ctx->rspPubKey + WOLFSPDM_ECC_KEY_SIZE, - WOLFSPDM_ECC_KEY_SIZE) != 0) { - wolfSPDM_DebugPrint(ctx, "GET_PUBK: Responder key mismatch\n"); - return WOLFSPDM_E_PEER_ERROR; - } - - return WOLFSPDM_SUCCESS; -} - -int wolfSPDM_TCG_GetPubKey( - WOLFSPDM_CTX* ctx, - byte* pubKey, word32* pubKeySz) -{ - WOLFSPDM_VENDOR_RSP rsp; - int rc; - - if (ctx == NULL || pubKey == NULL || pubKeySz == NULL) { - return WOLFSPDM_E_INVALID_ARG; - } - - wolfSPDM_DebugPrint(ctx, "TCG: GET_PUBK\n"); - - rc = wolfSPDM_TCG_VendorCmdClear(ctx, WOLFSPDM_VDCODE_GET_PUBK, - NULL, 0, &rsp); - if (rc != WOLFSPDM_SUCCESS) { - return rc; - } - - if (XMEMCMP(rsp.vdCode, WOLFSPDM_VDCODE_GET_PUBK, - WOLFSPDM_VDCODE_LEN) != 0) { - wolfSPDM_DebugPrint(ctx, "GET_PUBK: Unexpected VdCode '%.8s'\n", - rsp.vdCode); - return WOLFSPDM_E_PEER_ERROR; - } - - wolfSPDM_DebugPrint(ctx, "GET_PUBK: Got TPMT_PUBLIC (%u bytes)\n", - rsp.payloadSz); - - rc = wolfSPDM_TCG_CheckPubKey(ctx, rsp.payload, rsp.payloadSz); - if (rc != WOLFSPDM_SUCCESS) { - return rc; - } - - if (*pubKeySz < rsp.payloadSz) { - return WOLFSPDM_E_BUFFER_SMALL; - } - XMEMCPY(pubKey, rsp.payload, rsp.payloadSz); - *pubKeySz = rsp.payloadSz; - - return WOLFSPDM_SUCCESS; -} - -int wolfSPDM_TCG_GivePubKey( - WOLFSPDM_CTX* ctx, - const byte* pubKey, word32 pubKeySz) -{ - int rc; - - if (ctx == NULL || pubKey == NULL) { - return WOLFSPDM_E_INVALID_ARG; - } - - if (ctx->state < WOLFSPDM_STATE_KEY_EX) { - return WOLFSPDM_E_BAD_STATE; - } - - wolfSPDM_DebugPrint(ctx, "TCG: GIVE_PUB (%u bytes)\n", pubKeySz); - - rc = wolfSPDM_TCG_VendorCmdSecured(ctx, WOLFSPDM_VDCODE_GIVE_PUB, - pubKey, pubKeySz); - if (rc != WOLFSPDM_SUCCESS) { - wolfSPDM_DebugPrint(ctx, "GIVE_PUB: SecuredExchange failed %d\n", rc); - return rc; - } - - wolfSPDM_DebugPrint(ctx, "GIVE_PUB: Success\n"); - return WOLFSPDM_SUCCESS; -} - -/* ----- Shared GET_CAPABILITIES + NEGOTIATE_ALGORITHMS ----- */ - -#define WOLFSPDM_TCG_CAPABILITIES_RSP 0x61 -#define WOLFSPDM_TCG_ALGORITHMS_RSP 0x63 -#define WOLFSPDM_TCG_CAPABILITIES_RSP_SZ 20 -#define WOLFSPDM_TCG_ALGORITHMS_RSP_SZ 52 -#define WOLFSPDM_TCG_MIN_DATA_TRANSFER_SZ 42 - -#define WOLFSPDM_TCG_CAP_ENCRYPT 0x00000040UL -#define WOLFSPDM_TCG_CAP_MAC 0x00000080UL -#define WOLFSPDM_TCG_CAP_KEY_EX 0x00000200UL -#define WOLFSPDM_TCG_CAP_PSK 0x00000400UL -#define WOLFSPDM_TCG_CAP_PSK_WITH_CONTEXT 0x00000800UL -#define WOLFSPDM_TCG_CAP_PSK_MASK 0x00000C00UL -#define WOLFSPDM_TCG_CAP_PUB_KEY_ID 0x00010000UL - -static int wolfSPDM_TCG_CheckResponse(WOLFSPDM_CTX* ctx, const byte* rsp, - word32 rspSz, word32 minRspSz, byte expectedCode) -{ - int errorCode; - - if (rspSz < 4) { - return WOLFSPDM_E_BUFFER_SMALL; - } - if (wolfSPDM_CheckError(rsp, rspSz, &errorCode)) { - wolfSPDM_DebugPrint(ctx, "SPDM error: 0x%02x\n", errorCode); - return WOLFSPDM_E_PEER_ERROR; - } - if (rspSz < minRspSz) { - return WOLFSPDM_E_BUFFER_SMALL; - } - if (rsp[0] != ctx->spdmVersion) { - return WOLFSPDM_E_VERSION_MISMATCH; - } - if (rsp[1] != expectedCode) { - return WOLFSPDM_E_PEER_ERROR; - } - - return WOLFSPDM_SUCCESS; -} - -static int wolfSPDM_TCG_CheckCapabilities(WOLFSPDM_CTX* ctx, - const byte* rsp, word32 rspSz, word32 capsFlags) -{ - word32 requiredFlags; - word32 rspFlags; - word32 dataTransferSz; - word32 maxSpdmMsgSz; - int rc; - - rc = wolfSPDM_TCG_CheckResponse(ctx, rsp, rspSz, - WOLFSPDM_TCG_CAPABILITIES_RSP_SZ, WOLFSPDM_TCG_CAPABILITIES_RSP); - if (rc != WOLFSPDM_SUCCESS) { - return rc; - } - if (rspSz != WOLFSPDM_TCG_CAPABILITIES_RSP_SZ) { - return WOLFSPDM_E_PEER_ERROR; - } - - requiredFlags = WOLFSPDM_TCG_CAP_ENCRYPT | WOLFSPDM_TCG_CAP_MAC | - WOLFSPDM_TCG_CAP_PUB_KEY_ID; - if ((capsFlags & WOLFSPDM_TCG_CAP_PSK) == 0) { - requiredFlags |= WOLFSPDM_TCG_CAP_KEY_EX; - } - - rspFlags = SPDM_Get32LE(rsp + 8); - dataTransferSz = SPDM_Get32LE(rsp + 12); - maxSpdmMsgSz = SPDM_Get32LE(rsp + 16); - if ((rspFlags & requiredFlags) != requiredFlags || - ((capsFlags & WOLFSPDM_TCG_CAP_PSK) != 0 && - (rspFlags & WOLFSPDM_TCG_CAP_PSK_MASK) != WOLFSPDM_TCG_CAP_PSK && - (rspFlags & WOLFSPDM_TCG_CAP_PSK_MASK) != - WOLFSPDM_TCG_CAP_PSK_WITH_CONTEXT) || - dataTransferSz < WOLFSPDM_TCG_MIN_DATA_TRANSFER_SZ || - maxSpdmMsgSz < dataTransferSz) { - return WOLFSPDM_E_PEER_ERROR; - } - - return WOLFSPDM_SUCCESS; -} - -static int wolfSPDM_TCG_CheckAlgorithms(WOLFSPDM_CTX* ctx, - const byte* rsp, word32 rspSz) -{ - static const byte expectedAlgStructs[16] = { - 0x02, 0x20, 0x10, 0x00, - 0x03, 0x20, 0x02, 0x00, - 0x04, 0x20, 0x80, 0x00, - 0x05, 0x20, 0x01, 0x00 - }; - int rc; - - rc = wolfSPDM_TCG_CheckResponse(ctx, rsp, rspSz, - WOLFSPDM_TCG_ALGORITHMS_RSP_SZ, WOLFSPDM_TCG_ALGORITHMS_RSP); - if (rc != WOLFSPDM_SUCCESS) { - return rc; - } - if (rspSz != WOLFSPDM_TCG_ALGORITHMS_RSP_SZ || - SPDM_Get16LE(rsp + 4) != rspSz || rsp[2] != 4 || rsp[3] != 0 || - rsp[6] != 0 || rsp[7] != 0x02 || - SPDM_Get32LE(rsp + 8) != 0 || - SPDM_Get32LE(rsp + 12) != 0x00000080UL || - SPDM_Get32LE(rsp + 16) != 0x00000002UL || - SPDM_Get32LE(rsp + 20) != 0 || SPDM_Get32LE(rsp + 24) != 0 || - SPDM_Get32LE(rsp + 28) != 0 || rsp[32] != 0 || rsp[33] != 0 || - rsp[34] != 0 || rsp[35] != 0 || - XMEMCMP(rsp + 36, expectedAlgStructs, - sizeof(expectedAlgStructs)) != 0) { - return WOLFSPDM_E_PEER_ERROR; - } - - return WOLFSPDM_SUCCESS; -} - -int wolfSPDM_TCG_GetCapabilities(WOLFSPDM_CTX* ctx, word32 capsFlags) -{ - byte capsReq[20]; - byte capsRsp[64]; - word32 capsRspSz = sizeof(capsRsp); - word32 off = 0; - int rc; - - if (ctx == NULL) { - return WOLFSPDM_E_INVALID_ARG; - } - - capsReq[off++] = ctx->spdmVersion; - capsReq[off++] = 0xE1; /* GET_CAPABILITIES */ - capsReq[off++] = 0x00; capsReq[off++] = 0x00; - /* Reserved(1) + CTExponent(1) + Reserved(2) */ - capsReq[off++] = 0x00; capsReq[off++] = 0x1F; - capsReq[off++] = 0x00; capsReq[off++] = 0x00; - /* Flags (4 bytes LE) */ - SPDM_Set32LE(capsReq + off, capsFlags); - off += 4; - /* DataTransferSize */ - capsReq[off++] = 0xC0; capsReq[off++] = 0x07; - capsReq[off++] = 0x00; capsReq[off++] = 0x00; - /* MaxSPDMmsgSize */ - capsReq[off++] = 0xC0; capsReq[off++] = 0x07; - capsReq[off++] = 0x00; capsReq[off++] = 0x00; - - wolfSPDM_DebugPrint(ctx, "TCG: GET_CAPABILITIES\n"); - rc = wolfSPDM_TranscriptAdd(ctx, capsReq, off); - if (rc == WOLFSPDM_SUCCESS) - rc = wolfSPDM_SendReceive(ctx, capsReq, off, capsRsp, &capsRspSz); - if (rc == WOLFSPDM_SUCCESS) - rc = wolfSPDM_TCG_CheckCapabilities(ctx, capsRsp, capsRspSz, - capsFlags); - if (rc == WOLFSPDM_SUCCESS) - rc = wolfSPDM_TranscriptAdd(ctx, capsRsp, capsRspSz); - if (rc != WOLFSPDM_SUCCESS) { - ctx->state = WOLFSPDM_STATE_ERROR; - } - return rc; -} - -int wolfSPDM_TCG_NegotiateAlgorithms(WOLFSPDM_CTX* ctx) -{ - /* Algorithm Set B: P-384/SHA-384/AES-256-GCM */ - byte algReq[48]; - byte algRsp[128]; - word32 algRspSz = sizeof(algRsp); - word32 off = 0; - int rc; - - if (ctx == NULL) { - return WOLFSPDM_E_INVALID_ARG; - } - - algReq[off++] = ctx->spdmVersion; - algReq[off++] = 0xE3; /* NEGOTIATE_ALGORITHMS */ - algReq[off++] = 0x04; /* Param1: NumAlgStructs = 4 */ - algReq[off++] = 0x00; - algReq[off++] = 0x30; algReq[off++] = 0x00; /* Length = 48 */ - algReq[off++] = 0x00; algReq[off++] = 0x02; /* MeasurementSpec + Reserved */ - /* BaseAsymAlgo: ECDSA_ECC_NIST_P384 */ - algReq[off++] = 0x80; algReq[off++] = 0x00; - algReq[off++] = 0x00; algReq[off++] = 0x00; - /* BaseHashAlgo: SHA_384 */ - algReq[off++] = 0x02; algReq[off++] = 0x00; - algReq[off++] = 0x00; algReq[off++] = 0x00; - /* Reserved (16 bytes) */ - XMEMSET(&algReq[off], 0, 16); off += 16; - /* AlgStruct[0]: DHE = SECP_384_R1 */ - algReq[off++] = 0x02; algReq[off++] = 0x20; - algReq[off++] = 0x10; algReq[off++] = 0x00; - /* AlgStruct[1]: AEAD = AES_256_GCM */ - algReq[off++] = 0x03; algReq[off++] = 0x20; - algReq[off++] = 0x02; algReq[off++] = 0x00; - /* AlgStruct[2]: ReqBaseAsymAlg = ECDSA_P384 */ - algReq[off++] = 0x04; algReq[off++] = 0x20; - algReq[off++] = 0x80; algReq[off++] = 0x00; - /* AlgStruct[3]: KeySchedule = SPDM */ - algReq[off++] = 0x05; algReq[off++] = 0x20; - algReq[off++] = 0x01; algReq[off++] = 0x00; - - wolfSPDM_DebugPrint(ctx, "TCG: NEGOTIATE_ALGORITHMS\n"); - rc = wolfSPDM_TranscriptAdd(ctx, algReq, off); - if (rc == WOLFSPDM_SUCCESS) - rc = wolfSPDM_SendReceive(ctx, algReq, off, algRsp, &algRspSz); - if (rc == WOLFSPDM_SUCCESS) - rc = wolfSPDM_TCG_CheckAlgorithms(ctx, algRsp, algRspSz); - if (rc == WOLFSPDM_SUCCESS) - rc = wolfSPDM_TranscriptAdd(ctx, algRsp, algRspSz); - if (rc != WOLFSPDM_SUCCESS) { - ctx->state = WOLFSPDM_STATE_ERROR; - } - return rc; -} - -/* ----- TCG SPDM Connection Flow ----- */ - -/* GET_VERSION -> [GET_CAPS -> NEG_ALGO] -> GET_PUBK -> KEY_EXCHANGE -> - * GIVE_PUB -> FINISH */ -int wolfSPDM_ConnectTCG(WOLFSPDM_CTX* ctx) -{ - int rc; - byte pubKey[WOLFSPDM_PUBKEY_BUF_SZ]; - word32 pubKeySz; - - if (ctx == NULL) { - return WOLFSPDM_E_INVALID_ARG; - } - - if (!ctx->flags.initialized) { - return WOLFSPDM_E_BAD_STATE; - } - - if (!ctx->flags.hasRspPubKey || - ctx->rspPubKeyLen != WOLFSPDM_ECC_POINT_SIZE) { - wolfSPDM_DebugPrint(ctx, - "TCG: Trusted responder public key is not configured\n"); - return WOLFSPDM_E_BAD_STATE; - } - - if (ctx->ioCb == NULL) { - return WOLFSPDM_E_IO_FAIL; - } - - wolfSPDM_DebugPrint(ctx, "TCG: Starting SPDM connection\n"); - - ctx->state = WOLFSPDM_STATE_INIT; - wolfSPDM_TranscriptReset(ctx); - - /* Step 1: GET_VERSION */ - SPDM_CONNECT_STEP(ctx, "TCG Step 1: GET_VERSION\n", - wolfSPDM_GetVersion(ctx)); - - /* Steps 2-3: GET_CAPABILITIES + NEGOTIATE_ALGORITHMS. - * TCG SPDM Binding mandates these before GET_PUB_KEY. Nuvoton silicon - * uses a simplified flow that skips them, so gate at runtime by mode. */ - if (ctx->mode != WOLFSPDM_MODE_NUVOTON) { - SPDM_CONNECT_STEP(ctx, "TCG Step 2: GET_CAPABILITIES\n", - wolfSPDM_TCG_GetCapabilities(ctx, WOLFSPDM_TCG_CAPS_FLAGS_DEFAULT)); - SPDM_CONNECT_STEP(ctx, "TCG Step 3: NEGOTIATE_ALGORITHMS\n", - wolfSPDM_TCG_NegotiateAlgorithms(ctx)); - } - - /* Step 4: GET_PUBK */ - wolfSPDM_DebugPrint(ctx, "TCG Step 4: GET_PUBK\n"); - pubKeySz = sizeof(pubKey); - rc = wolfSPDM_TCG_GetPubKey(ctx, pubKey, &pubKeySz); - if (rc != WOLFSPDM_SUCCESS) { - wolfSPDM_DebugPrint(ctx, "GET_PUBK failed: %d\n", rc); - ctx->state = WOLFSPDM_STATE_ERROR; - return rc; - } - ctx->state = WOLFSPDM_STATE_CERT; - - /* Compute Ct from the fetched wire object after its public point has - * matched the separately configured responder key. */ - wolfSPDM_DebugPrint(ctx, "TCG: Computing Ct = SHA-384(GET_PUBK[%u])\n", - pubKeySz); - rc = wolfSPDM_Sha384Hash(ctx->certChainHash, - pubKey, pubKeySz, NULL, 0, NULL, 0); - if (rc != WOLFSPDM_SUCCESS) { - ctx->state = WOLFSPDM_STATE_ERROR; - return rc; - } - rc = wolfSPDM_TranscriptAdd(ctx, ctx->certChainHash, - WOLFSPDM_HASH_SIZE); - if (rc != WOLFSPDM_SUCCESS) { - ctx->state = WOLFSPDM_STATE_ERROR; - return rc; - } - - /* Step 5: KEY_EXCHANGE */ - SPDM_CONNECT_STEP(ctx, "TCG Step 5: KEY_EXCHANGE\n", - wolfSPDM_KeyExchange(ctx)); - - /* Step 6: GIVE_PUB (secured) */ - if (ctx->flags.hasReqKeyPair && ctx->reqPubKeyTPMTLen > 0) { - wolfSPDM_DebugPrint(ctx, "TCG Step 6: GIVE_PUB\n"); - rc = wolfSPDM_TCG_GivePubKey(ctx, ctx->reqPubKeyTPMT, - ctx->reqPubKeyTPMTLen); - if (rc != WOLFSPDM_SUCCESS) { - wolfSPDM_DebugPrint(ctx, "GIVE_PUB failed: %d\n", rc); - ctx->state = WOLFSPDM_STATE_ERROR; - return rc; - } - } else { - wolfSPDM_DebugPrint(ctx, - "TCG Step 6: GIVE_PUB (skipped, no host key)\n"); - } - - /* Step 7: FINISH */ - SPDM_CONNECT_STEP(ctx, "TCG Step 7: FINISH\n", - wolfSPDM_Finish(ctx)); - - ctx->state = WOLFSPDM_STATE_CONNECTED; - wolfSPDM_DebugPrint(ctx, "TCG: SPDM Session Established! " - "SessionID=0x%08x\n", ctx->sessionId); - - return WOLFSPDM_SUCCESS; -} - -#endif /* WOLFTPM_SPDM_TCG */ - -#endif /* WOLFTPM_SPDM */ diff --git a/src/spdm/spdm_transcript.c b/src/spdm/spdm_transcript.c deleted file mode 100644 index 05bbd2b2c..000000000 --- a/src/spdm/spdm_transcript.c +++ /dev/null @@ -1,106 +0,0 @@ -/* spdm_transcript.c - * - * Copyright (C) 2006-2026 wolfSSL Inc. - * - * This file is part of wolfSPDM. - * - * wolfSPDM is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3 of the License, or - * (at your option) any later version. - * - * wolfSPDM is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA - */ - -#ifdef HAVE_CONFIG_H - #include -#endif - -#ifdef WOLFTPM_SPDM - -#include "spdm_internal.h" - -/* ----- Transcript Management ----- - * VCA = GET_VERSION || VERSION || GET_CAPS || CAPS || NEG_ALGO || ALGO - * Ct = Hash(certificate_chain) - * TH1 = Hash(VCA || Ct || KEY_EXCHANGE || KEY_EXCHANGE_RSP_partial || Signature) - * TH2 = Hash(VCA || Ct || message_k || FINISH_header) */ - -void wolfSPDM_TranscriptReset(WOLFSPDM_CTX* ctx) -{ - if (ctx == NULL) { - return; - } - - XMEMSET(ctx->transcript, 0, sizeof(ctx->transcript)); - ctx->transcriptLen = 0; - - XMEMSET(ctx->certChainHash, 0, sizeof(ctx->certChainHash)); - XMEMSET(ctx->th1, 0, sizeof(ctx->th1)); - XMEMSET(ctx->th2, 0, sizeof(ctx->th2)); -} - -int wolfSPDM_TranscriptAdd(WOLFSPDM_CTX* ctx, const byte* data, word32 len) -{ - if (ctx == NULL || data == NULL) { - return WOLFSPDM_E_INVALID_ARG; - } - - if (ctx->transcriptLen > WOLFSPDM_MAX_TRANSCRIPT || - len > WOLFSPDM_MAX_TRANSCRIPT - ctx->transcriptLen) { - return WOLFSPDM_E_BUFFER_SMALL; - } - - XMEMCPY(ctx->transcript + ctx->transcriptLen, data, len); - ctx->transcriptLen += len; - - wolfSPDM_DebugPrint(ctx, "Transcript: added %u bytes, total=%u\n", - len, ctx->transcriptLen); - - return WOLFSPDM_SUCCESS; -} - -int wolfSPDM_Sha384Hash(byte* out, - const byte* d1, word32 d1Sz, - const byte* d2, word32 d2Sz, - const byte* d3, word32 d3Sz) -{ - wc_Sha384 sha; - int rc; - - rc = wc_InitSha384(&sha); - if (rc != 0) return WOLFSPDM_E_CRYPTO_FAIL; - if (d1 != NULL && d1Sz > 0) { - rc = wc_Sha384Update(&sha, d1, d1Sz); - if (rc != 0) { wc_Sha384Free(&sha); return WOLFSPDM_E_CRYPTO_FAIL; } - } - if (d2 != NULL && d2Sz > 0) { - rc = wc_Sha384Update(&sha, d2, d2Sz); - if (rc != 0) { wc_Sha384Free(&sha); return WOLFSPDM_E_CRYPTO_FAIL; } - } - if (d3 != NULL && d3Sz > 0) { - rc = wc_Sha384Update(&sha, d3, d3Sz); - if (rc != 0) { wc_Sha384Free(&sha); return WOLFSPDM_E_CRYPTO_FAIL; } - } - rc = wc_Sha384Final(&sha, out); - wc_Sha384Free(&sha); - return (rc == 0) ? WOLFSPDM_SUCCESS : WOLFSPDM_E_CRYPTO_FAIL; -} - -int wolfSPDM_TranscriptHash(WOLFSPDM_CTX* ctx, byte* hash) -{ - if (ctx == NULL || hash == NULL) { - return WOLFSPDM_E_INVALID_ARG; - } - return wolfSPDM_Sha384Hash(hash, ctx->transcript, ctx->transcriptLen, - NULL, 0, NULL, 0); -} - -#endif /* WOLFTPM_SPDM */ diff --git a/src/spdm/wolfspdm/options.h b/src/spdm/wolfspdm/options.h new file mode 100644 index 000000000..e4fdde00b --- /dev/null +++ b/src/spdm/wolfspdm/options.h @@ -0,0 +1,30 @@ +/* options.h + * + * Copyright (C) 2006-2026 wolfSSL Inc. + * + * This file is part of wolfSPDM. + * + * wolfSPDM is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * wolfSPDM is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA + */ + +/* Installed as wolfspdm/options.h: wolfSPDM built into wolfTPM takes its + * switches from wolfTPM's options */ + +#ifndef WOLFSPDM_OPTIONS_H +#define WOLFSPDM_OPTIONS_H + +#include + +#endif /* WOLFSPDM_OPTIONS_H */ diff --git a/wolftpm/include.am b/wolftpm/include.am index 92e351e33..024dda9a7 100644 --- a/wolftpm/include.am +++ b/wolftpm/include.am @@ -33,3 +33,17 @@ nobase_include_HEADERS+= \ wolftpm/fwtpm/fwtpm_crypto.h \ wolftpm/fwtpm/fwtpm_nv.h \ wolftpm/fwtpm/fwtpm_tis.h + +if BUILD_SPDM +wolfspdmincdir = $(includedir)/wolfspdm +wolfspdminc_HEADERS = \ + lib/wolfSPDM/wolfspdm/spdm.h \ + lib/wolfSPDM/wolfspdm/spdm_types.h \ + lib/wolfSPDM/wolfspdm/spdm_error.h \ + lib/wolfSPDM/wolfspdm/spdm_tcg.h \ + lib/wolfSPDM/wolfspdm/spdm_nuvoton.h \ + lib/wolfSPDM/wolfspdm/spdm_nations.h \ + lib/wolfSPDM/wolfspdm/spdm_psk.h \ + lib/wolfSPDM/wolfspdm/spdm_responder.h \ + src/spdm/wolfspdm/options.h +endif diff --git a/wolftpm/spdm/spdm.h b/wolftpm/spdm/spdm.h index a694bfba4..9fa5043f5 100644 --- a/wolftpm/spdm/spdm.h +++ b/wolftpm/spdm/spdm.h @@ -19,132 +19,14 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA */ -#ifndef WOLFSPDM_SPDM_H -#define WOLFSPDM_SPDM_H +/* Forwards to the wolfSPDM submodule (lib/wolfSPDM) */ -#ifdef HAVE_CONFIG_H - #include -#endif - -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/* Protocol mode: TCG binding + vendor commands. - * For standard SPDM (emulator, measurements, challenge), see wolfSPDM standalone. */ -typedef enum { - WOLFSPDM_MODE_AUTO = 0, - WOLFSPDM_MODE_NUVOTON = 1, - WOLFSPDM_MODE_NATIONS = 2, - WOLFSPDM_MODE_NATIONS_PSK = 3 -} WOLFSPDM_MODE; - -/* wolfSPDM: Lightweight SPDM requester using wolfCrypt. - * Algorithm Set B fixed: P-384/SHA-384/AES-256-GCM. - * - * Usage (static, zero-malloc): - * WOLFSPDM_CTX ctx; - * wolfSPDM_Init(&ctx); - * wolfSPDM_SetIO(&ctx, callback, userPtr); - * wolfSPDM_SetResponderPubKey(&ctx, trustedPubKey, trustedPubKeySz); - * wolfSPDM_Connect(&ctx); - * wolfSPDM_SecuredExchange(&ctx, ...); - * wolfSPDM_Disconnect(&ctx); - * wolfSPDM_Free(&ctx); - * - * Dynamic (requires --enable-dynamic-mem): - * ctx = wolfSPDM_New(); - * // ... same as above ... - * wolfSPDM_Free(ctx); - * - * WOLFSPDM_CTX is ~22KB. Use static global on small-stack systems. - * SecuredExchange call chain uses ~20KB stack for message buffers. */ - -/* Compile-time buffer size for static allocation (32KB, runtime-verified) */ -#define WOLFSPDM_CTX_STATIC_SIZE 32768 - -struct WOLFSPDM_CTX; -typedef struct WOLFSPDM_CTX WOLFSPDM_CTX; - -#ifdef WOLFTPM_SPDM_TCG - #include -#endif -#ifdef WOLFSPDM_NUVOTON - #include -#endif -#ifdef WOLFSPDM_NATIONS - #include -#endif -#ifdef WOLFTPM_SPDM_PSK - #include -#endif - -/* I/O callback: transport-agnostic send/receive. - * Returns 0 on success, negative on error. - * rxSz: [in] buffer size, [out] actual received size. */ -typedef int (*WOLFSPDM_IO_CB)( - WOLFSPDM_CTX* ctx, - const byte* txBuf, word32 txSz, - byte* rxBuf, word32* rxSz, - void* userCtx -); - -/* Context management */ -WOLFTPM_API int wolfSPDM_Init(WOLFSPDM_CTX* ctx); -#ifdef WOLFTPM_SMALL_STACK -WOLFTPM_API WOLFSPDM_CTX* wolfSPDM_New(void); -#endif -WOLFTPM_API void wolfSPDM_Free(WOLFSPDM_CTX* ctx); -WOLFTPM_API int wolfSPDM_GetCtxSize(void); -WOLFTPM_API int wolfSPDM_InitStatic(WOLFSPDM_CTX* ctx, int size); - -/* Configuration */ -WOLFTPM_API int wolfSPDM_SetIO(WOLFSPDM_CTX* ctx, WOLFSPDM_IO_CB ioCb, - void* userCtx); -WOLFTPM_API int wolfSPDM_SetMode(WOLFSPDM_CTX* ctx, WOLFSPDM_MODE mode); -WOLFTPM_API WOLFSPDM_MODE wolfSPDM_GetMode(WOLFSPDM_CTX* ctx); -/* Pin the responder key for cert-less operation (96 bytes P-384 X||Y). - * Required before a TCG identity-key connection. */ -WOLFTPM_API int wolfSPDM_SetResponderPubKey(WOLFSPDM_CTX* ctx, - const byte* pubKey, word32 pubKeySz); -/* Set requester key pair for mutual auth (privKey=48, pubKey=96 bytes) */ -WOLFTPM_API int wolfSPDM_SetRequesterKeyPair(WOLFSPDM_CTX* ctx, - const byte* privKey, word32 privKeySz, - const byte* pubKey, word32 pubKeySz); - -/* Session establishment */ -WOLFTPM_API int wolfSPDM_Connect(WOLFSPDM_CTX* ctx); -WOLFTPM_API int wolfSPDM_IsConnected(WOLFSPDM_CTX* ctx); -WOLFTPM_API int wolfSPDM_Disconnect(WOLFSPDM_CTX* ctx); - -/* Individual handshake steps (for fine-grained control) */ -WOLFTPM_API int wolfSPDM_GetVersion(WOLFSPDM_CTX* ctx); -WOLFTPM_API int wolfSPDM_KeyExchange(WOLFSPDM_CTX* ctx); -WOLFTPM_API int wolfSPDM_Finish(WOLFSPDM_CTX* ctx); - -/* Secured messaging: encrypt, send, receive, decrypt in one call */ -WOLFTPM_API int wolfSPDM_SecuredExchange(WOLFSPDM_CTX* ctx, - const byte* cmdPlain, word32 cmdSz, - byte* rspPlain, word32* rspSz); - -/* Session info */ -WOLFTPM_API word32 wolfSPDM_GetSessionId(WOLFSPDM_CTX* ctx); -WOLFTPM_API byte wolfSPDM_GetNegotiatedVersion(WOLFSPDM_CTX* ctx); -#ifdef WOLFTPM_SPDM_TCG -WOLFTPM_API word32 wolfSPDM_GetConnectionHandle(WOLFSPDM_CTX* ctx); -WOLFTPM_API word16 wolfSPDM_GetFipsIndicator(WOLFSPDM_CTX* ctx); -#endif - -/* wolfSPDM_SetPSK declared in spdm_psk.h */ - -/* Debug */ -WOLFTPM_API void wolfSPDM_SetDebug(WOLFSPDM_CTX* ctx, int enable); +#ifndef WOLFTPM_SPDM_FWD_SPDM_H +#define WOLFTPM_SPDM_FWD_SPDM_H -#ifdef __cplusplus -} +#include +#ifdef WOLFTPM_SPDM + #include #endif -#endif /* WOLFSPDM_SPDM_H */ +#endif /* WOLFTPM_SPDM_FWD_SPDM_H */ diff --git a/wolftpm/spdm/spdm_error.h b/wolftpm/spdm/spdm_error.h index b6befc75e..f54ee00ef 100644 --- a/wolftpm/spdm/spdm_error.h +++ b/wolftpm/spdm/spdm_error.h @@ -19,47 +19,14 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA */ -#ifndef WOLFSPDM_ERROR_H -#define WOLFSPDM_ERROR_H +/* Forwards to the wolfSPDM submodule (lib/wolfSPDM) */ -#include +#ifndef WOLFTPM_SPDM_FWD_SPDM_ERROR_H +#define WOLFTPM_SPDM_FWD_SPDM_ERROR_H -#ifdef __cplusplus -extern "C" { +#include +#ifdef WOLFTPM_SPDM + #include #endif -/* wolfSPDM Error Codes */ -enum WOLFSPDM_ERROR { - WOLFSPDM_SUCCESS = 0, /* Operation successful */ - WOLFSPDM_E_INVALID_ARG = -1, /* Invalid argument provided */ - WOLFSPDM_E_BUFFER_SMALL = -2, /* Buffer too small for operation */ - WOLFSPDM_E_BAD_STATE = -3, /* Invalid state for operation */ - WOLFSPDM_E_VERSION_MISMATCH = -4, /* SPDM version negotiation failed */ - WOLFSPDM_E_CRYPTO_FAIL = -5, /* Cryptographic operation failed */ - WOLFSPDM_E_BAD_SIGNATURE = -6, /* Signature verification failed */ - WOLFSPDM_E_BAD_HMAC = -7, /* HMAC verification failed */ - WOLFSPDM_E_IO_FAIL = -8, /* I/O callback failed */ - WOLFSPDM_E_TIMEOUT = -9, /* Operation timed out */ - WOLFSPDM_E_PEER_ERROR = -10, /* Responder sent ERROR message */ - WOLFSPDM_E_DECRYPT_FAIL = -11, /* AEAD decryption/tag verification failed */ - WOLFSPDM_E_SEQUENCE = -12, /* Sequence number error */ - WOLFSPDM_E_NOT_CONNECTED = -13, /* Session not established */ - WOLFSPDM_E_ALREADY_INIT = -14, /* Context already initialized */ - WOLFSPDM_E_NO_MEMORY = -15, /* Memory allocation failed */ - WOLFSPDM_E_SESSION_INVALID = -16, /* Session ID invalid or mismatch */ - WOLFSPDM_E_KEY_EXCHANGE = -17, /* Key exchange failed */ - WOLFSPDM_E_NOT_AVAILABLE = -18, /* Feature/mode not compiled in */ - WOLFSPDM_E_FRAMING = -19, /* Frame did not parse (e.g. plaintext - * TPM2 sent while SPDM mode active - - * bus-snooping defence) */ - WOLFSPDM_E_NOT_IMPL = -20, /* Handler not yet implemented */ -}; - -/* Get human-readable error string */ -WOLFTPM_API const char* wolfSPDM_GetErrorString(int error); - -#ifdef __cplusplus -} -#endif - -#endif /* WOLFSPDM_ERROR_H */ +#endif /* WOLFTPM_SPDM_FWD_SPDM_ERROR_H */ diff --git a/wolftpm/spdm/spdm_nations.h b/wolftpm/spdm/spdm_nations.h index 361c3ea84..1c6162b26 100644 --- a/wolftpm/spdm/spdm_nations.h +++ b/wolftpm/spdm/spdm_nations.h @@ -19,81 +19,20 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA */ -/* Nations Technology NS350 TPM SPDM Support - * - * Two SPDM modes (mutually exclusive): - * - * 1. Identity key mode — TCG "TPM Communication over SPDM" - * - Uses shared TCG binding code (spdm_tcg.c) - * - GET_PUB_KEY, GIVE_PUB_KEY, TPM_CMD vendor commands - * - Algorithm Set B (P-384/SHA-384/AES-256-GCM) - * - * 2. PSK mode — PSK_EXCHANGE/PSK_FINISH - * - GET_STATUS, SPDM_ONLY, PSK_SET, PSK_CLEAR vendor commands - * - Same Algorithm Set B - * - * Reference: NS350 Datasheet Rev 2.06 Section 4.5.8 - */ - -#ifndef WOLFSPDM_NATIONS_H -#define WOLFSPDM_NATIONS_H +/* Forwards to the wolfSPDM submodule (lib/wolfSPDM) */ -#ifdef WOLFSPDM_NATIONS - -/* Include shared TCG declarations */ -#include +#ifndef WOLFTPM_SPDM_FWD_SPDM_NATIONS_H +#define WOLFTPM_SPDM_FWD_SPDM_NATIONS_H -#ifdef __cplusplus -extern "C" { +#include +#ifdef WOLFTPM_SPDM + #include #endif -/* ----- Nations Vendor TPM Command ----- */ - -#define TPM_CC_Nations_SpdmIdentityKeySet (0x20000708) - -/* Nations vendor capability properties */ -#define TPM_PT_VENDOR_NATIONS_FIPS_SL2 (TPM_PT_VENDOR + 11) -#define TPM_PT_VENDOR_NATIONS_IDENTITY_KEY (TPM_PT_VENDOR + 12) - -/* ----- Nations-Only Vendor-Defined Commands ----- */ - -#define WOLFSPDM_NATIONS_VDCODE_PSK_SET "PSK_SET_" -#define WOLFSPDM_NATIONS_VDCODE_PSK_CLEAR "PSK_CLR_" - -/* ----- Nations SPDM Status ----- */ - -/* GET_STATUS_RSP fields per TCG spec Table 15 */ -typedef struct WOLFSPDM_NATIONS_STATUS { - unsigned int spdmEnabled : 1; - unsigned int sessionActive : 1; - unsigned int spdmOnlyLocked : 1; - unsigned int spdmOnlyPending : 1; - unsigned int pskProvisioned : 1; - unsigned int identityKeyProvisioned : 1; -} WOLFSPDM_NATIONS_STATUS; - -/* ----- Nations PSK-Mode SPDM Functions ----- */ - -WOLFTPM_API int wolfSPDM_Nations_GetStatus(WOLFSPDM_CTX* ctx, - WOLFSPDM_NATIONS_STATUS* status); - -WOLFTPM_API int wolfSPDM_Nations_SetOnlyMode(WOLFSPDM_CTX* ctx, int lock); - -WOLFTPM_API int wolfSPDM_Nations_PskSet(WOLFSPDM_CTX* ctx, - const byte* psk, word32 pskSz); - -WOLFTPM_API int wolfSPDM_Nations_PskClear(WOLFSPDM_CTX* ctx, - const byte* clearAuth, word32 clearAuthSz); - -WOLFTPM_API int wolfSPDM_Nations_PskClearWithVCA(WOLFSPDM_CTX* ctx, - const byte* clearAuth, word32 clearAuthSz); - -/* wolfSPDM_ConnectNationsPsk is an alias for wolfSPDM_ConnectPsk (spdm_psk.h) */ - -#ifdef __cplusplus -} +#ifdef WOLFSPDM_NATIONS + #define TPM_CC_Nations_SpdmIdentityKeySet (0x20000708) + #define TPM_PT_VENDOR_NATIONS_FIPS_SL2 (TPM_PT_VENDOR + 11) + #define TPM_PT_VENDOR_NATIONS_IDENTITY_KEY (TPM_PT_VENDOR + 12) #endif -#endif /* WOLFSPDM_NATIONS */ - -#endif /* WOLFSPDM_NATIONS_H */ +#endif /* WOLFTPM_SPDM_FWD_SPDM_NATIONS_H */ diff --git a/wolftpm/spdm/spdm_nuvoton.h b/wolftpm/spdm/spdm_nuvoton.h index 42f92c22c..412b0ed5f 100644 --- a/wolftpm/spdm/spdm_nuvoton.h +++ b/wolftpm/spdm/spdm_nuvoton.h @@ -19,58 +19,14 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA */ -/* Nuvoton TPM SPDM Support - * - * Nuvoton-specific SPDM functions (GetStatus, SetOnlyMode). - * Shared TCG code is in spdm_tcg.h / spdm_tcg.c. - * - * The Nuvoton NPCT75x TPM uses a simplified SPDM flow: - * GET_VERSION -> GET_PUB_KEY -> KEY_EXCHANGE -> GIVE_PUB_KEY -> FINISH - * - * Notable differences from standard SPDM: - * - No GET_CAPABILITIES or NEGOTIATE_ALGORITHMS (Algorithm Set B is fixed) - * - Uses vendor-defined commands for identity key exchange - * - TCG binding headers wrap all SPDM messages - * - * Reference: Nuvoton SPDM Guidance Rev 1.11 - */ - -#ifndef WOLFSPDM_NUVOTON_H -#define WOLFSPDM_NUVOTON_H +/* Forwards to the wolfSPDM submodule (lib/wolfSPDM) */ -/* Include shared TCG declarations */ -#include +#ifndef WOLFTPM_SPDM_FWD_SPDM_NUVOTON_H +#define WOLFTPM_SPDM_FWD_SPDM_NUVOTON_H -#ifdef WOLFSPDM_NUVOTON - -#ifdef __cplusplus -extern "C" { +#include +#ifdef WOLFTPM_SPDM + #include #endif -/* ----- Nuvoton SPDM Status ----- */ - -typedef struct WOLFSPDM_NUVOTON_STATUS { - int spdmEnabled; - int sessionActive; - int spdmOnlyLocked; - byte specVersionMajor; - byte specVersionMinor; -} WOLFSPDM_NUVOTON_STATUS; - -/* ----- Nuvoton-Only Functions ----- */ - -WOLFTPM_API int wolfSPDM_Nuvoton_GetStatus( - WOLFSPDM_CTX* ctx, - WOLFSPDM_NUVOTON_STATUS* status); - -WOLFTPM_API int wolfSPDM_Nuvoton_SetOnlyMode( - WOLFSPDM_CTX* ctx, - int lock); - -#ifdef __cplusplus -} -#endif - -#endif /* WOLFSPDM_NUVOTON */ - -#endif /* WOLFSPDM_NUVOTON_H */ +#endif /* WOLFTPM_SPDM_FWD_SPDM_NUVOTON_H */ diff --git a/wolftpm/spdm/spdm_psk.h b/wolftpm/spdm/spdm_psk.h index 23c52761f..7a4647463 100644 --- a/wolftpm/spdm/spdm_psk.h +++ b/wolftpm/spdm/spdm_psk.h @@ -19,73 +19,14 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA */ -/* Shared SPDM PSK Support (DSP0274 1.2+) - * - * Standard SPDM PSK protocol: - * - PSK_EXCHANGE / PSK_EXCHANGE_RSP - * - PSK_FINISH / PSK_FINISH_RSP - * - PSK key derivation (HKDF-Extract with PSK) - * - Shared PSK connection flow - * - * Vendor-specific PSK provisioning commands (PSK_SET, PSK_CLEAR, etc.) - * remain in the vendor files (spdm_nations.c, etc.). - */ - -#ifndef WOLFSPDM_PSK_H -#define WOLFSPDM_PSK_H - -#include - -#ifdef WOLFTPM_SPDM_PSK - -#ifdef __cplusplus -extern "C" { -#endif - -/* ----- PSK Context Setup ----- */ - -WOLFTPM_API int wolfSPDM_SetPSK(WOLFSPDM_CTX* ctx, - const byte* psk, word32 pskSz, - const byte* hint, word32 hintSz); - -/* ----- PSK Message Builders/Parsers ----- */ +/* Forwards to the wolfSPDM submodule (lib/wolfSPDM) */ -WOLFTPM_API int wolfSPDM_BuildPskExchange(WOLFSPDM_CTX* ctx, - byte* buf, word32* bufSz); +#ifndef WOLFTPM_SPDM_FWD_SPDM_PSK_H +#define WOLFTPM_SPDM_FWD_SPDM_PSK_H -WOLFTPM_API int wolfSPDM_ParsePskExchangeRsp(WOLFSPDM_CTX* ctx, - const byte* buf, word32 bufSz); - -WOLFTPM_API int wolfSPDM_BuildPskFinish(WOLFSPDM_CTX* ctx, - byte* buf, word32* bufSz); - -WOLFTPM_API int wolfSPDM_ParsePskFinishRsp(WOLFSPDM_CTX* ctx, - const byte* buf, word32 bufSz); - -/* ----- PSK Key Derivation ----- */ - -WOLFTPM_API int wolfSPDM_DeriveHandshakeKeysPsk(WOLFSPDM_CTX* ctx, - const byte* th1Hash); - -/* ----- Shared PSK Connection Flow ----- */ - -/** - * Perform PSK SPDM connection. - * GET_VERSION -> GET_CAPABILITIES -> NEGOTIATE_ALGORITHMS -> - * PSK_EXCHANGE -> PSK_FINISH -> app key derivation. - * - * @param ctx wolfSPDM context (must have PSK set via wolfSPDM_SetPSK) - * @return WOLFSPDM_SUCCESS or negative error code - */ -WOLFTPM_API int wolfSPDM_ConnectPsk(WOLFSPDM_CTX* ctx); - -/* Backward compatibility */ -#define wolfSPDM_ConnectNationsPsk wolfSPDM_ConnectPsk - -#ifdef __cplusplus -} +#include +#ifdef WOLFTPM_SPDM + #include #endif -#endif /* WOLFTPM_SPDM_PSK */ - -#endif /* WOLFSPDM_PSK_H */ +#endif /* WOLFTPM_SPDM_FWD_SPDM_PSK_H */ diff --git a/wolftpm/spdm/spdm_responder.h b/wolftpm/spdm/spdm_responder.h index ca9223e41..a942247c3 100644 --- a/wolftpm/spdm/spdm_responder.h +++ b/wolftpm/spdm/spdm_responder.h @@ -19,94 +19,14 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA */ -/* SPDM responder. Lives above fwtpm's transport HAL and reuses wolfSPDM - * crypto + framing helpers, flipped to answer requester-driven messages. */ +/* Forwards to the wolfSPDM submodule (lib/wolfSPDM) */ -#ifndef WOLFSPDM_RESPONDER_H -#define WOLFSPDM_RESPONDER_H +#ifndef WOLFTPM_SPDM_FWD_SPDM_RESPONDER_H +#define WOLFTPM_SPDM_FWD_SPDM_RESPONDER_H -#ifdef HAVE_CONFIG_H - #include +#include +#ifdef WOLFTPM_SPDM + #include #endif -#include - -#ifdef WOLFTPM_SPDM_RESPONDER - -#ifdef __cplusplus -extern "C" { -#endif - -struct WOLFSPDM_RESP_CTX; -typedef struct WOLFSPDM_RESP_CTX WOLFSPDM_RESP_CTX; - -/* Dispatcher for tunneled TPM2_CMD payloads. fwtpm_server wires this to - * FWTPM_ProcessCommand; unit tests wire a stub. */ -typedef int (*WOLFSPDM_RESP_TPM_CB)(void* userCtx, - const byte* cmd, word32 cmdSz, - byte* resp, word32 respBufSz, word32* respSz); - -WOLFTPM_API int wolfSPDM_RespInit(WOLFSPDM_RESP_CTX* ctx); -WOLFTPM_API void wolfSPDM_RespFree(WOLFSPDM_RESP_CTX* ctx); - -/* The tunnel buffers stay at WOLFSPDM_MAX_MSG_SIZE: the secured path - * (encrypt, transport and requester buffers) is capped there too, so a - * larger TPM response could not be delivered even if staged here. */ -#define WOLFSPDM_MAX_TPM_MSG_SIZE WOLFSPDM_MAX_MSG_SIZE - -/* RESP_CTX embeds the requester CTX + four MAX_MSG_SIZE working buffers - * (4 * 4096) + identity/PSK material + tpm callback + flags. Static buffer - * is sized for that worst case; spdm_responder.c has a compile-time assert - * so it can't silently undersize. */ -#define WOLFSPDM_RESP_CTX_STATIC_SIZE \ - (WOLFSPDM_CTX_STATIC_SIZE + (4 * WOLFSPDM_MAX_MSG_SIZE) + 1024) -WOLFTPM_API int wolfSPDM_RespGetCtxSize(void); - -WOLFTPM_API int wolfSPDM_RespSetMode(WOLFSPDM_RESP_CTX* ctx, - int useTcg, int usePsk); - -WOLFTPM_API int wolfSPDM_RespSetPSK(WOLFSPDM_RESP_CTX* ctx, - const byte* psk, word32 pskSz, - const byte* hint, word32 hintSz); - -/* privKey: 48 bytes (P-384 scalar). pubKey: 96 bytes (X||Y, big-endian). - * Rejected with WOLFSPDM_E_BAD_STATE while a session is negotiating or - * connected; reset the responder first. */ -WOLFTPM_API int wolfSPDM_RespSetIdentityKey(WOLFSPDM_RESP_CTX* ctx, - const byte* privKey, word32 privSz, - const byte* pubKey, word32 pubSz); - -WOLFTPM_API int wolfSPDM_RespSetTpmCallback(WOLFSPDM_RESP_CTX* ctx, - WOLFSPDM_RESP_TPM_CB cb, void* userCtx); - -WOLFTPM_API void wolfSPDM_RespSetDebug(WOLFSPDM_RESP_CTX* ctx, int enable); - -/* Returns WOLFSPDM_E_FRAMING on a non-TCG inbound frame. Callers MUST drop - * the connection on E_FRAMING; never fall through to the TPM parser. */ -WOLFTPM_API int wolfSPDM_RespHandleMessage(WOLFSPDM_RESP_CTX* ctx, - const byte* inBuf, word32 inSz, - byte* outBuf, word32* outSz); - -WOLFTPM_API void wolfSPDM_RespReset(WOLFSPDM_RESP_CTX* ctx); - -/* SPDMONLY lock: when 1, the transport must reject plaintext TPM frames. - * Toggled by the requester via SPDMONLY vendor command. */ -WOLFTPM_API int wolfSPDM_RespIsLocked(const WOLFSPDM_RESP_CTX* ctx); - -/* Returns 1 when a secured SPDM session is established. */ -WOLFTPM_API int wolfSPDM_RespIsSessionActive(const WOLFSPDM_RESP_CTX* ctx); - -/* On success, points idPub at the responder's own SPDM identity key (raw - * P-384 X||Y) and returns its length. Returns 0 when there is no identity - * key or the active session did not authenticate with it (PSK sessions). - * The requester's key is never exposed: no requester mutual-auth is done. */ -WOLFTPM_API word32 wolfSPDM_RespGetIdentityKey(const WOLFSPDM_RESP_CTX* ctx, - const byte** idPub); - -#ifdef __cplusplus -} -#endif - -#endif /* WOLFTPM_SPDM_RESPONDER */ - -#endif /* WOLFSPDM_RESPONDER_H */ +#endif /* WOLFTPM_SPDM_FWD_SPDM_RESPONDER_H */ diff --git a/wolftpm/spdm/spdm_tcg.h b/wolftpm/spdm/spdm_tcg.h index fd9ac1225..84b29c7c1 100644 --- a/wolftpm/spdm/spdm_tcg.h +++ b/wolftpm/spdm/spdm_tcg.h @@ -19,160 +19,14 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA */ -/* Shared TCG SPDM Binding Support - * - * This header provides shared TCG SPDM functionality used by both - * Nuvoton and Nations Technology TPMs: - * - TCG SPDM Binding message framing (per TCG SPDM Binding Spec v1.0) - * - Vendor-defined command helpers - * - Identity key exchange (GET_PUBK, GIVE_PUB) - * - GET_CAPABILITIES + NEGOTIATE_ALGORITHMS - * - TCG SPDM connection flow - */ - -#ifndef WOLFSPDM_TCG_H -#define WOLFSPDM_TCG_H - -#include - -/* Transport framing constants - needed by any SPDM-over-TPM build, - * not just the TCG cert handshake. */ - -/* Message Tags */ -#define WOLFSPDM_TCG_TAG_CLEAR 0x8101 /* Clear (unencrypted) message */ -#define WOLFSPDM_TCG_TAG_SECURED 0x8201 /* Secured (encrypted) message */ +/* Forwards to the wolfSPDM submodule (lib/wolfSPDM) */ -/* Header Sizes */ -#define WOLFSPDM_TCG_HEADER_SIZE 16 /* TCG binding header size */ +#ifndef WOLFTPM_SPDM_FWD_SPDM_TCG_H +#define WOLFTPM_SPDM_FWD_SPDM_TCG_H -#ifdef WOLFTPM_SPDM_TCG - -#ifdef __cplusplus -extern "C" { +#include +#ifdef WOLFTPM_SPDM + #include #endif -/* ----- TCG SPDM Binding Constants (per TCG SPDM Binding Spec v1.0) ----- */ - -/* FIPS Service Indicator */ -#define WOLFSPDM_FIPS_NON_FIPS 0x00 -#define WOLFSPDM_FIPS_APPROVED 0x01 - -/* ----- TCG Vendor-Defined Command Codes (shared) ----- */ - -/* 8-byte ASCII vendor codes for SPDM VENDOR_DEFINED messages */ -#define WOLFSPDM_VDCODE_LEN 8 - -#define WOLFSPDM_VDCODE_TPM2_CMD "TPM2_CMD" /* TPM command over SPDM */ - -/* Locality-aware TPM command VdCodes (TCG spec Table 11, optional). - * Response to all TPM_CMD_L* is TPM_RSP with VdCode "TPM2_CMD". - * Not currently used -- our code sends TPM2_CMD for all localities. */ -#define WOLFSPDM_VDCODE_TPM2CMD0 "TPM2CMD0" /* TPM_CMD_L0: locality 0 */ -#define WOLFSPDM_VDCODE_TPM2CMD1 "TPM2CMD1" /* TPM_CMD_L1: locality 1 */ -#define WOLFSPDM_VDCODE_TPM2CMD2 "TPM2CMD2" /* TPM_CMD_L2: locality 2 */ -#define WOLFSPDM_VDCODE_TPM2CMD3 "TPM2CMD3" /* TPM_CMD_L3: locality 3 */ -#define WOLFSPDM_VDCODE_TPM2CMD4 "TPM2CMD4" /* TPM_CMD_L4: locality 4 */ -#define WOLFSPDM_VDCODE_GET_PUBK "GET_PUBK" /* Get TPM's identity key */ -#define WOLFSPDM_VDCODE_GIVE_PUB "GIVE_PUB" /* Give host's identity key */ -#define WOLFSPDM_VDCODE_GET_STS "GET_STS_" /* Get SPDM status */ -#define WOLFSPDM_VDCODE_SPDMONLY "SPDMONLY" /* Lock/unlock SPDM-only */ - -/* SPDMONLY command parameters */ -#define WOLFSPDM_SPDMONLY_LOCK 0x01 -#define WOLFSPDM_SPDMONLY_UNLOCK 0x00 - -/* ----- TCG Binding Header Structures ----- */ - -/* Clear message header (tag 0x8101) - * Layout: tag(2/BE) + size(4/BE) + connectionHandle(4/BE) + - * fipsIndicator(2/BE) + reserved(4) = 16 bytes */ -typedef struct WOLFSPDM_TCG_CLEAR_HDR { - word16 tag; - word32 size; - word32 connectionHandle; - word16 fipsIndicator; - word32 reserved; -} WOLFSPDM_TCG_CLEAR_HDR; - -/* ----- Vendor Command Response Container ----- */ - -typedef struct { - char vdCode[WOLFSPDM_VDCODE_LEN + 1]; - byte payload[WOLFSPDM_VENDOR_BUF_SZ]; - word32 payloadSz; -} WOLFSPDM_VENDOR_RSP; - -/* ----- Vendor Command Helpers ----- */ - -WOLFTPM_API int wolfSPDM_TCG_VendorCmdClear(WOLFSPDM_CTX* ctx, - const char* vdCode, const byte* payload, word32 payloadSz, - WOLFSPDM_VENDOR_RSP* rsp); - -WOLFTPM_API int wolfSPDM_TCG_VendorCmdSecured(WOLFSPDM_CTX* ctx, - const char* vdCode, const byte* payload, word32 payloadSz); - -/* ----- TCG Binding Message Framing ----- */ - -WOLFTPM_API int wolfSPDM_BuildTcgClearMessage( - WOLFSPDM_CTX* ctx, - const byte* spdmPayload, word32 spdmPayloadSz, - byte* outBuf, word32 outBufSz); - -WOLFTPM_API int wolfSPDM_ParseTcgClearMessage( - const byte* inBuf, word32 inBufSz, - byte* spdmPayload, word32* spdmPayloadSz, - WOLFSPDM_TCG_CLEAR_HDR* hdr); - -/* ----- Vendor-Defined Message Helpers ----- */ - -WOLFTPM_API int wolfSPDM_BuildVendorDefined( - byte spdmVersion, const char* vdCode, - const byte* payload, word32 payloadSz, - byte* outBuf, word32 outBufSz); - -WOLFTPM_API int wolfSPDM_ParseVendorDefined( - const byte* inBuf, word32 inBufSz, char* vdCode, - byte* payload, word32* payloadSz); - -/* ----- Shared TCG SPDM Functions ----- */ - -/* Cleartext key discovery. The result is never installed as trusted state. - * If a responder key is pinned, the discovered public point must match it. */ -WOLFTPM_API int wolfSPDM_TCG_GetPubKey(WOLFSPDM_CTX* ctx, - byte* pubKey, word32* pubKeySz); - -WOLFTPM_API int wolfSPDM_TCG_GivePubKey(WOLFSPDM_CTX* ctx, - const byte* pubKey, word32 pubKeySz); - -WOLFTPM_API int wolfSPDM_TCG_GetCapabilities(WOLFSPDM_CTX* ctx, - word32 capsFlags); - -WOLFTPM_API int wolfSPDM_TCG_NegotiateAlgorithms(WOLFSPDM_CTX* ctx); - -WOLFTPM_API int wolfSPDM_SetRequesterKeyTPMT(WOLFSPDM_CTX* ctx, - const byte* tpmtPub, word32 tpmtPubSz); - -WOLFTPM_API int wolfSPDM_ConnectTCG(WOLFSPDM_CTX* ctx); - -/* Backward compatibility aliases */ -#define wolfSPDM_ConnectNuvoton wolfSPDM_ConnectTCG -#define wolfSPDM_Nuvoton_GetPubKey wolfSPDM_TCG_GetPubKey -#define wolfSPDM_Nuvoton_GivePubKey wolfSPDM_TCG_GivePubKey - -/* ----- TCG Context Defaults ----- */ - -#define WOLFSPDM_NUVOTON_CONN_HANDLE_DEFAULT 0 -#define WOLFSPDM_NUVOTON_FIPS_DEFAULT WOLFSPDM_FIPS_NON_FIPS - -/* Default capabilities flags (identity key mode, no PSK_CAP) */ -#define WOLFSPDM_TCG_CAPS_FLAGS_DEFAULT 0x000193C0UL -/* Capabilities flags with PSK_CAP (bit 10) set */ -#define WOLFSPDM_TCG_CAPS_FLAGS_PSK 0x000197C0UL - -#ifdef __cplusplus -} -#endif - -#endif /* WOLFTPM_SPDM_TCG */ - -#endif /* WOLFSPDM_TCG_H */ +#endif /* WOLFTPM_SPDM_FWD_SPDM_TCG_H */ diff --git a/wolftpm/spdm/spdm_types.h b/wolftpm/spdm/spdm_types.h index eb62ec497..d589a8571 100644 --- a/wolftpm/spdm/spdm_types.h +++ b/wolftpm/spdm/spdm_types.h @@ -19,153 +19,14 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA */ -#ifndef WOLFSPDM_TYPES_H -#define WOLFSPDM_TYPES_H +/* Forwards to the wolfSPDM submodule (lib/wolfSPDM) */ -/* wolfSSL options MUST be included first */ -#ifndef WOLFSSL_USER_SETTINGS - #include -#endif -#include - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/* Include wolfSSL types */ -#ifndef WOLFSSL_TYPES - #include -#endif - -/* ----- SPDM Protocol Constants (DMTF DSP0274 / DSP0277) ----- */ - -/* SPDM Version Numbers (used in version negotiation and key derivation) */ -#define SPDM_VERSION_10 0x10 /* GET_VERSION always uses 1.0 */ -#define SPDM_VERSION_12 0x12 /* SPDM 1.2 */ -#define SPDM_VERSION_13 0x13 /* SPDM 1.3 */ -#define SPDM_VERSION_14 0x14 /* SPDM 1.4 */ - -/* SPDM Request Codes (used by this implementation) */ -#define SPDM_GET_VERSION 0x84 -#define SPDM_KEY_EXCHANGE 0xE4 -#define SPDM_FINISH 0xE5 -#define SPDM_END_SESSION 0xEC -#define SPDM_VENDOR_DEFINED_REQUEST 0xFE - -/* SPDM Response Codes (used by this implementation) */ -#define SPDM_VERSION 0x04 -#define SPDM_KEY_EXCHANGE_RSP 0x64 -#define SPDM_FINISH_RSP 0x65 -#define SPDM_END_SESSION_ACK 0x6C -#define SPDM_ERROR 0x7F - -/* SPDM Error Codes (in Param1 of ERROR response) */ -#define SPDM_ERROR_INVALID_REQUEST 0x01 -#define SPDM_ERROR_BUSY 0x03 -#define SPDM_ERROR_UNEXPECTED_REQUEST 0x04 -#define SPDM_ERROR_UNSPECIFIED 0x05 -#define SPDM_ERROR_DECRYPT_ERROR 0x06 -#define SPDM_ERROR_UNSUPPORTED_REQUEST 0x07 -#define SPDM_ERROR_REQUEST_IN_FLIGHT 0x08 -#define SPDM_ERROR_INVALID_RESPONSE 0x09 -#define SPDM_ERROR_SESSION_LIMIT 0x0A -#define SPDM_ERROR_SESSION_REQUIRED 0x0B -#define SPDM_ERROR_RESET_REQUIRED 0x0C -#define SPDM_ERROR_RESPONSE_TOO_LARGE 0x0D -#define SPDM_ERROR_REQUEST_TOO_LARGE 0x0E -#define SPDM_ERROR_LARGE_RESPONSE 0x0F -#define SPDM_ERROR_MSG_LOST 0x10 -#define SPDM_ERROR_MAJOR_VERSION_MISMATCH 0x41 -#define SPDM_ERROR_RESPONSE_NOT_READY 0x42 -#define SPDM_ERROR_REQUEST_RESYNCH 0x43 - -/* Algorithm Set B Fixed Parameters (FIPS 140-3 Level 3 compliant) - * P-384 ECDSA/ECDH, SHA-384, AES-256-GCM, HKDF */ -#define WOLFSPDM_HASH_SIZE 48 /* SHA-384 output size */ -#define WOLFSPDM_ECC_KEY_SIZE 48 /* P-384 coordinate size */ -#define WOLFSPDM_ECC_POINT_SIZE (2 * WOLFSPDM_ECC_KEY_SIZE) /* P-384 X||Y */ -#define WOLFSPDM_ECC_SIG_SIZE (2 * WOLFSPDM_ECC_KEY_SIZE) /* ECDSA r||s */ -#define WOLFSPDM_AEAD_KEY_SIZE 32 /* AES-256 key size */ -#define WOLFSPDM_AEAD_IV_SIZE 12 /* AES-GCM IV size */ -#define WOLFSPDM_AEAD_TAG_SIZE 16 /* AES-GCM tag size */ -#define WOLFSPDM_AEAD_OVERHEAD 48 /* Max AEAD record overhead (hdr+pad+tag) */ - -/* ----- Buffer/Message Size Limits ----- */ - -#define WOLFSPDM_MAX_MSG_SIZE 4096 /* Maximum SPDM message size */ -#define WOLFSPDM_MAX_TRANSCRIPT 4096 /* Maximum transcript buffer */ -#define WOLFSPDM_RANDOM_SIZE 32 /* Random data in KEY_EXCHANGE */ - -/* ----- MCTP Transport Constants ----- */ - -#define MCTP_MESSAGE_TYPE_SPDM 0x05 /* SPDM over MCTP */ - -/* ----- Key Derivation Labels (SPDM 1.2 per DSP0277) ----- */ - -#define SPDM_BIN_CONCAT_PREFIX_12 "spdm1.2 " -#define SPDM_BIN_CONCAT_PREFIX_13 "spdm1.3 " -#define SPDM_BIN_CONCAT_PREFIX_14 "spdm1.4 " -#define SPDM_BIN_CONCAT_PREFIX_LEN 8 - -#define SPDM_LABEL_REQ_HS_DATA "req hs data" -#define SPDM_LABEL_RSP_HS_DATA "rsp hs data" -#define SPDM_LABEL_REQ_DATA "req app data" -#define SPDM_LABEL_RSP_DATA "rsp app data" -#define SPDM_LABEL_FINISHED "finished" -#define SPDM_LABEL_KEY "key" -#define SPDM_LABEL_IV "iv" - -/* ----- Buffer Size Macros (overridable) ----- */ - -#ifndef WOLFSPDM_KEY_EX_TX_SZ -#define WOLFSPDM_KEY_EX_TX_SZ 192 /* KEY_EXCHANGE request (~158 bytes) */ -#endif -#ifndef WOLFSPDM_KEY_EX_RX_SZ -#define WOLFSPDM_KEY_EX_RX_SZ 384 /* KEY_EXCHANGE_RSP (~302 bytes) */ -#endif -#ifndef WOLFSPDM_FINISH_BUF_SZ -#define WOLFSPDM_FINISH_BUF_SZ 152 /* FINISH mutual auth (~148 bytes) */ -#endif -#ifndef WOLFSPDM_VENDOR_BUF_SZ -#define WOLFSPDM_VENDOR_BUF_SZ 256 /* Vendor command message/payload */ -#endif -#ifndef WOLFSPDM_VENDOR_RX_SZ -#define WOLFSPDM_VENDOR_RX_SZ 512 /* Vendor response buffer */ -#endif -#ifndef WOLFSPDM_PUBKEY_BUF_SZ -#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 */ -#if defined(WOLFSPDM_NATIONS) && !defined(WOLFTPM_SPDM_PSK) - #define WOLFTPM_SPDM_PSK -#endif - -/* ----- PSK Message Codes (SPDM 1.2+ DSP0274) ----- */ - -#define SPDM_PSK_EXCHANGE 0xE6 -#define SPDM_PSK_EXCHANGE_RSP 0x66 -#define SPDM_PSK_FINISH 0xE7 -#define SPDM_PSK_FINISH_RSP 0x67 - -/* ----- PSK Size Limits ----- */ +#ifndef WOLFTPM_SPDM_FWD_SPDM_TYPES_H +#define WOLFTPM_SPDM_FWD_SPDM_TYPES_H -#define WOLFSPDM_PSK_MAX_SIZE 64 /* Max PSK size (Nations NS350) */ -#define WOLFSPDM_PSK_HINT_MAX 32 /* Max PSK hint size */ -#ifdef __cplusplus -} +#include +#ifdef WOLFTPM_SPDM + #include #endif -#endif /* WOLFSPDM_TYPES_H */ +#endif /* WOLFTPM_SPDM_FWD_SPDM_TYPES_H */