Debug a FIDO Key Failure Without Calling ssh-sk-helper Yourself
A security key that worked yesterday suddenly refuses to sign, and the instinct is to go straight at the helper that talks to it. Resist that: ssh-sk-helper is an internal program, and running it directly tells you almost nothing about your actual FIDO problem. This guide turns on debugging at the command that owns the operation instead, then separates a missing key, a PIN or touch failure, and a genuine helper problem. Allow about fifteen minutes for a first check, and none of the steps create, revoke or overwrite credentials.
The route
Jump straight to the step you need, or tick off Done means at the end.
1. Check the installed helper and package version
The installed manual says ssh-sk-helper is used by ssh, ssh-agent and ssh-keygen to reach FIDO authenticator keys, and that it is not intended to be invoked directly. On this machine it comes from Ubuntu's openssh-client package, version 1:9.6p1-3ubuntu13.19.
$ dpkg-query -W -f='${Package} ${Version}\n' openssh-client
openssh-client 1:9.6p1-3ubuntu13.19
$ command -v ssh
/usr/bin/ssh
$ dpkg -L openssh-client | grep '/ssh-sk-helper$'
/usr/lib/openssh/ssh-sk-helper
Checkpoint
Note the package version and helper path before you compare your problem against advice written for a different OpenSSH release. The helper is normally off the shell's PATH too, another sign it is a child process rather than a public tool.
2. Do not test the helper as a standalone command
The only documented option is -v, which enables progress diagnostics; up to three of them raise the verbosity further. None of that makes the helper a complete FIDO test on its own. It expects a private message protocol from its OpenSSH parent, so calling it directly proves nothing about the authenticator:
$ /usr/lib/openssh/ssh-sk-helper -v
ssh_msg_recv failed
$ printf 'exit status: %s\n' "$?"
exit status: 255
That failure is expected: the helper has no parent process feeding it the protocol it wants. Do not add sudo, do not put the helper in a startup script, and do not treat this exit status 255 as proof the FIDO key itself is broken. Nothing here changes persistent state, so there is nothing to undo.
3. Reproduce the real operation with debug output
Run the client or key-management command that actually fails, and add its debug flags there instead. OpenSSH passes its debug level to the helper automatically. Use -vvv for a connection, or the matching verbose option for whichever ssh-keygen operation you are running, starting with the exact host, user and key you normally use:
$ ssh -vvv -i ~/.ssh/id_ecdsa_sk USER@HOSTNAME
The output varies with the server, key type and local configuration, but the checkpoint that matters is the sequence around the FIDO key: confirm the client offered the intended public key, look for helper diagnostics, then check whether the server accepted the resulting signature. Do not paste the whole log into a ticket unreviewed; debug output can carry usernames, host names, file paths and server details.
For a local check that never touches a server, inspect the public key file instead:
$ ssh-keygen -lf ~/.ssh/id_ecdsa_sk.pub
256 SHA256:REPLACE_WITH_YOUR_FINGERPRINT USER@HOST (ECDSA-SK)
Point that at the public half of your own key. It confirms which fingerprint and key type you are looking at, but it proves neither that the authenticator can sign nor that the remote account authorises the key.
4. Classify the failure before changing anything
Read the debug output for the first failure, not the last line. If the intended public key is never offered, check the -i path, the effective SSH configuration and file permissions. If the client offers the key but then waits on a PIN or touch and stalls, that is the authenticator asking something of you, not a missing helper.
If the log shows the helper starting but failing to communicate, keep the complete local debug output and check the installed package rather than running the helper by hand again. If the helper completes fine but the server rejects the key, look at the server's authorised key, account and authentication policy: a successful helper exchange only proves the local side produced a signature, not that the remote account grants access.
- The authenticator performs a protected signing operation; its private key material is never something to copy into a shell command.
- The public key file identifies a credential, but it cannot stand in for the hardware key when a signature is actually needed.
- ssh-sk-helper debug messages describe helper progress only. They do not by themselves prove the server accepted anything.
5. Increase verbosity only when the first log falls short
Use the client's debug levels deliberately. One -v is often enough to show configuration and authentication decisions. Two or three levels expose the helper hand-off and protocol progress, but they also make logs larger and more revealing. The helper itself tops out at three -v options, and its parent passes its own debug level through automatically:
$ ssh -vv -i ~/.ssh/id_ecdsa_sk USER@HOSTNAME 2> ssh-fido-debug.log
$ grep -Ei 'sk|fido|security key|helper|publickey|auth' ssh-fido-debug.log
$ rm -- ssh-fido-debug.log
The redirection writes a local diagnostic file and the last command deletes it. Review it before sharing it with anyone. If you do need to keep it, lock it down with normal user-only permissions and delete it once the incident is closed. Never let a PIN, recovery code or private key end up in a log, a command line or a support message.
6. Recover without changing credentials
If the cause is still unclear, stop once you have collected evidence rather than pushing further. Unplug and reconnect the authenticator, retry the same parent command, and compare the two logs. If an agent holds the key, check its normal listing and restart only that user-level agent once you understand the effect on existing sessions. Do not delete key files or reset the authenticator as a first troubleshooting step: both can be irreversible and can destroy access to resident credentials.
If a package repair turns out to be necessary, use your normal system administration process and a maintenance window. A reinstall changes system files and may need elevated privileges; an expected ssh_msg_recv failed result from a standalone helper invocation does not justify that on its own. After any repair, rerun the real ssh -vvv operation and compare the package version and helper path again.
Done means
- You recorded the installed
openssh-clientversion and the helper's path. - You tested the real
ssh,ssh-agentorssh-keygenoperation, not the private helper protocol. - You used the parent command's debug flags and checked whether the intended key was offered.
- You separated local authenticator, helper, and remote authorisation failures.
- You reviewed and removed diagnostic logs without exposing PINs or private key material.
- You left credentials alone: no reset, no configuration change, while the cause remained uncertain.