SSH authentication with your PGP key

A few weeks ago I learned that a few of my colleagues were using PGP. I myself started using PGP around 2003, using the GnuPG implementation. However, since I didn't know many people who used it my usage slowly faded after a few years. In 2009 I shortly picked it up again by creating a new key to phase out SHA-1, but that was also of short duration. Thanks to my colleagues, I'm now starting to use GnuPG again. My key is still the same as created in 2009: 610DB834.

I noticed that both my PGP-key and my SSH-keys use the RSA-algorithm, so I started wondering whether it was possible to use my PGP-key to authenticate myself to SSH-servers. After some Googling it seemed possible, but not very straightforward. In the end I managed to get it working, thanks to the very friendly support of Werner Koch (the main developer of GnuPG). Since it is not very straightforward I will document my findings here for future reference.

Adding an authentication key

First add an authentication subkey to your PGP-key, as it is apparently a best practice to use subkeys for each type of usage. To do so you need to start gpg with the --expert flag like this:

1
2
# where 610DB834 is the id of my key
gpg --expert --edit-key 610DB834

When you are in gpg type addkey and type '8' to choose (8) RSA (set your own capabilities). This option let's you manually configure the new key. Then type (each time followed by enter): S, E, A, Q, so that it says 'Current allowed actions: Authenticate'. Then choose a keysize (I use 4096) and an expiration date (5 years from now for example) and wait for the key to be created. Finally save to save your key. Your authentication-subkey is now ready.

Getting it working on the client

Now that we have a new authentication subkey on our PGP key, we can configure everything so that we can use our PGP key for SSH authentication. Sadly enough, this is not as straightforward as I had hoped for. At least not if you are using the current stable version of GnuPG (2.0.x). Werner Koch explained on the mailinglist that it should be rather easy with GnuPG 2.1, which is currently in beta.

GnuPG 2.1

As of GnuPG 2.1 the gpg-agent will be used to store all the keys. So to set-up everything, you only have to start gpg-agent with the --enable-ssh-support option and add the 'keygrip' of your authentication key to the ~/.gnupg/sshcontrol file and you are done.

Sidenote. What is a 'keygrip'? As explained by Werner:

That is a protocol neutral way to identify a public key. It is a hash over the actual public key parameters. It is GnuPG specific but for example, pkcs#15 uses a similar technique. To compute it, you should use the respective Libgcrypt function.

GnuPG 2.0

When you prefer to use the current stable version of GnuPG it takes a few additional steps. The problem is that your key is not available to gpg-agent to be used for SSH-authentication, so you need to get it in the gpg-agent. One method to do this is by installing monkeysphere (available from the ubuntu repos). After installing this, you can run the command monkeysphere subkey-to-ssh-agent (or it's short form: monkeysphere s). Monkeysphere will then extract your private authentication key from GnuPG, run it through the openpgp2ssh-script to convert it into the correct format, and then add it to gpg-agent using the standard ssh-add-command. After you have ran that command your authentication subkey will (also) be stored by gpg-agent and it will be added to the ~/.gnupg/sshcontrol-file so you can use it for SSH-authentication. (As with GnuPG 2.1, make sure that your gpg-agent is started with the --enable-ssh-support flag.)

GNOME keyring

If you prefer to use GNOME keyring, a similar solution is possible. The easiest solution is to simply run the aforementioned monkeysphere subkey-to-ssh-agent-command. However, you will have to do this every time you log on again. This is because the regular ssh-agent doesn't "remember" keys which are added using ssh-add (while gpg-agent really copies them and stores them safely).

This problem can be solved by manually extracting your key, converting it, setting a new passphrase and storing it with the correct name in your ~/.ssh/-directory. By doing this GNOME keyring will automatically pick up the key. To do this execute the following commands (where C83CBC1B is my subkey):

1
2
3
4
56
7
8
9
1011
12
13
14
1516
17
18
cd ~/.ssh/
# export the key without a passphrase (the openpgp2ssh script
# can't handle encrypted keys)
gpg2 --export-options export-reset-subkey-passwd,export-minimal,\
    no-export-attributes --export-secret-subkeys --no-armor \     0xC83CBC1B! > C83CBC1B.key
 
# convert the raw key to the correct format
openpgp2ssh C83CBC1B < C83CBC1B.key > C83CBC1B
 # remove the exported raw key
rm C83CBC1B.key
 
# set the correct permissions for the private key
chmod 600 C83CBC1B 
# add back a passphrase to the key
ssh-keygen -f C83CBC1B -p

After doing this you will have your PGP key in the correct format inside your SSH-directory. However, for GNOME keyring to automatically pick up your key you also need to add the public key as C83CBC1B.pub. (see the next section)

Getting the key on the server

Before you can log on to a server using your PGP key, you also have to add it on the server. More correctly, you have to add your public key to the ~/.ssh/authorized_keys-file. So how do you obtain the public key of your authentication subkey?

Luckily that is rather easy. After you have added your key to gpg-agent or GNOME keyring you can simply run ssh-add -L and the public keys for all your loaded keys will be shown. Pick the correct one, add it into the authorized_keys-file on the server and you are done!

side note: while I was searching for information about this I regularly found references to the gpgkey2ssh script. This will also output your public key if you run it like gpgkey2ssh C83CBC1B. However since ssh-add -L does exactly the same, you don't need this script.

Side note: replacing GNOME keyring with gpg-agent

If you are using GNOME or XFCE with the "Launch GNOME services on startup"-option enabled, you won't be using the 'real' gpg-agent by default. The reason for this is that GNOME keyring implements it's own version of ssh-agent and gpg-agent. It took me some time before I realized that not everything worked as I expected because I was using keyring while I thought I was using gpg-agent.

To get it working I finally disabled the GNOME services (I'm using XFCE) on one laptop so I could try the solution with the "real" gpg-agent. After I got this working, I decided to try and get it working with GNOME keyring on my laptop from work, just to see if that would also be possible. It turned out to be not so difficult and now I have two laptops with two different solutions for the same problem :)

I'd really like to thank Werner Koch and the people from the gnupg-users mailinglist for their help!

Comments

Hauke Laging's picture

That's what this is called:
cat C83CBC1B.key | ...

If you want to read from a file, use redirection:
openpgp2ssh C83CBC1B < C83CBC1B.key > C83CBC1B

jeroen's picture

You are completely correct. In fact I knew the cat was useless here, but often I find it more readable to use cat. I'll update it in the article. Thanks for your input!

Lloyd's picture

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA256

Hi, I was just wondering if you know of anywhere I can obtain a compiled verision of GnuPG-2.1 in .deb format? I use Trisquel 6.0, which is based on Ubuntu 12.04. I've found the sources but don't really fancy compiling it myself if I can avoid it.

Thanks!
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v2.0.17 (GNU/Linux)

iF4EAREIAAYFAlEJbdUACgkQgijxUCZnvlu9lwD+O5eQEoQPVdM7WYE2PTGUC5hi
NEDuUBUClu/z8q3i6CsBAIm0Yl5cMsFWRZS7Z35aAFmuyUyNWHRxXUkuglY8mv54
=uRD7
-----END PGP SIGNATURE-----

jeroen's picture

Hi Lloyd,
I don't know of any .deb version of GnuPG 2.1. I think the best place to ask this is on the gnupg mailinglist: http://lists.gnupg.org/mailman/listinfo/gnupg-users

Lloyd's picture

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA256

Quick reply - thanks! I'll check out that mailing list but I guess I'll have to try and compile myself.
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.11 (GNU/Linux)

iF4EAREIAAYFAlEJlMwACgkQgijxUCZnvlu/JQD/TvKSFSyLeXhnp7mzAtjzS3Mv
nakhutv76PpPYzzKNw8A/3nfaBPjxzrigg9/CzsUCh4UpPrGIko/0jspvTxFXaYk
=UsdN
-----END PGP SIGNATURE-----

Add new comment