James Stanley

YubiKey SSH authentication: the easy way

Fri 1 May 2020

Tagged: cryptography

I bought a YubiKey quite a while ago, with the intention of using it for SSH authentication, but never got to the point of actually using it because I found it too hard to set up. Today I had another go and managed to get it working using the "PIV" mode.

(If you read this and you think "I've been using a YubiKey for ages and my way is easier than this", then chances are you're more of an expert than me, and what's easy for you might not be easy for me).

Requirements

I only wanted SSH authentication and found that the PIV way was easier than the others I tried. Lots of people seem to use their YubiKey via GPG. I couldn't get this to work and gave up.

The PIV method does not require any special support from the SSH server. You just write the public key into ~/.ssh/authorized_keys on the remote end and then you can SSH in, authenticated by your YubiKey.

Set it up

You mostly want to follow YubiCo's tutorial on using PIV for SSH through PKCS #11, which I would modify so that it reads as follows:

Step 1: Install the dependencies:

$ sudo apt install yubico-piv-tool ykcs11

Step 2: Generate a key on the YubiKey. YubiCo suggest slot 9a but note that "any slot should suffice". I don't know what a slot is or what the options are, so I chose 9a.

$ yubico-piv-tool -s 9a -a generate -o public.pem

Step 3: Change the PIN. The default YubiKey PIN is 123456. Interestingly I had already changed the PIN while trying to get the GPG stuff to work, but found that the PIV mode PIN was still 123456. I believe that the PIV mode is separate software running on the YubiKey and therefore has a separate PIN.

Good to know is you can actually use (relatively?) arbitrary characters in the PIN, it does not have to be numeric.

$ yubico-piv-tool -a change-pin

There seems to be a limit on the allowable length. I first tried to set a long password and was told "Retrieving new pin failed.", so if you get that message, you just need to pick a shorter password.

Step 4: Create a certificate for the key and import it. YubiCo state that "The only use for the X.509 certificate is to satisfy PIV/PKCS #11 lib. It needs to be able to extract the public-key from the smartcard, and to do that through the X.509 certificate."

$ yubico-piv-tool -a verify-pin -a selfsign-certificate -s 9a -S "/CN=SSH key/" -i public.pem -o cert.pem
$ yubico-piv-tool -a import-certificate -s 9a -i cert.pem

You won't need cert.pem after this.

Step 5: Add libykcs11 to your SSH agent:

$ ssh-add -s /usr/lib/x86_64-linux-gnu/libykcs11.so

Step 6: You can now copy your public key to a remote host with ssh-copy-id:

$ ssh-copy-id babyspice.example.com

And then you should be able to SSH to the remote host without being asked for a password! Great success.

Alternatively, find out what the key is so you can manually paste it into ~/.ssh/authorized_keys on a remote host, or into your GitHub profile, etc.:

$ ssh-add -L

Step 7: So far, so good. The problem comes when you unplug the device and reinsert it. SSH just gives an error "agent refused operation":

$ ssh babyspice.example.com
sign_and_send_pubkey: signing failed for RSA "Public key for PIV Authentication" from agent: agent refused operation
jes@babyspice.example.com's password:

It took me a little while to find out what was going on here because it wasn't mentioned in the YubiCo tutorial. Eventually I found this GitHub issue. The problem is that the SSH agent does not reinitialise libykcs11 when the YubiKey is plugged in (because it has no way to know that it should), which means libykcs11 doesn't get a chance to ask you for the PIN, which means it can't unlock the YubiKey, which means it can't use it for SSH authentication.

This seems like a pretty big oversight, but fortunately it's quite easy to work around. All you need to do is remove and re-add the keys provided by libykcs11. I added this to my ~/.bashrc based on this comment on the GitHub issue:

alias yf="ssh-add -e /usr/lib/x86_64-linux-gnu/libykcs11.so; ssh-add -s /usr/lib/x86_64-linux-gnu/libykcs11.so"

Then whenever you plug in the YubiKey, you just need to run yf (for "YubiKey fix") before you'll be able to SSH anywhere. I suspect it might be possible to trigger this automatically, but running it manually is adequate for now.

$ yf
Card removed: /usr/lib/x86_64-linux-gnu/libykcs11.so
Enter passphrase for PKCS#11: 
Card added: /usr/lib/x86_64-linux-gnu/libykcs11.so

More

I did this on Ubuntu 20.04 LTS. If you're doing it on a different system then the path to libykcs11.so for example might be different. Also, Ubuntu seems to have YubiKey udev rules present out-of-the-box, and automatically starts an ssh-agent, which you may have to sort out manually on other systems.

Sometimes when I plug the YubiKey in, instead of sitting there happily ready to work, the light flickers rapidly and nothing shows up in dmesg. At first I thought I had bricked the device, but it seems like sometimes it just doesn't work when you plug it in. I'm not sure if it sometimes gets a bad contact on the data pins, or if there is a software problem on it. I just unplug it and plug it back in until the light stops flickering. I don't know if this is just a problem with mine or they all do that.

We generated the key on the YubiKey itself, rather than generating it on the computer and sending it to the key. This means there's no risk of leaving key material lying around anywhere it shouldn't be, but it also means there is no way to make a backup of the key! If the YubiKey is lost or broken, you'll have no way to use those keys for authentication. This means you need to have another way to gain access to your machines for use in emergencies (for example, physical access to the machine, or a separate SSH key that you keep safe, or password auth if nothing else). If you really want to import an existing key instead of generating a new one, then see the YubiCo tutorial and use import-key instead of generate in their Step 1.

I don't know what happens if you've unlocked your YubiKey to use SSH, and then someone comes across your locked PC with the unlocked YubiKey inserted, attaches their own power supply to the USB connector, and then unplugs the YubiKey without interrupting the power supply, and then plugs it into their own computer. Will the YubiKey still be unlocked because it never lost power? Seems likely. You probably want to make sure to always unplug the key every time you lose sight of it.

If you like my blog, please consider subscribing to the RSS feed or the mailing list:

James Stanley - james@incoherency.co.uk | ricochet:it2j3z6t6ksumpzd | jesblogfnk2boep4.onion | [rss]