How to import your existing SSH keys into your GPG key

Learn how to handle multiple SSH keys.
Register or Login to like
Browser of things

In the first article in this series, I explained how to use your GPG key to authenticate your SSH connections. If you're like me, you already have one or more existing SSH keys. And, if you're like me, you also don't want to have to log into every server you use to update the authorized_keys file. A way around this is to import your existing SSH keys into your GPG key. This will eliminate the need for private key files. Doing this has allowed me to eliminate nine other key files, reducing my backup/privacy footprint a lot.

Import an existing SSH key

To add the key, you need to convert the key format from the Privacy-Enhanced Mail (PEM)-encoded format that SSH uses to an OpenPGP-formatted certificate. The Monkeysphere Project provides a utility, pem2openpgp, that does this for you.

Unfortunately, making this newly added key a subkey is not a one-step process. This longer process is required because there is no clean way to delete the GPG key in the keyring that is just the SSH key. The keys are identified and operated on by keygrip, and the keygrip for a key is the same whether it is a subkey or a standalone key. Thankfully, you only need to work with the private keys, as you can regenerate the public keys at the end.

Also, if you have a newer style OpenSSH key, you'll have a couple of extra steps to convert that into something pem2openpgp can read. Unfortunately, as of version 0.41, Monkeysphere cannot read newer style OpenSSH keys. (Your key is a newer style key if the first line of the private key file is: -----BEGIN OPENSSH PRIVATE KEY-----. If your key starts with: -----BEGIN RSA PRIVATE KEY-----, then you have the PEM-encoded format.)

To import newer keys, you need to convert them into old-style formats. This is done by using ssh-keygen and taking advantage of its ability to write in multiple key formats. You can trigger the conversion by changing the password on the key. You don't have to change the password in this situation, so feel free to reuse your existing one if you prefer.

The workflow below walks us through these steps.

  1. If you have a newer style OpenSSH key, convert it using the ssh-keygen utility. You can use this utility to change the password (if you want) and force the key to be rewritten in the older format. The only difference between a typical use of ssh-keygen and this one is the addition of -m to change the format of the key.
    $ ssh-keygen -p -m PEM -f <private-key-file>
  2. Back up your existing GPG key.
    $ gpg2 -a --export-secret-keys 96F33EA7F4E0F7051D75FC208715AF32191DB135 > my_gpg_key.asc
  3. In a new keyring, import your existing GPG key.
    $ mkdir temp_gpg
    $ chmod go-rwx temp_gpg/
    $ gpg2 --homedir temp_gpg --import my_gpg_key.asc
    gpg: key 8715AF32191DB135: public key "Brian Exelbierd" imported
    gpg: key 8715AF32191DB135: secret key imported

    # Optionally, verify the import
    $ gpg2 -K --homedir temp_gpg/
    /home/bexelbie/temp_gpg/pubring.kbx
    --------------------------------
    sec   rsa2048 2019-03-21 [SC] [expires: 2021-03-20]
          96F33EA7F4E0F7051D75FC208715AF32191DB135
    uid           [ unknown] Brian Exelbierd
    ssb   rsa2048 2019-03-21 [E] [expires: 2021-03-20]
    ssb   rsa2048 2019-03-21 [A]
  4. Import the SSH key as a new standalone GPG key.
    # get the software
    $ dnf install -y monkeysphere

    # temporary_id is a temporary identifier required by GPG
    $ pem2openpgp temporary_id < .ssh/my_fancy_key  | gpg2 --import --homedir temp_gpg/
    Enter PEM pass phrase:
    gpg: key 66091F2C70AF02A9: public key "temporary_id" imported
    gpg: key 66091F2C70AF02A9: secret key imported
    gpg: Total number processed: 1
    gpg:               imported: 1
    gpg:       secret keys read: 1
    gpg:   secret keys imported: 1

    # verify the key loaded and get the keygrip of the new GPG key and the hash of your GPG key
    $ gpg2 -K --with-keygrip  --homedir temp_gpg/
    /home/bexelbie/temp_gpg/pubring.kbx
    --------------------------------
    sec   rsa2048 2019-03-21 [SC] [expires: 2021-03-20]
          96F33EA7F4E0F7051D75FC208715AF32191DB135
          Keygrip = 90E08830BC1AAD225E657AD4FBE638B3D8E50C9E
    uid           [ unknown] Brian Exelbierd
    ssb   rsa2048 2019-03-21 [E] [expires: 2021-03-20]
          Keygrip = 5FA04ABEBFBC5089E50EDEB43198B4895BCA2136
    ssb   rsa2048 2019-03-21 [A]
          Keygrip = 7710BA0643CC022B92544181FF2EAC2A290CDC0E

    sec   rsa2048 2019-03-23 [C]
          D4F6B35B52B96A092FB8F418A41A06197749FBA4
          Keygrip = 1F824257B107D9E3371B9A4957751D78FC8BB190
    uid           [ unknown] temporary_id

    # We can remove monkeysphere unless you need it for other reasons
    $ dnf remove -y monkeysphere
  5. Add the SSH key as a subkey of your GPG key.
    $ gpg2 --homedir temp_gpg  --expert --edit-key 96F33EA7F4E0F7051D75FC208715AF32191DB135
    gpg> addkey
    Please select what kind of key you want:
       (3) DSA (sign only)
       (4) RSA (sign only)
       (5) Elgamal (encrypt only)
       (6) RSA (encrypt only)
       (7) DSA (set your own capabilities)
       (8) RSA (set your own capabilities)
      (10) ECC (sign only)
      (11) ECC (set your own capabilities)
      (12) ECC (encrypt only)
      (13) Existing key
    Your selection? 13
    Enter the keygrip: 1F824257B107D9E3371B9A4957751D78FC8BB190

    Possible actions for a RSA key: Sign Encrypt Authenticate
    Current allowed actions: Sign Encrypt

       (S) Toggle the sign capability
       (E) Toggle the encrypt capability
       (A) Toggle the authenticate capability
       (Q) Finished

    Your selection? s
    Your selection? e
    Your selection? a

    Possible actions for a RSA key: Sign Encrypt Authenticate
    Current allowed actions: Authenticate

       (S) Toggle the sign capability
       (E) Toggle the encrypt capability
       (A) Toggle the authenticate capability
       (Q) Finished

    Your selection? q
    Please specify how long the key should be valid.
    Key is valid for? (0)
    Key does not expire at all
    Is this correct? (y/N) y
    Really create? (y/N) y

    sec  rsa2048/8715AF32191DB135
         created: 2019-03-21  expires: 2021-03-20  usage: SC  
         trust: unknown       validity: unknown
    ssb  rsa2048/150F16909B9AA603
         created: 2019-03-21  expires: 2021-03-20  usage: E  
    ssb  rsa2048/17E7403F18CB1123
         created: 2019-03-21  expires: never       usage: A  
    ssb  rsa2048/4A9EE7790817C411
         created: 2019-03-23  expires: never       usage: A  
    [ unknown] (1). Brian Exelbierd

    gpg> quit
    Save changes? (y/N) y

    Notice there are now two authentication subkeys.

  6. Export your existing GPG key with the new subkey.
    $ gpg2 --homedir temp_gpg -a --export-secret-keys 96F33EA7F4E0F7051D75FC208715AF32191DB135 > my_new_gpg_key.asc
  7. Import your existing GPG key with the new subkey into your customary keyring (only the subkey will import).
    $ gpg2 --import my_new_gpg_key.asc
    gpg: key 8715AF32191DB135: "Brian Exelbierd" 1 new signature
    gpg: key 8715AF32191DB135: "Brian Exelbierd" 1 new subkey
    gpg: key 8715AF32191DB135: secret key imported
    gpg: Total number processed: 1
    gpg:            new subkeys: 1
    gpg:         new signatures: 1
    gpg:       secret keys read: 1
    gpg:   secret keys imported: 1
    gpg:  secret keys unchanged: 1

    # verify the input and get the keygrip (it should be the same)
    $ gpg2 -K --with-keygrip
    /home/bexelbie/.gnupg/pubring.kbx
    ------------------------------
    sec   rsa2048 2019-03-21 [SC] [expires: 2021-03-20]
          96F33EA7F4E0F7051D75FC208715AF32191DB135
          Keygrip = 90E08830BC1AAD225E657AD4FBE638B3D8E50C9E
    uid           [ultimate] Brian Exelbierd
    ssb   rsa2048 2019-03-21 [E] [expires: 2021-03-20]
          Keygrip = 5FA04ABEBFBC5089E50EDEB43198B4895BCA2136
    ssb   rsa2048 2019-03-21 [A]
          Keygrip = 7710BA0643CC022B92544181FF2EAC2A290CDC0E
    ssb   rsa2048 2019-03-23 [A]
          Keygrip = 1F824257B107D9E3371B9A4957751D78FC8BB190
  8. Optionally, you may want to pre-specify that this key is to be used for SSH. This means you will not have to use ssh-add to load the key. To do this, specify the keys in the ~/.gnupg/sshcontrol file. The entries in this file are keygrips.
    ~/.gnupg/sshcontrol file.  The entries in this file are key grips

    # Add the new keygrip to your sshcontrol file
    $ echo 1F824257B107D9E3371B9A4957751D78FC8BB190 >> ~/.gnupg/sshcontrol

Success!

You can now delete the old SSH private key file. When you attempt to SSH into the appropriate servers, you will be prompted to unlock your GPG key (it better have a password!), then gpg-agent will provide the authentication in place of ssh-agent. You have fewer files to keep securely backed up and your key management is a bit easier. If you ever need a new key, you can follow the directions in the previous article to create more authentication subkeys. If the project you're working on ends, you can always delete any extra subkeys you wind up with.

In the third and final article, I will share some tips for managing multiple authentication subkeys/SSH keys. Once you have more than two or three, it gets a bit more complicated.

What to read next
Brian "bex" Exelbierd is the RHEL Community Business Owner and works to inform the RHEL roadmap with community efforts and to support Operating System communities. At Red Hat, Brian has worked as a technical writer, software engineer, content strategist, community architect and now as a product manager.

6 Comments

I am wondering how all this would work with keybase?

As far as I can tell keybase.io has no support for Authentication subkeys. I am not sure how much subkey support they have overall.

In theory they should be able to extend their API to support authentication but a hook would need to be written into either ssh-agent or gpg-agent. I wonder if replacing gpg-agent with a keybase enabled agent would be useful for those who choose to store their key on keybase.

While I do have a keybase account, no one has interacted with me via it and I haven't given them my private key.

Hey Bex,

I've been following your ssh blog articles, thanks for them they've been a good read!

Whilst running through these steps I encountered a problem with converting my newer style ssh key to PEM format. It wasn't immediately apparent as there was no error or output when i did the conversion using the -p option you used in the article so I just assumed it had been converted and moved on in the steps.

It seems that it's not possible to change ED25519 key types to PEM format:

$ ssh-keygen -e -m PEM -f .ssh/my_special_key_id_ed25519
do_convert_to_pem: unsupported key type ED25519

I couldn't find anything about this error, just wondering if you had any ideas?

Hi Blake, As I recall the monkeysphere project can handle most, but not all formats with pem2openpgp. Did you try that? If not, I encourage you to engage with that upstream.

In reply to by Blake

> And, if you're like me, you also don't want to have
> to log into every server you use to update the
> authorized_keys file. A way around this is to import
> your existing SSH keys into your GPG key.

You make this claim and nothing that followed explains how putting my private SSH keys in my gpg keystore automatically grants me access to machines without putting my public key in the authorized_keys file as a measure to explicitly declare which private keys are authorized access. Which requires that I log in to each one at least once to update the authorized_keys file.

I honestly can't make sense of your claim. Could you elaborate how that works?

Hi @boxofrox

If you import existing SSH keys into your GPG key you are not changing your keys. Therefore any machines that were already set up with your SSH key in their authorized_keys file will continue to work with the new GPG stored key.

The quote you include is meant to mean that you don’t have to updated your already authorized hosts. There is no system to take care of that for you automatically, you always have to do a login or ssh-key-copy to get the initial setup.

In the third part of the series I talk about managing multiple imported SSH keys to avoid key try attempt fails.

In reply to by boxofrox (not verified)

Creative Commons LicenseThis work is licensed under a Creative Commons Attribution-Share Alike 4.0 International License.