The rust-tpm2-cli crate provides a suite of Rust-based command-line tools for interacting with Trusted Platform Module 2.0 (TPM 2.0) devices.
Note
This project is heavily inspired by tpm2-tools and gratefully acknowledges the work of its contributors.
The (sub)command names and CLI argument names are designed to be largely compatible with those of tpm2-tools.
See the Comparison with tpm2-tools section for details.
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
source "$HOME/.cargo/env"rust-tpm2-cli targets the latest tpm2-tss's main branch, which includes significant updates beyond the 4.1.3 release (e.g. Unix domain socket support for the swtpm TCTI).
However, as of now, the next version (v4.2.0) has not yet been released.
To build tpm2-tss from source:
# Install build dependencies
sudo apt update
sudo apt install -y \
git autoconf autoconf-archive automake build-essential doxygen pkg-config \
libtool libcmocka0 libcmocka-dev libcurl4-openssl-dev libftdi-dev libini-config-dev \
libjson-c-dev libltdl-dev libssl-dev libusb-1.0-0-dev uthash-dev uuid-dev
# Clone latest main and build
git clone --depth 1 https://github.com/tpm2-software/tpm2-tss
cd tpm2-tss
git tag "4.1.999" # Dummy version
./bootstrap
./configure --prefix=/usr \
--disable-fapi --disable-weakcrypto --disable-integration
make -j$(nproc)
sudo make install
sudo ldconfigSee also Installation instructions for tpm2-tss.
git clone https://github.com/hyperfinitism/rust-tpm2-cli
cd rust-tpm2-cli
TSS2_ESYS_STATIC=1 TSS2_SYS_STATIC=1 TSS2_MU_STATIC=1 TSS2_TCTILDR_STATIC=1 cargo build --release
# => ./target/release/tpm2The TPM Command Transmission Interface (TCTI) is the abstraction layer within the TPM Software Stack (TSS) that defines how commands are transmitted to a TPM device.
rust-tpm2-cli reads the default TCTI from the RUST_TPM2_CLI_TCTI environment variable.
This can be overridden per invocation with the --tcti, -T global option.
Caution
A platform TPM may already be in use by the system for measured boot, full disk encryption, or remote attestation. Careless operations — such as clearing hierarchies or changing auth values — can irreversibly break these functions.
Use a software TPM emulator such as swtpm or mssim for development and testing.
See also Using swtpm.
# Find TPM device paths, e.g., /dev/tpm0, /dev/tpmrm0
ls -l /dev/tpm*
# Add current user to tss usergroup to grant access permissions to TPMRM
sudo usermod "$USER" -aG tss
newgrp tss
# Set default TCTI to device:/dev/tpmrm0
export RUST_TPM2_CLI_TCTI="device:/dev/tpmrm0"/dev/tpm* exposes the TPM character device provided by the kernel TPM driver.
Only one process can safely use this path at a time.
If you encounter a "device busy" error when using /dev/tpm*, it is likely because another process (such as tpm2-abrmd) already holds an exclusive session.
In contrast, /dev/tpmrm* provides the in-kernel TPM 2.0 resource manager (TPMRM).
It virtualises handles and manages context swapping so that multiple processes can share the TPM safely.
For most applications, /dev/tpmrm* is the recommended device node.
TPM2 Access Broker & Resource Manager (tpm2-abrmd) is a user space daemon that serves as an alternative to the in-kernel resource manager on older kernels (< 4.12) where /dev/tpmrm* is not available.
# Install tpm2-abrmd
sudo apt install -y tpm2-abrmd
# Start tpm2-abrmd service
sudo systemctl start tpm2-abrmd.service
# Check status
systemctl status tpm2-abrmd.service
# Set default TCTI to tabrmd
# Note: Argument "bus_type=system" may be omitted
export RUST_TPM2_CLI_TCTI="tabrmd:bus_type=system"swtpm is a software TPM 2.0 emulator that runs entirely in user space.
It is safe for development and testing — its state is ephemeral and isolated from the platform TPM.
It is also useful for trying out rust-tpm2-cli on environments without a platform TPM.
# Install swtpm
sudo apt install -y swtpm
# Start swtpm
mkdir -p /tmp/swtpm
swtpm socket \
--tpm2 \
--tpmstate dir=/tmp/swtpm \
--server type=tcp,port=2321 \
--ctrl type=tcp,port=2322 \
--flags startup-clear
# In another terminal, set default TCTI to swtpm
export RUST_TPM2_CLI_TCTI="swtpm:host=localhost,port=2321"tpm2 [GLOBAL_OPTIONS...] <subcommand> [SUBCOMMAND_OPTIONS]For a full list of subcommands:
tpm2 -hFor details on a specific subcommand:
tpm2 <subcommand> -h# Print all supported capability names (ecc-curves, handles-persistent, ...)
tpm2 getcap --list
# Supported elliptic curves for cryptography
tpm2 getcap ecc-curves
# Persistent object handles
tpm2 getcap handles-persistent
# NV index handles
tpm2 getcap handles-nv-index
# PCR handles (typically 0x0..0x17, i.e., 0..23)
tpm2 getcap handles-pcrtpm2 getrandom 32 --hex
tpm2 getrandom 32 -o random.binecho "hello world" > message.dat
tpm2 hash message.dat -g sha384 --hex
tpm2 hash message.dat -g sha384 -o digest.bin -t ticket.bin# Create a primary key under the owner hierarchy
tpm2 createprimary -C o -G ecc -c primary.ctx
# Create an unrestricted signing key
tpm2 create -C file:primary.ctx -G ecc -u key.pub -r key.priv
# Load the signing key
tpm2 load -C file:primary.ctx -u key.pub -r key.priv -c key.ctx
# Hash a message
echo -n "message" > message.dat
tpm2 hash message.dat -g sha256 -o digest.bin
# Sign the digest
tpm2 sign -c file:key.ctx -g sha256 -s ecdsa -d digest.bin -o sig.bin
# Verify
tpm2 verifysignature -c file:key.ctx -g sha256 -m message.dat -s sig.bin
tpm2 verifysignature -c file:key.ctx -d digest.bin -s sig.bin# Create and persist an Endorsement Key (EK)
tpm2 createek -c ek.ctx -G ecc -u ek.pub
tpm2 evictcontrol 0x81010001 -C o -c file:ek.ctx
# Create and persist an Attestation Key (AK)
tpm2 createak -C file:ek.ctx -c ak.ctx -G ecc -u ak.pub
tpm2 evictcontrol 0x81000002 -C o -c file:ak.ctx
# Generate a nonce for freshness
tpm2 getrandom 32 -o nonce.bin
# Quote PCRs 0–7 signed by the AK
tpm2 quote -c hex:0x81000002 -l sha256:0,1,2,3,4,5,6,7 \
-q file:nonce.bin \
-m quote.bin -s sig.bin -o pcrs.bin
# Verify the quote
tpm2 checkquote -u hex:0x81000002 -m quote.bin -s sig.bin \
-l sha256:0,1,2,3,4,5,6,7 \
-q file:nonce.bin \
-f pcrs.bin
# Verify quote signature only
tpm2 verifysignature -c file:ak.ctx -g sha256 -m quote.bin -s sig.bin# Create a primary key under the owner hierarchy
tpm2 createprimary -C o -G ecc -c primary.ctx
# Create an unrestricted signing key
tpm2 create -C file:primary.ctx -G ecc -u key.pub -r key.priv
# Load the signing key
tpm2 load -C file:primary.ctx -u key.pub -r key.priv -c key.ctx
# Generate a nonce for freshness
tpm2 getrandom 32 -o nonce.bin
# Get signed timestamp
tpm2 gettime -c file:key.ctx -g sha256 -q file:nonce.bin -o time-attest.bin -s time-sig.bin
# Verify signature
tpm2 verifysignature -c file:key.ctx -g sha256 -m time-attest.bin -s time-sig.bin# Define NV index
tpm2 nvdefine 0x01400002 -s 64 -C o
# Write binary file to NV index
openssl rand 64 > random.bin
tpm2 nvwrite 0x01400002 -i random.bin -C o
# Read data from NV index
tpm2 nvread 0x01400002 -C o
# Undefine NV index
tpm2 nvundefine 0x01400002 -C o# Read PCR bank
tpm2 pcrread sha1:0,1,2+sha256:all
tpm2 pcrread sha256:16 -o pcr16.bin
# Extend PCR 16
echo "hello world" > message.dat
tpm2 hash message.dat -g sha256 -o digest.bin
DIGEST_HEX=$(xxd -p digest.bin | tr -d '\n')
tpm2 pcrextend 16:sha256=${DIGEST_HEX}
tpm2 pcrread sha256:16
# == cat pcr16.bin digest.bin | sha256sum
# Reset PCR 16
tpm2 pcrreset 16While broadly following the tpm2-tools APIs, rust-tpm2-cli is a from-scratch implementation.
The key differences are:
| - | rust-tpm2-cli |
tpm2-tools |
|---|---|---|
| Language | Rust | C |
| TPM Software Stack (TSS) | rust-tss-esapi1 | tpm2-tss |
| Binary size order2 | several MB | sub MB |
tpm2-tools has a significantly smaller binary footprint, making it a better fit for resource-constrained environments such as IoT devices with limited storage or memory.
It also benefits from a long track record and broad backward compatibility.
rust-tpm2-cli trades binary size for Rust's memory safety guarantees, rich type system, and expressive language features, which reduce entire classes of bugs at compile time.
rust-tpm2-cli introduces a number of deliberate improvements (breaking changes) for clarity and consistency:
-
Explicit handle vs. context arguments:
tpm2-toolsaccepts either a TPM handle (hex string) or a raw context file path through a single argument.rust-tpm2-clirequires such arguments to have prefixhex:orfile:, making the type of the input unambiguous. -
Extended context file support: Some arguments in
tpm2-toolsaccept only a TPM handle in hex string form without an apparent reason (e.g. public key incheckquote).rust-tpm2-cliremoves this restriction and allows a context file to be specified wherever it is semantically appropriate. -
Subcommand splitting: Subcommands that conflate distinct operations have been separated. For example, the
encryptdecryptsubcommand oftpm2-toolsis split into two dedicated subcommandsencryptanddecrypt. (At the moment,encryptdecryptis kept for compatibility.) -
Flexible logging:
rust-tpm2-cliuses flexi_logger for flexible logging control via CLI flags. Logs can also be written to a file.
- The source code is licensed under Apache-2.0.
- The project logo assets are licensed under CC0-1.0.
Footnotes
-
Note that
rust-tss-esapiis a Rust wrapper around the C-basedtpm2-tsslibrary, not a pure Rust implementation. Both projects currently depend on the same underlying C library for TPM communication. ↩ -
Approx. 6.5MB (6,523,504B) vs. 0.85MB (850,552B). The actual sizes depend on both the version and the build environment. This comparison is based on
rust-tpm2-cli(commit:3986a79271c64cbc29a58453d56ebd00e776d1ea) andtpm2-tools(commit:bc4cf8bca83c15deb62af448f609caa8ba0111da). ↩
