Skip to content

Add TPM MLDSA authentication for post quantum TLS 1.3 with example and tests #334

Add TPM MLDSA authentication for post quantum TLS 1.3 with example and tests

Add TPM MLDSA authentication for post quantum TLS 1.3 with example and tests #334

Workflow file for this run

name: PQC Examples (v1.85)
on:
push:
branches: [ 'master', 'main', 'release/**' ]
pull_request:
branches: [ '*' ]
types: [opened, synchronize, reopened, ready_for_review]
repository_dispatch:
types: [nightly-trigger]
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true
jobs:
pqc-examples:
if: github.event_name != 'pull_request' || github.event.pull_request.draft == false
runs-on: ubuntu-latest
# Host runner: tpm2-tools make-check (activatecredential) hits a tpm2-tools
# OpenSSL credential-integrity quirk inside a container, so stay on the host
# (where it passes) and just make apt resilient to mirror timeouts.
timeout-minutes: 30
steps:
- name: Checkout wolfTPM
uses: actions/checkout@v4
- name: Install tpm2-tools
uses: ./.github/actions/apt-retry
with:
packages: tpm2-tools libtss2-tcti-mssim0
- name: Setup wolfSSL with PQC
uses: ./.github/actions/setup-wolfssl
with:
configure-flags: >-
--enable-wolftpm --enable-pkcallbacks --enable-keygen
--enable-dilithium --enable-mlkem --enable-experimental --enable-harden
cflags: -DWC_RSA_NO_PADDING
- name: Build wolfTPM with v1.85 + fwTPM + debug
run: |
./autogen.sh
# --enable-swtpm omitted: it's the Linux configure default
# (configure.ac:287). Passing it explicitly was redundant.
# --enable-debug=verbose: full client + fwTPM dispatch logs so
# CI failures (e.g. keyload integrity) come with TPM-side trace.
./configure --enable-v185 --enable-fwtpm --enable-debug=verbose
make -j"$(nproc)"
# ----- Tier 1: make check -----
# Runs unit.test (wrapper) + fwtpm_unit.test (handler) + tpm2-tools
# compatibility + tests/pqc_mssim_e2e.sh in one shot via fwtpm_check.sh.
- name: make check (unit + fwtpm_unit + tpm2-tools + pqc_mssim_e2e.sh)
env:
WOLFSSL_PATH: ${{ github.workspace }}/wolfssl
run: |
FWTPM_USE_FIXED_PORT=1 \
sudo -E unshare --net /bin/bash -c '
set -e
ip link set lo up
make check
'
# make check runs as root via sudo -E unshare; restore ownership of
# any files left in the workspace so later steps (running as the
# unprivileged runner) can rewrite them — otherwise stale root-owned
# blobs (e.g. eccblob.bin) silently break run_examples.sh later.
sudo chown -R "$(id -u):$(id -g)" .
# ----- Tier 2: per-example standalone runs -----
# Each example gets its own GitHub Actions check so a regression
# surfaces with a clear failure signal — not buried inside make check.
- name: Start fwtpm_server for standalone example runs
run: |
rm -f fwtpm_nv.bin
./src/fwtpm/fwtpm_server > /tmp/fwtpm_server.log 2>&1 &
echo $! > /tmp/fwtpm_server.pid
sleep 1
kill -0 $(cat /tmp/fwtpm_server.pid)
- name: PQC keygen — every parameter set
run: |
for ps in 44 65 87; do
./examples/keygen/keygen mldsa_sk.bin -mldsa=$ps || exit 1
./examples/keygen/keygen hmldsa_sk.bin -hash_mldsa=$ps || exit 1
done
for ps in 512 768 1024; do
./examples/keygen/keygen mlkem_sk.bin -mlkem=$ps || exit 1
done
- name: ML-DSA sign + verify example (standalone)
run: ./examples/pqc/mldsa_sign
- name: ML-KEM encap + decap example (standalone)
run: ./examples/pqc/mlkem_encap
- name: Stop Tier 2 fwtpm_server (free port 2321 for E2E)
run: |
if [ -f /tmp/fwtpm_server.pid ]; then
kill "$(cat /tmp/fwtpm_server.pid)" 2>/dev/null || true
rm -f /tmp/fwtpm_server.pid
fi
# Defensive: kill any other default-port server lingering.
pkill -f "fwtpm_server$" 2>/dev/null || true
sleep 1
- name: PQC mssim E2E (MLKEM-768 + HashMLDSA-65 round-trips)
run: ./tests/pqc_mssim_e2e.sh
- name: Restart fwtpm_server for Tier 5 (run_examples.sh)
run: |
# pqc_mssim_e2e.sh started + stopped its own server; Tier 5 needs
# one again. Reuse the same default-port launch as Tier 2.
pkill -f "fwtpm_server" 2>/dev/null || true
sleep 1
rm -f fwtpm_nv.bin
./src/fwtpm/fwtpm_server > /tmp/fwtpm_server.log 2>&1 &
echo $! > /tmp/fwtpm_server.pid
sleep 1
kill -0 "$(cat /tmp/fwtpm_server.pid)"
- name: Doc constants parity check
run: |
./tests/check_doc_constants.sh
rc=$?
if [ $rc -eq 77 ]; then
echo "Step skipped (exit 77 — header or doc missing)"
exit 0
fi
exit $rc
# ----- Tier 5: full run_examples.sh sweep -----
# run_examples.sh does not start its own TPM — it expects one already
# listening. Reuse the fwtpm_server started in Tier 2. Trace each
# command (set -x) so the failing call line is in the CI log; on
# failure, dump run.out (where the script redirects example stdout).
- name: run_examples.sh full pass (auto-detects v1.85, runs 18-way matrix)
env:
WOLFSSL_PATH: ${{ github.workspace }}/wolfssl
run: |
set +e
bash -x ./examples/run_examples.sh
rc=$?
set -e
if [ $rc -ne 0 ]; then
echo "=== run.out (last 200 lines) ==="
tail -200 run.out
echo "=== fwtpm_server.log (last 100 lines) ==="
tail -100 /tmp/fwtpm_server.log
fi
exit $rc
- name: Stop fwtpm_server
if: always()
run: |
if [ -f /tmp/fwtpm_server.pid ]; then
kill $(cat /tmp/fwtpm_server.pid) 2>/dev/null || true
rm -f /tmp/fwtpm_server.pid
fi
- name: Upload failure logs
if: failure()
uses: actions/upload-artifact@v4
with:
name: pqc-examples-logs
path: |
/tmp/fwtpm_server.log
/tmp/fwtpm_check_*.log
test-suite.log
tests/*.log
config.log
run.out
retention-days: 5
# Full TPM-backed PQC TLS 1.3 handshake: ML-KEM key exchange + ML-DSA
# CertificateVerify signed on the TPM (device key never leaves the chip).
pqc-tls-examples:
name: PQC TLS 1.3 examples (ML-DSA auth + ML-KEM)
permissions:
contents: read
if: github.event_name != 'pull_request' || github.event.pull_request.draft == false
runs-on: ubuntu-latest
container:
image: ghcr.io/wolfssl/wolftpm-ci:v1.0
credentials:
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
timeout-minutes: 30
steps:
- name: Checkout wolfTPM
uses: actions/checkout@v4
with:
persist-credentials: false
# TODO(revert-when-merged): build wolfSSL from the aidangarske/wolfssl
# mldsa-signctx-cryptocb-devkey branch because the wc_MlDsaKey_SignCtx
# crypto-callback fix (device-key ML-DSA signing) is not yet upstream.
# Once that wolfSSL PR merges, switch this back to a wolfSSL/wolfssl tag
# (>= the release carrying the fix) and delete this note.
- name: Build wolfSSL (PQC TLS + crypto-cb ML-DSA device-key fix)
env:
# aidangarske/wolfssl mldsa-signctx-cryptocb-devkey
WOLFSSL_PQC_SHA: 6b0c832284286dbaec8e5ab35581ff470e90826b
run: |
cd ~
# pinned to an immutable commit: a mutable branch tip would let a
# force-push run unreviewed code inside this job
git clone --no-checkout https://github.com/aidangarske/wolfssl.git
cd wolfssl
git fetch --depth 1 origin "$WOLFSSL_PQC_SHA"
git checkout "$WOLFSSL_PQC_SHA"
./autogen.sh
./configure --enable-wolftpm --enable-pkcallbacks --enable-keygen \
--enable-certgen --enable-dilithium --enable-mlkem \
--enable-experimental --enable-tls-mlkem-standalone --enable-harden \
CPPFLAGS="-DWOLFSSL_TLSX_PQC_MLKEM_STORE_OBJ -DWC_RSA_NO_PADDING" \
--prefix="$HOME/wolfssl-install"
make -j"$(nproc)"
make install
- name: wolfSSL version info
run: grep LIBWOLFSSL_VERSION_STRING "$HOME/wolfssl-install/include/wolfssl/version.h"
- name: Build wolfTPM with v1.85 + fwTPM + debug
run: |
./autogen.sh
CPPFLAGS="-I$HOME/wolfssl-install/include" \
LDFLAGS="-L$HOME/wolfssl-install/lib -Wl,-rpath,$HOME/wolfssl-install/lib" \
./configure --enable-v185 --enable-fwtpm --enable-debug=verbose
make -j"$(nproc)"
# A stub means wolfSSL was missing a required feature (cert-gen, ML-DSA
# keygen/sign, private-key-id, or TLS 1.3) — fail loudly rather than skip.
- name: Verify PQC TLS examples built (not stubs)
run: |
for b in examples/pqc/gen_pqc_certs \
examples/tls/tls_server examples/tls/tls_client; do
if ./$b -h 2>&1 | grep -q "Requires"; then
echo "FAIL: $b is a stub — wolfSSL missing a required feature"
exit 1
fi
done
- name: PQC TLS handshake E2E (ML-KEM x ML-DSA matrix)
run: |
set +e
export LD_LIBRARY_PATH="$HOME/wolfssl-install/lib"
# run_examples.sh pairs the classical TLS tests with the wolfSSL
# example client/server, so point it at the clone built above
export WOLFSSL_PATH="$HOME/wolfssl"
./src/fwtpm/fwtpm_server >/tmp/fwtpm_tls.log 2>&1 &
echo $! > /tmp/fwtpm_tls.pid
sleep 2
ENABLE_PQC_TLS=1 ./examples/run_examples.sh
rc=$?
exit $rc
- name: Stop fwtpm_server (PQC TLS)
if: always()
run: kill "$(cat /tmp/fwtpm_tls.pid)" 2>/dev/null || true
- name: Upload failure logs
if: failure()
uses: actions/upload-artifact@v4
with:
name: pqc-tls-examples-logs
path: |
/tmp/fwtpm_tls.log
run.out
pqtls.out
config.log
tests/*.log
retention-days: 5