Using Nitrokey for server auth and regular ssh-keys everywhere else

I use an openpgp smartcard called NitroKey to store in hardware my private keys for my production server. This is a pretty common set up with lots of companies deploying these and other brand of keys around the world. Other brands are Yubikey and Google have just brought out their own key as well.

When using ssh to access my server, I needed to make changes to how ssh handles keys. This means that you are modifying ssh as a whole, so any regular private keys you use (such as git commit keys or other servers) won't work without adding them to the gpg-agent.

Set up your nitrokey for ssh auth

Disclaimer I take no responsibility for any damage or hardships caused by you using this information. This was performed on Debian stable (stretch). I am assuming you have already set your private keys up and have also updated your server to use your auth public key.

First we need to make sure that your card can be read by gpg, (with nitrokey inserted) run gpg --card-status or gpg2 --card-status. You should have returned some information like so Reader ...........: 20A0:0000:0000000000000:0 Application ID ...: D0000000000000010005000035F60000 Version ..........: 2.1 Manufacturer .....: ZeitControl Serial number ....: 00001234 Name of cardholder: [not set] Language prefs ...: uk Sex ..............: unspecified URL of public key : [not set] Login data .......: [not set] Signature PIN ....: forced Key attributes ...: rsa2048 rsa2048 rsa2048 Max. PIN lengths .: 32 32 32 PIN retry counter : 3 0 3 Signature counter : 11 Signature key ....: (a hash here) created ....: 2017-01-30 14:49:45 Encryption key....: (a hash here) created ....: 2017-01-30 14:49:45 Authentication key: (a hash here) created ....: 2017-01-30 14:49:45 General key info..: [none] This is your keys general information and you should see an Authentication key hash here. If you don't, regenerate your keys.

Next we will set gpg daemon to be used as an agent. First we need to pipe into ~/.gnupg/gpg.conf “use-agent”.

echo use-agent >> ~/.gnupg/gpg.conf

Next we need to tell gpg-agent it will be used as the replacement for ssh-agent.

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

FInally, in our .bashrc file, we need to add this snippet of shell code. What this does is it changes the environment variable SSH_AUTH_SOCK to gpg-agent for all our key auth.

unset SSH_AGENT_PID if [ "${gnupg_SSH_AUTH_SOCK_by:-0}" -ne $$ ]; then export SSH_AUTH_SOCK="$(gpgconf --list-dirs agent-ssh-socket)" fi

Now, your nitrokey “should” be set up and working. Mine wasn't, so I'll list the extra things I had to do for this to work. Skip to the next section if everything is okay for you.

(Optional) Troubleshooting

Firstly, I had a config set up for my bitbucket account in ~/.ssh/config that allowed Visual Studio Code to use the correct ssh key for git. I had to remove this as it conflicted with gpg-agent and caused ssh-agent to be used.

Secondly, my nitrokey wasn't being read as an openpgp card. I has to install the scdaemon for this to work. The packages are in regular Debian repos.

sudo apt-get update && sudo apt-get install libccid

And finally, I was greeted with an error

sign_and_send_pubkey: signing failed: agent refused operation This was a problem with Debian Stretch. Luckily, there is a bug report detailing that to fix this, I needed to install dbus-user-session which I did.

sudo apt-get install dbus-user-session

Using regular ssh keys

Luckily, gpg-agent has built in ssh-agent emulation. To add your ssh keys to the gpg-agent, just use regular ssh-add with the location to your private key e.g

ssh-add ~/keys/supersecretkey

gpg-agent requires you to have a passphrase on the key from now on though, so make a backup of your key just in case you forget the phrase.

The key configs are stored in ~/.gnupg/sshcontrol and will contain a MD5 hash of your key information.

That's it!

I hope this has been helpful to you, please email me if you find anything that is wrong.