Using a U2F/FIDO key with OpenSSH

Introduction

The following article describes how a key deployment setup with Universal 2nd Factor (U2F) OpenSSH keys can look like. U2F is a standard that was invented to simplify an authentication process while maintaining the security level. If not well designed, making an authentication process easier for the end user leads to a decreased security level. The FIDO alliance (members, among others, are Google, PayPal, Yubico and Microsoft) created the U2F standard to exactly overcome this problem. Basically, the end user has a device they own (usually some form of USB device) and another factor they know (usually a password). Most prominent example of the aforementioned USB devices are Yubikeys produced by the company Yubico.

Here is a photo of one of my Yubico Security Keys:

Blue Yubikey with golden button and pins on a brown desk

Securing a remote SSH login with a Yubikey is nothing new, there is a variety of instructions out there in the Internet. The one thing nearly all instructions have in common is the complexity of the setup and complexity is the adversary of security. If you take some time and scroll through the articles you will recognize what I mean. Since I am doing something with Information Security in my daily job, I jumped the gun and tried a lot of different setups over the last years. I never found a solution that is simple, easy to set up, low on maintenance and still works after some years. Especially solutions where a person has to use a physical device as Java Smartcard and use GnuPG plus SSH to store their private SSH key on the device are very popular among admins. NOT! Believe me, I’ve been there.

So, why another article now? OpenSSH since Version 8.2 supports FIDO/U2F hardware out-of-the-box. As a smart move, the developers included libfido2 so that USB keys can be used out of the box. libfido2 acts as a middleware here and other tokens attached via NFC or Bluetooth can also be used. However, since I don’t own and use Bluetooth nor NFC devices this articles focuses on USB tokens. Further, they didn’t reinvent the wheel or introduced additional complexity, they just created two new key types that work like the SSH keys you’re already used to.

As of today, OpenSSH Version 8.2 is already available on the following major operating systems and I am sure I’ve missed a dozen :)

Threat Model

I was asked for the threat model and the reason why I deploy such a setup. Basically, I am a lazy person so I don’t change my personal SSH keys very often. The last big key rollover on my side was when OpenSSH introduced ed25519 keys. So, I rely on the assumption that no one stole my private keys from one of my personal devices. I personally consider the likelihood of an attacker that extracts keys from my physical devices as low (YMMV).

However, an attacker could steal my private SSH keys by exploiting a vulnerability in the software I use. If you look up the security vulnerabilities found in Chrome or Firefox this is not an unlikely scenario. To make an attacker’s life harder, I rely on patching the software, using additional security mechanisms and running most prominent software under another user.

Having FIDO SSH keys is another way to prevent that an attacker who stole my keys can access my servers.

Disaster Recovery Plan

I learned over the years and with certain experiments that having a proper disaster recovery plan is key in order not to lose access to my servers. Thus, my current setup looks as follows:

  1. Two different U2F Security Keys from Yubico. Both ordered some month apart from each other to avoid having two keys from a faulty production charge.
  2. An offline backup SSH key for disaster access.

Both public SSH keys bound to the respective Yubikeys are rolled out to all servers so that I can log in no matter which key I have around. Should I lose/break one Yubikey, I can still use the other one to gain access. The offline key is stored on several, fully encrypted backup disks stored in different physical locations. There is no online or cloud backup. I haven’t (yet) tried to work with printed offline keys, however, with short ed25519 keys and a proper QR code this should also work.

Generate a U2F SSH Key Pair

With Version 8.2, the OpenSSH developers created two new public key types “ecdsa-sk” and “ed25519-sk”. Both are backed by a FIDO token and can be used like any other SSH key as long as the token is attached. As before, you can still use ssh-keygen to create a key pair, the only differences is that you need to have a token attached during generation and press the device’s button to confirm the generation. I also increased the number of encryption rounds by setting the “-a” flags to 250 rounds (keep in mind that this flags is hardware dependent, so 250 rounds on my system can be different from your system).

$ ssh-keygen -t ed25519-sk -a 250 -f ed-key
Generating public/private ed25519-sk key pair.
You may need to touch your authenticator to authorize key generation.
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in ed-key
Your public key has been saved in ed-key-2.pub
The key fingerprint is:
[...]

In the example, I created a ed22519-sk key since both my Yubico security keys support them. If you have older Yubikeys or an older firmware you might get an error and have to choose ecdsa-sk.

Distributing and using the Public Keys

No changes from the Status Quo, so you can still add your key to your ssh-agent and use it accordingly.

$ ssh-add ed-key
Enter passphrase for ed-key:
Identity added: ed-key (me@localhost)

To use the key for login just copy the public key to the authorized_keys file on your remote machine. To actually use the key just use SSH as usual and confirm via pressing the device’s button that you indeed want to connect. ssh will ask you either on the console or as depicted in the following picture via gra[hical interface (here ssh-askpass):

SSHAskPass windows with a black background and a white font that asks the user to press a key on their authentication device

If your key is not loaded into the agent and you try to connect to a system where only FIDO keys are deployed, the error message looks like the following:

$ ssh example.com
sign_and_send_pubkey: signing failed for ED25519-SK "/home/user/.ssh/ed-key" from agent: agent refused operation

FIDO2 Resident Keys

Disclaimer: In the following, I give a brief introduction about FIDO2 resident keys, however, I don’t use them myself. As I said before, I am not a fan of keys stored on devices so I’ll stick with keys on disk plus a hardware token. I mention resident keys here to give you an idea what’s also possible.

In the setup I described in the last sections, a “key handle” part is stored in the private key file on disk and a per-device private key that is unique to each FIDO/U2F token and that cannot be exported from the device. To facilitate the use of the same key on different systems without the need to copy it around, FIDO2 resident keys can be used. Hereby, the “key handle” part can be retrieved from the device itself.

ssh-keygen can be used with the “-O resident” option to generate such a key. It will then be stored on the device itself and typically requires that you set a PIN before generation. By using the “-K” option you can download the key from the device.

$Id: u2fandssh.md,v 1.2 2020/06/09 18:02:24 cvs Exp $