spdm-rs

August 18, 2026 · View on GitHub

CI Deny Format Fuzzing OpenSSF Best Practices

spdm-rs

This project provides a Rust language implementation of SPDM, IDE_KM and TDISP. These protocols are used to facilitate direct device assignment for Trusted Execution Environment I/O (TEE-I/O) in Confidential Computing.

There are a number of use cases that benefit from including devices and accelerators in the trust boundary of a Confidential Virtual Machine (CVM). In machine learning, for example, these protocols can be used to build a trusted connection between a GPU’s TEE and a CVM to accelerate performance.

Features

Specification

DMTF

DMTF DSP0274 Security Protocol and Data Model (SPDM) Specification (version 1.4.0)

DMTF DSP0277 Secured Messages using SPDM Specification (version 1.2.0)

PCI-SIG

PCIe Base Specification Version 6.0.1, 6.1, 6.2.

PCIe DOE 1.0 ECN for PCIe 4.0, 5.0 (integrated in 6.0), DOE 1.1 ECN for PCIe 5.0, 6.0 (integrated in 6.1).

PCIe CMA 1.0 ECN for PCIe 4.0, 5.0 (integrated in 6.0), CMA 1.1 ECN for PCIe 6.1 (integrated in 6.2).

PCIe IDE ECN for PCIe 5.0 (integrated in 6.0).

PCIe TDISP ECN for PCIe 5.0, 6.0 (integrated in 6.1).

SPDM Implemented Requests and Responses

SPDM 1.0: GET_VERSION, GET_CAPABILITIES, NEGOTIATE_ALGORITHMS, GET_DIGESTS, GET_CERTIFICATE, CHALLENGE, GET_MEASUREMENTS, and VENDOR_DEFINED messages.

SPDM 1.1: KEY_EXCHANGE, FINISH, PSK_EXCHANGE, PSK_FINISH, END_SESSION, HEARTBEAT, KEY_UPDATE, and ENCAPSULATED messages.

SPDM 1.2: CHUNK messages.

SPDM 1.3: No new messages.

SPDM 1.4: No new messages.

SPDM Vendor Defined Message

IDE_KM 1.0 in PCIe 6.0.

TDISP 1.0 in PCIe 6.1.

SPDM Capability Support

Requester: ENCRYPT_CAP, MAC_CAP, KEY_EX_CAP, PSK_CAP, HBEAT_CAP, KEY_UPD_CAP, HANDSHAKE_IN_THE_CLEAR_CAP, CHUNK_CAP, LARGE_RESP_CAP.

Responder: CERT_CAP, CHAL_CAP, MEAS_CAP_NO_SIG, MEAS_CAP_SIG, MEAS_FRESH_CAP, ENCRYPT_CAP, MAC_CAP, KEY_EX_CAP, PSK_CAP_WITHOUT_CONTEXT, PSK_CAP_WITH_CONTEXT, HBEAT_CAP, KEY_UPD_CAP, HANDSHAKE_IN_THE_CLEAR_CAP, CHUNK_CAP, ALIAS_CERT_CAP, LARGE_RESP_CAP.

SPDM Cryptographic Algorithm Support

It depends on crypto wrapper. Current support algorithms:

  • Hash: SHA2(256/384/512)
  • Signature: RSA-SSA(2048/3072/4096) / RSA-PSS(2048/3072/4096) / ECDSA (P256/P384)
  • PQC Signature: ML-DSA (44/65/87) — requires spdm-aws-lc feature and aws-lc-rs
  • KeyExchange: ECDHE(P256/P384)
  • PQC KeyExchange: ML-KEM (512/768/1024) — requires spdm-aws-lc feature and aws-lc-rs
  • AEAD: AES_GCM(128/256) / ChaCha20Poly1305

Documentation

All documents are put at doc folder.

Build Rust SPDM

Checkout repo

git clone https://github.com/ccc-spdm-tools/spdm-rs.git
git submodule update --init --recursive

Then patch ring.

sh_script/pre-build.sh

Tools

  1. Install RUST

Please use stable version.

  1. Install NASM

Please make sure nasm can be found in PATH.

  1. Install LLVM

Please make sure clang can be found in PATH.

  1. Install Perl

    1. This is for crate ring
    2. This is for windows

Please make sure perl can be found in PATH.

Unset env (CC and AR):

export CC=
export AR=

Set the following environment variables:

export AR_x86_64_unknown_none=llvm-ar
export CC_x86_64_unknown_none=clang

Build OS application

Enter linux shell or mingw shell (e.g. git bash) in windows.

cargo clippy
cargo fmt
cargo build

Build async no_std spdm

pushd spdmlib
cargo build --target x86_64-unknown-none --release --no-default-features --features="spdm-ring"

Build sync no_std spdm

pushd spdmlib
cargo build --target x86_64-unknown-none --release --no-default-features --features="spdm-ring,is_sync"

Run Rust SPDM emulator

Run emulator with default feature

Open one command windows and run:

cargo run -p spdm-responder-emu --no-default-features --features "spdm-ring,hashed-transcript-data,async-executor"

Open another command windows and run:

cargo run -p spdm-requester-emu --no-default-features --features "spdm-ring,hashed-transcript-data,async-executor"

Run emulator with selected feature

The following list shows the supported combinations for both spdm-requester-emu and spdm-responder-emu

FeaturesCryptoLibraryHashed transcript data supportsync/asyncnotes
spdm-ring,is_syncringNosyncuse ring as crypto library with hashed-transcript-data disabled, sync version.
spdm-ring,hashed-transcript-data,is_syncringYessyncuse ring as crypto library with hashed-transcript-data enabled, sync version.
spdm-ring,hashed-transcript-data,async-tokioringYestokio async runtimeuse ring as crypto library with hashed-transcript-data enabled, async version, use tokio as async runtime
spdm-mbedtls,is_syncmbedtlsNosyncuse mbedtls as crypto library with hashed-transcript-data disabled, sync version.
spdm-mbedtls,hashed-transcript-data,is_syncmbedtlsYessyncuse mbedtls as crypto library with hashed-transcript-data enabled, sync version.
spdm-mbedtls,hashed-transcript-data,async-executormbedtlsYesexecutor async runtimeuse mbedtls as crypto library with hashed-transcript-data enabled, async version, use executor as async runtime
spdm-ring,hashed-transcript-data,async-executor,spdm-aws-lcring+aws-lc-rsYesexecutor async runtimeuse ring + aws-lc-rs for PQC (ML-DSA, ML-KEM) with hashed-transcript-data enabled, async version
spdm-mbedtls,hashed-transcript-data,async-executor,spdm-aws-lcmbedtls+aws-lc-rsYesexecutor async runtimeuse mbedtls + aws-lc-rs for PQC (ML-DSA, ML-KEM) with hashed-transcript-data enabled, async version
spdm-aws-lc,hashed-transcript-data,async-executoraws-lc-rs (standalone)Yesexecutor async runtimeaws-lc-rs alone (no spdm-ring/spdm-mbedtls) for BOTH classical and PQC — no ring, no mbedtls linked. std-only.

Notes on spdm-aws-lc:

  • Combined with a classical backend (spdm-ring or spdm-mbedtls), spdm-aws-lc is a PQC overlay: it supplies only the post-quantum algorithms (ML-DSA, ML-KEM) on top of that backend, which still provides the traditional algorithms (hash, HMAC, AEAD, ECDHE, RSA/ECDSA, HKDF, cert chain).
  • On its own — spdm-aws-lc with neither spdm-ring nor spdm-mbedtls — it is the standalone backend: aws-lc-rs supplies both classical and PQC crypto, with no ring and no mbedtls linked (cargo tree -i ring reports ring absent). This mode is std-only — aws-lc-rs cannot serve the no_std (x86_64-unknown-none) target, so ring/mbedtls remain the backends for embedded/UEFI builds.

For example, run the emulator with spdm-ring enabled and without hashed-transcript-data enabled, and use executor as async runtime. Open one command windows and run:

cargo run -p spdm-responder-emu --no-default-features --features "spdm-ring,async-executor "

run the emulator with spdm-mbedtls enabled and with hashed-transcript-data enabled, and use tokio as async runtime.
Open another command windows and run:

cargo run -p spdm-requester-emu --no-default-features --features "spdm-mbedtls,hashed-transcript-data,async-tokio"

run the emulator with spdm-mbedtls enabled and with hashed-transcript-data enabled, and without using async style.
Open another command windows and run:

cargo run -p spdm-requester-emu --no-default-features --features "spdm-mbedtls,hashed-transcript-data,is_sync"

NOTE: In order to run the emu without hashed-transcript-data, please change max_cert_chain_data_size in spdmlib/etc/config.json from 4096 to 3500.

Run the responder emulator using the certificate chain and private key specified in environment variables

Open command window and run:

export SPDMRS_RSP_EMU_CERT_CHAIN_PATH=/path/to/cert_bundle.der
export SPDMRS_RSP_EMU_PRIVATE_KEY_PATH=/path/to/device.key.p8

cargo run -p spdm-responder-emu --no-default-features --features "spdm-ring,hashed-transcript-data,async-executor"

If RSA is used instead of ECDSA, following environment variables can be set before running spdm-requester-emu, spdm-responder-emu, or spdmlib-test:

export SPDMRS_USE_ECDSA=false        # controls base_asym_algo (BaseAsymAlgo)
export SPDMRS_REQ_USE_ECDSA=false    # controls req_asym_algo (ReqBaseAsymAlg)

Run emulator with raw public key (PUB_KEY_ID) mode

spdm-rs supports raw public key authentication per RFC 7250 (PUB_KEY_ID) as an alternative to certificate chains. In this mode, the responder uses a SubjectPublicKeyInfo DER-encoded public key instead of a full certificate chain.

To enable raw public key mode, set the SPDMRS_USE_RAW_PUB_KEY environment variable:

export SPDMRS_USE_RAW_PUB_KEY=true

cargo run -p spdm-responder-emu --no-default-features --features "spdm-ring,hashed-transcript-data,async-executor"
export SPDMRS_USE_RAW_PUB_KEY=true

cargo run -p spdm-requester-emu --no-default-features --features "spdm-ring,hashed-transcript-data,async-executor"

Both spdm-ring and spdm-mbedtls crypto backends support raw public key verification.

Run emulator with PQC algorithms (ML-DSA + ML-KEM)

SPDM 1.4 introduces Post-Quantum Cryptography (PQC) support. spdm-rs supports ML-DSA for signature and ML-KEM for key exchange via the aws-lc-rs crypto backend.

The patched aws-lc-rs dependency supports both hosted builds and the x86_64-unknown-none freestanding target.

Prerequisites:

  1. Initialize the aws-lc-rs submodule and apply its pinned patch stack:
git submodule update --init external/aws-lc-rs
bash external/patches/aws-lc-rs/setup-aws-lc-rs.sh
  1. Build with the spdm-aws-lc feature and pqc_config.json (PQC signatures and key exchanges require larger buffer sizes than the default configuration):
export SPDM_CONFIG="etc/pqc_config.json"
cargo build -p spdm-requester-emu -p spdm-responder-emu --no-default-features --features "spdm-ring,hashed-transcript-data,async-executor,spdm-aws-lc"

Run PQC self-test (spdm-rs requester vs spdm-rs responder):

PQC is supported in both certificate chain mode (the default) and raw public key mode (RFC 7250). Certificate chain validation of ML-DSA certificates is provided by the spdm_x509 library together with the aws-lc-rs backend (the spdm-aws-lc feature), which recognizes the ML-DSA OIDs and verifies ML-DSA certificate signatures.

Certificate chain mode (default): set the following environment variables to enable PQC:

export SPDM_CONFIG="etc/pqc_config.json"
export SPDMRS_USE_PQC=true

Open one command window and run the responder:

SPDM_CONFIG="etc/pqc_config.json" SPDMRS_USE_PQC=true cargo run -p spdm-responder-emu --no-default-features --features "spdm-ring,hashed-transcript-data,async-executor,spdm-aws-lc"

Open another command window and run the requester:

SPDM_CONFIG="etc/pqc_config.json" SPDMRS_USE_PQC=true cargo run -p spdm-requester-emu --no-default-features --features "spdm-ring,hashed-transcript-data,async-executor,spdm-aws-lc"

Raw public key mode (RFC 7250): additionally set SPDMRS_USE_RAW_PUB_KEY=true on both peers:

SPDM_CONFIG="etc/pqc_config.json" SPDMRS_USE_PQC=true SPDMRS_USE_RAW_PUB_KEY=true cargo run -p spdm-responder-emu --no-default-features --features "spdm-ring,hashed-transcript-data,async-executor,spdm-aws-lc"
SPDM_CONFIG="etc/pqc_config.json" SPDMRS_USE_PQC=true SPDMRS_USE_RAW_PUB_KEY=true cargo run -p spdm-requester-emu --no-default-features --features "spdm-ring,hashed-transcript-data,async-executor,spdm-aws-lc"

This exercises the full SPDM handshake with ML-DSA-87 for signature and ML-KEM-1024 for key exchange, including: GET_VERSION, GET_CAPABILITIES, NEGOTIATE_ALGORITHMS, GET_DIGESTS, GET_CERTIFICATE, CHALLENGE, GET_MEASUREMENTS, KEY_EXCHANGE, FINISH, HEARTBEAT, KEY_UPDATE, GET_MEASUREMENTS (in-session), END_SESSION, PSK_EXCHANGE, PSK_FINISH, and END_SESSION. (GET_DIGESTS/GET_CERTIFICATE are exchanged in certificate chain mode; they are skipped in raw public key mode.)

Environment variables:

VariableDescription
SPDM_CONFIGSet to "etc/pqc_config.json" for PQC builds (larger buffers for ML-DSA signatures and cert chains)
SPDMRS_USE_PQCSet to true to enable PQC-only mode (ML-DSA-87 + ML-KEM-1024)
SPDMRS_USE_RAW_PUB_KEYSet to true to use raw public key (RFC 7250) instead of the default certificate chain

Cross test with spdm_emu

Open one command windows in workspace and run:

git clone https://github.com/DMTF/spdm-emu.git
cd spdm-emu
git submodule update --init --recursive
mkdir build
cd build
cmake -G"NMake Makefiles" -DARCH=<x64|ia32> -DTOOLCHAIN=<toolchain> -DTARGET=<Debug|Release> -DCRYPTO=<mbedtls|openssl> ..
nmake copy_sample_key
nmake

Test spdm-rs as requester:

  1. run libspdm in spdm-emu as responder:
cd bin
spdm_responder_emu.exe --trans PCI_DOE
  1. run spdm-rs-emu as requester:
cargo run -p spdm-requester-emu --no-default-features --features "spdm-ring,hashed-transcript-data,async-executor "

Test spdm-rs as responder:

  1. run spdm-rs-emu as Test spdm-rs as responder:
cargo run -p spdm-responder-emu --no-default-features --features "spdm-ring,hashed-transcript-data,async-executor "
  1. run libspdm in spdm-emu as requester:
cd bin
spdm_requester_emu.exe --trans PCI_DOE --exe_conn DIGEST,CERT,CHAL,MEAS --exe_session KEY_EX,PSK,KEY_UPDATE,HEARTBEAT,MEAS,DIGEST,CERT

Cross test the SupportedAlgorithms extended capability (DSP0274 1.3)

The SUPPORTED_ALGOS_EXT_CAP capability lets a Requester ask the Responder to include its Supported Algorithms Block in the CAPABILITIES response. It requires CHUNK_CAP on both peers.

Note: at SPDM 1.4 the SupportedAlgorithms block plus the ALGORITHMS response can exceed libspdm's default VCA transcript buffer (LIBSPDM_MAX_MESSAGE_VCA_BUFFER_SIZE = 200 + 2*LIBSPDM_MAX_VERSION_COUNT); if the 1.4 handshake fails with BUFFER_FULL, rebuild libspdm with a larger LIBSPDM_MAX_VERSION_COUNT.

Test spdm-rs as requester (spdm-rs Requester queries libspdm Responder):

cd bin && spdm_responder_emu.exe --trans PCI_DOE
SPDMRS_USE_SUPPORTED_ALGOS=1 cargo run -p spdm-requester-emu --no-default-features --features "spdm-ring,hashed-transcript-data,async-executor,chunk-cap"

Run test cases

Setting up enough stack before running tests

export RUST_MIN_STACK=10485760

Test with hashed-transcript-data:

cargo test --no-default-features --features "spdmlib/std,spdmlib/spdm-ring,spdmlib/hashed-transcript-data,async-executor" -- --test-threads=1

Test without hashed-transcript-data:

cargo test --no-default-features --features "spdmlib/std,spdmlib/spdm-ring,async-executor" -- --test-threads=1

To run a specific test, use cargo test <test_func_name>

To run test with println!() message, use cargo test -- --nocapture

To run tests with chunk capability:

export SPDM_CONFIG="etc/chunk_test_config.json"
cargo test --no-default-features --features "spdmlib/std,spdmlib/spdm-ring,spdm-emu/is_sync,spdmlib/is_sync,maybe-async/is_sync,idekm/is_sync,tdisp/is_sync,mctp_transport/is_sync,pcidoe_transport/is_sync,spdm-requester-emu/is_sync,spdm-responder-emu/is_sync,chunk-cap" -- --test-threads=1
export SPDM_CONFIG="etc/config.json"

To run spdmlib-test:

pushd test/spdmlib-test
cargo test --no-default-features -- --test-threads=1
popd

To run spdmlib-test with chunk capability:

pushd test/spdmlib-test
export SPDM_CONFIG="etc/chunk_test_config.json"
cargo test --no-default-features --features "chunk-cap" -- --test-threads=1
export SPDM_CONFIG="etc/config.json"
popd

Collect memory usage

To collect memory usage, use

python sh_script/collect_memory_usage.py

This script will display the peak memory used by spdm-emu

Known limitation

This package is only the sample code to show the concept. It does not have a full validation such as robustness functional test and fuzzing test. It does not meet the production quality yet. Any codes including the API definition, the libary and the drivers are subject to change.