Using the fwTPM¶
This page covers running the fwTPM server, connecting clients, transport modes, NV persistence, testing, the C API, and real-world board examples. To build the server first, see Building.
Starting the Server¶
./src/fwtpm/fwtpm_server [options]
Options:
| Option | Description |
|---|---|
--help, -h |
Show usage information |
--version, -v |
Print version string |
--port <port> |
Command port (default: 2321) |
--platform-port <port> |
Platform port (default: 2322) |
--clear |
Start with cleared NV |
--spdm-tcg, --spdm-psk, --no-spdm |
SPDM responder mode (see SPDM Responder) |
The --port and --platform-port options are socket-mode only and are not available in TIS builds (--enable-fwtpm --disable-swtpm).
Example:
# Start with default ports (localhost:2321 command, :2322 platform)
./src/fwtpm/fwtpm_server
# Start on custom ports
./src/fwtpm/fwtpm_server --port 2331 --platform-port 2332
# Start with clear NV
./src/fwtpm/fwtpm_server --clear
The server prints its configuration on startup:
wolfTPM fwTPM Server v0.1.0
Command port: 2321
Platform port: 2322
Manufacturer: WOLF
Model: fwTPM
In --spdm-tcg test mode the server also prints its generated responder public key. This is a local test-harness convenience, not a provisioning or trust-anchor channel for hardware responders.
Connecting wolfTPM Clients¶
Any wolfTPM application built with --enable-swtpm connects to the fwTPM server automatically over TCP. The built-in swtpm client speaks the mssim protocol.
# In one terminal: start the server
./src/fwtpm/fwtpm_server
# In another terminal: run wolfTPM examples
./examples/wrap/wrap_test
./examples/wrap/caps
./examples/keygen/keygen keyblob.bin -rsa -t
./examples/attestation/make_credential
Using tpm2-tools¶
In socket mode (--enable-swtpm), the server supports both the mssim (Microsoft TPM simulator) and swtpm (Stefan Berger) TCTI protocols, which it auto-detects on the command port. Either TCTI works:
# mssim TCTI (default for wolfTPM test scripts)
export TPM2TOOLS_TCTI="mssim:host=localhost,port=2321"
tpm2_startup -c
# swtpm TCTI (also works, auto-detected)
export TPM2TOOLS_TCTI="swtpm:host=localhost,port=2321"
tpm2_getrandom 8
NV Persistence¶
The server stores persistent state (hierarchy seeds, auth values, PCR state, NV indices) in fwtpm_nv.bin (configurable with FWTPM_NV_FILE). On first start, seeds are randomly generated and saved. Later starts reload the existing state.
Embedded targets replace the file backend with a flash, EEPROM, or other NV HAL, including an append-only mode for write-once flash. See HAL and Porting.
Transport Modes¶
Socket / SWTPM (Default)¶
Built with --enable-fwtpm --enable-swtpm. The server listens on two TCP ports using the SWTPM wire protocol:
- Command port (default 2321): TPM command and response traffic
- Platform port (default 2322): Platform signals (power on and off, NV on, cancel, reset, session end, stop)
SWTPM TCP protocol commands (platform port):
| Signal | Value | Description |
|---|---|---|
SIGNAL_POWER_ON |
1 | Power on the TPM |
SIGNAL_POWER_OFF |
2 | Power off the TPM |
SIGNAL_PHYS_PRES_ON |
3 | Assert physical presence |
SIGNAL_PHYS_PRES_OFF |
4 | Deassert physical presence |
SIGNAL_HASH_START |
5 | Start measured boot hash |
SIGNAL_HASH_DATA |
6 | Provide measured boot data |
SIGNAL_HASH_END |
9 | End measured boot hash |
SEND_COMMAND |
8 | Send TPM command (command port) |
SIGNAL_NV_ON |
11 | NV storage available |
SIGNAL_CANCEL_ON |
13 | Cancel current command |
SIGNAL_CANCEL_OFF |
14 | Clear cancel |
SIGNAL_RESET |
17 | Reset TPM |
SESSION_END |
20 | End TCP session |
STOP |
21 | Stop server |
wolfTPM clients connect through the standard SWTPM interface, which is compatible with tpm2-tools and other SWTPM-aware software.
TIS / Shared Memory¶
Built with --enable-fwtpm --disable-swtpm. This mode uses POSIX shared memory and named semaphores to emulate TIS (TPM Interface Specification) register-level access. It simulates an SPI-attached TPM.
Shared memory layout (FWTPM_TIS_SHM):
| Field | Description |
|---|---|
magic / version |
Validation header (0x57544953 / "WTIS", protocol version 2) |
reg_addr, reg_len, reg_is_write, reg_data |
Register access request |
TIS register shadow: access, sts, int_enable, int_status, intf_caps, did_vid, rid |
Emulated TIS registers |
cmd_buf[4096], cmd_len, fifo_write_pos |
Command FIFO |
rsp_buf[4096], rsp_len, fifo_read_pos |
Response FIFO |
Paths (compile-time configurable):
| Define | Default | Description |
|---|---|---|
FWTPM_TIS_SHM_PATH |
/tmp/fwtpm.shm |
Shared memory file; clients require a regular, single-link, same-UID, exact-size 0600 endpoint |
FWTPM_TIS_SEM_CMD |
/fwtpm_cmd |
Command semaphore name |
FWTPM_TIS_SEM_RSP |
/fwtpm_rsp |
Response semaphore name |
Clients require an exact protocol version and shared-region-size match, so rebuild the client library and fwtpm_server together when changing options that affect FWTPM_TIS_FIFO_SIZE. The default paths are global, so run one server per host.
Server-side API:
FWTPM_TIS_Init(): create shared memory and semaphoresFWTPM_TIS_Cleanup(): remove shared memory and semaphoresFWTPM_TIS_ServerLoop(): process TIS register accesses and dispatch commands
Client-side API (enabled by WOLFTPM_FWTPM_HAL):
FWTPM_TIS_ClientConnect(): attach to existing shared memoryFWTPM_TIS_ClientDisconnect(): detach from shared memory
Testing¶
make check # Build + unit.test + run_examples.sh + tpm2-tools
scripts/tpm2_tools_test.sh # tpm2-tools only (311 tests)
make check runs tests/fwtpm_check.sh, which starts and stops fwtpm_server automatically. Do not start the server manually for it.
CI Tests (fwtpm-test.yml)¶
All tests below run in GitHub Actions CI. Run them manually before PR submission. ASan, UBSan, and LeakSan coverage lives in sanitizer.yml, not this workflow.
Runtime tests (build, run_examples.sh, make check):
| Name | wolfTPM Config | Extra | Notes |
|---|---|---|---|
| fwtpm-socket | --enable-fwtpm --enable-swtpm --enable-debug |
Primary test | |
| fwtpm-tis | --enable-fwtpm --disable-swtpm --enable-debug |
TIS/SHM transport | |
| fwtpm-v185 | --enable-fwtpm --enable-v185 |
PQC: wrapper and handler unit tests | |
| fwtpm-macos-socket | --enable-fwtpm --enable-swtpm --enable-debug |
macOS runner |
Runtime tests, gated builds (fwtpm-gated-runtime job):
These configurations remove commands, so make check (which drives the examples and tpm2-tools) does not apply. The job builds and runs only tests/fwtpm_unit.test. Its test_fwtpm_command_gates, test_fwtpm_total_commands, and test_fwtpm_pcr_bounds cases assert that a gated command is rejected with TPM_RC_COMMAND_CODE, is absent from TPM_CAP_COMMANDS, and is not counted in TPM_PT_TOTAL_COMMANDS.
| Name | wolfTPM Config | wolfSSL Config | Extra CFLAGS |
|---|---|---|---|
| all-gates-ecc-only | --enable-fwtpm --enable-swtpm |
--disable-rsa |
the eleven command-group -DFWTPM_NO_* gates together (NV retained) |
| all-gates-mldsa | --enable-fwtpm --enable-swtpm --enable-v185 --enable-mldsa |
--enable-dilithium --enable-mlkem |
the same eleven gates; proves SequenceUpdate survives for ML-DSA while SequenceComplete does not |
| reduced-pcr | --enable-fwtpm --enable-swtpm |
-DIMPLEMENTATION_PCR=8 -DPLATFORM_PCR=8 |
Build-only tests:
| Name | wolfTPM Config | wolfSSL Config | Extra CFLAGS |
|---|---|---|---|
| fwtpm-no-rsa | --enable-fwtpm --enable-swtpm |
--disable-rsa |
|
| fwtpm-no-ecc | --enable-fwtpm --enable-swtpm |
--disable-ecc |
|
| fwtpm-no-sha384 | --enable-fwtpm --enable-swtpm |
--disable-sha384 |
|
| fwtpm-no-sha1 | --enable-fwtpm --enable-swtpm |
--disable-sha |
-DNO_SHA |
| fwtpm-v185-build-only | --enable-fwtpm --enable-v185 |
-DDEBUG_WOLFTPM |
|
| fwtpm-only | --enable-fwtpm-only --enable-swtpm |
No 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-key-migration | --enable-fwtpm --enable-swtpm |
-DFWTPM_NO_KEY_MIGRATION |
|
| fwtpm-no-ecdh | --enable-fwtpm --enable-swtpm |
-DFWTPM_NO_ECDH |
|
| fwtpm-no-hash-cmds | --enable-fwtpm --enable-swtpm |
-DFWTPM_NO_HASH_CMDS |
|
| fwtpm-no-context | --enable-fwtpm --enable-swtpm |
-DFWTPM_NO_CONTEXT |
|
| fwtpm-no-sym-encrypt | --enable-fwtpm --enable-swtpm |
-DFWTPM_NO_SYM_ENCRYPT |
|
| fwtpm-no-clock | --enable-fwtpm --enable-swtpm |
-DFWTPM_NO_CLOCK |
|
| fwtpm-reduced-pcr | --enable-fwtpm --enable-swtpm |
-DIMPLEMENTATION_PCR=8 -DPLATFORM_PCR=8 |
|
| 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):
| Name | Compiler | Config |
|---|---|---|
| fwtpm-pedantic-gcc | gcc | --enable-fwtpm --enable-swtpm |
| fwtpm-pedantic-clang | clang | --enable-fwtpm --enable-swtpm |
| fwtpm-pedantic-only | gcc | --enable-fwtpm-only |
Separate job: tpm2-tools (311 tests):
scripts/tpm2_tools_test.sh
API Reference¶
Core (fwtpm.h)¶
| Function | Description |
|---|---|
int FWTPM_Init(FWTPM_CTX* ctx) |
Initialize fwTPM context, RNG, load NV state |
int FWTPM_Cleanup(FWTPM_CTX* ctx) |
Save NV, free resources, zero sensitive data |
const char* FWTPM_GetVersionString(void) |
Return version string (for example "0.1.0") |
Command Processor (fwtpm_command.h)¶
| Function | Description |
|---|---|
int FWTPM_ProcessCommand(FWTPM_CTX* ctx, const byte* cmdBuf, int cmdSize, byte* rspBuf, int* rspSize, int locality) |
Process a raw TPM command packet and produce a response. Returns TPM_RC_SUCCESS on successful processing; the response buffer may contain a TPM error RC. |
IO Transport (fwtpm_io.h)¶
| Function | Description |
|---|---|
int FWTPM_IO_SetHAL(FWTPM_CTX* ctx, FWTPM_IO_HAL* hal) |
Register custom IO transport callbacks |
int FWTPM_IO_Init(FWTPM_CTX* ctx) |
Initialize transport (sockets or custom HAL) |
void FWTPM_IO_Cleanup(FWTPM_CTX* ctx) |
Close transport and release resources |
int FWTPM_IO_ServerLoop(FWTPM_CTX* ctx) |
Main server loop; blocks until ctx->running is cleared |
NV Storage (fwtpm_nv.h)¶
| Function | Description |
|---|---|
int FWTPM_NV_Init(FWTPM_CTX* ctx) |
Load NV state from storage or create new (generates seeds) |
int FWTPM_NV_Save(FWTPM_CTX* ctx) |
Save current TPM state to NV storage |
int FWTPM_NV_SetHAL(FWTPM_CTX* ctx, FWTPM_NV_HAL* hal) |
Register custom NV storage callbacks |
TIS Server (fwtpm_tis.h)¶
| Function | Description |
|---|---|
int FWTPM_TIS_Init(FWTPM_CTX* ctx) |
Create shared memory region and semaphores |
void FWTPM_TIS_Cleanup(FWTPM_CTX* ctx) |
Unlink shared memory and semaphores |
int FWTPM_TIS_ServerLoop(FWTPM_CTX* ctx) |
Process TIS register accesses (blocks) |
TIS Client (fwtpm_tis.h, requires WOLFTPM_FWTPM_HAL)¶
| Function | Description |
|---|---|
int FWTPM_TIS_ClientConnect(FWTPM_TIS_CLIENT_CTX* client) |
Attach to fwTPM shared memory |
void FWTPM_TIS_ClientDisconnect(FWTPM_TIS_CLIENT_CTX* client) |
Detach from shared memory |
Real-world examples¶
The wolftpm-examples repository holds complete fwTPM projects for real boards. Each one shows a different isolation or storage choice.
| Board | Project | What it shows |
|---|---|---|
| STM32H5 NUCLEO-H563ZI | STM32/fwtpm-stm32h5 | fwTPM in the Cortex-M33 TrustZone secure world, internal-flash NV, UART with the mssim protocol |
| Xilinx ZCU102 (R5, lock-step) | Xilinx/fwtpm-zcu102-r5 | AMP: fwTPM bare-metal on the Cortex-R5 pair in lock-step, PetaLinux client on the A53 over OpenAMP RPMsg; volatile DDR NV or persistent QSPI |
| Xilinx ZC702 (A9) | Xilinx/fwtpm-zc702-a9 | SRAM-PUF derived device-unique NV key, so no root key is stored in flash |
| SCU35 (MicroBlaze-V soft core) | Xilinx/fwtpm-scu35-microblazev | ECC-only fwTPM that fits in about 190 KB of block RAM |
| PolarFire SoC MPFS250T | Microchip/fwtpm-polarfire-miv | AMP: fwTPM bare-metal on a U54 hart, isolated from Linux, TIS over shared L2-LIM memory |
| PolarFire MPF300 Splash (soft MIV) | Microchip/miv-mpf300-splash | Soft Mi-V core with persistent on-die sNVM |
The STM32H5, PolarFire SoC, and ZCU102 projects are also listed as ports in HAL and Porting.