wolfTPM Firmware TPM (fwTPM / fTPM / swtpm) Server

June 8, 2026 · View on GitHub

A portable firmware TPM 2.0 implementation built entirely on wolfCrypt. The fwTPM provides a standards-compliant TPM 2.0 command processor that can replace a hardware TPM on embedded platforms without a discrete TPM chip, or serve as a drop-in development and CI/CD replacement for external simulators. Supports TCP socket transport (Microsoft TPM simulator protocol, compatible with wolfTPM examples and tpm2-tools) and TIS register-level transport over shared memory or SPI/I2C for bare-metal integration. Implements 105 of 113 TPM 2.0 v1.38 commands (93% coverage) with HAL abstractions for IO and NV storage portability.

Post-quantum cryptography support is available with --enable-pqc (alias for --enable-v185), adding ML-DSA (FIPS 204) signing and ML-KEM (FIPS 203) key encapsulation per TCG TPM 2.0 Library Specification v1.85. Configure auto-detects PQC and enables it when --enable-fwtpm is built against a wolfCrypt that has both. See docs/FWTPM.md for algorithm and command details.

Building

wolfSSL must be built with --enable-keygen and WC_RSA_NO_PADDING:

cd wolfssl
./configure --enable-wolftpm --enable-pkcallbacks --enable-keygen CFLAGS="-DWC_RSA_NO_PADDING"
make && make install

Then build wolfTPM with the fwTPM server:

cd wolftpm
./configure --enable-fwtpm --enable-swtpm
make

Running

# Listens on localhost:2321 (cmd) and :2322 (platform)
src/fwtpm/fwtpm_server

# Optionally start with clear NV
src/fwtpm/fwtpm_server --clear

Testing with tpm2-tools

In socket mode (--enable-swtpm), the fwTPM server supports both the mssim (Microsoft TPM simulator) and swtpm (Stefan Berger) TCTI protocols via auto-detection on the command port. Either TCTI works:

# Using mssim TCTI (default for wolfTPM test scripts)
export TPM2TOOLS_TCTI="mssim:host=localhost,port=2321"
tpm2_startup -c

# Using swtpm TCTI (also works — auto-detected)
export TPM2TOOLS_TCTI="swtpm:host=localhost,port=2321"
tpm2_getrandom 8

The --port and --platform-port options are socket-mode only and not available in TIS builds (--enable-fwtpm without --enable-swtpm).

Testing with wolfTPM examples

wolfTPM examples use the built-in swtpm client which speaks the mssim protocol automatically:

./examples/wrap/caps
./examples/keygen/keygen

Test Suite

# Full test: unit.test + run_examples.sh + tpm2-tools (311 tests)
make check

# tpm2-tools only
scripts/tpm2_tools_test.sh

make check runs tests/fwtpm_check.sh, which manages the fwtpm_server lifecycle automatically.

CI Tests (fwtpm-test.yml)

All tests below run in GitHub Actions CI. Run manually before PR submission.

Runtime Tests (build + run_examples.sh + make check)

NamewolfTPM ConfigExtraNotes
fwtpm-socket--enable-fwtpm --enable-swtpm --enable-debugPrimary test
fwtpm-tis--enable-fwtpm --enable-debugTIS/SHM transport
fwtpm-asan--enable-fwtpm --enable-swtpm --enable-debug-fsanitize=addressMemory errors
fwtpm-ubsan--enable-fwtpm --enable-swtpm --enable-debug-fsanitize=undefinedUB detection

Build-Only Tests

NamewolfTPM ConfigwolfSSL ConfigExtra CFLAGS
fwtpm-no-rsa--enable-fwtpm --enable-swtpm--disable-rsa
fwtpm-no-ecc--enable-fwtpm --enable-swtpm--disable-ecc
fwtpm-only--enable-fwtpm-only --enable-swtpmNo client library
fwtpm-minimal--enable-fwtpm --enable-swtpm-DFWTPM_NO_ATTESTATION -DFWTPM_NO_NV -DFWTPM_NO_POLICY -DFWTPM_NO_CREDENTIAL -DFWTPM_NO_DA -DFWTPM_NO_PARAM_ENC
fwtpm-no-policy--enable-fwtpm --enable-swtpm-DFWTPM_NO_POLICY
fwtpm-no-nv--enable-fwtpm --enable-swtpm-DFWTPM_NO_NV
fwtpm-no-attestation--enable-fwtpm --enable-swtpm-DFWTPM_NO_ATTESTATION
fwtpm-no-credential--enable-fwtpm --enable-swtpm-DFWTPM_NO_CREDENTIAL
fwtpm-no-da--enable-fwtpm --enable-swtpm-DFWTPM_NO_DA
fwtpm-no-param-enc--enable-fwtpm --enable-swtpm-DFWTPM_NO_PARAM_ENC
fwtpm-no-rsa-no-policy--enable-fwtpm --enable-swtpm--disable-rsa-DFWTPM_NO_POLICY
fwtpm-no-ecc-no-nv--enable-fwtpm --enable-swtpm--disable-ecc-DFWTPM_NO_NV
fwtpm-small-stack--enable-fwtpm --enable-swtpm-DWOLFTPM_SMALL_STACK

Pedantic Builds (build-only, -Werror)

NameCompilerConfig
fwtpm-pedantic-gccgcc--enable-fwtpm --enable-swtpm
fwtpm-pedantic-clangclang--enable-fwtpm --enable-swtpm
fwtpm-pedantic-onlygcc--enable-fwtpm-only

Separate Job: tpm2-tools (311 tests)

scripts/tpm2_tools_test.sh

Build Options and Feature Macros

See docs/FWTPM.md for the full list of configure options, compile-time macros (feature groups, algorithm flags, size limits, stack/heap control), spec version targeting, and HAL abstraction details.

Key options: --enable-fwtpm, --enable-fwtpm-only, --enable-swtpm, --enable-fwtpm-small-ctx, --enable-fuzz. Feature disable macros: FWTPM_NO_ATTESTATION, FWTPM_NO_NV, FWTPM_NO_POLICY, FWTPM_NO_CREDENTIAL, FWTPM_NO_DA, FWTPM_NO_PARAM_ENC.

SPDM Responder Mode

fwtpm_server ships an SPDM 1.3 responder so the SPDM stack (TCG cert handshake + DSP0274 PSK) can be tested without real silicon. When SPDM is on, the responder sits above the existing transport HAL and dispatches TCG-framed messages (tags 0x8101 clear, 0x8201 secured) into the SPDM state machine; plaintext TPM frames fall through to the regular dispatcher until the requester issues SPDMONLY LOCK, after which only GetCapability is allowed through in plaintext (matching Nuvoton/Nations silicon).

Build with --enable-fwtpm --enable-spdm plus at least one of --enable-tcg / --enable-psk. Start in one of two modes:

./src/fwtpm/fwtpm_server --spdm-tcg              # TCG cert handshake
./src/fwtpm/fwtpm_server --spdm-psk \
    --spdm-psk-hex dbc2192291d807742441b963f6712841...   # PSK handshake
./src/fwtpm/fwtpm_server --no-spdm               # plaintext only (default)

The responder generates a fresh P-384 identity keypair at startup (used for GET_PUBK/KEY_EXCHANGE signing); the private key never leaves fwtpm_server memory and the stack copy is zeroed with wc_ForceZero after handoff to the responder context.

End-to-end coverage runs via the same script that drives real silicon:

./examples/spdm/spdm_test.sh ./examples/spdm/spdm_ctrl fwtpm-tcg
./examples/spdm/spdm_test.sh ./examples/spdm/spdm_ctrl fwtpm-psk

CI exercises 7 build-only configure permutations + the two e2e modes on ubuntu-latest via spdm-test.yml, against the fwTPM SPDM responder.

TPM 2.0 Command Coverage

Currently Implemented (105 commands)

The fwTPM implements 105 of 113 commands from the v1.38 baseline (93% coverage).

Always enabled (47 commands): Startup, Shutdown, SelfTest, IncrementalSelfTest, GetTestResult, GetRandom, StirRandom, GetCapability, TestParms, PCR_Read, PCR_Extend, PCR_Reset, PCR_Event, PCR_Allocate, PCR_SetAuthPolicy, PCR_SetAuthValue, ReadClock, ClockSet, ClockRateAdjust, CreatePrimary, FlushContext, ContextSave, ContextLoad, ReadPublic, Clear, ClearControl, ChangeEPS, ChangePPS, HierarchyControl, HierarchyChangeAuth, SetPrimaryPolicy, EvictControl, Create, ObjectChangeAuth, Load, Sign, VerifySignature, Hash, HMAC, HMAC_Start, HashSequenceStart, SequenceUpdate, SequenceComplete, EventSequenceComplete, StartAuthSession, Unseal, LoadExternal, Import, Duplicate, Rewrap, CreateLoaded, Vendor_TCG_Test

Conditional on algorithm (NO_RSA / HAVE_ECC / NO_AES): RSA_Encrypt, RSA_Decrypt, ECDH_KeyGen, ECDH_ZGen, ECC_Parameters, EC_Ephemeral, ZGen_2Phase, EncryptDecrypt, EncryptDecrypt2

Conditional on feature macros:

  • FWTPM_NO_POLICY: PolicyGetDigest, PolicyRestart, PolicyPCR, PolicyPassword, PolicyAuthValue, PolicyCommandCode, PolicyOR, PolicySecret, PolicyAuthorize, PolicyLocality, PolicySigned, PolicyNV, PolicyPhysicalPresence, PolicyCpHash, PolicyNameHash, PolicyDuplicationSelect, PolicyNvWritten, PolicyTemplate, PolicyCounterTimer, PolicyTicket, PolicyAuthorizeNV (21 commands)
  • FWTPM_NO_NV: NV_DefineSpace, NV_UndefineSpace, NV_UndefineSpaceSpecial, NV_ReadPublic, NV_Write, NV_Read, NV_Extend, NV_Increment, NV_WriteLock, NV_ReadLock, NV_SetBits, NV_ChangeAuth, NV_GlobalWriteLock (13 commands). Also gates PolicyNV and PolicyAuthorizeNV when policy is enabled.
  • FWTPM_NO_ATTESTATION: Quote, Certify, CertifyCreation, GetTime, NV_Certify
  • FWTPM_NO_CREDENTIAL: MakeCredential, ActivateCredential
  • FWTPM_NO_DA: DictionaryAttackLockReset, DictionaryAttackParameters (2 commands)
  • FWTPM_NO_PARAM_ENC: Disables parameter encryption/decryption for command and response parameters. Sessions still work for HMAC auth, but encrypted transport is disabled. Reduces code size by removing AES-CFB and XOR param encryption.

Missing Commands -- TODO

v1.38 Baseline (8 missing commands)

Medium (moderate logic, builds on existing infrastructure)
CommandSpec SectionDifficultyNotes
TPM2_SetCommandCodeAuditStatus21.2MediumManage list of commands that are audited. Needs audit bitmap in context
TPM2_PP_Commands26.2MediumManage physical presence command list. Needs PP command bitmap
Hard (complex crypto or new subsystems)
CommandSpec SectionDifficultyNotes
TPM2_GetSessionAuditDigest18.5HardSign session audit digest. Requires session audit tracking (running hash of all commands in session). New subsystem
TPM2_GetCommandAuditDigest18.6HardSign command audit digest. Requires command audit log with running hash. New subsystem
TPM2_Commit19.2HardDAA/anonymous attestation ephemeral key. Complex ECC point math (K,L,E generation). Needs DAA support in wolfCrypt
TPM2_SetAlgorithmSet26.3HardVendor-specific algorithm configuration. Rarely implemented, can return TPM_RC_COMMAND_CODE
TPM2_FieldUpgradeStart27.2HardFirmware upgrade initiation. Vendor-specific, requires secure update infrastructure
TPM2_FieldUpgradeData27.3HardFirmware upgrade data blocks. Vendor-specific
TPM2_FirmwareRead27.4HardRead firmware for backup. Vendor-specific

v1.59 Additions (7 commands)

CommandSpec SectionDifficultyNotes
TPM2_MAC15.6MediumBlock cipher MAC (CMAC). Like HMAC but uses symmetric key. Needs wolfCrypt CMAC
TPM2_MAC_Start17.3MediumStart MAC sequence. Mirrors HMAC_Start for CMAC
TPM2_CertifyX50918.8HardGenerate partial X.509 certificate. Complex ASN.1 construction, caller provides tbsCert template. Deprecated in v1.84
TPM2_AC_GetCapability32.2HardAttached component capability query. Hardware-specific, rarely needed for software TPM
TPM2_AC_Send32.3HardSend data to attached component. Hardware-specific
TPM2_Policy_AC_SendSelect32.4MediumPolicy for AC_Send. Like other policy commands
TPM2_ACT_SetTimeout33.2MediumSet authenticated countdown timer. Needs ACT state + timer infrastructure

v1.84 Additions (9 commands)

CommandSpec SectionDifficultyNotes
TPM2_ECC_Encrypt14.8MediumECC-based encryption (ECIES/ElGamal). wolfCrypt ECIES support available
TPM2_ECC_Decrypt14.9MediumECC-based decryption. Paired with ECC_Encrypt
TPM2_PolicyCapability23.xEasyAssert TPM capability value in policy session
TPM2_PolicyParameters23.xEasyAssert command parameters in policy session
TPM2_SetCapability30.xMediumModify TPM capability settings. Platform auth required
TPM2_NV_DefineSpace231.xMediumExtended NV space definition (larger attribute field). Extends existing NV_DefineSpace
TPM2_NV_ReadPublic231.xEasyExtended NV public read. Extends existing NV_ReadPublic
TPM2_ReadOnlyControl24.xEasyToggle TPM read-only mode. Simple flag
TPM2_PolicyTransportSPDM23.xHardSPDM transport policy. Requires SPDM protocol support

Coverage Summary

The eight v1.85 PQC commands (TPM2_Encapsulate, TPM2_Decapsulate, TPM2_SignDigest, TPM2_VerifyDigestSignature, TPM2_SignSequenceStart, TPM2_SignSequenceComplete, TPM2_VerifySequenceStart, TPM2_VerifySequenceComplete) are implemented under --enable-pqc (alias --enable-v185). See "v1.85 Limitations / Scope" below for the documented PQC-only restriction.

Spec VersionTotal CommandsImplementedMissingCoverage
v1.38113105893%
v1.591201051588%
v1.841291052481%
v1.851371132482%

v1.85 Limitations / Scope

The following v1.85 commands are implemented for post-quantum keys only; non-PQC key types are rejected with TPM_RC_KEY / TPM_RC_SCHEME even when the v1.85 spec defines them generically:

  • TPM2_Encapsulate / TPM2_Decapsulate — ML-KEM only. ECC DHKEM (Table 100 ecdh arm with non-NULL KDF) is not implemented.
  • TPM2_SignSequenceStart / VerifySequenceStart / SignSequenceComplete / VerifySequenceComplete — ML-DSA and Hash-ML-DSA only. Classical schemes (RSASSA, RSAPSS, ECDSA, SM2, ECSCHNORR, HMAC) that the spec also permits via these commands are not supported.
  • TPM2_SignDigest / TPM2_VerifyDigestSignature — ML-DSA and Hash-ML-DSA only. Classical digest signing (RSASSA, RSAPSS, ECDSA) over these new commands is not supported; use the existing TPM2_Sign / TPM2_VerifySignature commands for those schemes.