YubiKey for SSH

YubiKey for SSH

There aren’t too many great articles out there about how to set up a YubiKey simply for SSH access. I will be showing you how to:

  1. Generate a GPG key

  2. Move the keys over to your YubiKey

  3. Enable SSH on GPG so that your SSH authenticates with GPG

Prerequisites

YubiKey implements the smart card interface for GPG, which means you shouldn’t need any external libraries specific to YubiKey. However you still need an up-to-date version of GPG and gpg-agent to allow SSH. You can check if your version of gpg-agent is recent by running the command below.

$ gpg-agent --help | grep ssh
     --enable-ssh-support         enable ssh support

If the --enable-ssh-support ssh flag exists, you can continue, otherwise, download the latest versions of GPG and gpg-agent from your package manager of choice.

Getting Started

First, let’s plug in the blank YubiKey and make sure you can edit it with GPG.

    $ gpg --card-edit

    Application ID ...: D2760001240102010006061566540000
    Version ..........: 2.1
    Manufacturer .....: unknown
    Serial number ....: 06156654
    Name of cardholder: [not set]
    Language prefs ...: [not set]
    Sex ..............: unspecified
    URL of public key : [not set]
    Login data .......: [not set]
    Private DO 1 .....: [not set]
    Private DO 2 .....: [not set]
    Signature PIN ....: not forced
    Key attributes ...: 2048R 2048R 2048R
    Max. PIN lengths .: 127 127 127
    PIN retry counter : 3 0 3
    Signature counter : 0
    Signature key ....: [none]
    Encryption key....: [none]
    Authentication key: [none]
    General key info..: [none]

If your YubiKey already has data on it and you want to reset it, I’ve created this little script you can use to reset it. The hex values to reset the device I got off a GPG forum, but but you can probably find them elsewhere:

Once you have a clean slate, we can get started! I’ll wait…ok that’s enough.

Generate a GPG Key

Open a terminal an type:

    $ gpg --gen-key

Now it should ask for at least a full name, email and password. DO NOT leave your password blank. If your GPG password is blank, anyone who gains access to your computer or the key itself, will be able to use it without authentication. This will generate an RSA 2048 bit key for you without an expiration. If you’d like to have more options, strengthen the key or add an expiration, you can use the expert flag like so:

    $ gpg --expert --gen-key

RSA 2048 might not be as secure as other bit lengths, but it’s perfectly fine for most use cases. Once you have the key, you can validate it like so:

    $ gpg --list-keys
    pub   rsa2048/D0B4CE63 2017-12-28 [SC]
    uid         [ultimate] Ryan Canty <[jrcanty@gmail.com](mailto:jrcanty@gmail.com)>
    sub   rsa2048/157D0431 2017-12-28 [E]

GPG Core Concepts

Let’s talk a bit about this output. If you don’t care, feel free to skip to the next section. As a disclaimer, these are learnings I picked up from doing this and reading a few articles, so if I’m missing something, please leave a comment letting me know where I’m wrong.

The first column is the descriptor, you’ll notice pub, uid, and sub. One of the core pieces of GPG I didn’t know before doing this, is that a single GPG key can have multiple sub-keys that can potentially handle different things, such as encryption, authentication, etc. The first two lines in the output give the public key portion of the master key and the user identifier.

The next column is the key identifier (I’m making up terms here, so again correct me if I’m wrong). The first portion (before the slash) is the type of key and the portion after the slash is the actual unique id for that key. You’ll need this later when you want to edit a key.

Finally the flags in the brackets are capabilities of the key. Here is a good post detailing all the flags, which is where I got this:

  • [C] Certificate

  • [E] Encryption

  • [S] Sign

  • [A] Authenticate

Creating an Authentication and Signature Key

To get SSH to work you mainly just need to create an authentication and signature sub-key since we already have an encryption sub-key created for us. We also don’t want to move the primary key to the card since the private key will be unusable by other keys. To do this you’ll want to plug in your YubiKey and then edit the master key you just created. As I mentioned previously, you’ll need the key identifier to do this. So with my example above:

    $ gpg --edit-key D0B4CE63

You’ll now be dropped into the GPG shell, where you can do many magical things that are out of the scope of this tutorial, but I’d encourage you to look at the options in help and find out for yourself.

So with our card plugged in, within the GPG shell you can either create a subkey and transfer it to the YubiKey OR you can create a key directly on the device. We’re going to be doing both, but let’s start with adding a key directly to the card:

    gpg> addcardkey

    Signature key ....: [none]
    Encryption key....: [none]
    Authentication key: [none]

    Please select the type of key to generate:
       (1) Signature key
       (2) Encryption key
       (3) Authentication key

As I mentioned above, the only type of key we don’t currently have is an Authentication key, so just type 3 to create one of those. You’ll have to enter both the user and admin PIN on your YubiKey as well as your GPG password. As mentioned in the script above, the defaults are 123456 and 12345678 respectively. You’ll want to change those once we’re done adding keys. Just repeat this process for the signature key.

Moving Encryption Key to the YubiKey

At this point we have only one key on the card. You can verify this by running gpg --card-edit and noticing the key in the spot for authentication. Now let’s move the existing keys to the YubiKey. Still within the GPG shell, let’s try to switch the key we’re working with. By default, the current key is the primary or master key, with an index of 0. If you want to change the current key, simply run:

    gpg> key 1

This should give you an output similar to this:

    gpg> key 1

    sec  rsa2048/D0B4CE63
         created: 2017-12-28  expires: never       usage: SC  
         trust: ultimate      validity: ultimate
    ssb* rsa2048/157D0431
         created: 2017-12-28  expires: never       usage: E   
    ssb  rsa2048/8E6FAB0A
         created: 2017-12-28  expires: never       usage: A   
         card-no: 0006 06156654
    ssb  rsa2048/16BA1B45
         created: 2017-12-28  expires: never       usage: S  
         card-no: 0006 06156654
    [ultimate] (1). Ryan Canty <[jrcanty@gmail.com](mailto:jrcanty@gmail.com)>

Notice the * next to the Encryption key? Ok now that the encryption key is selected, we can move it to the card using the command:

    gpg> keytocard

You’ll be asked what key slot you want to place this key into, and be give a single option of Encryption which you should select with it’s corresponding number. At this point you can exit out of the GPG shell by typing quit. Make sure you type y to save your changes or you’ll have to start all over.

Exporting the SSH Key

You should now be able to export the SSH public key to be used with whatever server you have. I’ll show you how to export the SSH key as well as the PGP public key so you can use it to sign code into GitHub with the same key.

First, to export as an ssh key, just run:

    $ gpg --export-ssh D0B4CE63

Second, to get the PGP key ASCII armored, run:

    $ gpg --export --armor D0B4CE63

Save these two outputs somewhere safe!

Enable SSH and GPG

This part might be the trickiest to wrap your head around unless you’re familiar with Unix Sockets. I’m not an expert either so bare with me. SSH has an authentication socket (or file) that it uses to communicate with the key chain on your computer. This file is referenced by the SSH_AUTH_SOC environment variable. What we’re doing here is enabling gpg-agent to run with SSH support and telling SSH where to find the authentication data it needs, as opposed to the standard ~/.ssh/id_rsa files. So first, you’ll need to kill your running gpg-agent if you have one running:

    $ pkill gpg-agent

Then just restart it with the --enable-ssh-support flag:

    $ gpg-agent --enable-ssh-support --daemon
    SSH_AUTH_SOCK=/home/ryan/.gnupg/S.gpg-agent.ssh; export SSH_AUTH_SOCK;

The output here is what you need to run in order to let SSH know about your GPG private key. You’ll either need to copypasta this onto your shell or add it into your .bashrc (or whatever fancy shell you’re using). Be careful though, if you have other SSH keys in your .ssh directory once you have that line in your .bashrc, SSH will ONLY authenticate with GPG and if your YubiKey isn’t inserted, you’ll get a “permission denied” error.

Changing Your PINs

Now for the final step before hooking your YubiKey to your key ring, strapping on your messenger bag, and riding your bike to a coffee shop: Please, please, please change your PINs. This is super simple using the same method we used earlier.

    $ gpg --card-edit
    ...

    gpg/card> admin
    Admin commands are allowed

    gpg/card> passwd
    1 - change PIN
    2 - unblock PIN
    3 - change Admin PIN
    4 - set the Reset Code
    Q - quit

    Your Selection? 1

Once you open up the card edit shell, you’ll need to switch to admin mode and the run the passwd command. You’ll need to run this twice: once for the admin and once for the user. I’d highly recommend making the keys different. Once this is done, you’re off to the races.

Final Remarks

GPG is a fantastic tool that has myriad uses that can help protect your sensitive information during communications. This use not only protects you from fallout of a compromised machine, but it gives you the ability to have a single centralized authentication key for all your devices and logins. Let me know if I missed anything or you’d like help.

SSH Authentication with AuthorizedKeysCommand

Imagine a world where adding or removing a user’s SSH access was as simple as a single button in AWS.

Next article

Here for you

Have questions? Leverage our expertise to help you meet your business goals with a strong security posture.

Join us

ScaleSec is a well-connected, fully remote team. We thive in the great undocumented beyond. We’re hiring in most US metros.

Get in touch

Considering cloud? Want to optimize and transform your existing digital portfolio?
Reach out to us.

Gap Assessment

Get perspective. Address security comprehensively.

Prepare for compliance.

ScaleSec
San Diego, CA 92120, United States

619-SCALE15

© 2019 ScaleSec. All rights reserved. | Privacy Policy