From 6f8bae6c58486478ad55c040b520eb621086a97c Mon Sep 17 00:00:00 2001 From: Aidan Garske Date: Fri, 8 May 2026 10:04:01 -0700 Subject: [PATCH 1/4] Fix changes to pqc header file rename --- configure.ac | 6 +++--- src/fwtpm/fwtpm_crypto.c | 2 +- src/tpm2_wrap.c | 10 +++------- tests/fwtpm_unit_tests.c | 2 +- 4 files changed, 8 insertions(+), 12 deletions(-) diff --git a/configure.ac b/configure.ac index 0b39dec3..032e1fee 100644 --- a/configure.ac +++ b/configure.ac @@ -714,7 +714,7 @@ else test "x$ENABLED_WOLFCRYPT" = "xyes" then # Probe the actual symbols, not just the headers. wolfSSL ships - # dilithium.h / mlkem.h even without the implementation compiled + # dilithium.h / wc_mlkem.h even without the implementation compiled # (function decls are gated behind HAVE_DILITHIUM / HAVE_MLKEM # which only get defined via wolfssl/options.h after the right # --enable-* flags). Include options.h first so the gate is set @@ -728,7 +728,7 @@ else [WOLFTPM_HAVE_MLKEM_FN=yes], [WOLFTPM_HAVE_MLKEM_FN=no], [[#include - #include ]]) + #include ]]) if test "x$WOLFTPM_HAVE_DILITHIUM_FN" = "xyes" && \ test "x$WOLFTPM_HAVE_MLKEM_FN" = "xyes" then @@ -756,7 +756,7 @@ then AC_CHECK_DECL([wc_MlKemKey_Init], [], [AC_MSG_ERROR([--enable-v185/--enable-pqc requires wolfSSL built with --enable-mlkem --enable-experimental])], [[#include - #include ]]) + #include ]]) AM_CFLAGS="$AM_CFLAGS -DWOLFTPM_V185" fi AM_CONDITIONAL([BUILD_V185], [test "x$ENABLED_V185" = "xyes"]) diff --git a/src/fwtpm/fwtpm_crypto.c b/src/fwtpm/fwtpm_crypto.c index 68695992..508cbe3e 100644 --- a/src/fwtpm/fwtpm_crypto.c +++ b/src/fwtpm/fwtpm_crypto.c @@ -61,7 +61,7 @@ #include #ifdef WOLFTPM_V185 #include -#include +#include #endif /* ================================================================== */ diff --git a/src/tpm2_wrap.c b/src/tpm2_wrap.c index 1edafc2d..fd41133d 100644 --- a/src/tpm2_wrap.c +++ b/src/tpm2_wrap.c @@ -2285,14 +2285,10 @@ static int wolfTPM2_EncryptSecret_RSA(WOLFTPM2_DEV* dev, const WOLFTPM2_KEY* tpm #if defined(WOLFTPM_V185) && !defined(WOLFTPM2_NO_WOLFCRYPT) && \ (defined(WOLFSSL_HAVE_MLKEM) || defined(WOLFSSL_KYBER512) || \ defined(WOLFSSL_KYBER768) || defined(WOLFSSL_KYBER1024)) -#include -/* mlkem.h only forward-declares struct MlKemKey; pull the impl header - * for the full struct so callers can stack-allocate. Pattern mirrors - * wolfssl/wolfcrypt/cryptocb.h. */ -#ifdef WOLFSSL_WC_MLKEM - #include -#elif defined(HAVE_LIBOQS) +#if defined(HAVE_LIBOQS) #include +#else + #include #endif /* ML-KEM session-salt path per TCG TPM 2.0 Library v1.85 Part 1 Sec.24 diff --git a/tests/fwtpm_unit_tests.c b/tests/fwtpm_unit_tests.c index cc83b4f1..573fb9b5 100644 --- a/tests/fwtpm_unit_tests.c +++ b/tests/fwtpm_unit_tests.c @@ -2920,7 +2920,7 @@ static void test_fwtpm_mldsa_sequence_roundtrip(void) #include "pqc_kat_vectors.h" #include -#include +#include /* Layer A: wolfCrypt-only verify against NIST ACVP MLDSA-44 pinned vector. */ static void test_fwtpm_mldsa_nist_kat_verify(void) From 182230c9336804a522f364c1067a70b2c386b72a Mon Sep 17 00:00:00 2001 From: Aidan Garske Date: Fri, 8 May 2026 13:10:52 -0700 Subject: [PATCH 2/4] PR #501: enforce wolfSSL >= v5.8.0 floor for PQC + add nightly upstream-drift CI configure.ac: add LIBWOLFSSL_VERSION_HEX check so --enable-v185/--enable-pqc fails fast against unsupported wolfSSL releases (kyber.h era), instead of relying on transitive header aliasing through wc_mlkem.h. Add .github/workflows/wolfssl-versions.yml matrix: builds wolfTPM PQC against wolfSSL v5.8.0-stable, v5.8.4-stable, v5.9.1-stable, and master. Catches the next upstream rename within the matrix run, not 9 days later. Add .github/workflows/nightly.yml: cron 02:17 UTC fan-out via repository_dispatch[nightly-trigger]. 12 workflows opt in (cmake-build, codespell, fwtpm-test, make-test-swtpm, multi-compiler, pqc-examples, release-checks, sanitizer, seal-test, win-test, wolfssl-versions, zephyr). hw-spdm-test deliberately does NOT opt in so the self-hosted Pi runner cannot be batch-triggered. repository_dispatch is API-only (no UI button) so only the nightly job can fire these. --- .github/workflows/cmake-build.yml | 2 + .github/workflows/codespell.yml | 2 + .github/workflows/fwtpm-test.yml | 2 + .github/workflows/make-test-swtpm.yml | 2 + .github/workflows/multi-compiler.yml | 2 + .github/workflows/nightly.yml | 40 +++++++++++ .github/workflows/pqc-examples.yml | 2 + .github/workflows/release-checks.yml | 2 + .github/workflows/sanitizer.yml | 2 + .github/workflows/seal-test.yml | 2 + .github/workflows/win-test.yml | 2 + .github/workflows/wolfssl-versions.yml | 97 ++++++++++++++++++++++++++ .github/workflows/zephyr.yml | 2 + configure.ac | 25 +++++-- 14 files changed, 178 insertions(+), 6 deletions(-) create mode 100644 .github/workflows/nightly.yml create mode 100644 .github/workflows/wolfssl-versions.yml diff --git a/.github/workflows/cmake-build.yml b/.github/workflows/cmake-build.yml index 0fef6258..94f43767 100644 --- a/.github/workflows/cmake-build.yml +++ b/.github/workflows/cmake-build.yml @@ -5,6 +5,8 @@ on: branches: [ 'master', 'main', 'release/**' ] pull_request: branches: [ '*' ] + repository_dispatch: + types: [nightly-trigger] jobs: build: diff --git a/.github/workflows/codespell.yml b/.github/workflows/codespell.yml index 9b3ac250..e570d586 100644 --- a/.github/workflows/codespell.yml +++ b/.github/workflows/codespell.yml @@ -5,6 +5,8 @@ on: branches: [ 'master', 'main', 'release/**' ] pull_request: branches: [ '*' ] + repository_dispatch: + types: [nightly-trigger] concurrency: group: ${{ github.workflow }}-${{ github.ref }} diff --git a/.github/workflows/fwtpm-test.yml b/.github/workflows/fwtpm-test.yml index 757149fe..4714d491 100644 --- a/.github/workflows/fwtpm-test.yml +++ b/.github/workflows/fwtpm-test.yml @@ -5,6 +5,8 @@ on: branches: [ 'master', 'main', 'release/**' ] pull_request: branches: [ '*' ] + repository_dispatch: + types: [nightly-trigger] jobs: # ---------------------------------------------------------------- diff --git a/.github/workflows/make-test-swtpm.yml b/.github/workflows/make-test-swtpm.yml index e7988e85..eb7c6fcc 100644 --- a/.github/workflows/make-test-swtpm.yml +++ b/.github/workflows/make-test-swtpm.yml @@ -5,6 +5,8 @@ on: branches: [ 'master', 'main', 'release/**' ] pull_request: branches: [ '*' ] + repository_dispatch: + types: [nightly-trigger] jobs: build: diff --git a/.github/workflows/multi-compiler.yml b/.github/workflows/multi-compiler.yml index 89f0d0eb..31116558 100644 --- a/.github/workflows/multi-compiler.yml +++ b/.github/workflows/multi-compiler.yml @@ -5,6 +5,8 @@ on: branches: [ 'master', 'main', 'release/**' ] pull_request: branches: [ '*' ] + repository_dispatch: + types: [nightly-trigger] concurrency: group: ${{ github.workflow }}-${{ github.ref }} diff --git a/.github/workflows/nightly.yml b/.github/workflows/nightly.yml new file mode 100644 index 00000000..e58d0ff5 --- /dev/null +++ b/.github/workflows/nightly.yml @@ -0,0 +1,40 @@ +name: Nightly CI + +# Daily fan-out to every wolfTPM workflow that listens for the +# 'nightly-trigger' repository_dispatch event. Catches upstream wolfSSL +# drift (e.g. header renames, API breaks) within ~24h. +# +# Workflows opt in by adding the listener to their `on:` block: +# repository_dispatch: +# types: [nightly-trigger] +# +# repository_dispatch is API-only — there is no UI button to trigger +# these workflows by hand. Maintainers cannot accidentally fire them. +# Workflows that should never be batch-triggered (e.g. hw-spdm-test on +# the self-hosted Pi runner) simply don't add the listener. + +on: + schedule: + # 02:00 UTC daily (offset from typical top-of-hour congestion). + - cron: '17 2 * * *' + +permissions: + contents: write + +jobs: + fan-out: + name: Dispatch nightly-trigger to all listening workflows + runs-on: ubuntu-latest + if: github.repository == 'wolfSSL/wolfTPM' + + steps: + - name: Send repository_dispatch event + uses: actions/github-script@v7 + with: + script: | + await github.rest.repos.createDispatchEvent({ + owner: context.repo.owner, + repo: context.repo.repo, + event_type: 'nightly-trigger', + }); + core.info('Dispatched nightly-trigger; all listening workflows will fire.'); diff --git a/.github/workflows/pqc-examples.yml b/.github/workflows/pqc-examples.yml index 468a3e1f..183bcfc7 100644 --- a/.github/workflows/pqc-examples.yml +++ b/.github/workflows/pqc-examples.yml @@ -5,6 +5,8 @@ on: branches: [ 'master', 'main', 'release/**' ] pull_request: branches: [ '*' ] + repository_dispatch: + types: [nightly-trigger] jobs: pqc-examples: diff --git a/.github/workflows/release-checks.yml b/.github/workflows/release-checks.yml index 8bcc1c9a..ef3f004d 100644 --- a/.github/workflows/release-checks.yml +++ b/.github/workflows/release-checks.yml @@ -11,6 +11,8 @@ on: branches: [ 'master', 'main', 'release/**', 'rel_v*_prep' ] pull_request: branches: [ '**' ] + repository_dispatch: + types: [nightly-trigger] concurrency: group: ${{ github.workflow }}-${{ github.ref }} diff --git a/.github/workflows/sanitizer.yml b/.github/workflows/sanitizer.yml index 1d66d977..dc747e1c 100644 --- a/.github/workflows/sanitizer.yml +++ b/.github/workflows/sanitizer.yml @@ -5,6 +5,8 @@ on: branches: [ 'master', 'main', 'release/**' ] pull_request: branches: [ '*' ] + repository_dispatch: + types: [nightly-trigger] concurrency: group: ${{ github.workflow }}-${{ github.ref }} diff --git a/.github/workflows/seal-test.yml b/.github/workflows/seal-test.yml index 95e0d34c..9da55af9 100644 --- a/.github/workflows/seal-test.yml +++ b/.github/workflows/seal-test.yml @@ -19,6 +19,8 @@ on: - 'src/tpm2_wrap.c' - 'src/fwtpm/**' - 'wolftpm/tpm2_wrap.h' + repository_dispatch: + types: [nightly-trigger] jobs: seal-test: diff --git a/.github/workflows/win-test.yml b/.github/workflows/win-test.yml index 5b48dcb1..1c73502e 100644 --- a/.github/workflows/win-test.yml +++ b/.github/workflows/win-test.yml @@ -5,6 +5,8 @@ on: branches: [ 'master', 'main', 'release/**' ] pull_request: branches: [ '*' ] + repository_dispatch: + types: [nightly-trigger] jobs: build: diff --git a/.github/workflows/wolfssl-versions.yml b/.github/workflows/wolfssl-versions.yml new file mode 100644 index 00000000..c5617485 --- /dev/null +++ b/.github/workflows/wolfssl-versions.yml @@ -0,0 +1,97 @@ +name: wolfSSL Version Matrix (PQC) + +on: + push: + branches: [ 'master', 'main', 'release/**' ] + pull_request: + branches: [ '*' ] + repository_dispatch: + types: [nightly-trigger] + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + pqc-build-test: + name: wolfSSL ${{ matrix.wolfssl-version }} + runs-on: ubuntu-latest + timeout-minutes: 25 + strategy: + fail-fast: false + matrix: + include: + - wolfssl-version: 'v5.8.0-stable' + wolfssl-ref: 'v5.8.0-stable' + cache-key: 'wolfssl-pqc-v5.8.0-v1' + - wolfssl-version: 'v5.8.4-stable' + wolfssl-ref: 'v5.8.4-stable' + cache-key: 'wolfssl-pqc-v5.8.4-v1' + - wolfssl-version: 'v5.9.1-stable' + wolfssl-ref: 'v5.9.1-stable' + cache-key: 'wolfssl-pqc-v5.9.1-v1' + # master always rebuilds (no cache) so wolfSSL upstream renames / + # API breaks surface within ~24h on the next scheduled run. + - wolfssl-version: 'master' + wolfssl-ref: 'master' + + steps: + - name: Checkout wolfTPM + uses: actions/checkout@v4 + + - name: Install build deps + run: | + sudo apt-get update + sudo apt-get install -y autoconf automake libtool + + - name: Cache wolfSSL ${{ matrix.wolfssl-version }} + if: matrix.wolfssl-version != 'master' + id: cache-wolfssl + uses: actions/cache@v4 + with: + path: ~/wolfssl-install + key: ${{ matrix.cache-key }} + + - name: Build wolfSSL ${{ matrix.wolfssl-version }} with PQC + if: matrix.wolfssl-version == 'master' || steps.cache-wolfssl.outputs.cache-hit != 'true' + run: | + cd ~ + git clone --depth 1 --branch ${{ matrix.wolfssl-ref }} \ + https://github.com/wolfSSL/wolfssl.git + cd wolfssl + ./autogen.sh + ./configure --enable-wolftpm --enable-pkcallbacks --enable-keygen \ + --enable-dilithium --enable-mlkem --enable-experimental \ + --enable-harden CFLAGS="-DWC_RSA_NO_PADDING" \ + --prefix=$HOME/wolfssl-install + make -j"$(nproc)" + make install + + - name: wolfSSL version info + run: | + grep LIBWOLFSSL_VERSION_STRING $HOME/wolfssl-install/include/wolfssl/version.h + grep LIBWOLFSSL_VERSION_HEX $HOME/wolfssl-install/include/wolfssl/version.h + + - name: Build wolfTPM with v1.85 + fwTPM + run: | + ./autogen.sh + CPPFLAGS="-I$HOME/wolfssl-install/include" \ + LDFLAGS="-L$HOME/wolfssl-install/lib -Wl,-rpath,$HOME/wolfssl-install/lib" \ + ./configure --enable-v185 --enable-fwtpm --enable-debug=verbose + make -j"$(nproc)" + + - name: Run fwtpm_unit.test (PQC KAT block) + run: | + export LD_LIBRARY_PATH=$HOME/wolfssl-install/lib + ./tests/fwtpm_unit.test + + - name: Upload failure logs + if: failure() + uses: actions/upload-artifact@v4 + with: + name: wolfssl-versions-${{ matrix.wolfssl-version }}-logs + path: | + config.log + tests/*.log + test-suite.log + retention-days: 5 diff --git a/.github/workflows/zephyr.yml b/.github/workflows/zephyr.yml index 080b4af0..75b3e6f9 100644 --- a/.github/workflows/zephyr.yml +++ b/.github/workflows/zephyr.yml @@ -5,6 +5,8 @@ on: branches: [ 'master', 'main', 'release/**' ] pull_request: branches: [ '*' ] + repository_dispatch: + types: [nightly-trigger] jobs: run_test: diff --git a/configure.ac b/configure.ac index 032e1fee..a00fb7ca 100644 --- a/configure.ac +++ b/configure.ac @@ -714,11 +714,11 @@ else test "x$ENABLED_WOLFCRYPT" = "xyes" then # Probe the actual symbols, not just the headers. wolfSSL ships - # dilithium.h / wc_mlkem.h even without the implementation compiled - # (function decls are gated behind HAVE_DILITHIUM / HAVE_MLKEM - # which only get defined via wolfssl/options.h after the right - # --enable-* flags). Include options.h first so the gate is set - # before the header decls are parsed. + # dilithium.h and wc_mlkem.h even without the implementation + # compiled (function decls are gated behind HAVE_DILITHIUM / + # HAVE_MLKEM which only get defined via wolfssl/options.h after + # the right --enable-* flags). Include options.h first so the + # gate is set before the header decls are parsed. AC_CHECK_DECL([wc_dilithium_init], [WOLFTPM_HAVE_DILITHIUM_FN=yes], [WOLFTPM_HAVE_DILITHIUM_FN=no], @@ -754,9 +754,22 @@ then [[#include #include ]]) AC_CHECK_DECL([wc_MlKemKey_Init], [], - [AC_MSG_ERROR([--enable-v185/--enable-pqc requires wolfSSL built with --enable-mlkem --enable-experimental])], + [AC_MSG_ERROR([--enable-v185/--enable-pqc requires wolfSSL >= v5.8.0-stable built with --enable-mlkem --enable-experimental])], [[#include #include ]]) + + AC_MSG_CHECKING([wolfSSL version >= v5.8.0 for PQC]) + AC_COMPILE_IFELSE([AC_LANG_SOURCE([[ + #include + #if LIBWOLFSSL_VERSION_HEX < 0x05008000 + #error "wolfSSL < v5.8.0" + #endif + int main(void) { return 0; } + ]])], + [AC_MSG_RESULT([yes])], + [AC_MSG_RESULT([no]) + AC_MSG_ERROR([wolfTPM PQC requires wolfSSL >= v5.8.0-stable. Please upgrade wolfSSL.])]) + AM_CFLAGS="$AM_CFLAGS -DWOLFTPM_V185" fi AM_CONDITIONAL([BUILD_V185], [test "x$ENABLED_V185" = "xyes"]) From aeffbfacd7b53029edc25b909b1cfc057bade6ce Mon Sep 17 00:00:00 2001 From: Aidan Garske Date: Fri, 8 May 2026 13:34:09 -0700 Subject: [PATCH 3/4] Support wolfSSL v5.8.0+ for PQC: cast RSA, H-set workaround, ForceZero shim Three small workarounds let wolfTPM PQC build + run cleanly against every wolfSSL stable since v5.8.0, instead of requiring v5.9.0+: * src/fwtpm/fwtpm_crypto.c (FwVerifySignatureCore): cast sig->signature.rsapss.sig.buffer to (byte*)(uintptr_t) so the call compiles against v5.8.0 (where wc_RsaPSS_VerifyCheck takes byte*) AND v5.8.4+ (where it takes const byte*). Cast is a no-op on the const path. * src/fwtpm/fwtpm_crypto.c (FwMlkemDecapsulate): for LIBWOLFSSL_VERSION_HEX < 0x05009000, encode the public key once before wc_MlKemKey_Decapsulate. wolfSSL <= v5.8.4 has a Decap-from-seed bug (commit 8a75e7d1c "ML-KEM decapsulate: check for H" landed in v5.9.0): Decap needs H = hash(pubkey) cached on the key, but MakeKeyWithRandom from seed never populated it. EncodePublicKey triggers the cache as a side effect. * wolftpm/tpm2_types.h: when LIBWOLFSSL_VERSION_HEX < 0x05008004, define a static-inline wc_ForceZero (volatile byte-wise zero, mirroring wolfssl/wolfcrypt/src/misc.c::ForceZero). wc_ForceZero was first declared in wolfssl/wolfcrypt/memory.h at v5.8.4. Lives in tpm2_types.h so all callers (SPDM, PQ examples, etc.) get it without per-file shims. Add v5.8.2 and v5.9.0 to wolfssl-versions.yml matrix so the boundaries of every workaround are covered: 5 stable versions (v5.8.0, v5.8.2, v5.8.4, v5.9.0, v5.9.1) + master. Locally validated: all 6 pass build + fwtpm_unit.test (PQC KAT block). --- .github/workflows/wolfssl-versions.yml | 10 ++++++++++ src/fwtpm/fwtpm_crypto.c | 27 +++++++++++++++++++++++++- wolftpm/tpm2_types.h | 10 ++++++++++ 3 files changed, 46 insertions(+), 1 deletion(-) diff --git a/.github/workflows/wolfssl-versions.yml b/.github/workflows/wolfssl-versions.yml index c5617485..c01f8c67 100644 --- a/.github/workflows/wolfssl-versions.yml +++ b/.github/workflows/wolfssl-versions.yml @@ -21,12 +21,22 @@ jobs: fail-fast: false matrix: include: + # v5.8.x: needs version-gated workarounds in fwtpm_crypto.c for + # (a) non-const wc_RsaPSS_VerifyCheck (v5.8.0 only) and + # (b) Decapsulate not computing H from seed-derived keys (all v5.8.x). - wolfssl-version: 'v5.8.0-stable' wolfssl-ref: 'v5.8.0-stable' cache-key: 'wolfssl-pqc-v5.8.0-v1' + - wolfssl-version: 'v5.8.2-stable' + wolfssl-ref: 'v5.8.2-stable' + cache-key: 'wolfssl-pqc-v5.8.2-v1' - wolfssl-version: 'v5.8.4-stable' wolfssl-ref: 'v5.8.4-stable' cache-key: 'wolfssl-pqc-v5.8.4-v1' + # v5.9.0+: H-set fix landed; workaround is skipped via VERSION_HEX gate. + - wolfssl-version: 'v5.9.0-stable' + wolfssl-ref: 'v5.9.0-stable' + cache-key: 'wolfssl-pqc-v5.9.0-v1' - wolfssl-version: 'v5.9.1-stable' wolfssl-ref: 'v5.9.1-stable' cache-key: 'wolfssl-pqc-v5.9.1-v1' diff --git a/src/fwtpm/fwtpm_crypto.c b/src/fwtpm/fwtpm_crypto.c index 508cbe3e..31d818ca 100644 --- a/src/fwtpm/fwtpm_crypto.c +++ b/src/fwtpm/fwtpm_crypto.c @@ -60,6 +60,7 @@ #endif #include #ifdef WOLFTPM_V185 +#include #include #include #endif @@ -1003,6 +1004,27 @@ TPM_RC FwDecapsulateMlkem(TPMI_MLKEM_PARAMETER_SET parameterSet, if (rc == 0 && ssSz > sizeof(sharedSecretOut->buffer)) { rc = TPM_RC_SIZE; } +#if LIBWOLFSSL_VERSION_HEX < 0x05009000 + /* Workaround: wolfSSL < v5.9.0 Decapsulate does not compute H (hash of + * public key) when the key was generated from a seed via MakeKey. Encode + * the public key once to trigger H caching before Decapsulate. */ + if (rc == 0) { + word32 pubLen = 0; + wcRet = wc_MlKemKey_PublicKeySize(mlkemKey, &pubLen); + if (wcRet == 0 && pubLen > 0) { + byte tmpPub[WC_ML_KEM_MAX_PUBLIC_KEY_SIZE]; + if (pubLen <= sizeof(tmpPub)) { + wcRet = wc_MlKemKey_EncodePublicKey(mlkemKey, tmpPub, pubLen); + } + else { + wcRet = BUFFER_E; + } + } + if (wcRet != 0) { + rc = TPM_RC_FAILURE; + } + } +#endif if (rc == 0) { wcRet = wc_MlKemKey_Decapsulate(mlkemKey, sharedSecretOut->buffer, ctBuf, ctSize); @@ -3588,8 +3610,11 @@ TPM_RC FwVerifySignatureCore(FWTPM_Object* obj, sig->signature.rsassa.hash); int mgf = FwGetMgfType(sig->signature.rsassa.hash); FWTPM_ALLOC_BUF(decSig, FWTPM_MAX_PUB_BUF); + /* Cast: wc_RsaPSS_VerifyCheck took byte* (non-const) in + * wolfSSL <= v5.8.0; the input buffer is const here. + * v5.8.4+ accepts const byte* and the cast is a no-op. */ wcRc = wc_RsaPSS_VerifyCheck( - sig->signature.rsapss.sig.buffer, + (byte*)(uintptr_t)sig->signature.rsapss.sig.buffer, sig->signature.rsapss.sig.size, decSig, (word32)FWTPM_MAX_PUB_BUF, digest, digestSz, diff --git a/wolftpm/tpm2_types.h b/wolftpm/tpm2_types.h index b715eb41..b9a8c975 100644 --- a/wolftpm/tpm2_types.h +++ b/wolftpm/tpm2_types.h @@ -150,6 +150,16 @@ typedef int64_t INT64; /* The wc_HashFree was added in v3.15.4, so use stub to allow building */ #define wc_HashFree(h, t) (0) #endif + #if defined(LIBWOLFSSL_VERSION_HEX) && LIBWOLFSSL_VERSION_HEX < 0x05008004 + /* wc_ForceZero was first declared in wolfssl/wolfcrypt/memory.h at + * v5.8.4. Mirror the upstream byte-wise volatile zero so older + * wolfSSL releases still build wolfTPM. */ + static WC_INLINE void wc_ForceZero(void* mem, size_t len) + { + volatile byte* z = (volatile byte*)mem; + while (len--) *z++ = 0; + } + #endif #define ENCODING_TYPE_PEM 1 /* CTC_FILETYPE_PEM */ #define ENCODING_TYPE_ASN1 2 /* CTC_FILETYPE_ASN1 */ From be879c82561bf9b3cf27dac5a264c7bcdd104e74 Mon Sep 17 00:00:00 2001 From: Aidan Garske Date: Fri, 8 May 2026 14:02:05 -0700 Subject: [PATCH 4/4] Rename wolfssl-versions.yml -> wolfssl-versions-pqc.yml Make it explicit that this matrix is PQC-only. Other wolfTPM workflows (fwtpm-test.yml, make-test-swtpm.yml, pqc-examples.yml) already cover core wolfTPM build/test against wolfSSL master. --- ...-versions.yml => wolfssl-versions-pqc.yml} | 65 ++++++++++++------- 1 file changed, 40 insertions(+), 25 deletions(-) rename .github/workflows/{wolfssl-versions.yml => wolfssl-versions-pqc.yml} (58%) diff --git a/.github/workflows/wolfssl-versions.yml b/.github/workflows/wolfssl-versions-pqc.yml similarity index 58% rename from .github/workflows/wolfssl-versions.yml rename to .github/workflows/wolfssl-versions-pqc.yml index c01f8c67..8a48b3d0 100644 --- a/.github/workflows/wolfssl-versions.yml +++ b/.github/workflows/wolfssl-versions-pqc.yml @@ -12,38 +12,53 @@ concurrency: group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true +permissions: + contents: read + jobs: + # Resolve the latest -stable wolfSSL tag at run time so we don't have to + # bump this workflow every release. Floor (v5.8.0) and master are fixed: + # v5.8.0 exercises every version-gated workaround in fwtpm_crypto.c, and + # master surfaces upstream drift on the nightly run. + discover-versions: + name: Resolve wolfSSL version matrix + runs-on: ubuntu-latest + outputs: + matrix: ${{ steps.set-matrix.outputs.matrix }} + latest-stable: ${{ steps.set-matrix.outputs.latest-stable }} + steps: + - name: Resolve latest -stable wolfSSL tag + id: set-matrix + run: | + set -euo pipefail + # List remote v*-stable tags, version-sort, take the highest. + # Equivalent to `git tag -l 'v*-stable' | sort -V | tail -1` in a + # local clone, but avoids cloning just to read tag names. + LATEST=$(git ls-remote --tags --refs https://github.com/wolfSSL/wolfssl.git 'v*-stable' \ + | awk -F/ '{print $NF}' | sort -V | tail -n 1) + if [ -z "${LATEST:-}" ]; then + echo "::error::Could not resolve latest wolfSSL -stable tag from remote" + exit 1 + fi + echo "Latest stable wolfSSL: $LATEST" + echo "latest-stable=$LATEST" >> "$GITHUB_OUTPUT" + MATRIX=$(jq -nc --arg latest "$LATEST" '{ + include: [ + {"wolfssl-version":"v5.8.0-stable","wolfssl-ref":"v5.8.0-stable","cache-key":"wolfssl-pqc-v5.8.0-v1"}, + {"wolfssl-version":$latest,"wolfssl-ref":$latest,"cache-key":("wolfssl-pqc-" + $latest + "-v1")}, + {"wolfssl-version":"master","wolfssl-ref":"master","cache-key":""} + ] + }') + echo "matrix=$MATRIX" >> "$GITHUB_OUTPUT" + pqc-build-test: name: wolfSSL ${{ matrix.wolfssl-version }} + needs: discover-versions runs-on: ubuntu-latest timeout-minutes: 25 strategy: fail-fast: false - matrix: - include: - # v5.8.x: needs version-gated workarounds in fwtpm_crypto.c for - # (a) non-const wc_RsaPSS_VerifyCheck (v5.8.0 only) and - # (b) Decapsulate not computing H from seed-derived keys (all v5.8.x). - - wolfssl-version: 'v5.8.0-stable' - wolfssl-ref: 'v5.8.0-stable' - cache-key: 'wolfssl-pqc-v5.8.0-v1' - - wolfssl-version: 'v5.8.2-stable' - wolfssl-ref: 'v5.8.2-stable' - cache-key: 'wolfssl-pqc-v5.8.2-v1' - - wolfssl-version: 'v5.8.4-stable' - wolfssl-ref: 'v5.8.4-stable' - cache-key: 'wolfssl-pqc-v5.8.4-v1' - # v5.9.0+: H-set fix landed; workaround is skipped via VERSION_HEX gate. - - wolfssl-version: 'v5.9.0-stable' - wolfssl-ref: 'v5.9.0-stable' - cache-key: 'wolfssl-pqc-v5.9.0-v1' - - wolfssl-version: 'v5.9.1-stable' - wolfssl-ref: 'v5.9.1-stable' - cache-key: 'wolfssl-pqc-v5.9.1-v1' - # master always rebuilds (no cache) so wolfSSL upstream renames / - # API breaks surface within ~24h on the next scheduled run. - - wolfssl-version: 'master' - wolfssl-ref: 'master' + matrix: ${{ fromJson(needs.discover-versions.outputs.matrix) }} steps: - name: Checkout wolfTPM