PGP keys and SSH keys are different. It took me longer than I care to admit to understand this, given that the first StackExchange thread I found on the subject made it pretty clear that it’s not trivial to use one where you’re supposed to use the other.

To be fair, the are the same kind of thing — that is, asymmetric encryption keys. They can even use the same encryption algorithms. But they are different in their implementation, which makes them not the same thing.

Confused? Asymmetric encryption keys are files (technically pairs of files) that are used to prove your identity in the course of your digital life — sort of like a password, but far more versatile. An SSH key authorizes you to log into an SSH server without a password (see this guide from Indiana University for details), and a PGP key can be used to sign a document or a git commit (i.e., prove you’re the one who made it) or decrypt messages intended only for you, among other things. A note on terminology: PGP (“Pretty Good Privacy”) is the commercial, proprietary software package which introduced PGP encryption to the world.

(“Pretty Good Privacy”) is the commercial, proprietary software package which introduced PGP encryption to the world. OpenPGP is an Internet Standard message format (RFC 4880) initiated by PGP Inc. and followed by all PGP encryption software.

is an Internet Standard message format (RFC 4880) initiated by PGP Inc. and followed by all PGP encryption software. gpg (“GNU Privacy Guard”) is a free and open-source PGP encryption program that most people use to manage their keys. It’s easy to get these terms mixed up, but usually when people say “PGP”, they’re talking about the OpenPGP standard.

In any case, I almost never use my PGP key, so I still don’t really know how to use it. But I use my SSH key all the time, so I figured, why not consolidate?

Because it will eat a day and a half of your precious time.

(Too late!)

As mentioned above, PGP keys and SSH keys are not the same thing, so you can’t just use one in place of the other. However, you can get GnuPG to manage this trickery for you, if you ask nicely. I had my moments of doubt and tribulation, but somewhere I read that Werner Koch does this himself, so I pressed on. It was a long and difficult road. Here’s the short version.

The Players

ssh The OpenSSH client. I believe you need at least v6.7; check with ssh -V and upgrade with brew install openssh if necessary.

ssh-agent Comes bundled with OpenSSH. Its job is to cache SSH key passwords for the duration of the current login session. (That is, you can set a passphrase on your SSH key for extra security. You’ll be prompted for this passphrase the first time you log in, and if ssh-agent is running, you can use the same key to log into other servers, or log out and back in again, without needing the password.) GnuPG provides its own utility as a stand-in for ssh-agent (and has since at least 2005), which means ssh-agent is not required for this to work . In fact, better safe than sorry: make sure ssh-agent is not running ( ps x | grep [s]sh-agent ). If it is, kill it ( ssh-agent -k , or killall ssh-agent if that doesn’t work). To make sure it stays dead, check your login scripts for a line containing eval "$(ssh-agent)" or similar and remove them.

gpg The GnuPG suite. You need at least v2.1; check with gpg --version and upgrade with brew install gpg if necessary.

gpg-agent Comes bundled with GnuPG and serves the same purpose that ssh-agent does: caches passwords so you don’t have to enter them twice in the same session. There is a separate, keg-only brew formula for gpg-agent. Don’t install it; just use the one that comes with gpg.

pinentry / pinentry-mac This is a lightweight program used to accept password input so that GnuPG doesn’t have to (for more on the security considerations behind this design, see here). This is installed as a dependency of gpg , but fails to be invoked by ssh for reasons beyond the scope of this guide. The GUI version of the utility, pinentry-mac , is the easiest alternative.

The Procedure

Generating an authentication-only subkey

Keys are used for three purposes (signing, encrypting, and authenticating), and it’s a best practice to generate and use separate subkeys exclusively for each separate purpose.

If you’re reading this guide, you probably already have a PGP key; we just need to make sure you have an authentication-only subkey. If you do, you should see output for the following command:

$ gpg -k | grep "\[A\]"

and may skip down to Step 1 below.

If not, follow the directions under “Create an authentication subkey” here.

Retraction

This segment originally outlined the option of using no password at all for your authentication subkey, but the described behavior appears to have been removed in recent versions of GnuPG. In any case, the option remains to use a different password for subkeys.

During the process, you’ll be prompted for your private key’s passphrase. It’s not stated anywhere in the prompt, but you actually have two options: enter the passphrase (in which case, that same passphrase will apply to your new subkey), or enter nothing (in which case, you will be prompted to set a separate passphrase for your new subkey, and then asked for your private key’s passphrase again). If, like me, you take infosec purely has a hobby and have no real security concerns to speak of, I suggest taking the latter approach and setting no password on the subkey (or else you’ll have to enter it when logging into your SSH servers from time to time, and may even run into the aforementioned issues with pinentry). I believe it only poses a security risk in the event that someone gains access to your system and manages to copy the contents of your ~/.gnupg directory, but if someone knows something I don’t, I’m always happy to learn something new. If, on the other hand, your situation demands actual security, you should absolutely set a passphrase on the subkey, which will require the use of a pinentry utility. You’ll have to jump through some hoops to get it to work purely in the terminal (which I’ll cover in an upcoming post); in the meantime, be sure to install pinentry-mac instead.

Basic configuration

Bookmark your remote server: # ~/.ssh/config Host server_nickname HostName server.domain.com User username Enable SSH support in gpg-agent: # ~/.gnupg/gpg-agent.conf enable-ssh-support Initialize SSH_AUTH_SOCK and launch gpg-agent on login: # ~/.bash_profile export SSH_AUTH_SOCK=$(gpgconf --list-dirs agent-ssh-socket) gpgconf --launch gpg-agent Source your .bash_profile , (re)starting gpg-agent to load the new config: $ gpgconf --kill gpg-agent # (just in case it’s already running) $ source ~/.bash_profile

Adding keys

Tell gpg-agent which subkey to pass to ssh by adding its “keygrip” to ~/.gnupg/sshcontrol : $ gpg -k --with-keygrip /Users/you/.gnupg/pubring.kbx ------------------------------ pub rsa2048/93BDD96B 2017-06-29 [SC] D03833D3D52F5FFCCC73452461671825E8DEC139 Keygrip = 8A6CDC5FCE05A5B251BD8C397B269607534B4702 uid [ultimate] Big John <big.john@gmail.com> sub rsa2048/0424163D 2017-06-29 [E] Keygrip = E110250E32B811D45879A66F487CE95BC1906D77 sub rsa2048/8F228EDB 2017-06-29 [A] Keygrip = 32BC5688805A640D495E8A7B41EC78F74E77E098 $ echo 32BC5688805A640D495E8A7B41EC78F74E77E098 > ~/.gnupg/sshcontrol Confirm key has been added: $ ssh-add -l 2048 SHA256:zQ1wF6qOq8UNqcSRMYhDc+Cg3yM9lgp8dWvXwjnPcvU (none) (RSA) Authorize key on remote server: $ brew install ssh-copy-id # if you don’t already have it $ ssh-copy-id server_nickname Log in! $ ssh server_nickname

Recap

For SSH key authorization to work, the remote host must store a local copy of all authorized users’ public keys. That way, when a user’s ssh client presents their private key on login, the server can compare that against its collection of public keys to see if there’s a match.

ssh-agent manages SSH private keys and presents them to remote hosts for authentication. It comes with a couple helper utilities: ssh-add (which, when called with the -l / -L flags, lists the keys it knows about), and ssh-copy-id (which adds those public keys to a given remote host’s list of authorized users).

gpg-agent manages GPG private keys and can be used as a drop-in replacement for ssh-agent . In order for this to work, a few things have to happen:

ssh must be directed to authorize via gpg-agent rather than ssh-agent (by setting SSH_AUTH_SOCK ), gpg-agent must be directed to receive authorization requests from ssh (either by having the --enable-ssh-support option included on the command line or having it set in the gpg-agent.conf file), and the GPG keys you wish to use must be listed in the sshcontrol file.

The rest of the setup (namely, adding the public key to the remote host) is the same as it would be for ordinary SSH keys.

Caveat: GNOME/XFCE Users

This guide is written for Mac users, but if you’re a GNOME user who found yourself looking for insight here, it appears that GNOME keyring runs its own, conflicting version of gpg-agent. This might be outdated information, since the last reference I saw to it was in 2012, but if you’re still having problems, see here for more.