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
12 changes: 12 additions & 0 deletions .github/workflows/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# CI Workflows

| Workflow | File | Description |
|----------|------|-------------|
| Build and Test | `build-test.yml` | Matrix build across OS (ubuntu-latest, 22.04) and configure options (debug, nuvoton, dynamic-mem). Runs unit tests for each combination. |
| Multiple Compilers | `multi-compiler.yml` | Builds and tests with GCC 11-13 and Clang 14-17 using `-Wall -Wextra -Werror`. |
| Compiler Warnings | `compiler-warnings.yml` | GCC strict warnings (`-Wpedantic -Wconversion -Wshadow -Werror`) and Clang `-Werror` build. |
| Static Analysis | `static-analysis.yml` | Runs cppcheck (style, performance, portability) and Clang Static Analyzer (scan-build). |
| Memory Check | `memory-check.yml` | Valgrind leak check with `--leak-check=full` for both static and dynamic memory modes. |
| CodeQL Security | `codeql.yml` | GitHub CodeQL security-and-quality analysis. Runs on PRs and weekly (Monday 6 AM UTC). |
| Codespell | `codespell.yml` | Spell-checks source files. |
| SPDM Emulator Test | `spdm-emu-test.yml` | End-to-end integration test against the DMTF libspdm emulator via wolfTPM. Runs 6 tests: session establishment, signed/unsigned measurements, challenge authentication, heartbeat, and key update. Dependencies (wolfSSL, spdm-emu, wolfTPM) are cached and refreshed every ~15 days. |
67 changes: 67 additions & 0 deletions .github/workflows/multi-compiler.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
name: Multiple Compilers

on:
push:
branches: [ 'master', 'main', 'release/**' ]
pull_request:
branches: [ '*' ]

concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

jobs:
compiler_test:
name: ${{ matrix.cc }}
runs-on: ubuntu-latest
timeout-minutes: 10
strategy:
fail-fast: false
matrix:
include:
- cc: gcc-11
- cc: gcc-12
- cc: gcc-13
- cc: clang-14
- cc: clang-15
- cc: clang-17

steps:
- uses: actions/checkout@v4

- name: Install compiler and tools
run: |
sudo apt-get update
sudo apt-get install -y ${{ matrix.cc }} autoconf automake libtool

- name: Cache wolfSSL
id: cache-wolfssl
uses: actions/cache@v4
with:
path: ~/wolfssl-install
key: wolfssl-ubuntu-latest-v1

- name: Build wolfSSL
if: steps.cache-wolfssl.outputs.cache-hit != 'true'
run: |
cd ~
git clone --depth 1 https://github.com/wolfSSL/wolfssl.git
cd wolfssl
./autogen.sh
./configure --enable-ecc --enable-sha384 --enable-aesgcm --enable-hkdf \
--enable-ecccustcurves --enable-keygen \
--prefix=$HOME/wolfssl-install
make -j$(nproc)
make install

- name: Build wolfSPDM with ${{ matrix.cc }}
run: |
./autogen.sh
CC=${{ matrix.cc }} ./configure --with-wolfssl=$HOME/wolfssl-install \
--enable-nuvoton
make -j$(nproc) CFLAGS="-Wall -Wextra -Werror"

- name: Run unit tests
run: make check
env:
LD_LIBRARY_PATH: ${{ github.workspace }}/src/.libs:$HOME/wolfssl-install/lib
112 changes: 112 additions & 0 deletions .github/workflows/spdm-emu-test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
name: SPDM Emulator Integration Test

on:
push:
branches: [ 'master', 'main', 'release/**' ]
pull_request:
branches: [ '*' ]

jobs:
spdm-emu-test:
name: SPDM emulator integration test
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v4

- name: Install dependencies
run: |
sudo apt-get update
sudo apt-get install -y autoconf automake libtool cmake libmbedtls-dev

# Cache period rotates every ~15 days so dependencies stay fresh
- name: Compute cache period
id: cache-period
run: |
echo "biweekly=$(( $(date +%s) / 1296000 ))" >> $GITHUB_OUTPUT

# --- Build wolfSSL (cached) ---
- name: Cache wolfSSL
id: cache-wolfssl
uses: actions/cache@v4
with:
path: ~/wolfssl-install
key: wolfssl-${{ steps.cache-period.outputs.biweekly }}

- name: Build wolfSSL
if: steps.cache-wolfssl.outputs.cache-hit != 'true'
run: |
cd ~
git clone --depth 1 https://github.com/wolfSSL/wolfssl.git
cd wolfssl
./autogen.sh
./configure --enable-wolftpm --enable-all \
--prefix=$HOME/wolfssl-install
make -j$(nproc)
make install

# --- Build wolfSPDM (always, this is what we're testing) ---
- name: Build and install wolfSPDM
run: |
./autogen.sh
./configure --with-wolfssl=$HOME/wolfssl-install \
--prefix=$HOME/wolfspdm-install
make -j$(nproc)
make install

# --- Build spdm-emu (cached) ---
- name: Cache spdm-emu
id: cache-spdm-emu
uses: actions/cache@v4
with:
path: ~/spdm-emu
key: spdm-emu-${{ steps.cache-period.outputs.biweekly }}

- name: Build spdm-emu
if: steps.cache-spdm-emu.outputs.cache-hit != 'true'
run: |
cd ~
git clone --depth 1 --recursive https://github.com/DMTF/spdm-emu.git
cd spdm-emu
mkdir build && cd build
cmake -DARCH=x64 -DTOOLCHAIN=GCC -DTARGET=Release -DCRYPTO=mbedtls ..
make copy_sample_key && make -j$(nproc)

# --- Build wolfTPM (cached, dynamically links wolfspdm at runtime) ---
- name: Cache wolfTPM
id: cache-wolftpm
uses: actions/cache@v4
with:
path: ~/wolfTPM
key: wolftpm-${{ steps.cache-period.outputs.biweekly }}

- name: Build wolfTPM
if: steps.cache-wolftpm.outputs.cache-hit != 'true'
run: |
cd ~
# TODO: Switch to wolfSSL/wolfTPM once PR #453 is merged
git clone --depth 1 -b add-wolfspdm-backend \
https://github.com/aidangarske/wolfTPM.git wolfTPM
cd wolfTPM
./autogen.sh
./configure --enable-spdm --enable-swtpm \
--with-wolfspdm=$HOME/wolfspdm-install \
--with-wolfcrypt=$HOME/wolfssl-install
make -j$(nproc)

# --- Run integration tests ---
- name: Run SPDM emulator tests
run: |
cd ~/wolfTPM
export LD_LIBRARY_PATH=$HOME/wolfspdm-install/lib:$HOME/wolfssl-install/lib
export SPDM_EMU_PATH=$HOME/spdm-emu/build/bin
./examples/spdm/spdm_test.sh --emu

- name: Upload logs on failure
if: failure()
uses: actions/upload-artifact@v4
with:
name: spdm-emu-test-logs
path: |
config.log
~/wolfTPM/config.log
39 changes: 26 additions & 13 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,14 @@ Lightweight SPDM 1.2+ requester-only stack implementation using wolfSSL/wolfCryp

- SPDM 1.2 requester implementation
- Algorithm Set B (FIPS 140-3 Level 3): ECDSA/ECDHE P-384, SHA-384, AES-256-GCM, HKDF-SHA384
- **Zero-malloc by default** — fully static memory, ideal for constrained/embedded environments
- **Zero-malloc by default** — fully static memory (~32 KB context), ideal for constrained/embedded environments
- Optional `--enable-dynamic-mem` for heap-allocated contexts (useful for small-stack platforms)
- Session establishment with full key exchange and encrypted messaging
- Device attestation via signed/unsigned measurements (GET_MEASUREMENTS)
- Sessionless attestation via CHALLENGE/CHALLENGE_AUTH with signature verification
- Certificate chain validation against trusted root CAs
- Session keep-alive via HEARTBEAT/HEARTBEAT_ACK
- Session key rotation via KEY_UPDATE/KEY_UPDATE_ACK (DSP0277)
- Hardware SPDM via wolfTPM + Nuvoton TPM
- Full transcript tracking for TH1/TH2 computation
- Compatible with DMTF spdm-emu for interoperability testing
Expand Down Expand Up @@ -53,7 +59,7 @@ make
### Memory Modes

**Static (default):** Zero heap allocation. The caller provides a buffer
(`WOLFSPDM_CTX_STATIC_SIZE` bytes, ~22 KB) and wolfSPDM operates entirely
(`WOLFSPDM_CTX_STATIC_SIZE` bytes, ~32 KB) and wolfSPDM operates entirely
within it. This is ideal for embedded and constrained environments where
malloc is unavailable or undesirable.

Expand All @@ -68,7 +74,7 @@ wolfSPDM_Free(ctx);
```

**Dynamic (`--enable-dynamic-mem`):** Context is heap-allocated via
`wolfSPDM_New()`. Useful on platforms with small stacks where a ~22 KB
`wolfSPDM_New()`. Useful on platforms with small stacks where a ~32 KB
local variable is impractical.

```c
Expand Down Expand Up @@ -98,17 +104,15 @@ cd wolfTPM
./configure --enable-spdm --enable-swtpm --with-wolfspdm=path/to/wolfspdm
make

# Terminal 1: Start responder with Algorithm Set B
cd spdm-emu
./bin/spdm_responder_emu --ver 1.2 \
--hash SHA_384 --asym ECDSA_P384 \
--dhe SECP_384_R1 --aead AES_256_GCM

# Terminal 2: Run wolfTPM example
# Run emulator tests (starts/stops emulator automatically)
cd wolfTPM
./examples/spdm/spdm_demo --emu
./examples/spdm/spdm_test.sh --emu
```

The test script automatically finds `spdm_responder_emu` in `../spdm-emu/build/bin/`,
starts it for each test, and runs session establishment, signed measurements,
unsigned measurements, challenge authentication, heartbeat, and key update.

## Testing with Nuvoton NPCT75x

```bash
Expand All @@ -122,8 +126,8 @@ cd wolfTPM
./configure --enable-spdm --enable-nuvoton --with-wolfspdm=path/to/wolfspdm
make

# Run test suite
./examples/spdm/spdm_test.sh
# Run Nuvoton test suite
./examples/spdm/spdm_test.sh --nuvoton
```

## API Reference
Expand All @@ -143,6 +147,15 @@ make
| `wolfSPDM_EncryptMessage()` | Encrypt outgoing message |
| `wolfSPDM_DecryptMessage()` | Decrypt incoming message |
| `wolfSPDM_SecuredExchange()` | Combined send/receive |
| `wolfSPDM_SetTrustedCAs()` | Load trusted root CA certificates for chain validation |
| `wolfSPDM_GetMeasurements()` | Retrieve device measurements with optional signature verification |
| `wolfSPDM_GetMeasurementCount()` | Get number of measurement blocks retrieved |
| `wolfSPDM_GetMeasurementBlock()` | Access individual measurement block data |
| `wolfSPDM_Challenge()` | Sessionless device attestation via CHALLENGE/CHALLENGE_AUTH |
| `wolfSPDM_Heartbeat()` | Session keep-alive (HEARTBEAT/HEARTBEAT_ACK) |
| `wolfSPDM_KeyUpdate()` | Rotate session encryption keys (KEY_UPDATE/KEY_UPDATE_ACK) |
| `wolfSPDM_SendData()` | Send application data over established session |
| `wolfSPDM_ReceiveData()` | Receive application data over established session |

## License

Expand Down
Loading
Loading