Skip to content
Draft
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
270 changes: 270 additions & 0 deletions .github/workflows/test-uart-swtpm.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,270 @@
name: Test UART Communication with SWTPM

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

jobs:
test-uart-swtpm:
runs-on: ubuntu-latest

steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Install basic dependencies
run: |
sudo apt-get update
sudo apt-get install -y \
automake \
autotools-dev \
libtool \
pkg-config \
gcc \
make \
git \
socat \
strace \
acl

- name: Install swtpm
run: |
sudo apt-get install -y swtpm swtpm-tools

- name: Setup wolfSSL
uses: actions/checkout@v4
with:
repository: wolfssl/wolfssl
path: wolfssl

- name: Build wolfSSL
working-directory: ./wolfssl
run: |
./autogen.sh
./configure --enable-wolftpm --prefix=${GITHUB_WORKSPACE}/wolfssl-install
make -j$(nproc)
make install

- name: Start swtpm in socket mode
run: |
mkdir -p /tmp/swtpm-state

# Start swtpm with socket backend (this works reliably in GitHub Actions)
swtpm socket \
--tpm2 \
--tpmstate dir=/tmp/swtpm-state \
--ctrl type=tcp,port=2322 \
--server type=tcp,port=2321 \
--flags not-need-init &
SWTPM_PID=$!
echo $SWTPM_PID > /tmp/swtpm.pid

# Give swtpm time to start
sleep 3

# Verify swtpm is running and socket is accessible
ps aux | grep swtpm | grep -v grep || exit 1
timeout 2 bash -c 'until nc -z localhost 2321; do sleep 0.1; done' || exit 1

- name: Create UART bridge
id: uart
run: |
# Create a PTY for wolfTPM to connect to as UART device
# Use socat to create a PTY with proper permissions
socat -d -d pty,raw,echo=0,link=/tmp/tpm-uart-client,perm=0666 pty,raw,echo=0,link=/tmp/tpm-uart-server,perm=0666 &
SOCAT_PID=$!
echo $SOCAT_PID > /tmp/socat.pid
sleep 2

# Get the actual PTY device names
CLIENT_PTY=$(readlink -f /tmp/tpm-uart-client)
SERVER_PTY=$(readlink -f /tmp/tpm-uart-server)

echo "client_pty=$CLIENT_PTY" >> $GITHUB_OUTPUT
echo "server_pty=$SERVER_PTY" >> $GITHUB_OUTPUT

echo "Client PTY (for wolfTPM): $CLIENT_PTY"
echo "Server PTY (bridge endpoint): $SERVER_PTY"

# Verify PTYs exist
ls -la $CLIENT_PTY $SERVER_PTY || exit 1

- name: Bridge socket to UART
run: |
SERVER_PTY="${{ steps.uart.outputs.server_pty }}"

# Ensure swtpm socket is ready before starting bridge
echo "Waiting for swtpm socket to be ready..."
timeout 5 bash -c 'until nc -z localhost 2321; do sleep 0.1; done' || {
echo "ERROR: swtpm socket not ready!"
exit 1
}

# Bridge between swtpm socket (port 2321) and the server PTY
# Use TCP-CONNECT to connect to swtpm and bridge to PTY
# Add buffering and proper options for reliable data transfer
echo "Starting bridge from PTY $SERVER_PTY to socket localhost:2321"
# Use OPEN to open the existing PTY device directly
# Add readbytes=0 to read all available data, and setsockopt to handle socket properly
socat OPEN:$SERVER_PTY,raw,echo=0,readbytes=0 TCP:localhost:2321,keepalive,so-keepalive > /tmp/bridge.log 2>&1 &
BRIDGE_PID=$!
echo $BRIDGE_PID > /tmp/bridge.pid

sleep 2

# Verify bridge is running
if ! ps -p $BRIDGE_PID > /dev/null 2>&1; then
echo "ERROR: Bridge process died!"
echo "Bridge log:"
cat /tmp/bridge.log || true
exit 1
fi

# Also check if it shows up in ps
if ! ps aux | grep "socat.*2321" | grep -v grep > /dev/null; then
echo "WARNING: Bridge not found in ps, but PID file exists"
echo "Checking bridge log:"
cat /tmp/bridge.log || true
fi

echo "Bridge is running (PID: $BRIDGE_PID), connecting PTY $SERVER_PTY to socket localhost:2321"

- name: Build wolfTPM with UART support
env:
CLIENT_PTY: ${{ steps.uart.outputs.client_pty }}
run: |
cd ${{ github.workspace }}
./autogen.sh
# Set UART device path via CPPFLAGS
# TPM2_SWTPM_PORT is already set by configure, so we only need to set HOST
# The quotes need to be passed through correctly to the C preprocessor
echo "Building with UART device: $CLIENT_PTY"
./configure \
--enable-swtpm=uart \
--enable-debug \
--with-wolfcrypt=${GITHUB_WORKSPACE}/wolfssl-install \
CPPFLAGS="-DTPM2_SWTPM_HOST=\"${CLIENT_PTY}\""
make -j$(nproc)

# Verify the define by checking the compiled code
echo "Verifying TPM2_SWTPM_HOST define..."
strings src/.libs/libwolftpm.so 2>/dev/null | grep -E "(ttyS0|pts)" | head -5 || echo "Cannot verify from library"

- name: Verify UART setup
env:
CLIENT_PTY: ${{ steps.uart.outputs.client_pty }}
SERVER_PTY: ${{ steps.uart.outputs.server_pty }}
run: |
echo "Verifying UART setup..."
echo "Client PTY: $CLIENT_PTY"
echo "Server PTY: $SERVER_PTY"

# Verify PTYs are still accessible
[ -c "$CLIENT_PTY" ] || (echo "Client PTY not found!" && exit 1)
[ -c "$SERVER_PTY" ] || (echo "Server PTY not found!" && exit 1)

# Verify swtpm is still running
ps aux | grep swtpm | grep -v grep || (echo "swtpm not running!" && exit 1)

# Verify bridge is running
ps aux | grep "socat.*2321" | grep -v grep || (echo "bridge not running!" && exit 1)

# Test socket connectivity to swtpm
timeout 2 bash -c 'until nc -z localhost 2321; do sleep 0.1; done' || (echo "Cannot connect to swtpm socket!" && exit 1)

echo "UART setup verified successfully"

- name: Run UART communication test
env:
CLIENT_PTY: ${{ steps.uart.outputs.client_pty }}
run: |
cd ${{ github.workspace }}

# Build the caps example with the same CPPFLAGS to ensure TPM2_SWTPM_HOST is defined
cd examples/wrap
# Re-export the CPPFLAGS to ensure the example build uses them
export CPPFLAGS="-DTPM2_SWTPM_HOST=\"${CLIENT_PTY}\""
echo "Building caps with CPPFLAGS: $CPPFLAGS"
make caps CPPFLAGS="$CPPFLAGS"

echo "Running UART communication test..."
echo "Using UART device: $CLIENT_PTY"

# Verify bridge is still running
echo "Checking bridge status..."
if [ -f /tmp/bridge.pid ]; then
BRIDGE_PID=$(cat /tmp/bridge.pid)
if ps -p $BRIDGE_PID > /dev/null 2>&1; then
echo "Bridge is running (PID: $BRIDGE_PID)"
else
echo "WARNING: Bridge PID file exists but process is not running"
echo "Bridge log:"
cat /tmp/bridge.log 2>/dev/null || echo "No bridge log found"
fi
else
echo "WARNING: Bridge PID file not found"
fi
ps aux | grep "socat.*2321" | grep -v grep || echo "WARNING: Bridge process not found in ps"

# Test basic PTY connectivity
echo "Testing PTY connectivity..."
timeout 1 cat $CLIENT_PTY > /dev/null 2>&1 || echo "PTY read test (may timeout, that's ok)"

# Run the test with a timeout and capture all output
# The test should connect to the PTY as if it were a UART device
echo "Starting caps test..."
set +e # Don't exit on error so we can capture output
# Run with stderr to stdout to capture all output
timeout 30 ./caps > /tmp/caps_output.log 2>&1
CAPS_RC=$?
set -e

# Also check if we can manually test the connection
echo "Testing manual connection..."
echo "test" | timeout 1 cat $CLIENT_PTY > /dev/null 2>&1 || echo "Manual PTY test (may timeout)"

if [ $CAPS_RC -ne 0 ]; then
echo "Test failed with exit code $CAPS_RC"
echo "=== Test output ==="
cat /tmp/caps_output.log || true
echo "=== Checking processes ==="
echo "swtpm:"
ps aux | grep swtpm | grep -v grep || echo "swtpm is not running"
echo "bridge:"
ps aux | grep "socat.*2321" | grep -v grep || echo "bridge is not running"
echo "PTY pair:"
ps aux | grep "socat.*pty" | grep -v grep || echo "PTY pair is not running"
echo "PTY devices:"
ls -la $CLIENT_PTY || echo "Client PTY not found"
exit 1
else
echo "=== Test output ==="
cat /tmp/caps_output.log || true
fi

echo "UART communication test passed!"

- name: Cleanup
if: always()
run: |
# Kill bridge
if [ -f /tmp/bridge.pid ]; then
kill $(cat /tmp/bridge.pid) 2>/dev/null || true
fi

# Kill socat PTY pair
if [ -f /tmp/socat.pid ]; then
kill $(cat /tmp/socat.pid) 2>/dev/null || true
fi

# Kill swtpm
if [ -f /tmp/swtpm.pid ]; then
kill $(cat /tmp/swtpm.pid) 2>/dev/null || true
pkill -f "swtpm socket" 2>/dev/null || true
fi

# Clean up PTY links
rm -f /tmp/tpm-uart-server /tmp/tpm-uart-client
20 changes: 15 additions & 5 deletions configure.ac
Original file line number Diff line number Diff line change
Expand Up @@ -242,7 +242,7 @@ AC_ARG_WITH([swtpm-port],
]
)

if test "x$ENABLED_SWTPM" = "xyes"
if test "x$ENABLED_SWTPM" != "xno"
then
if test "x$ENABLED_DEVTPM" = "xyes"
then
Expand All @@ -252,6 +252,16 @@ then
AM_CFLAGS="$AM_CFLAGS -DWOLFTPM_SWTPM"
AM_CFLAGS="$AM_CFLAGS -DTPM2_SWTPM_PORT=$SWTPM_PORT"

if test "x$ENABLED_SWTPM" = "xuart"
then
AM_CFLAGS="$AM_CFLAGS -DWOLFTPM_SWTPM_UART"
fi

if test "x$ENABLED_SWTPM" = "xuartns550"
then
AM_CFLAGS="$AM_CFLAGS -DWOLFTPM_SWTPM_UARTNS550"
fi

# Set distcheck flag if port is not default (only when SWTPM is enabled)
if test "x$SWTPM_PORT" != "x2321"; then
DISTCHECK_SWTPM_PORT_FLAG="--with-swtpm-port=$SWTPM_PORT"
Expand All @@ -278,7 +288,7 @@ AC_ARG_ENABLE([winapi],

if test "x$ENABLED_WINAPI" = "xyes" || test "x$ENABLED_WINTBS" = "xyes"
then
if test "x$ENABLED_DEVTPM" = "xyes" -o "x$ENABLED_SWTPM" = "xyes"
if test "x$ENABLED_DEVTPM" = "xyes" -o "x$ENABLED_SWTPM" != "xno"
then
AC_MSG_ERROR([Cannot enable swtpm or devtpm with windows API])
fi
Expand Down Expand Up @@ -425,7 +435,7 @@ AC_ARG_ENABLE([hal],
[ ENABLED_EXAMPLE_HAL=$enableval ],
[ ENABLED_EXAMPLE_HAL=yes ]
)
if test "x$ENABLED_EXAMPLE_HAL" = "xyes"
if test "x$ENABLED_EXAMPLE_HAL" = "xyes" || test "x$ENABLED_MMIO" = "xyes"
Copy link

Copilot AI Jan 21, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The change from "x$ENABLED_EXAMPLE_HAL" = "xyes" on line 438 now includes "|| test x$ENABLED_MMIO = xyes", but line 504 removes the same MMIO check from BUILD_HAL. This creates an inconsistency: WOLFTPM_EXAMPLE_HAL will be defined when MMIO is enabled (line 440), but BUILD_HAL won't be set for MMIO. This will cause build issues where the HAL code is conditionally compiled but not linked.

Suggested change
if test "x$ENABLED_EXAMPLE_HAL" = "xyes" || test "x$ENABLED_MMIO" = "xyes"
if test "x$ENABLED_EXAMPLE_HAL" = "xyes"

Copilot uses AI. Check for mistakes.
then
AM_CFLAGS="$AM_CFLAGS -DWOLFTPM_EXAMPLE_HAL"
fi
Expand Down Expand Up @@ -485,13 +495,13 @@ AM_CONDITIONAL([BUILD_ST], [test "x$ENABLED_ST" = "xyes"])
AM_CONDITIONAL([BUILD_MICROCHIP], [test "x$ENABLED_MICROCHIP" = "xyes"])
AM_CONDITIONAL([BUILD_INFINEON], [test "x$ENABLED_INFINEON" != "xno"])
AM_CONDITIONAL([BUILD_DEVTPM], [test "x$ENABLED_DEVTPM" = "xyes"])
AM_CONDITIONAL([BUILD_SWTPM], [test "x$ENABLED_SWTPM" = "xyes"])
AM_CONDITIONAL([BUILD_SWTPM], [test "x$ENABLED_SWTPM" != "xno"])
AM_CONDITIONAL([BUILD_WINAPI], [test "x$ENABLED_WINAPI" = "xyes"])
AM_CONDITIONAL([BUILD_NUVOTON], [test "x$ENABLED_NUVOTON" = "xyes"])
AM_CONDITIONAL([BUILD_CHECKWAITSTATE], [test "x$ENABLED_CHECKWAITSTATE" = "xyes"])
AM_CONDITIONAL([BUILD_AUTODETECT], [test "x$ENABLED_AUTODETECT" = "xyes"])
AM_CONDITIONAL([BUILD_FIRMWARE], [test "x$ENABLED_FIRMWARE" = "xyes"])
AM_CONDITIONAL([BUILD_HAL], [test "x$ENABLED_EXAMPLE_HAL" = "xyes" || test "x$ENABLED_MMIO" = "xyes"])
AM_CONDITIONAL([BUILD_HAL], [test "x$ENABLED_EXAMPLE_HAL" = "xyes"])
Copy link

Copilot AI Jan 21, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The condition has been changed from testing if ENABLED_SWTPM equals "yes" to testing if it does not equal "no". However, on line 498, AM_CONDITIONAL for BUILD_SWTPM uses the same "!= xno" test. This means BUILD_HAL will now be set incorrectly - it was reverted from the logical OR condition with ENABLED_MMIO back to only testing ENABLED_EXAMPLE_HAL. This appears to be an unintended regression that removes the MMIO check that was present on line 504 in the original code.

Suggested change
AM_CONDITIONAL([BUILD_HAL], [test "x$ENABLED_EXAMPLE_HAL" = "xyes"])
AM_CONDITIONAL([BUILD_HAL], [test "x$ENABLED_EXAMPLE_HAL" = "xyes" -o "x$ENABLED_MMIO" = "xyes"])

Copilot uses AI. Check for mistakes.


CREATE_HEX_VERSION
Expand Down
Loading
Loading