Full Release Overview
wolfTPM’s firmware TPM (fTPM) is available with full TCG TPM 2.0 Library Specification v1.85 post-quantum support. This release adds the eight new v1.85 commands, the ML-DSA and ML-KEM algorithm structures, and supporting infrastructure (examples, unit tests, NIST ACVP known-answer-tests, a libFuzzer harness) to wolfSSL’s portable software TPM 2.0 implementation. The work merged in wolfTPM PR #445.
This post is the technical companion to the wolfTPM client library and fTPM release announcements. It covers exactly what shipped, where to find it in the source tree, and which embedded targets it runs on today.
What the v1.85 Specification Adds
TCG TPM 2.0 Library Specification v1.85 introduces the post-quantum surface to TPM 2.0: three new algorithm identifiers, eight new commands, and the wire formats and structures to support them.
| Algorithm | Identifier | Use |
|---|---|---|
| ML-KEM | TPM_ALG_MLKEM (0x00A0) | Key encapsulation, decrypt-only keys |
| Pure ML-DSA | TPM_ALG_MLDSA (0x00A1) | Message signing |
| Hash-ML-DSA | TPM_ALG_HASH_MLDSA (0x00A2) | Pre-hashed signing |
Eight New Commands Implemented in fTPM
Every v1.85 post-quantum command is implemented in src/fwtpm/fwtpm_command.c with full TPM 2.0 authorization, NV persistence, and parameter encryption support.
| Command | CC | Purpose |
|---|---|---|
| TPM2_Encapsulate | 0x000001A7 | ML-KEM encapsulation; returns shared secret + ciphertext |
| TPM2_Decapsulate | 0x000001A8 | ML-KEM decapsulation; recovers shared secret from ciphertext |
| TPM2_SignSequenceStart | 0x000001AA | Begin ML-DSA sign sequence |
| TPM2_SignSequenceComplete | 0x000001A4 | Finalize sign sequence with message buffer |
| TPM2_VerifySequenceStart | 0x000001A9 | Begin ML-DSA verify sequence |
| TPM2_VerifySequenceComplete | 0x000001A3 | Finalize verify sequence; returns TPMT_TK_VERIFIED |
| TPM2_SignDigest | 0x000001A6 | One-shot digest sign (Hash-ML-DSA) |
| TPM2_VerifyDigestSignature | 0x000001A5 | Verify digest signature; returns TPMT_TK_VERIFIED |
Parameter Set Coverage
The full NIST-standardized parameter range is supported on both client and server.
| Algorithm | Standard | Parameter Sets |
|---|---|---|
| ML-DSA | FIPS 204 | ML-DSA-44, ML-DSA-65, ML-DSA-87 |
| ML-KEM | FIPS 203 | ML-KEM-512, ML-KEM-768, ML-KEM-1024 |
Post-Quantum Primary Key Derivation
PQC primary keys derive deterministically from the hierarchy seed using the same KDFa-based model TPM 2.0 already uses for RSA and ECC primary keys.
- ML-DSA: KDFa(nameAlg, seed, “MLDSA”, hashUnique) produces a 32-byte Xi, which is passed to wc_dilithium_make_key_from_seed. Wire format stores the 32-byte Xi per TCG Part 2 Table 210.
- Hash-ML-DSA: Same expansion model with label “HASH_MLDSA”.
- ML-KEM: KDFa(nameAlg, seed, “MLKEM”, hashUnique) produces a 64-byte (d||z) seed, which is passed to wc_MlKemKey_MakeKeyWithRandom. Wire format stores the 64-byte seed per TCG Part 2 Table 206.
This preserves the cold-boot recovery model of TPM 2.0: the same seed regenerates the same primary key bit-for-bit across reboots.
New Example Programs
Three new programs in examples/pqc/ exercise the post-quantum path end-to-end against a running fTPM server.
| Program | Description |
|---|---|
| pqc_mssim_e2e | Round-trips both algorithms over mssim socket transport. ML-KEM-768 CreatePrimary + Encapsulate + Decapsulate (asserts ciphertext is 1088 bytes, shared secrets match), then Hash-ML-DSA-65 CreatePrimary + SignDigest + VerifyDigestSignature (asserts signature is 3309 bytes, validation ticket is TPM_ST_DIGEST_VERIFIED). |
| mlkem_encap | ML-KEM encapsulation/decapsulation round-trip with selectable parameter set (-mlkem=512|768|1024). |
| mldsa_sign | Pure ML-DSA sign + verify with selectable parameter set (-mldsa=44|65|87). Demonstrates one-shot signing per Part 3 Sec. 17.5 and streaming verify per Sec. 20.3. |
The existing keygen and keyload examples also accept new flags (-mldsa, -hash_mldsa, -mlkem) for primary key creation and persistence.
Test Coverage
This release ships 132 fTPM unit tests in tests/fwtpm_unit_tests.c and 83 client unit tests in tests/unit_tests.c. Roughly 30 fTPM tests and 18 client tests are post-quantum-specific.
fTPM PQC Unit Tests (in-process)
- CreatePrimary(MLKEM-768), CreatePrimary(MLDSA-65)
- CreateLoaded(MLDSA-65), CreateLoaded(MLKEM-768)
- MLKEM Encap/Decap Roundtrip, MLDSA Sign/Verify Sequence
- MLDSA SignDigest/Verify Roundtrip
- Encap/Decap ECC DHKEM (P-256/HKDF-SHA256), P-384/HKDF-SHA384 variants
- FwEncryptSeed/FwDecryptSeed MLKEM Roundtrip
- Classical sign/verify regression tests (RSA, ECDSA, HMAC) over the new sequence/digest commands
- Negative-path tests for scheme mismatch, digest-size mismatch, NULL-scheme rejection, handle-auth enforcement
Client Wrapper PQC Tests (over mssim socket)
- ML-DSA Sign Sequence, Verify Sequence, Verify Seq data-chain
- Hash-ML-DSA SignSeqUpdate streaming, Hash-ML-DSA SignDigest roundtrip
- ML-DSA SignSeqStart no-session, Sign Seq w/ key auth
- ML-KEM Encapsulate, Decapsulate, Round Trip
- EncryptSecret MLKEM, PQC Key Templates, Signature PQC serialize, Public PQC roundtrip
NIST ACVP Known-Answer Tests
tests/pqc_kat_vectors.h (802 lines) ships pinned vectors used to validate the implementation against NIST’s published ACVP answer keys.
- ML-DSA-44 verify, against NIST ACVP and wolfSSL internal vectors
- ML-DSA-44 keygen determinism
- ML-KEM-512 encapsulation with pinned randomness, against NIST ACVP
- ML-KEM-512 keygen determinism
- LoadExternal of a NIST ACVP ML-DSA-44 public key through the fwTPM command handler
A KAT regression in any of these tests would indicate a wire-format or algorithm-implementation drift, not just a wrapper bug.
Fuzzing
tests/fuzz/fwtpm_fuzz.c is a libFuzzer harness for FWTPM_ProcessCommand. It feeds raw byte sequences directly into the fTPM command processor, exercising every parser, dispatcher, and authorization path without any wolfTPM-client-side wrapping.
| Component | Details |
|---|---|
| Build | ./configure –enable-fwtpm –enable-fuzz CFLAGS=”-fsanitize=fuzzer-no-link,address -g” LDFLAGS=”-fsanitize=fuzzer,address” |
| Dictionary | tests/fuzz/tpm2.dict: 97 entries of TPM 2.0 command codes, algorithm identifiers, response tags, and structure markers |
| Corpus generator | tests/fuzz/gen_corpus.py (212 lines): synthesizes seed inputs covering classical and PQC paths |
| CI | fuzz.yml runs the harness on every PR (smoke run) and weekly (extended run) under AddressSanitizer |
Buffer Sizing Under v1.85
Post-quantum signatures and public keys are dramatically larger than their classical equivalents. fTPM auto-sizes at compile time based on which PQC parameter sets are enabled.
| Symbol | Classical | DSA-44+KEM-512 | DSA-65+KEM-768 | DSA-87+KEM-1024 |
|---|---|---|---|---|
| FWTPM_TIS_FIFO_SIZE | 4096 | 4096 | 8192 | 8192 |
| FWTPM_MAX_COMMAND_SIZE | 4096 | 4096 | 8192 | 8192 |
| FWTPM_MAX_PUB_BUF | 512 | 1408 | 2048 | 2720 |
| FWTPM_MAX_DER_SIG_BUF | 256 | 2536 | 3373 | 4736 |
ML-DSA-44-only and ML-KEM-only builds stay at 4096-byte FIFOs. The 8192 lift only applies when ML-DSA-65 or ML-DSA-87 is enabled, because their signatures do not fit a 4096-byte response with TPM headers.
Embedded Targets
The fTPM is portable C built on wolfCrypt, with no dynamic allocation in hot paths and WOLFTPM_SMALL_STACK support for constrained environments. The following HAL drivers ship with wolfTPM and are usable today as the transport layer for the fTPM server.
| HAL | Source |
|---|---|
| Linux (/dev/spidev*, /dev/tpm0) | hal/tpm_io_linux.c |
| STMicro Cube (STM32 family) | hal/tpm_io_st.c |
| Atmel ASF | hal/tpm_io_atmel.c |
| Infineon TriCore | hal/tpm_io_infineon.c |
| Microchip | hal/tpm_io_microchip.c |
| Xilinx | hal/tpm_io_xilinx.c |
| QNX | hal/tpm_io_qnx.c |
| Espressif (ESP32) | hal/tpm_io_espressif.c |
| Zephyr | hal/tpm_io_zephyr.c |
| BareBox | hal/tpm_io_barebox.c |
| U-Boot | hal/tpm_io_uboot.c |
| Generic MMIO | hal/tpm_io_mmio.c |
Anywhere wolfTPM runs, fTPM with v1.85 post-quantum support runs.
STM32H5 Reference Port
A complete STM32H5 Cortex-M33 with TrustZone (CMSE) reference port is available in the wolfTPM examples repository. It runs the fTPM server on the STM32H5, exposes the SWTPM protocol over UART, and accepts commands from a host-side wolfTPM client built with –enable-swtpm=uart.
This means a development board can run a fully post-quantum TPM 2.0 server today: ML-DSA signing, ML-KEM key encapsulation, NV persistence, and attestation primitives, with no discrete TPM chip on the board.
Open Source Availability
wolfTPM is dual-licensed under GPLv2+ for open source use and commercially for proprietary integration. The fTPM source, the eight v1.85 PQC command handlers, all unit tests, all examples, the NIST ACVP KAT vectors, and the libFuzzer harness are in the public wolfSSL/wolfTPM repository on GitHub.
This release makes wolfTPM the first openly available, freely usable software TPM 2.0 implementation that ships v1.85 post-quantum support. Other TPM 2.0 simulators in common use, including the TCG-controlled reference implementation, do not currently expose v1.85 commands publicly. Products that need to evaluate, integrate, or ship post-quantum TPM functionality today can do so against fTPM without an NDA, without TCG membership, and without waiting for the discrete-TPM vendor rollout.
Build and Run
wolfSSL (ML-DSA and ML-KEM in wolfCrypt):
# wolfSSL with PQC + keygen
./configure --enable-wolftpm --enable-pkcallbacks \
--enable-keygen --enable-dilithium \
--enable-mlkem --enable-experimental \
--enable-harden CFLAGS="-DWC_RSA_NO_PADDING"
make && sudo make install
wolfTPM:
# wolfTPM with fwTPM + v1.85 ./configure --enable-fwtpm --enable-pqc make make check
Run only the PQC end-to-end test (fastest PQC-focused check):
./tests/pqc_mssim_e2e.sh
CI Coverage
Continuous integration runs the full PQC matrix on every PR and on a nightly schedule.
- pqc-examples.yml: wolfSSL + wolfTPM PQC build, examples sweep, mssim E2E
- fwtpm-test.yml: fTPM matrix (10+ build variants including PQC, no-PQC, small-stack)
- fuzz.yml: libFuzzer smoke run per-PR, extended weekly run under AddressSanitizer
- sanitizer.yml: AddressSanitizer / UndefinedBehaviorSanitizer / MemorySanitizer
Documentation
- Specification mapping and per-command spec citations: docs/FWTPM.md
- Example programs: examples/pqc/README.md
- Embedded port reference (STM32H5): src/fwtpm/ports/README.md
If you have questions about any of the above, please contact us at facts@wolfssl.com or call us at +1 425 245 8247.
Download wolfSSL Now

