Repository navigation
feat(ssh): implement the built-in internal SecurityKeyProvider for USB HID authenticators #331
Description
Background
Depends on #328. On 2026-10-22 FIDO security keys were put in scope for bssh, matching OpenSSH 10.3p1, including the default internal provider. #328 adds the sk-* host-key algorithms and their verification, user authentication through an external SecurityKeyProvider library (sk-api), and the provider interface. Under #328, internal returns an explicit "not yet supported" diagnostic. This issue makes internal work.
OpenSSH 10.3p1 defaults SecurityKeyProvider to internal (readconf.c:3014-3018). That is the built-in USB HID support in sk-usbhid.c, which is built on libfido2.
Scope
- Implement the sign operation behind the fix(openssh): decide FIDO host-key coverage for the hostkey-agent sk certificate phases #328 provider interface for
sk-ssh-ed25519@openssh.comandsk-ecdsa-sha2-nistp256@openssh.comprivate key files (key handle, application, flags), followingsk-usbhid.c: CTAP2 getAssertion with the CTAP1/U2F fallback thatsk-usbhid.cuses where applicable, device discovery, and selection of the device that holds the credential when several authenticators are attached (sk-usbhid.cprobes each device with a dummy assertion). - Honor the key flags exactly as OpenSSH does: user presence (print OpenSSH's "Confirm user presence for key ..." prompt),
verify-required(PIN prompt), andno-touch-required. - Platforms: Linux (hidraw) and macOS (IOKit HID), which covers every target in
.github/workflows/release.yml.
Hard constraint: dependencies
Release builds include static musl binaries (x86_64-unknown-linux-musl, aarch64-unknown-linux-musl), which cannot dlopen, and the Debian, Launchpad PPA, and Homebrew packaging add no runtime library today. The implementation must build for every release.yml target without a new system library requirement. Evaluate the following options and record the choice and the reason in the PR: hidapi with its pure-Rust Linux backend (linux-native-basic-udev), ctap-hid-fido2, or a minimal in-tree CTAPHID plus CTAP2 getAssertion implementation over hidraw and IOKit. Linking libfido2 (fido2-rs, libfido2-sys) is rejected unless it meets this constraint.
Out of scope
Key enrollment (ssh-keygen -t ed25519-sk, sk_enroll) and resident-key loading (ssh-keygen -K, ssh-add -K). Note both in the PR as possible follow-ups.
Testing
CI has no authenticator, so behavior is covered by unit tests against a mock HID transport: CTAPHID framing (INIT and channel allocation, continuation packets, KEEPALIVE), CBOR getAssertion request encoding and response parsing, and conversion into the SSH sk signature (flags, counter, Ed25519 and ECDSA encodings). Add one end-to-end test through the provider interface with the mock transport whose signature verifies with ssh-key. State in the PR that a manual check with a real authenticator on Linux and macOS is pending user validation.
Acceptance Criteria
-
SecurityKeyProvider internal, and the default when the option is unset, signs with an attached FIDO2 authenticator for both sk key types, using OpenSSH's prompt wording. (PR feat(ssh): add the built-in internal SecurityKeyProvider over USB HID #334; verified against the mock authenticator only, a physical-key check on Linux and macOS is pending) - With no authenticator attached or no matching credential, bssh prints a clear error and authentication continues with the next identity, as OpenSSH does.
- Every release.yml target builds, including both musl targets, and no new runtime library is added to
debian/control, the PPA rules, or the Homebrew formula. (Linux gnu and macOS build in CI, no packaging change, Linux release binary links only libc/libm/libgcc_s; musl checked for the new crates only, full musl build first runs in the next release workflow) - The mock-transport tests above exist and each fails when its behavior is reverted.
- The
internal"not yet supported" diagnostic from fix(openssh): decide FIDO host-key coverage for the hostkey-agent sk certificate phases #328 is removed anddocs/openssh-compatibility-status.mdis updated. -
cargo fmt --check,cargo clippy -- -D warnings,cargo test --lib, andcargo test --tests -- --skip integration_testpass, and the openssh-regress workflow shows no new failures on Linux or macOS. (PR feat(ssh): add the built-in internal SecurityKeyProvider over USB HID #334; CI regress Ubuntu 69/70, macOS 66/67, unchanged) - Implemented in one PR, with the local gate run once at the end and as few pushes as possible.
Activity
feat(ssh): support FIDO security keys through SecurityKeyProvider (#333)
fix(ssh): bound and harden internal security-key device handling
docs: document built-in security key provider limits and platform notes
feat(ssh): add the built-in internal SecurityKeyProvider over USB HID (…