Skip to content

Instantly share code, notes, and snippets.

@ciardullo-apps
Last active December 9, 2023 14:15
Show Gist options
  • Save ciardullo-apps/8f57b5ea827b7beae0a1edabaf473874 to your computer and use it in GitHub Desktop.
Save ciardullo-apps/8f57b5ea827b7beae0a1edabaf473874 to your computer and use it in GitHub Desktop.

GPG / PGP

Best Practices

  • Generate your master key only on an air-gapped PC booted from a live Linux distribution on a bootable USB drive
  • Generate your master key only with only the CERTIFY action
  • Add separate subkeys for SIGN, ENCRYPT, and AUTHENTICATE actions
  • Set an expiration date for all subkeys
  • Export your secret master key in ASCII armored output
  • Do not transfer your secret master and subkeys to a hardware authentication device UNTIL you have exported them in ASCII armored output
  • Export your secret subkeys in ASCII armored output
  • Store your exported secret master and subkeys offline, never on a PC with network access
  • Transfer your secret subkeys to a hardware authentication device, like a Yubikey
  • Once the secret master and subkeys have been exported and backed up to offline storage AND once the subkeys have been transferred to a hardware authentication device, delete your secret master key from your GPG keyring
  • Export your secret subkey "stubs" in ASCII armored output. A stub is what is exported when you use "gpg --export-secret-subkeys" after they have been transferred to a hardware authentication device.
  • When you need to use your master key (such as when you extend expiration dates or certify other signatures), import it from offline storage on an air-gapped PC booted from a live Linux distribution.
  • Do not transfer your master key to a hardware authentication device
  • Do transfer your SIGN, ENCRYPT, and AUTHENTICATE subkeys to a hardware authentication device
  • Generate and retain a revocation certificate
  • Use GPG keys for SSH
  • Before you send your public key to a public keyserver, research the issues, like privacy concerns (increased spam, social graph reverse engineering) and problems with keyservers ("keyserver plaque", spoofed email addresses)

Key Maintenance

How to extend the expiration date of the subkeys

Your master key must be in your gpg keyring. Without it, you cannot extend the expiration date. If gpg -K shows the master key followed by a #, the master key is unavailable on your gpg keyring. You must import it from your offline backup. Remember to always do this on an air-gapped PC using a Live Linux distribution on a bootable USB drive.

  • Import the secret master key
gpg --import secret-masterkey.asc

gpg -K should now list your master key as available

  • Get the key id
gpg --list-keys
  • Insert your USB hardware authentication device

  • Edit the key

gpg --edit-key key_id
  • You want to expire the subkeys, not the master key, so choose all subkeys using key n where n >= 1
gpg> key 1
gpg> key 2
gpg> key 3
gpg> expire
Enter the number of days/weeks/months/years: `1y  # for 1` year
  • Enter your passphrase The expiration date of the public and private primary key is now changed

    IMPORTANT: Remember to remove your master key from the gpg keyring.

  • This will delete the master secret key and all subkey stubs from the keyring. Since your Sign, Encrypt and Authenticate subkeys are on your hardware authentication device, you will bring the subkeys back in the next step

gpg --delete-secret-keys key_id
  • Restore the gpg keyring using the hardware authentication device
gpg --card-status

gpg -K should now show the master key as unavailable, and the subkeys as on the hardware authentication device

  • You now need to transfer the updated keyring to your other PCs. See instructions below.

How to export a public key

gpg --output gpg-public-key.asc --export --armor recipient@mail.com

How to export a secret master key and all subkeys

gpg --output gpg-secret-key.asc --export-secret-keys --armor recipient@mail.com

If the secret key has already been moved to a smartcard, this will export a "stub". This is because the keytocard command, which transfers the secret key to a smartcard, replaces the secret key with a stub in the keyring.

How to use a PGP key with SSH

  • Get the keygrip of your AUTHENTICATION subkey
gpg -k --with-keygrip
  • Paste that keygrip into ~/.gnupg/sshcontrol
echo KEYGRIP_ID >> ~/.gnupg/sshcontrol
  • Confirm the key has been added. Note this command shows an additional entry when the smartcard is connected
ssh-add -L
  • Add that key (the one with "cardno" at the end") to the end of ~/.ssh/authorized_keys

Hardware Authentication Devices

AKA smart card. Assuming Yubikey here.

How to move a gpg keyring to another PC when the secret subkeys are on a hardware authentication device

  • Copy the public key and secret subkey stub armor ascii files to the other pc using rsync, USB flash drive, etc

  • Import the public key on the other pc

gpg --import gpg-publickey.asc
  • Import your secret sub key stubs
gpg --import gpg-secret-subkey-stubs.asc
  • Populate your keyring with the information from your smartcard
gpg --card-status
  • Check that your master key is unavailable. gpg -K should list the secret key with sec#, meaning it is unavailable.

  • Check that your subkeys are available on the hardware authentication device. The subkeys should be followed by sub>, the right chevron indicates its on a card

  • Restart the agent

gpgconf --kill gpg-agent  
gpg-agent --daemon # Ubuntu doesn't need this, Mac Only

How to reset the hardware authentication device's pin and admin pin

gpg --change-pin

gpg: OpenPGP card no. ... detected

1 - change PIN
2 - unblock PIN
3 - change Admin PIN
4 - set the Reset Code
Q - quit

Your selection? 1
PIN changed.

1 - change PIN
2 - unblock PIN
3 - change Admin PIN
4 - set the Reset Code
Q - quit

Your selection? 3
PIN changed.

1 - change PIN
2 - unblock PIN
3 - change Admin PIN
4 - set the Reset Code
Q - quit

Your selection? Q

How to backup your gpg secret subkeys to a backup Yubikey

Background

Having a backup Yubikey with a copy of your secret subkeys is a good idea to guard against loss or damage. If you followed the advice of Yubico and others, you generated your secret keys externally from the Yubikey, exported your secret keys, and then transferred them to your Yubikey, in that order. Using that export, you can create a backup of your Yubikey with the same secret subkeys.

Pre-requisites

  • You have an ASCII armored export of your secret master key on an encrypted (e.g. LUKS) USB stick
  • You have a Live Linux distribution on a bootable USB drive (this assumes Ubuntu 20.04)

Steps

  • Boot your Live Linux distribution; access a console prompt

  • Update your package repository sources list /etc/apt/sources.list to include the sources for pcscd, scdaemon, and gpgconf

    On Ubuntu 20.04

    For pcscd and scdaemon:

deb http://us.archive.ubuntu.com/ubuntu/ focal universe
deb http://us.archive.ubuntu.com/ubuntu/ focal-updates universe

For gpgconf: deb http://us.archive.ubuntu.com/ubuntu/ focal main restricted

  • Download package information from all configured sources with sudo apt update

  • Install pcscd, scdaemon, and gpgconf with sudo apt install pcscd scdaemon gpgconf

  • You're about to import your master secret key. Airgap your PC. Stop networking; don't restart networking again. Unplug your ethernet cable. Disable WiFi. When you're done, you'll restart your PC and end your Live Linux distro session. You can also stop networking from settings.

sudo systemctl stop networking.service
  • Mount your encrypted USB stick containing the ASCII armored export of your secret master key

  • Import your secret master key into your gpg keyring

sudo cat /media/ubuntu/PATH_TO_YOUR_EXPORTED_MASTER_KEY | gpg --import
  • Confirm your secret master key and secret subkeys are now in your gpg keyring with gpg -K

  • Insert your backup Yubikey

  • Transfer your secret subkeys to your backup Yubikey:

    Use gpg --edit-key key_id, select each key individually, then use keytocard to individually move each subkey to the Encrypt, Authenticate, and Sign slots on the Yubikey card. Save when you are done (It has been reported that at this point, the secret subkeys have been moved to the card, but not deleted from the PC's gpg keyring. If you quit without saving, the secret subkeys are on the card AND on the PC. I have not tried this).

  • Confirm that the secret subkeys are now on the Yubikey gpg -K shows ssb> for each secret subkey; gpg --edit-key key_id shows the backup Yubikey's card-no for each secret subkey

How to switch among different Yubikey cards for the same private keys

Background

In order to use different Yubikeys for the same private subkeys (for example, you need to use a backup Yubikey because the primary Yubikey was lost or damaged), you first need to delete the secret subkeys from your gpg secret keyring. However, simply using gpg --delete-secret-keys key_id does not work. Problematically, gpg --delete-keys key_id also does not work. This is because the key's associated card is stored in ~/.gnupg/private-keys-v1.d, which gpg --delete-keys does not delete. Hence, after using gpg --delete-keys key_id, when you re-import your public key, the previous card-no is still associated with the subkeys. There are two solutions:

  1. After gpg --delete-keys key_id, delete the KEYGRIP.key files from ~/.gnupg/private-keys-v1.d Not ideal
  2. Use gpg --delete-secret-keys <FINGERPRINT>! using the fingerprint of the subkey. This will properly delete the secret subkey. Let's do it!

Pre-requisites

  • You have two Yubikeys that have the same secret subkeys.
  • Your gpg keyring should show that the secret master key is not available sec# and your secret subkeys for Encrypt, Authenticate, and Sign are on an external smart card ssb>.
  • Confirm which card-no is currently associated with each private subkey using gpg --edit-key key_id. You should see each subkey's associated card-no (i.e. the Yubikey you no longer want to use)

Steps

  • Get the fingerprint of each subkey with gpg -k --with-subkey-fingerprint. You may also want to get each key's grip, which correspond to the filenames under ~/.gnupg/private-keys-v1.d, by using the --with-keygrip option. You can then verify that the files are properly deleted from ~/.gnupg/private-keys-v1.d once the secret subkeys have been deleted.

  • Delete each secret subkey. Note that the fingerprint must be suffixed with an exclamation point, or the secret subkeys will not be properly deleted.

gpg --delete-secret-keys <FINGERPRINT>!
  • Confirm the following

    • The secret keys have been removed from the gpg keyring. gpg -K shows the secret sub keys are gone. Likewise, gpg does not display Secret subkeys are available
    • The public keys are still in the gpg keyring. gpg -k still shows the public keys.
    • The card-nos previously associated with each subkey are gone. gpg --edit-key key_id shows no associated card-nos with the secret subkeys. Likewise, gpg does not display Secret subkeys are available
  • Insert the Yubikey you now want to associate with these secret subkeys

  • Use gpg --card-status to associate the public subkeys keys with the secret subkeys on the Yubikey.

    Although the gpg man page simply says Show the content of the smart card for the --card-status option, it clearly does more than that. The secret subkeys will now be associated with the new Yubikey's card-no.

  • Confirm the following

    • The secret keys have been restored to the gpg keyring. gpg -K shows the secret subkeys, and those secret subkeys have been moved to the card ssb>
    • The public keys are still in the gpg keyring. gpg -k still shows the public keys.
    • The card-nos now associated with each subkey reflect the Yubikey. gpg --edit-key key_id shows the newly associated card-no with the secret subkeys. Likewise, gpg --edit-key key_id now displays Secret subkeys are available

Encrypt and Decrypt

How to test an encryption key

echo "The message is clearly encrypted" > file
gpg --default-recipient-self --encrypt file
rm file
gpg --decrypt file.gpg

How to encrypt a file in ASCII armor format as the body of an email

gpg --armor --recipient recipient@mail.com --encrypt file

Copy and paste the ASCII armored text into your email client.

How to encrypt and sign a message in ASCII armor format for use as the body of an email

Sign the message using your private PGP key

echo "Hello, How are you?" | gpg --armor --recipient recipient@mail.com --sign --local-user sender@mail.com -e

Copy and paste the ASCII armored text into your email client.

Miscellany

How to import my ProtonMail public key into your public keyring

gpg --keyserver hkps://api.protonmail.ch --receive-keys 47DB709848F0272A

Notes

  • In order to use your hardware authentication device on Ubuntu, you must install scdaemon.
sudo apt install scdaemon
  • To test github has been correctly configured for SSH use ssh -T git@github.com

  • Some gpg edit commands require a restart of the gpg agent gpgconf --kill gpg-agent

  • gpg requires the following env vars in your .bashrc or .bash_profile

export SSH_AUTH_SOCK=`gpgconf --list-dirs agent-ssh-socket`
export GPG_TTY=`tty`
gpgconf --launch gpg-agent
  • Export GPG public key gpg --export --armor key_id
  • Configure git for signed commits
git config --global user.signingKey key_id
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment