SSH (Yubi)Key Authentication
SSH with private keys coming from secure hardware. What's not to like?
You've read the How-To. You've changed the pin with:
yubico-piv-tool -a change-pin
You're generating a resident key with:
ssh-keygen -t ed25519-sk -O resident -f ~/.ssh/yubi_ed255_key
After entering your pin, the above command breaks with "enrollment failed: invalid format". Surely you're doing something wrong? After a minute of head scratching, you try again, this time with:
ssh-keygen -vv -t ed25519-sk -O resident -f ~/.ssh/yubi_ed255_key
And are greeted with a confusing error. According to the error code
(FIDO_ERR_PIN_NOT_SET
) the resident key can not be
generated because your YubiKey is not protected with a pin. But you've
changed it already - what gives?
You've changed the PIN for the PIV application... which is different from the FIDO2 application.
Right idea, right PIN, wrong application?
Turns out you're missing the right tool. Get the correct one with:
${SUDO} apt install yubikey-manager
And then configure the FIDO2 application code with:
ykman fido set-pin
Now you can rerun the command from above and generate a private key directly with the YubiKey.
Things that work
The private key file, generated by the ssh-keygen
command,
can be nuked. It is after all a resident key, accessible directly from
the YubiKey device. And you probably didn't add a keyphrase for it
either.
So you can now load the private key into SSH agent, with:
ssh-add -K
You'll need to type in the PIN you set earlier.
... and a few that don't
The main problem with the above setup is that every use of the private key, even when loaded to the agent, requires to touch the magic button. To make things worse, the client doesn't show any hint what is needed, from a casual observer's point of view establishing the connection seems to hang.
This is okay for random logins, but breaks non-interactive workflows, and utterly messes up remote autocomplete. Touch the key one time too few, and the autocomplete never finishes. Touch it one time too many, and you've just vomited an OTP string to your terminal.
An ideal setup would allow the agent to authenticate without interaction for a configurable time, but so far this seems not to be supported.
Near-future experimentation
Documentation for ssh-keygen
states that the resident key
may be generated with the additional option -O
no-touch-required
to allow fully non-interactive use. At least at
the time of writing, portable OpenSSH v8.4 does not appear to support
the option, which may be for the best. Additionally, the public key
requires special annotation for its entry in
authorised_keys
but even then it's not a good idea.
Because this option essentially would turn the YubiKey into a USB-attached SSH trust/identity dongle, it's far too dangerous to be used without other mitigations.
The missing hint
The bit about FIDO2 application for SSH client and the necessary command was found here.
Helpful two-liners
When changing the PIN/PUK codes, of course you want the new codes to be random. A really easy way to generate them is with python. Like this:
% python3
import secrets
secrets.randbelow(10**6) # for PIN
secrets.randbelow(10**8) # for PUK