iliana weller

Protect yourself from the next CVE-2016-0777 with a smart card

CVE-2016-0777 describes a vulnerability in the OpenSSH client via an enabled-by-default undocumented option (UseRoaming) by which a malicious SSH server could steal your private SSH key.

Mitigations and whether or not you’re even vulnerable aside, this is likely not going to be the last private key disclosure vulnerability for every SSH client you will use in the future.

A good way to protect your private key from these sorts of vulnerabilities is to ensure it can never be read into memory.

Enter smart cards

Smart cards are embedded devices that can be used to provide trusted storage for credentials and other data. Many of them have built-in cryptographic capabilities. It’s possible you carry smart cards all the time without realizing it — the SIM card in your phone, payment cards with chips, and many contactless public transit passes are all based on smart card technology.

Most smart cards have a secure element containing a secret, which can only be accessed with a PIN. If your on-disk private SSH key stored is encrypted with a passphrase, it’s a similar concept, but smart cards go one step further: most implementations make it impossible to extract the key from the card, and often will allow you to generate the key on the card itself, giving you the ability to ensure there is ever only one copy of a private key.

OpenSSH on its own has no idea what a smart card is. It has support for talking to PKCS #11 libraries, but a far easier method is using the OpenPGPCard applet, which allows you to store signing, encryption, and authentication GPG subkeys. gpg-agent can act as an OpenSSH-compatible ssh-agent on UNIX-like systems, and Gpg4win can act as a PuTTY-compatible SSH agent on Windows, making your authentication subkey usable by SSH clients.

If you have a smart card reader, you can buy a blank smart card, and compile and install the OpenPGPCard applet. Or you can buy a YubiKey 4 or a YubiKey Neo; both have the OpenPGPCard applet pre-installed. The YubiKey 4 is capable of storing 4096-bit RSA keys; the YubiKey Neo is capable of storing 2048-bit RSA keys, but also has an NFC interface (while I know of no SSH clients that support the OpenPGPCard applet over NFC, if you set up signing and encryption subkeys you can use them for K-9 Mail and Password Store).

First-time setup environment

Since SSH doesn’t know how to talk to smart cards, but GPG does, and GPG can be an SSH agent, we’ll set up a GPG authentication subkey to use with SSH.

If you would like to use your smart card with all GPG subkey functionality, I recommend following Tom Lowenthal’s excellent GPG-on-a-smart card guide.

Get started by creating a secure environment. Download a live image of an operating system that comes with GnuPG — I recommend Fedora — and verify the download. Burn it to a DVD or dd it to a USB drive (you can also use the Fedora LiveUSB Creator, even on Windows, but be sure to specify no persistent storage). Whatever you download doesn’t need to have a graphical interface, since we’ll be running terminal commands in this guide (sorry).

Find a computer you trust, and boot this computer with the live media you created and log in (if you used Fedora, the username is liveuser and there is no password).

We need network access at least temporarily to install a few packages. (Strictly speaking, if you intend to generate the key on the card and not make an off-card backup, you can use any Linux machine you like.)

Fedora 23 (Workstation Edition)
Kernel 4.2.3-300.fc23.x86_64 on an x86_64 (tty1)

localhost login: liveuser
[liveuser@localhost ~]$

If you’re using a YubiKey, plug it in and run lsusb to determine what mode it’s in.

[liveuser@localhost ~]$ lsusb | grep -i yubi
Bus 001 Device 005: ID 1050:0111 Yubico..com Yubikey NEO(-N) OTP+CCID

The last part of the device name is what mode your device is in. It can have one or more of OTP, CCID, or U2F enabled. To use the OpenPGPCard applet, your device needs to have the CCID mode enabled — you can use ykpersonalize to set the mode with the -m switch.

For Fedora, you’ll need to install gnupg2-smime pcsc-lite-ccid. (Please let me know if you can provide a package list for other live distributions.)

[liveuser@localhost ~]$ sudo dnf install gnupg2-smime pcsc-lite-ccid
[ dnf makes lots of noise ]
Complete!

At this point you can disconnect from your network. pcscd needs to be running for GPG to use your card; it’s probably available as a service in the init system.

[liveuser@localhost ~] sudo systemctl start pcscd.service

Hello, smart card

After ensuring the necessary software is installed and pcscd is started, GPG should be able to talk to your card. (I’m using the gpg2 command here, because Fedora provides both GPG 1.x and 2.x. You may need to run a slightly different command.)

[liveuser@localhost ~]$ gpg2 --card-edit

Application ID ...: D2760001240102000006030136050000
Version ..........: 2.0
Manufacturer .....: Yubico
Serial number ....: 03013605
Name of cardholder: [not set]
Language prefs ...: [not set]
Sex ..............: unspecified
URL of public key : [not set]
Login data .......: [not set]
Signature PIN ....: forced
Key attributes ...: rsa2048 rsa2048 rsa2048
Max. PIN lengths .: 127 127 127
PIN retry counter : 3 3 3
Signature counter : 0
Signature key ....: [none]
Encryption key....: [none]
Authentication key: [none]
General key info..: [none]

gpg/card>

There’s a lot going on here, but if you see something like this, GPG was successfully able to get information about your card’s emptiness.

Before we load any keys on the card, we need to set the PINs. First we need to turn on admin mode:

gpg/card> admin
Admin commands are allowed

The default user PIN is 123456 and the default admin PIN is 12345678. The PIN is really a passphrase, since you can use whatever characters you like; some smart cards can be used with physical PIN pads that only allow numbers, but for the most part we’ll be using keyboards.

Start with the admin PIN; this is used to modify the card, such as changing the keys, user PIN, or other attributes. The Max. PIN Lengths line in the GPG output tells you how long each PIN can be (in bytes, in case you’re using Unicode characters).

Because the admin PIN can effectively let someone use your private key, it’s important for it to be secure. Because you don’t need to use it every day, you probably don’t have to memorize it. You’ll need it if you lock your card though; every time you mistype your PIN, the PIN retry counter goes down one, and when it hits zero, the card is locked.

(Enter 12345678 as the current admin PIN.)

gpg/card> passwd
gpg: OpenPGP card no. D2760001240102000006030136050000 detected

1 - change PIN
2 - unblock PIN
3 - change Admin PIN
4 - set the Reset Code
Q - quit

Your selection? 3
PIN changed.

(There isn’t a prompt in the above output — GPG uses the system’s pinentry command to ask for it, which usually does something incredibly obvious like taking over your entire screen or terminal, to prevent attacks that might trick you into typing your PIN somewhere else.)

Now change the user PIN. This will be the one you enter to use your private key, so remember this one. (Enter 123456 as the current user PIN.)

Your selection? 1
PIN changed.

The user PIN is what you’ll use daily to unlock your card and use it for authentication; your card will (usually) remain unlocked until you kill the GPG agent or remove the card.

If you like, you can set the Reset Code. If set, it allows you to use the factory-reset admin-mode command, which allows you to use your card again if you’ve locked both the user and admin PINs, with the cost of completely destroying the private keys and other attributes on the card. Most YubiKeys will allow you to use the factory-reset command if you’ve locked both the user and admin PINs, so it’s unnecessary (they provide a script which will guess your password wrong and reset your card for you).

Let’s exit the passwd mode.

Your selection? Q

gpg/card>

Key generation

Okay, let’s finally generate a key. This will actually generate all three subkeys (with the signature key being the “main” key holding them all together). As discussed, we only care about the authentication subkey.

gpg/card> generate
Make off-card backup of encryption key? (Y/n)

Understand that if you lose, damage, or lock your card, and you don’t have an off-card backup, you will not be able to use the key anymore and will need to generate a new one, requiring you to change your authorized_keys everywhere. Consider whether you want your card to have the only copy of this key in the world.

Upon answering this, you’re asked for both your admin PIN and your user PIN. Then, you’ll be asked the standard GPG questions of “how long should this key last” and “who do you think you are, telling me what to do”. In a world of only using GPG for SSH authentication, these don’t matter too much.

Make off-card backup of encryption key? (Y/n) n

Please specify how long the key should be valid.
         0 = key does not expire
      <n>  = key expires in n days
      <n>w = key expires in n weeks
      <n>m = key expires in n months
      <n>y = key expires in n years
Key is valid for? (0) 0
Key does not expire at all
Is this correct? (y/N) y

GnuPG needs to construct a user ID to identify your key.

Real name: Iliana Weller
Email address: ilianaw@buttslol.net
Comment:
You selected this USER-ID:
    "Iliana Weller <ilianaw@buttslol.net>"

Change (N)ame, (C)omment, (E)mail or (O)kay/(Q)uit? o

After answering all this, the card generates random bytes for a while. (On YubiKeys, you can see the light blink while it’s doing this.) It finishes after a couple of minutes.

gpg: /home/liveuser/.gnupg/trustdb.gpg: trustdb created
gpg: key 68255940 marked as ultimately trusted
gpg: directory '/home/liveuser/.gnupg/openpgp-revocs.d' created
public and secret key created and signed.

gpg: checking the trustdb
gpg: 3 marginal(s) needed, 1 complete(s) needed, PGP trust model
gpg: depth: 0  valid:   1  signed:   0  trust: 0-, 0q, 0n, 0m, 0f, 1u

gpg/card> quit
pub   rsa2048/68255940 2016-01-15
      Key fingerprint = 89DE 77D8 BA91 CB24 8F89  5D47 A37C 748F 6825 5940
uid         [ultimate] Iliana Weller <ilianaw@buttslol.net>
sub   rsa2048/DC2956F2 2016-01-15
sub   rsa2048/AE968BCB 2016-01-15

[liveuser@localhost ~]$ gpg2 --card-status

Application ID ...: D2760001240102000006030136050000
Version ..........: 2.0
Manufacturer .....: Yubico
Serial number ....: 03013605
Name of cardholder: [not set]
Language prefs ...: [not set]
Sex ..............: unspecified
URL of public key : [not set]
Login data .......: [not set]
Signature PIN ....: forced
Key attributes ...: rsa2048 rsa2048 rsa2048
Max. PIN lengths .: 127 127 127
PIN retry counter : 3 3 3
Signature counter : 4
Signature key ....: 89DE 77D8 BA91 CB24 8F89  5D47 A37C 748F 6825 5940
      created ....: 2016-01-15 05:07:03
Encryption key....: F698 CB7F C4A8 B805 4363  904F D9CB E15D AE96 8BCB
      created ....: 2016-01-15 05:07:03
Authentication key: 0982 0907 DB21 548A 8191  6A89 AE2B A54F DC29 56F2
      created ....: 2016-01-15 05:07:03
General key info..: pub  rsa2048/68255940 2016-01-15 Iliana Weller <ilianaw@buttslol.net>
sec>  rsa2048/68255940  created: 2016-01-15  expires: never
                        card-no: 0006 03013605
ssb>  rsa2048/DC2956F2  created: 2016-01-15  expires: never
                        card-no: 0006 03013605
ssb>  rsa2048/AE968BCB  created: 2016-01-15  expires: never
                        card-no: 0006 03013605

GPG goes ahead and creates all the other subkeys for you as well. As said earlier, if you really intend to use these for non-SSH GPG applications, you should consider following these excellent instructions to make a cold storage GPG key, generate subkeys, and put them on the smart card, as keeping the main key on a smart card is more risky than necessary.

Normally you’d want a copy of the generated public keys. But if you’re just using this for authentication, the card has all the information you need.

(If you’re planning on using this key on only Windows, you might consider completing the Linux SSH agent setup instructions below to see the public key in authorized_keys form.)

We’re done — you can shut down the live OS. Remember to keep your admin PIN in a safe place.

Setting up your SSH agent

Setting up your day-to-day computers to use your new smart card depends on what OS they’re running.

Linux, BSD, and Mac

For Linux, BSD, and the like, we already did this above — ensure you have the CCID component of pcsc-lite installed (sometimes called pcsc-lite-ccid), and the S/MIME component of GnuPG (sometimes called gnupg2-smime and sometimes included in the main GnuPG package). Once pcscd is running. gpg2 --card-status should show your card.

For Macs, Homebrew seems to provide GnuPG packages. You may find Glenn Rempe’s blog post on using a YubiKey for GPG and SSH on a Mac helpful. gpg2 --card-status should work with the smart card libraries on the system.

Once you have a working version of GnuPG, we need to configure it to enable SSH agent support.

$ echo "enable-ssh-support" >> ~/.gnupg/gpg-agent.conf

You can ensure gpg-agent is running with

$ gpg-connect-agent /bye

Because GPG always puts its sockets in the same place, you can simply export SSH_AUTH_SOCK to the correct value in your shell startup file.

export SSH_AUTH_SOCK="$HOME/.gnupg/S.gpg-agent.ssh"

Once SSH_AUTH_SOCK is exported, you can use ssh-add -L to view your public key in authorized_keys format (and to verify that everything is set up right).

$ ssh-add -L
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC8YHaUn3i/yd27wmO4d9if1tNzcpNSW1gkfYiFqX2xShgYAOPG+Vr6WmU6xN43Qx0jpuLfajBkvEyySnyw+XXD4WR+dtEBYrEAMJHLT2wIWRI89TUaMyV7+tiGUGAwD08JKm9vN5e1erdUFVJpejNN0o2fvglDDa3w0sKyhiqPSOjm64tIYys5s38pFp1fbAnEvasVzePBH5vz5ySJyfwqq61SEzefzCjUNF7JzWsP4c4vVKKvzCJnHAEs/5Iv0/3kAoQbHodXu4russXZ6mu4JBO03fzcFH7W69kdsrK4Vba4JjGu2e1Z1izpOK/r4455gxZKMxKY67B+KuQ9DGjB cardno:000603013605

And if ssh-add shows the key, ssh is likely to be able to use the key.

If you’d like to kill the agent, you can use

$ gpg-connect-agent killagent /bye

Windows

Install Gpg4win, a version of GnuPG built for Windows. It comes in many flavors; any will do, and for the purposes of SSH, the Vanilla version is plenty. (Gpg4win is signed for Authenticode and also has a GPG signature available.)

The equivalent of ~/.gnupg with Gpg4win is %APPDATA%\gnupg. In there, create a gpg-agent.conf file, which needs to contain only one line:

enable-putty-support

enable-putty-support is an extension on top of the normal GnuPG distribution that provides the same interface PuTTY’s Pageant provides, so you can just use PuTTY and anything else that works with Pageant out of the box.

(For Cygwin users, install the ssh-pageant package, which presents an OpenSSH-compatible agent that passes data back to a Pageant-compatible agent.)

Ensure the agent is running:

$ gpg-connect-agent.exe /bye

Is this worth the hassle?

I don’t know. I’m not you.

Weigh the cost of the smart card, setting it up, and bootstrapping all your client systems against the cost of having your private SSH key compromised once (which can be very bad if you don’t have a way of disabling your compromised key across your entire fleet of servers). It’s tempting to say “there’s a million-in-one chance that my key will be compromised”, but people still win the Powerball.

On-filesystem SSH keys are still perfectly suitable for automated systems, but just like all stored credentials, you should rotate them once a quarter, and especially after disclosures like CVE-2016-0777.

Next steps

Another important step in keeping SSH secure is using secure cryptography in transit. Read stribika’s analysis and guide on securing SSH.