Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 41 additions & 11 deletions .github/workflows/wolfssl-versions-pqc.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
name: wolfSSL Version Matrix (PQC)
name: wolfSSL Version Matrix

on:
push:
Expand All @@ -18,8 +18,9 @@ permissions:
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.
# v5.8.0 exercises wolfTPM's non-PQC backward-compat path (the v1.85 PQC
# code uses the post-v5.9.1 wc_MlDsaKey_* API and is skipped on this row),
# and master surfaces upstream drift on the nightly run.
discover-versions:
name: Resolve wolfSSL version matrix
runs-on: ubuntu-latest
Expand All @@ -42,11 +43,21 @@ jobs:
fi
echo "Latest stable wolfSSL: $LATEST"
echo "latest-stable=$LATEST" >> "$GITHUB_OUTPUT"
MATRIX=$(jq -nc --arg latest "$LATEST" '{
# Enable PQC when $LATEST is strictly newer than v5.9.1-stable
# (any v5.9.2+, v5.10+, v6+, ...). The wc_MlDsaKey_* API lands
# post-v5.9.1-stable in wolfSSL PR #10436.
PQC_FLOOR="v5.9.1-stable"
if [ "$(printf '%s\n%s\n' "$PQC_FLOOR" "$LATEST" | sort -V | tail -n1)" != "$PQC_FLOOR" ]; then
LATEST_PQC_ELIGIBLE=true
else
LATEST_PQC_ELIGIBLE=false
fi
echo "latest-stable PQC eligible: $LATEST_PQC_ELIGIBLE"
MATRIX=$(jq -nc --arg latest "$LATEST" --argjson latest_pqc "$LATEST_PQC_ELIGIBLE" '{
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":""}
{"wolfssl-version":"v5.8.0-stable","wolfssl-ref":"v5.8.0-stable","cache-key":"wolfssl-nopqc-v5.8.0-v1","pqc":false},
{"wolfssl-version":$latest,"wolfssl-ref":$latest,"cache-key":("wolfssl-" + (if $latest_pqc then "pqc" else "nopqc" end) + "-" + $latest + "-v1"),"pqc":$latest_pqc},
{"wolfssl-version":"master","wolfssl-ref":"master","cache-key":"","pqc":true}
]
}')
echo "matrix=$MATRIX" >> "$GITHUB_OUTPUT"
Expand Down Expand Up @@ -77,16 +88,25 @@ jobs:
path: ~/wolfssl-install
key: ${{ matrix.cache-key }}

- name: Build wolfSSL ${{ matrix.wolfssl-version }} with PQC
- name: Build wolfSSL ${{ matrix.wolfssl-version }}
if: matrix.wolfssl-version == 'master' || steps.cache-wolfssl.outputs.cache-hit != 'true'
env:
PQC: ${{ matrix.pqc }}
run: |
cd ~
git clone --depth 1 --branch ${{ matrix.wolfssl-ref }} \
https://github.com/wolfSSL/wolfssl.git
cd wolfssl
./autogen.sh
# PQC rows pull in ML-DSA + ML-KEM; non-PQC rows cover wolfSSL
# versions that predate the wc_MlDsaKey_* rename (PR #10436).
if [ "$PQC" = "true" ]; then
PQC_FLAGS="--enable-dilithium --enable-mlkem --enable-experimental"
else
PQC_FLAGS=""
fi
./configure --enable-wolftpm --enable-pkcallbacks --enable-keygen \
--enable-dilithium --enable-mlkem --enable-experimental \
$PQC_FLAGS \
--enable-harden CFLAGS="-DWC_RSA_NO_PADDING" \
--prefix=$HOME/wolfssl-install
make -j"$(nproc)"
Expand All @@ -97,15 +117,25 @@ jobs:
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
- name: Build wolfTPM with v1.85 + fwTPM (PQC)
if: matrix.pqc
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)
- name: Build wolfTPM with fwTPM (no PQC)
if: '!matrix.pqc'
run: |
./autogen.sh
CPPFLAGS="-I$HOME/wolfssl-install/include" \
LDFLAGS="-L$HOME/wolfssl-install/lib -Wl,-rpath,$HOME/wolfssl-install/lib" \
./configure --enable-fwtpm --disable-v185 --enable-debug=verbose
make -j"$(nproc)"

- name: Run fwtpm_unit.test
run: |
export LD_LIBRARY_PATH=$HOME/wolfssl-install/lib
./tests/fwtpm_unit.test
Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ Portable TPM 2.0 project designed for embedded use.
* Support for HMAC Sessions.
* Support for reading Endorsement certificates (EK Credential Profile).
* Includes a portable firmware TPM 2.0 implementation (fwTPM, also known as fTPM / swtpm) for embedded platforms without a discrete TPM chip. See [Firmware TPM (fwTPM / fTPM / swtpm)](#firmware-tpm-fwtpm--ftpm--swtpm) below.
* **Post-quantum cryptography support** via TPM 2.0 Library Specification v1.85: ML-DSA (FIPS 204) signing and ML-KEM (FIPS 203) key encapsulation, enabled with `--enable-pqc` (alias for `--enable-v185`). Auto-detected when `--enable-fwtpm` is built against a wolfCrypt that has Dilithium + ML-KEM. Both the client library and the fwTPM server implement the eight new v1.85 PQC commands. See [Post-Quantum Cryptography (v1.85)](#post-quantum-cryptography-v185) below.
* **Post-quantum cryptography support** via TPM 2.0 Library Specification v1.85: ML-DSA (FIPS 204) signing and ML-KEM (FIPS 203) key encapsulation, enabled with `--enable-pqc` (alias for `--enable-v185`). Auto-detected when `--enable-fwtpm` is built against a wolfCrypt that has ML-DSA + ML-KEM. Both the client library and the fwTPM server implement the eight new v1.85 PQC commands. See [Post-Quantum Cryptography (v1.85)](#post-quantum-cryptography-v185) below.

Note: See [examples/README.md](examples/README.md) for details on using the examples.

Expand Down Expand Up @@ -87,7 +87,7 @@ are forward-compatible — the same wrapper API targets both.

```
./configure --enable-wolftpm --enable-pkcallbacks --enable-keygen \
--enable-dilithium --enable-mlkem --enable-experimental \
--enable-mldsa --enable-mlkem \
--enable-harden CFLAGS="-DWC_RSA_NO_PADDING"
make
sudo make install
Expand Down
33 changes: 21 additions & 12 deletions configure.ac
Original file line number Diff line number Diff line change
Expand Up @@ -714,22 +714,27 @@ else
test "x$ENABLED_WOLFCRYPT" = "xyes"
then
# Probe the actual symbols, not just the headers. wolfSSL ships
# dilithium.h and wc_mlkem.h even without the implementation
# compiled (function decls are gated behind HAVE_DILITHIUM /
# wc_mldsa.h and wc_mlkem.h even without the implementation
# compiled (function decls are gated behind WOLFSSL_HAVE_MLDSA /
# 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],
# Probing the canonical wc_MlDsaKey_Init also doubles as a
# wolfSSL-version probe: older wolfSSL that predates PR #10436
# ships only <wolfssl/wolfcrypt/dilithium.h>, fails the probe,
# and auto-detect quietly stays off (explicit opt-in below emits
# an actionable error).
AC_CHECK_DECL([wc_MlDsaKey_Init],
[WOLFTPM_HAVE_MLDSA_FN=yes],
[WOLFTPM_HAVE_MLDSA_FN=no],
[[#include <wolfssl/options.h>
#include <wolfssl/wolfcrypt/dilithium.h>]])
#include <wolfssl/wolfcrypt/wc_mldsa.h>]])
AC_CHECK_DECL([wc_MlKemKey_Init],
[WOLFTPM_HAVE_MLKEM_FN=yes],
[WOLFTPM_HAVE_MLKEM_FN=no],
[[#include <wolfssl/options.h>
#include <wolfssl/wolfcrypt/wc_mlkem.h>]])
if test "x$WOLFTPM_HAVE_DILITHIUM_FN" = "xyes" && \
if test "x$WOLFTPM_HAVE_MLDSA_FN" = "xyes" && \
test "x$WOLFTPM_HAVE_MLKEM_FN" = "xyes"
then
AC_MSG_NOTICE([wolfCrypt ML-DSA + ML-KEM detected; auto-enabling --enable-v185 (use --disable-v185 or --disable-pqc to opt out)])
Expand All @@ -747,12 +752,16 @@ then
# Explicit opt-in: re-probe so we fail at configure time (with a
# clear hint about wolfSSL flags) rather than deep inside the compile
# with a cryptic error. Header existence alone is not enough -- the
# actual functions must be declared (gated by HAVE_DILITHIUM /
# HAVE_MLKEM in wolfssl/options.h).
AC_CHECK_DECL([wc_dilithium_init], [],
[AC_MSG_ERROR([--enable-v185/--enable-pqc requires wolfSSL built with --enable-dilithium --enable-experimental])],
# actual functions must be declared (gated by WOLFSSL_HAVE_MLDSA /
# HAVE_MLKEM in wolfssl/options.h). The probed symbol
# `wc_MlDsaKey_Init` is the canonical FIPS 204 entry point introduced
# by wolfSSL PR #10436 (post-v5.9.1-stable): wolfTPM consumes
# <wolfssl/wolfcrypt/wc_mldsa.h> directly, so older wolfSSL that
# only ships <wolfssl/wolfcrypt/dilithium.h> is not supported here.
AC_CHECK_DECL([wc_MlDsaKey_Init], [],
[AC_MSG_ERROR([--enable-v185/--enable-pqc requires wolfSSL built with --enable-mldsa (or alias --enable-dilithium) and --enable-experimental, ships post-v5.9.1-stable])],
[[#include <wolfssl/options.h>
#include <wolfssl/wolfcrypt/dilithium.h>]])
#include <wolfssl/wolfcrypt/wc_mldsa.h>]])
AC_CHECK_DECL([wc_MlKemKey_Init], [],
[AC_MSG_ERROR([--enable-v185/--enable-pqc requires wolfSSL >= v5.8.0-stable built with --enable-mlkem --enable-experimental])],
[[#include <wolfssl/options.h>
Expand Down
8 changes: 4 additions & 4 deletions docs/FWTPM.md
Original file line number Diff line number Diff line change
Expand Up @@ -504,7 +504,7 @@ Sizing logic lives in `wolftpm/fwtpm/fwtpm.h` (constants
`FWTPM_MAX_MLDSA_SIG_SIZE`, `FWTPM_MAX_MLDSA_PUB_SIZE`,
`FWTPM_MAX_MLKEM_CT_SIZE`, `FWTPM_MAX_MLKEM_PUB_SIZE`) and
`wolftpm/fwtpm/fwtpm_tis.h` (FIFO size). The MLDSA constants come from
wolfCrypt's `DILITHIUM_LEVEL{2,3,5}_*_SIZE` macros; the MLKEM constants
wolfCrypt's `WC_MLDSA_{44,65,87}_*_SIZE` macros; the MLKEM constants
are FIPS 203 spec values (wolfCrypt's `WC_ML_KEM_*_SIZE` macros aren't
preprocessor-evaluable).

Expand Down Expand Up @@ -741,7 +741,7 @@ every `Startup(CLEAR)`.

Enabled with `--enable-pqc` (alias `--enable-v185`) at configure time, or
auto-detected when `--enable-fwtpm` is built against a wolfCrypt that has
both Dilithium and ML-KEM available. Both flags set the internal
both ML-DSA and ML-KEM available. Both flags set the internal
`WOLFTPM_V185` macro that gates the implementation. Pass `--disable-pqc`
to opt out when auto-detect would otherwise enable it. Implements the
post-quantum additions from TCG TPM 2.0 Library Specification v1.85 using
Expand Down Expand Up @@ -776,7 +776,7 @@ PQC primary keys follow the same deterministic derivation model as RSA/ECC:
hierarchy seed + template → KDFa-derived seed → FIPS 203/204 key expansion.

- **ML-DSA**: `KDFa(nameAlg, seed, "MLDSA", hashUnique) → 32-byte Xi` →
`wc_dilithium_make_key_from_seed` → (pub, expanded-priv). The wire format stores
`wc_MlDsaKey_MakeKeyFromSeed` → (pub, expanded-priv). The wire format stores
only the 32-byte Xi per TCG Part 2 Table 210.
- **Hash-ML-DSA**: label is `"HASH_MLDSA"`; same seed size and expansion.
- **ML-KEM**: `KDFa(nameAlg, seed, "MLKEM", hashUnique) → 64-byte (d‖z)` →
Expand All @@ -797,7 +797,7 @@ buffer parameter.

Hash-ML-DSA sequences (both sign and verify) use wolfCrypt's `wc_HashAlg` context
to stream the message into the key's hash algorithm; `TPM2_SignSequenceComplete`
finalizes the hash and calls `wc_dilithium_sign_ctx_hash`.
finalizes the hash and calls `wc_MlDsaKey_SignCtxHash`.

Signature wire formats differ per spec Part 2 Table 217:

Expand Down
2 changes: 1 addition & 1 deletion docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ wolfTPM implements the post-quantum additions from **TCG TPM 2.0 Library Specifi

Eight new TPM 2.0 commands are supported: `TPM2_Encapsulate`, `TPM2_Decapsulate`, `TPM2_SignDigest`, `TPM2_VerifyDigestSignature`, `TPM2_SignSequenceStart`, `TPM2_SignSequenceComplete`, `TPM2_VerifySequenceStart`, `TPM2_VerifySequenceComplete`.

Algorithm behavior matches FIPS 203 / FIPS 204 via wolfCrypt's ML-KEM and ML-DSA (Dilithium) modules, validated against NIST ACVP test vectors.
Algorithm behavior matches FIPS 203 / FIPS 204 via wolfCrypt's ML-KEM and ML-DSA modules, validated against NIST ACVP test vectors.

The firmware TPM (fwTPM) server also implements v1.85 PQC — see [FWTPM.md](FWTPM.md#tpm-20-v185-post-quantum-support) for algorithm, command, primary-key derivation, and sequence-handler details.

Expand Down
4 changes: 2 additions & 2 deletions examples/pqc/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@ the full fwTPM PQC reference.
**wolfSSL** (ML-DSA and ML-KEM in wolfCrypt):

```
./configure --enable-wolftpm --enable-dilithium --enable-mlkem \
--enable-experimental --enable-harden --enable-keygen
./configure --enable-wolftpm --enable-mldsa --enable-mlkem \
--enable-harden --enable-keygen
make
sudo make install
```
Expand Down
Binary file added fwtpm_test_nv.bin
Binary file not shown.
9 changes: 3 additions & 6 deletions src/fwtpm/fwtpm_command.c
Original file line number Diff line number Diff line change
Expand Up @@ -1151,16 +1151,13 @@ static TPM_RC FwCmd_GetCapability(FWTPM_CTX* ctx, TPM2_Packet* cmd,
!defined(WOLFSSL_NO_KYBER1024)
TPMA_ML_PARAMETER_SET_mlKem_1024 |
#endif
#if (defined(WOLFSSL_WC_DILITHIUM) || defined(HAVE_DILITHIUM)) && \
!defined(WOLFSSL_NO_ML_DSA_44)
#if defined(WOLFSSL_HAVE_MLDSA) && !defined(WOLFSSL_NO_ML_DSA_44)
TPMA_ML_PARAMETER_SET_mlDsa_44 |
#endif
#if (defined(WOLFSSL_WC_DILITHIUM) || defined(HAVE_DILITHIUM)) && \
!defined(WOLFSSL_NO_ML_DSA_65)
#if defined(WOLFSSL_HAVE_MLDSA) && !defined(WOLFSSL_NO_ML_DSA_65)
TPMA_ML_PARAMETER_SET_mlDsa_65 |
#endif
#if (defined(WOLFSSL_WC_DILITHIUM) || defined(HAVE_DILITHIUM)) && \
!defined(WOLFSSL_NO_ML_DSA_87)
#if defined(WOLFSSL_HAVE_MLDSA) && !defined(WOLFSSL_NO_ML_DSA_87)
TPMA_ML_PARAMETER_SET_mlDsa_87 |
#endif
0 },
Expand Down
Loading
Loading