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
2 changes: 2 additions & 0 deletions .github/workflows/pqc-build-matrix.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ jobs:
fail-fast: false
matrix:
include:
- name: sealsq-qvault-vendor
wolftpm_config: --enable-pqc --enable-sealsq --disable-fwtpm --disable-examples
- name: cli-mldsa_all-mlkem_all
wolftpm_config: --enable-pqc --enable-mldsa=all --enable-mlkem=all --disable-fwtpm --disable-examples
- name: cli-mldsa_all-mlkem_enc
Expand Down
7 changes: 7 additions & 0 deletions .github/workflows/pqc-examples.yml
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,13 @@ jobs:
- name: ML-KEM encap + decap example (standalone)
run: ./examples/pqc/mlkem_encap

- name: PQC control tool (pqc_ctrl.sh suite + argument validation)
# pqc_ctrl.sh runs the full command set and the argument-validation
# negatives, exiting non-zero on any failure. PQC_CTRL_CLEAR is left off
# so the shared Tier-2 fwtpm_server is not wiped mid-sequence; the
# destructive --clear / --pcrextend paths are exercised on hardware.
run: ./examples/pqc/pqc_ctrl.sh

- name: Stop Tier 2 fwtpm_server (free port 2321 for E2E)
run: |
if [ -f /tmp/fwtpm_server.pid ]; then
Expand Down
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,9 @@ examples/pqc/mldsa_sign
examples/pqc/mlkem_encap
examples/pqc/pqc_mssim_e2e
examples/pqc/gen_pqc_certs
examples/pqc/pqc_ctrl
examples/pqc/mldsa_verify_neg
examples/pqc/mlkem_decap_neg
examples/nvram/extend
examples/nvram/store
examples/nvram/read
Expand Down
50 changes: 43 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ Portable TPM 2.0 project designed for embedded use.

* This implementation provides all TPM 2.0 API's in compliance with the specification.
* Wrappers provided to simplify Key Generation/Loading, RSA encrypt/decrypt, ECC sign/verify, ECDH, NV, Hashing/HACM, AES, Sealing/Unsealing, Attestation, PCR Extend/Quote and Secure Root of Trust.
* Any TPM 2.0 compliant module is supported. Tested modules include Infineon SLB9670, SLB9672, SLB9673, STMicroelectronics ST33KTPM2XSPI, ST33KTPM2I, ST33TPHF2XSPI, ST33TPHF2XI2C, Microchip ATTPM20, Nations Technologies/NSING Z32H330, NS350, and Nuvoton NPCT650, NPCT750.
* Any TPM 2.0 compliant module is supported. Tested modules include Infineon SLB9670, SLB9672, SLB9673, STMicroelectronics ST33KTPM2XSPI, ST33KTPM2I, ST33TPHF2XSPI, ST33TPHF2XI2C, Microchip ATTPM20, Nations Technologies/NSING Z32H330, NS350, Nuvoton NPCT650, NPCT750, and SealSQ QVault TPM (first TPM with post-quantum ML-DSA/ML-KEM in silicon).
* wolfTPM uses the TPM Interface Specification (TIS) to communicate either over SPI, or using a memory mapped I/O range.
* On Linux, wolfTPM auto-detects between the kernel TPM driver (`/dev/tpmX`) and direct SPI access at runtime - a simple `./configure && make` works with either interface.
* wolfTPM can also use the Linux TPM kernel interface (`/dev/tpmX`) to talk with any physical TPM on SPI, I2C and even LPC bus.
Expand Down Expand Up @@ -78,9 +78,12 @@ Supported algorithms:
| Hash-ML-DSA (pre-hash signing) | FIPS 204 | ML-DSA-44 / 65 / 87 with caller hash |
| ML-KEM (key encapsulation) | FIPS 203 | ML-KEM-512 / 768 / 1024 |

The examples run against the in-tree fwTPM server. No shipping hardware
TPM firmware implements v1.85 PQC yet; upgrade paths for discrete chips
are forward-compatible — the same wrapper API targets both.
wolfTPM **officially supports the SealSQ QVault TPM**, the first shipping TPM 2.0
with these v1.85 PQC algorithms in silicon. Build for it with `--enable-sealsq
--enable-pqc`. The same examples and wrapper API also run against the in-tree
fwTPM server for CI or when no hardware is present. See the
[TPM2 Benchmarks](#tpm2-benchmarks) section for measured ML-DSA / ML-KEM
performance on the QVault TPM.

### Building

Expand Down Expand Up @@ -144,9 +147,10 @@ make check
```

See [examples/pqc/README.md](examples/pqc/README.md) for per-example
details (`pqc_mssim_e2e`, `mlkem_encap`) and PQC options on the
general-purpose `keygen`/`keyload` tools (`-mldsa`, `-hash_mldsa`,
`-mlkem`).
details — the `pqc_ctrl` control center (every PQC operation plus board
control in one CLI, with `pqc_ctrl.sh` running the full command set),
`pqc_mssim_e2e`, `mlkem_encap`, and PQC options on the general-purpose
`keygen`/`keyload` tools (`-mldsa`, `-hash_mldsa`, `-mlkem`).

For the fwTPM server's PQC internals — the eight v1.85 commands,
primary-key derivation, buffer constants, and spec-interpretation
Expand Down Expand Up @@ -238,6 +242,7 @@ Tested with:
* Microchip ATTPM20 module
* Nuvoton NPCT65X or NPCT75x TPM2.0 modules
* Nations Technologies Z32H330 or NS350 TPM 2.0 modules
* SealSQ QVault TPM 2.0 module (SPI, post-quantum ML-DSA / ML-KEM)

#### Device Identification

Expand Down Expand Up @@ -283,6 +288,10 @@ Nuvoton NPCT750 TPM2.0
TPM2: Caps 0x30000697, Did 0x00fc, Vid 0x1050, Rid 0x 1
Mfg NTC (0), Vendor NPCT75x"!!4rls, Fw 7.2 (131072), FIPS 140-2 1, CC-EAL4 0

SealSQ QVault TPM 2.0
TPM2: Caps 0x30000797, Did 0x0083, Vid 0x2406, Rid 0x 3
Mfg SEAL (6), Vendor QVault TPM, Fw 2.1 (0x3010303), FIPS 140-3, CC-EAL4 0

## Building

### Building wolfSSL
Expand Down Expand Up @@ -346,6 +355,7 @@ make install
--enable-microchip Enable Microchip ATTPM20 Support (default: disabled) - WOLFTPM_MICROCHIP
--enable-nuvoton Enable Nuvoton NPCT65x/NPCT75x Support (default: disabled) - WOLFTPM_NUVOTON
--enable-nations Enable Nations Technology NS350 Support (default: disabled) - WOLFTPM_NATIONS
--enable-sealsq Enable SealSQ QVault post-quantum TPM Support (default: disabled) - WOLFTPM_SEALSQ

--enable-devtpm Enable using Linux kernel driver for /dev/tpmX (default: disabled) - WOLFTPM_LINUX_DEV
Note: With autodetect (default) this is no longer required on Linux;
Expand Down Expand Up @@ -594,6 +604,32 @@ ECDSA 256 verify 9 ops took 1.022 sec, avg 113.539 ms, 8.808 ops/se
ECDHE 256 agree 5 ops took 1.161 sec, avg 232.144 ms, 4.308 ops/sec
```

Run on the SealSQ QVault post-quantum TPM (ML-DSA / ML-KEM) on a Raspberry Pi 5
over SPI. These are the first post-quantum TPM benchmarks measured on
shipping-class silicon:

```
./examples/bench/bench
TPM2 Benchmark using Wrapper API's
RNG 10 KB took 1.061 seconds, 9.428 KB/s
AES-256-CBC-enc 57 KB took 1.000 seconds, 56.994 KB/s
SHA256 43 KB took 1.012 seconds, 42.470 KB/s
SHA384 43 KB took 1.024 seconds, 41.984 KB/s
RSA 2048 key gen 3 ops took 20.536 sec, avg 6845.188 ms, 0.146 ops/sec
RSA 2048 Public 71 ops took 1.015 sec, avg 14.289 ms, 69.985 ops/sec
RSA 2048 Private 7 ops took 1.154 sec, avg 164.827 ms, 6.067 ops/sec
ECC 256 key gen 4 ops took 1.170 sec, avg 292.538 ms, 3.418 ops/sec
ECDSA 256 sign 14 ops took 1.019 sec, avg 72.781 ms, 13.740 ops/sec
ECDSA 256 verify 17 ops took 1.031 sec, avg 60.661 ms, 16.485 ops/sec
ECDHE 256 agree 5 ops took 1.030 sec, avg 206.022 ms, 4.854 ops/sec
ML-DSA 65 key gen 8 ops took 16.357 sec, avg 2044.679 ms, 0.489 ops/sec
ML-DSA 65 sign 2 ops took 1.162 sec, avg 581.025 ms, 1.721 ops/sec
ML-DSA 65 verify 7 ops took 1.142 sec, avg 163.118 ms, 6.131 ops/sec
ML-KEM 768 key gen 19 ops took 15.216 sec, avg 800.819 ms, 1.249 ops/sec
ML-KEM 768 encap 5 ops took 1.059 sec, avg 211.777 ms, 4.722 ops/sec
ML-KEM 768 decap 3 ops took 1.276 sec, avg 425.471 ms, 2.350 ops/sec
```

Run on Infineon OPTIGA SLB9672 at 43MHz:

```
Expand Down
16 changes: 14 additions & 2 deletions configure.ac
Original file line number Diff line number Diff line change
Expand Up @@ -253,7 +253,7 @@ fi
WOLFTPM_HW_SELECTED=no
for _wt_v in "$enable_infineon" "$enable_st" "$enable_st33" \
"$enable_microchip" "$enable_mchp" \
"$enable_nuvoton" "$enable_nations" \
"$enable_nuvoton" "$enable_nations" "$enable_sealsq" \
"$enable_spi" "$enable_i2c" "$enable_mmio" \
"$enable_devtpm" "$enable_autodetect" \
"$enable_winapi" "$enable_wintbs"; do
Expand Down Expand Up @@ -540,6 +540,17 @@ then
AM_CFLAGS="$AM_CFLAGS -DWOLFTPM_NATIONS"
fi

# SealSQ QVault TPM (post-quantum ML-DSA/ML-KEM)
AC_ARG_ENABLE([sealsq],
[AS_HELP_STRING([--enable-sealsq],[Enable SealSQ QVault TPM Support (default: disabled)])],
[ ENABLED_SEALSQ=$enableval ],
[ ENABLED_SEALSQ=no ]
)
if test "x$ENABLED_SEALSQ" = "xyes"
then
AM_CFLAGS="$AM_CFLAGS -DWOLFTPM_SEALSQ"
fi

# Infineon SLB9670/SLB9672/SLB9673
AC_ARG_ENABLE([infineon],
[AS_HELP_STRING([--enable-infineon],[Enable Infineon SLB9670/SLB9672 TPM Support (default: disabled)])],
Expand Down Expand Up @@ -621,7 +632,7 @@ then
# If a module hasn't been selected then enable auto-detection
if test "x$ENABLED_INFINEON" = "xno" && test "x$ENABLED_MCHP" = "xno" && test "x$ENABLED_MICROCHIP" = "xno" && \
test "x$ENABLED_ST" = "xno" && test "x$ENABLED_ST33" = "xno" && test "x$ENABLED_NUVOTON" = "xno" && \
test "x$ENABLED_NATIONS" = "xno"
test "x$ENABLED_NATIONS" = "xno" && test "x$ENABLED_SEALSQ" = "xno"
then
ENABLED_AUTODETECT=yes
fi
Expand Down Expand Up @@ -1192,6 +1203,7 @@ echo " * STM ST33: $ENABLED_ST"
echo " * Microchip ATTPM20: $ENABLED_MICROCHIP"
echo " * Nuvoton NPCT75x: $ENABLED_NUVOTON"
echo " * Nations Tech NS350: $ENABLED_NATIONS"
echo " * SealSQ QVault TPM: $ENABLED_SEALSQ"

echo " * fwTPM Server: $ENABLED_FWTPM"
echo " * fwTPM Only (no client): $ENABLED_FWTPM_ONLY"
Expand Down
72 changes: 68 additions & 4 deletions examples/pqc/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,12 @@
Examples exercising the ML-DSA / ML-KEM post-quantum additions from TCG
TPM 2.0 Library Specification v1.85, wrapped by `wolfTPM2_*` API calls.

The examples run against the in-tree fwTPM server. No shipping hardware
TPM firmware implements v1.85 PQC yet. See
[docs/FWTPM.md](../../docs/FWTPM.md#tpm-20-v185-post-quantum-support) for
the full fwTPM PQC reference.
These examples run on the SealSQ QVault TPM — the first shipping TPM 2.0 with
v1.85 post-quantum (ML-DSA / ML-KEM) algorithms in silicon — over SPI, and on
the in-tree fwTPM server for CI or when no hardware is present. Build for the
SealSQ part with `--enable-sealsq --enable-pqc`; see
[docs/FWTPM.md](../../docs/FWTPM.md#tpm-20-v185-post-quantum-support) for the
fwTPM PQC reference.

## Building

Expand Down Expand Up @@ -67,6 +69,68 @@ All examples expect a running `fwtpm_server` on `127.0.0.1:2321`:
./src/fwtpm/fwtpm_server --clear &
```

### `pqc_ctrl` — PQC control center

One CLI to drive and validate a PQC TPM (SealSQ QVault TPM, or the fwTPM),
modeled on `examples/spdm/spdm_ctrl`: each command runs an operation and
controls the board. Every key operation flushes the transient object table
first, so a TPM with a small object memory (e.g. SealSQ QVault TPM) does not
hit `TPM_RC_OBJECT_MEMORY` when commands are chained.

```
./examples/pqc/pqc_ctrl # --all (default)
./examples/pqc/pqc_ctrl --caps --algs # identify + list supported algorithms
./examples/pqc/pqc_ctrl --mldsa=87 # ML-DSA-87 sign/verify
./examples/pqc/pqc_ctrl --mlkem=1024 # ML-KEM-1024 encap/decap
./examples/pqc/pqc_ctrl --selftest --getrandom=32 --pcrread=0
```

| Command | Description |
|---|---|
| `--caps` | Manufacturer, vendor string, firmware, FIPS mode |
| `--algs` | List the algorithms the TPM reports as supported |
| `--selftest` | `TPM2_SelfTest` |
| `--getrandom[=N]` | N random bytes (default 16) |
| `--pcrread[=idx]` | Read a PCR (SHA-256 bank, falling back to SHA-384) |
| `--pcrextend=idx` | Extend a PCR with a test digest (explicit index required) |
| `--flush` | Flush transient objects (board reset between ops) |
| `--clear` | `TPM2_Clear` — wipes the owner hierarchy |
| `--mldsa[=44/65/87]` | Pure ML-DSA sign/verify (default 65) |
| `--hash-mldsa[=44/65/87]` | Hash-ML-DSA (SHA-256 pre-hash) sign/verify |
| `--mlkem[=512/768/1024]` | ML-KEM encapsulate/decapsulate |
| `--all` | caps + algs + selftest + getrandom + pcrread + every PQC set |

Commands run left-to-right, so they can be chained. Requires `--enable-v185`
(or `--enable-pqc`). Point it at the SealSQ part with `--enable-sealsq`, or at
the fwTPM with `--enable-fwtpm --enable-swtpm`.

Run the whole command set as a pass/fail suite (mirrors
`examples/spdm/spdm_test.sh`). The destructive `--clear` is opt-in via
`PQC_CTRL_CLEAR=1` so the suite never wipes a TPM unexpectedly:

```
./examples/pqc/pqc_ctrl.sh
PQC_CTRL_CLEAR=1 ./examples/pqc/pqc_ctrl.sh # also exercise TPM2_Clear
```

### Benchmarks on SealSQ QVault TPM silicon

Measured with `examples/bench/bench` on a Raspberry Pi 5 driving the QVault TPM
over SPI (the first post-quantum TPM benchmarks on shipping-class silicon):

| Operation | Avg latency | Throughput |
|---|---|---|
| ML-DSA-65 key gen | 2044.7 ms | 0.49 ops/s |
| ML-DSA-65 sign | 581.0 ms | 1.72 ops/s |
| ML-DSA-65 verify | 163.1 ms | 6.13 ops/s |
| ML-KEM-768 key gen | 800.8 ms | 1.25 ops/s |
| ML-KEM-768 encapsulate | 211.8 ms | 4.72 ops/s |
| ML-KEM-768 decapsulate | 425.5 ms | 2.35 ops/s |

Verification is fast (comparable to ECDSA); key generation is a one-off
provisioning cost. See the top-level `README.md` TPM2 Benchmarks section for the
full classical + PQC run.

### `pqc_mssim_e2e`

End-to-end client test over the mssim socket. Two round-trips:
Expand Down
6 changes: 6 additions & 0 deletions examples/pqc/include.am
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,13 @@ examples_pqc_gen_pqc_certs_SOURCES = examples/pqc/gen_pqc_certs.c
examples_pqc_gen_pqc_certs_LDADD = src/libwolftpm.la $(LIB_STATIC_ADD)
examples_pqc_gen_pqc_certs_DEPENDENCIES = src/libwolftpm.la

noinst_PROGRAMS += examples/pqc/pqc_ctrl
examples_pqc_pqc_ctrl_SOURCES = examples/pqc/pqc_ctrl.c
examples_pqc_pqc_ctrl_LDADD = src/libwolftpm.la $(LIB_STATIC_ADD)
examples_pqc_pqc_ctrl_DEPENDENCIES = src/libwolftpm.la

EXTRA_DIST += examples/pqc/README.md
EXTRA_DIST += examples/pqc/pqc_ctrl.sh

endif
endif
Loading
Loading