FIDO2 Hardware Keys
FIDO2 hardware security keys (such as YubiKey) can be used for SSH authentication via the sk- key types introduced in OpenSSH 8.2. ZestSSH has a detailed architecture and implementation plan for FIDO2 support, but it is not yet functional. This page documents the current status, the planned approach, and workarounds.
Current Status: Stubbed
Section titled “Current Status: Stubbed”The Fido2Service class exists in the codebase with data models, enums, and method signatures, but all operations throw UnimplementedError. No FIDO2 hardware interaction occurs today. The service cannot detect authenticators, sign challenges, or register credentials.
Specifically:
isAuthenticatorAvailable()— Always returnsfalse.enumerateAuthenticators()— Always returns an empty list.signChallenge()— ThrowsUnimplementedError.registerCredential()— ThrowsUnimplementedError.
Availability (Planned)
Section titled “Availability (Planned)”| Platform | Planned Transport | Status |
|---|---|---|
| Android | NFC (tap YubiKey on phone) | Planned |
| iOS | NFC (tap YubiKey on phone) | Planned |
| Windows | USB HID | Planned |
| macOS | USB HID | Planned |
| Linux | USB HID | Planned |
What FIDO2 SSH Authentication Would Enable
Section titled “What FIDO2 SSH Authentication Would Enable”FIDO2 hardware keys provide a strong second factor for SSH authentication. Unlike standard public key authentication where the private key is stored on disk (or in a keychain), FIDO2 keys store the private key on the hardware token itself. Authentication requires physical possession of the token and a deliberate action (touch or tap).
OpenSSH 8.2+ supports two FIDO2 key types:
[email protected]— Supported by all FIDO2 keys.[email protected]— Supported by YubiKey 5 with firmware 5.2.3 or later.
These key types differ from standard keys by including an application string (usually ssh:) and requiring the hardware token to produce the signature along with flags (user presence, user verified) and a monotonic counter.
Technical Blockers
Section titled “Technical Blockers”There are four blockers preventing FIDO2 from being functional today, listed in priority order:
1. dartssh2 Async Signing
Section titled “1. dartssh2 Async Signing”The SSH library’s SSHKeyPair.sign() method is synchronous. FIDO2 requires user interaction (touch/tap), which is inherently asynchronous. The signing interface needs to support FutureOr<SSHSignature> instead of SSHSignature.
2. sk- Key Type Support
Section titled “2. sk- Key Type Support”dartssh2 does not parse or produce the [email protected] or [email protected] key/signature types. The FIDO2 signature wire format includes flags and counter fields that standard types do not carry.
3. Key Handle Storage
Section titled “3. Key Handle Storage”FIDO2 keys produce a “key handle” (credential ID) during registration that must be stored persistently and sent back to the authenticator during each signing operation. This requires a new database table or secure storage entry.
4. Platform-Specific Transport
Section titled “4. Platform-Specific Transport”USB HID access on Android requires special permissions. NFC requires physical proximity and platform-specific APIs. Desktop USB access varies by operating system.
Implementation Plan
Section titled “Implementation Plan”The planned implementation has three phases:
Phase 1 — Fork dartssh2 to add async signing support and sk- key type parsing, including the flags and counter fields in signature encoding.
Phase 2 — Build a Fido2SshAgent implementing the SSHAgentHandler interface. This agent would enumerate connected FIDO2 authenticators (using the u2f and fido2 Flutter packages), prompt the user to touch the key, and construct the sk- signature response.
Phase 3 — UI integration with a “Use hardware key” toggle in the identity editor, touch-to-authenticate prompts during the connection flow, and key handle storage.
Workarounds
Section titled “Workarounds”Desktop: System ssh-agent Passthrough
Section titled “Desktop: System ssh-agent Passthrough”On desktop platforms (macOS, Linux, Windows with WSL), your system’s ssh-agent likely already supports FIDO2 keys. While ZestSSH does not currently connect to the system agent, you can:
- Register your FIDO2 key with
ssh-keygen -t ed25519-skon your desktop. - Add the key to your system’s ssh-agent.
- Use a standard SSH client for connections requiring FIDO2.
- Use ZestSSH with a regular (non-FIDO2) key for the same servers, configured as a fallback in the server’s
authorized_keys.
Server-Side Fallback
Section titled “Server-Side Fallback”Configure your SSH server to accept both FIDO2 keys and standard keys:
# In ~/.ssh/authorized_keys[email protected] AAAA... user@yubikeyssh-ed25519 AAAA... user@ZestSSHThis allows you to use ZestSSH with a standard key while using FIDO2 from other clients.
Data Models (Existing)
Section titled “Data Models (Existing)”The following data structures are defined and ready for use once the implementation is complete:
- Fido2AuthenticatorStatus — Tracks the state of the authenticator: not detected, connected, waiting for touch, signing, success, or error.
- Fido2Transport — Enumerates transport methods: USB, NFC, BLE.
- Fido2AuthenticatorInfo — Describes a connected authenticator: name, AAGUID, transport, Ed25519 support, resident key support.
- Fido2SignResult — Contains the signature bytes, flags byte (user presence and user verified bits), and monotonic counter.
- Fido2RegistrationResult — Contains the public key, key handle, attestation certificate, and key type string.
Q: Can I use my YubiKey with ZestSSH today? A: Not for FIDO2/sk- key authentication. You can use a standard SSH key (Ed25519, RSA, ECDSA) stored in ZestSSH’s keychain. The physical YubiKey hardware cannot be used for SSH signing in ZestSSH at this time.
Q: When will FIDO2 support be available? A: There is no firm timeline. The implementation requires modifications to the SSH library and integration of platform-specific FIDO2 packages. It is on the roadmap.
Q: Does the FIDO2 stub affect performance or security? A: No. The stub code is never invoked during normal operation. It has no runtime impact.