Skip to content
Closed
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
47 changes: 47 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
name: HID runner

on:
push:
branches: ["*"]
pull_request:

env:
CARGO_TERM_COLOR: always

jobs:
framing-tests:
runs-on: ubuntu-latest
env:
CARGO_TARGET_DIR: ${{ github.workspace }}/target
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@stable
- name: Install dependencies
run: |
sudo apt-get update
sudo apt-get install -y libclang-dev
- name: Run ctaphid framing tests
run: cargo test -p pc-hid-runner --lib

hid-integration:
runs-on: ubuntu-latest
needs: framing-tests
env:
CARGO_TARGET_DIR: ${{ github.workspace }}/target
PC_HID_RUNNER_E2E: "1"
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@stable
- name: Install dependencies
run: |
sudo apt-get update
sudo apt-get install -y libclang-dev libudev-dev fido2-tools
sudo modprobe uhid || true
- name: Build HID runner
run: cargo build -p pc-hid-runner
- name: Run hid_integration test
run: sudo --preserve-env=PATH,CARGO_HOME,RUSTUP_HOME,CARGO_TARGET_DIR,PC_HID_RUNNER_E2E cargo test -p pc-hid-runner --test hid_integration
- name: Run fido2-token smoke test
run: sudo --preserve-env=PATH,CARGO_HOME,RUSTUP_HOME,CARGO_TARGET_DIR,PC_HID_RUNNER_E2E cargo test -p pc-hid-runner --test fido2_token
- name: Run end-to-end script
run: sudo --preserve-env=PATH,CARGO_HOME,RUSTUP_HOME,CARGO_TARGET_DIR,PC_HID_RUNNER_E2E ci/hid-e2e.sh
4 changes: 3 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@ members = [
"trussed-mldsa",
"authenticator",
"trussed-mlkem",
"pc-usbip-runner"
"pc-usbip-runner",
"host-runner",
"pc-hid-runner"
]

resolver = "2"
Expand Down
79 changes: 79 additions & 0 deletions ci/hid-e2e.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
#!/usr/bin/env bash
set -euo pipefail

if [[ "${PC_HID_RUNNER_E2E:-}" != "1" ]]; then
echo "PC_HID_RUNNER_E2E not set; skipping HID end-to-end script"
exit 0
fi

if [[ "$(uname -s)" != "Linux" ]]; then
echo "HID end-to-end script only runs on Linux"
exit 0
fi

if [[ $EUID -ne 0 ]]; then
echo "This script must be executed as root (access to /dev/uhid required)"
exit 1
fi

if ! command -v fido2-token >/dev/null 2>&1; then
echo "fido2-token not found in PATH"
exit 1
fi

if [[ ! -x target/debug/pc-hid-runner ]]; then
echo "Build the pc-hid-runner binary first (cargo build -p pc-hid-runner)"
exit 1
fi

serial="E2E-$(date +%s)"
runner="target/debug/pc-hid-runner"

modprobe uhid >/dev/null 2>&1 || true

echo "Starting pc-hid-runner with serial ${serial}"
"${runner}" --serial "${serial}" --product "HID E2E Test" --manufacturer "CI" &
runner_pid=$!
trap 'kill ${runner_pid} 2>/dev/null || true' EXIT

find_hidraw() {
local tries=60
while (( tries > 0 )); do
for entry in /sys/class/hidraw/hidraw*; do
[[ -e "${entry}" ]] || continue
if grep -q "HID_UNIQ=${serial}" "${entry}/device/uevent" 2>/dev/null; then
echo "/dev/$(basename "${entry}")"
return 0
fi
done
sleep 0.2
tries=$((tries - 1))
done
return 1
}

hidraw_node=$(find_hidraw)
if [[ -z "${hidraw_node}" ]]; then
echo "Timed out waiting for hidraw node"
exit 1
fi

echo "Running fido2-token -L"
list_output=$(fido2-token -L)
if [[ $? -ne 0 ]]; then
echo "fido2-token -L failed"
exit 1
fi

echo "${list_output}" | grep -q "${serial}" || {
echo "fido2-token -L output did not include serial ${serial}";
exit 1;
}

echo "Running fido2-token -I ${hidraw_node}"
if ! fido2-token -I "${hidraw_node}"; then
echo "fido2-token -I failed"
exit 1
fi

echo "HID end-to-end script completed successfully"
25 changes: 25 additions & 0 deletions docs/hid-runner-validation.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# HID Runner Manual Validation

The automated tests cover packet framing and basic CTAP2 echo flows, but each
release should also verify the transport with a real WebAuthn relying party.

1. Build the runner and start it with the default options:
```bash
cargo build -p pc-hid-runner
sudo target/debug/pc-hid-runner
```
2. Confirm the device is discoverable by the OS and tooling:
```bash
sudo fido2-token -L
sudo fido2-token -I /dev/hidrawX # replace with the device path from -L
```
3. Visit [https://webauthn.io](https://webauthn.io) in a Chromium-based browser.
Use **"Register"** to create a credential and **"Authenticate"** to exercise
the existing credential. The runner defaults to automatic user presence, so
both operations should complete without additional prompts.
4. Repeat the authenticate flow with the `--manual-user-presence` flag to ensure
the transport surfaces keepalive status updates correctly.

For environments without direct access to `/dev/uhid`, you can enable the
optional end-to-end checks by exporting `PC_HID_RUNNER_E2E=1` and running the
integration tests or the `ci/hid-e2e.sh` helper script under `sudo`.
20 changes: 20 additions & 0 deletions host-runner/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
[package]
name = "trussed-host-runner"
version = "0.1.0"
edition = "2021"

[dependencies]
littlefs2-core = "0.1"
log = { version = "0.4.14", default-features = false }
rand_chacha = { version = "0.3", default-features = false }
rand_core = { version = "0.6", features = ["getrandom"] }
trussed = { version = "0.1", default-features = false, features = ["log-all", "virt"] }

# optional features
ctaphid-dispatch = { version = "0.3", optional = true, features = ["log-all"] }
apdu-dispatch = { version = "0.3", optional = true }

[features]
default = ["ctaphid"]
ctaphid = ["ctaphid-dispatch"]
ccid = ["apdu-dispatch"]
Loading
Loading