Secure, easy to use, cheap: Pick three

I recently installed Ubuntu Wacky Whatever, the latest version, and I’m very excited about it shipping with SSH 8.2, which means that I can finally use hardware USB keys for secure, easy to use authentication. If securing your devices has been something you’ve wanted to easily do yourself, read on, because it’s finally happening.

FIDO2

One of the most exciting security-related developments recently has been the development of WebAuthn and FIDO2, which are basically euphemisms for “nice security stuff”. In summary, WebAuthn and FIDO2 aim to make it really easy to use security devices with stuff by standardizing the way the two talk to each other, and using better terms than “stuff”.

This is great news for us, because now we can have dirt-cheap USB keys that can be used to secure all our authentication very easily, without requiring any special security knowledge. All you need to know to be completely immune to phishing, password theft, and a whole host of other ways of losing Bitcoin is to just plug your USB key in, press the little button/type your PIN/enter your fingerprint, and you’re logged in.

What does this have to do with SSH? Very little, but I like rambling, it is known.

Using FIDO2 with SSH

Deanna had heard of phishing, and was extremely suspicious of the sound of rubber boots.

As you may have suspected from the two seemingly unrelated points above, and the dead giveaway title of this section, it would be tremendous if we could use FIDO2 keys to authenticate over SSH, and the OpenSSH developers made it happen. OpenSSH now supports FIDO (U2F) and FIDO2 for authentication, with FIDO2 with resident keys having a nicer UX.

At a high level, the USB device (FIDO2 devices don’t have to be USB, but they usually will be) will generate a secret key. The device can then use this secret key to prove that you have the device in your possession, without the key ever leaving the device. That means that, by extension, you can use the device to prove you are who you say you are to any server who asks. The key is either stored on the device (called “resident key”), which requires the device to support storage, or it isn’t, and you need to store the data somewhere else.

The way this works, in my understanding (which I’m not certain about and please correct me if I’m wrong), is the following: Each device comes from the factory with one key pair/seed built in, but it can accept an additional seed to derive more pairs from, by combining its current seed with the one given. This allows devices to generate keys without having any storage space, but it does require you to be giving them the seed every time. Devices with “resident key” capabilities can store the whole seed on their memory, and don’t need you to do anything else.

The benefit of using a device like this including eliminating phishing, password theft, authentication replay, and lots of other attacks. Since the device authenticates to a specfic realm (server address/URL/etc), an attacker can’t reuse one site’s authentication on another site, which makes phishing impossible. Nobody can steal your password or private key either, since it’s on the device itself and extracting it is impossible. The only plausible attack is physical theft with the device, which is mitigated by making the device ask for a PIN or fingerprint and wiping itself after a few wrong attempts.

Another benefit with having this built into SSH is that you don’t specifically need a Yubikey, or to mess with extra software like Yubikey agent, PIV mode or anything else. You just plug any FIDO2-compatible key in, and you can use it with SSH. I tried the following on both my Yubikey 5C, Yubikey FIDO2 and Yubikey NEO, they worked like a charm on all of them, but “resident key” mode only works on the 5C and later versions of the FIDO2 key.

Actual usage

With twelve padlocks, the city of Indianapolis was sure it had put a stop to miscreants stealing its favorite fence.

After all the needless detail about how devices work, we’re ready to actually use one for SSH. Setting that up is really simple, basically one or two commands (depending on the method) with no extra software to install, though you will need to be running OpenSSH 8.2 on both client and server.

I will split the instructions into two parts, one for if your key supports (and you want to use) the resident key mode, and one for if it doesn’t. There’s no harm in using either method, so if you don’t know if your device supports resident key mode, just try the first method and continue to the second one if it fails.

Resident key mode

Use the following command to generate a key and store it on the device:

ssh-keygen -t ed25519-sk -O resident -f ~/.ssh/id_mykey_sk

SSH will ask you to enter your PIN and touch your device, and then save the key pair where you told it. If that command complains about ed25519 not being available, try this one:

ssh-keygen -t ecdsa-sk -O resident -f ~/.ssh/id_mykey_sk

OpenSSH will save two files, one called id_mykey_sk, and one called id_mykey_sk.pub. You only really need the latter, it’s your public key, and you can now add it to the authorized_keys file of any server that runs OpenSSH 8.2 and above.

To add your private key to the SSH agent, you can either copy id_mykey_sk to your ~/.ssh/ directory, or (if you’re at a new computer and don’t have the key with you), run

ssh-add -K

with your device plugged in. This will add the key to the SSH agent, and you will be able to connect to servers immediately.

To get your public key from the SSH agent, run:

ssh-add -L

This will show you a list of public keys, including the FIDO2 one.

Non-resident key mode

The non-resident key mode is the same as the previous mode, except you can’t load your key with ssh-add -K directly from the device. As before, run:

ssh-keygen -t ed25519-sk -f ~/.ssh/id_mykey_sk

SSH will ask you to enter your PIN and touch your device, and then save the key pair where you told it. If that command complains about ed25519 not being available, try this one:

ssh-keygen -t ecdsa-sk -f ~/.ssh/id_mykey_sk

OpenSSH will save two files, one called id_mykey_sk, and one called id_mykey_sk.pub. You need both of these files, store id_mykey_sk in your ~/.ssh/ directory (where it got generated) and add the id_mykey_sk.pub file to any server you want to log in to.

That’s it, when you try to log in, OpenSSH will ask you for your PIN and to touch the device.

Security considerations

You can pass the no-touch-required option to ssh-keygen to tell it that you don’t want it to require touching the device every time, but I haven’t had great results with enabling that. If you try it, let me know how well it works in the comments, but it’s probably better for security if you leave it disabled.

Storing your key on the device means that nobody will be able to steal it (hopefully your device has a PIN or other authentication method set), but untrusted computers might still be able to send commands over the SSH session after you connect. Don’t SSH from computers you don’t trust, and be extra careful when using SSH forwarding (the -A option), as the server can then ask your computer to authenticate to other servers on your behalf.

Epilogue

I’m very excited about FIDO2 in general, and for SSH authentication specifically, because we finally have a way to secure authentication that my parents can easily use, with a much smaller attack surface. I’m particularly interested in seeing how WebAuthn takes off for authenticating on the web without usernames and passwords (see my django-webauthin library for a demo), and hope it becomes widespread.

If you have any feedback, please Tweet or toot at me, or email me directly. Also, check out my YouTube channel (because who doesn’t have a YouTube channel these days?), where I frequently livestream my late-night maker sessions.