Using GNU Privacy Guard - gpg.wtf

GNU Privacy Guard is very powerful software with a terrible interface.

This document attempts to give you the tools needed to answer questions and explain the mysteries of gpg and PGP so that you too can take advantage of this tool and stop making excuses.

This page assumes you have basic familiarity with gpg and have already created an OpenPGP key. If not, please see Secure PGP keys and Yubikey NEO.md for information on how to create an offline master key and then transfer the sub keys onto a YubiKey hardware device for daily use.

Get started

Web Of Trust

xkcd : web of trust + responsible behavior
xkcd.com

The OpenPGP Web Of Trust is a way to establish the authenticity of the binding between a public key and its owner without relying on centralized authorities. Participants can chose to verify, then sign each other's keys, then publish those signatures for other people to use. Once your key is in the "Strong Set" (set of cross-signed keys), anyone can use a tool such as the PGP pathfinder to easily calculate trust paths from one key to another (modern software will do this automatically). This can be especially helpful when verifying digital signatures on software for example.

"Signing" someone's key means that you use your Master key's C (Certify) capability to make a digital signature on one or more ID's of their public key. This indicates to what degree you verified the data in that specific UID (usually name and email address). Ideally the checking should be done in-person, government issued ID should be compared to the name listed in the key UID, and the key fingerprint should be provided by the owner on paper to be taken home and verified + signed later.

Here are slides from a presentation that I did on the OpenPGP Web Of Trust with visual examples.

Signing keys offline

Signing another person's key with your "offline" master key is far more secure than keeping the master key on a normal Internet-connected computer. It is also a bit more complex, but instructions below should easily guide you through the process. Replace KEYID below with the actual long ID of the key you want to sign:

  1. Locate the key you want to sign, eg: gpg --search KEYID. Then type the number of the key you want to import into Gnupg's database.
  2. Check the master key fingerprint, eg: gpg --fingerprint KEYID
  3. When satisfied, export the public key to a file, eg: gpg -a --export KEYID > KEYID_unsigned.asc
  4. Put the key you want to sign onto a clean USB stick (or find some other way to get it into your air-gapped computer).
  5. Enter your air-gapped environment (eg, boot into TailsOS).
  6. Import your current Secret key (aka Master key) to the air-gapped machine.
  7. Check your key is available with: gpg -K (big 'K') or gpg --list-secret-keys
  8. Import the public key to be signed: gpg --import KEYID_unsigned.asc
  9. Sign the person's public key: gpg --ask-cert-level --sign-key KEYID
    • You will be prompted to specify which IDs you want to sign and asked how thoroughly you checked the identity info. Here is a copy of my key signing policy which might be helpful place to start.
    • I recommend signing all IDs here (default) and later deleting any signatures you don't want to send.
  10. Export the signed key as a file: gpg -a --export KEYID > KEYID_signed.asc
  11. Transport that signed key file back from the air-gapped machine to the online system.
  12. Import the signed key: gpg --import KEYID_signed.asc
  13. Verify your signature on their key: gpg --check-sigs KEYID
  14. Finalize the verification process by emailing the signature to the owner (below).

Ensuring that your signature goes to the right UID

It is tempting to just upload the key directly to a keyserver, but this is considered bad form because the data you signed is not verified and uploading irrevocably publishes data that the user may not want to make public (see section below about what can be changed on a keyserver).

Instead, we will send each signed UID to the email address listed in an encrypted email.

This ensures that:

  1. They still control that email address. (can read the email)
  2. They control the private key for the public key you are signing. (can decrypt the message)

If there is only 1 email address listed in the key, then this is easy -- just send the KEYID_signed.asc file to the email address listed (encrypted email of course). If there is more than one email address, then I recommend exporting each email address UID separately into an asc file and then sending to the corresponding email address.

Some UID may not contain an email address, but rather a photo, website or other metadata. Personally I leave those sigs intact for all email addresses or don't sign them at all if they cannot be verified.

What is a keyserver?

A key server is a repository of keys. Anyone can upload their own key there or another person's key and the key there could be manipulated by the owner of the server. DO NOT BLINDLY TRUST THE KEYS. You can use a keyserver as a convenient way to locate a key from a fingerprint, but always verify the key after downloading.

Due to the design of OpenPGP keys, 3rd party signatures can be embedded into anyone's key. This unfortunately means that an attacker can cause a DOS someone by stuffing bogus signatures into a key and make it too big to effectively use. Most gpg implementations have quietly switched to a specific keyserver based on Hagrid which strips all 3rd party certs from keys it serves:

Very few people understand that this will make the OpenPGP Web of Trust basically unusable as none of the connection data will be visible.

When sharing your key (uploading), I highly recommend using these keyservers because they allow upload of signature data:

(NOTE: uploading keys does not expose you to the above mentioned attack vector)

One can use a keyserver to search for a key via the web by prefixing with https:// or on the commandline with the prefix hkps:// like this:

gpg --keyserver hkps://keys.openpgp.org --search 0xC0C076132FFA7695

You can also upload your key to a server:

gpg --keyserver hkps://keys.openpgp.org --send-key YOUR_KEY_ID

Feel free to use this script I made to automate the upload of your key to keyservers, your website and / or Keybase.io.

Generally speaking, you should not send other people's keys to keyservers unless you really know what you are doing. Better to email to them and have them upload (if they choose).

Concerns about the Web of Trust

The OpenPGP Web Of Trust is not perfect. Publishing keys and personal information on public servers may open you up to receiving more spam and analysis of your social graph via key signatures. These are all concerns that might prevent someone from participating. In my mind, the overall benefits outweigh the dangers, so I participate, but many do not agree and are waiting for better options.

More details about the OpenPGP trust model in gpg

When attempting to determine to what degree a key is "trusted", gpg will offer various pieces of information explaining how the trust level is being calculated. Example:

gpg: checking the trustdb
gpg: marginals needed: 3  completes needed: 1  trust model: pgp
gpg: depth: 0  valid:   4  signed: 115  trust: 0-, 0q, 0n, 0m, 0f, 4u
gpg: depth: 1  valid: 115  signed:  67  trust: 3-, 0q, 0n, 2m, 110f, 0u
gpg: depth: 2  valid:  50  signed:  39  trust: 35-, 2q, 1n, 5m, 7f, 0u
gpg: depth: 3  valid:   3  signed:   6  trust: 0-, 0q, 0n, 3m, 0f, 0u
gpg: next trustdb check due at 2019-07-09

Please see this excellent explanation from Jens Erat of the values and meanings seen above.

PGP is dead

Many people have declared PGP dead because it is hard to use, doesn't protect metadata in encrypted emails and supports too much legacy crypto. Although there are very good arguments against it, I still think it is undeniable that it works well for verifying digital signatures, has wide support (hardware, software and people) and does a decent job at encrypting email once you have a properly setup client. The Web Of Trust has huge problems, but for those who take the effort to participate, it provides one of the few functioning examples of decentralized key verification. Could this be done better? Absolutely! But this is the best we have right now and attempts to replace it have always fallen short of the features needed.

RANT: Random things that confused me about gpg

Which actions change your pubkey?

In gpg, your "public key" is actually a collection of many pieces of metadata, user IDs, the master key and subkeys, signatures, notations and preferences. After making changes, it was unclear to me which actions changed my public key file and would require it be uploaded to a keyserver. Here is a list:

Can I make changes to a key on a keyserver?

Generally, no.

You can add information such as valid signatures or new UIDs, but not delete anything. You can also update expiration dates (ie adding a signature with a later expiration date).

Many ways to represent a public key...

Examples representations of my key:

  1. The full pubkey file is needed to verify signatures and can be represented as ASCII text or binary (default). (the file can be hundreds of kilobytes of data depending on the number of signatures).
  2. You can have a "hash" of the key data (used to sync key updates between servers) - AECC01E6C0C2C94792F124968F4FFA4A.
  3. Key "fingerprint" (160 bit sha1 hash, eg gpg --fingerprint KEYID), normally displayed with spaces. Example:
    9386 A2FB 2DA9 D0D3 1FAF 0818 C0C0 7613 2FFA 7695
  4. "Long" (64 bit) key ID: C0C076132FFA7695 (last 16 hex chars of the fingerprint, ie --keyid-format long) [1]
  5. "Short" (32 bit) key ID: 2FFA7695 (last 8 hex chars of the fingerprint. INSECURE: Do not rely on these) [1][2]

[1] Long and Short Key IDs can be prefixed with 0x to indicate they are hex.
[2] Short Key IDs are deprecated as they are VERY EASY to brute-force.

Cryptic symbols and key properties

When listing Secret keys (gpg --list-secret-keys or gpg -K) you may see:

When listing Public keys (gpg --list-keys or gpg -k) you may see:

When editing a key (gpg --edit-key KEYID) you may see:

When listing signatures (gpg --list-sigs KEYID) you may see:

There are different types of keys, you can see this on the right as "usage":

Multiple private keys

The local user option allows you specify the key used for signing / encryption if you have multiple private keys.

gpg --sign-key 0xBAADABBA --local-user 0xDEADBEEF

Re-signing a key

In some circumstances you may want to re-sign a certain UID, eg using a stronger hash function like SHA512, adding a notation or a new expiration date. In most cases, you will need to add the --expert option in order to force gpg to sign the UID again.

gpg --ask-cert-level --expert --sign-key 0xBAADABBA

Exporting a specific UID

Public keys can contain a variety of UID assertions such as email address, name, photos, websites and arbitrary text. Sometimes you might want to only export a particular UID (eg when signing UIDs for a keysigning party and want to email each signed UID to the corresponding email address). You can use a complex set of filter expressions to achieve this. Here is an example:

gpg -q --armor --export \
    --export-filter keep-uid="uid = Jonathan Cross <jcross@gmail.com>" \
       0xC0C076132FFA7695 > just_his_email.asc

More complex examples can be made using substring match keep-uid="uid =~ Alfa", && or || logical connection operators, etc.

Using gnupg offline

The recommended way to use gpg in a secure manner is to keep the master key offline and only use it on an air-gapped computer. Booting into Tails OS is a convenient way to work with this kind of sensitive material as it will "forget" anything you do on the system as soon as it is restarted. Installing Tails on a USB stick works well on my MacBook Air as there is no functioning WiFi driver and furthermore it is easy to disable networking from the welcome screen. Tails now contains a modern version of Gnupg 2.1+ which fixes many known bugs in previous versions.

For everyday use, it is recommended to separate the primary (master) key from encryption, signing, and / or authentication subkeys and keep those subkeys on a hardware device (see below) while keeping the primary key offline. This allows you to use gpg easily, while ensuring that if the hardware device is lost / compromised, you can always revoke the subkeys and issue new ones without losing certification signatures on your key.

Hardware devices

Securing your keys using a hardware device that is independent from your computer is highly recommended. This will drastically reduce the attack surface and help ensure that you are in control of the keys. Here is a spreadsheet which compares the various properties of different hardware devices.

Creating stubs on a new computer

When you are on a new computer and want to use a hardware device (like the YubiKey or the NitroKey), you will need to create on-disk "stubs" of the keys that reside on your hardware device.

  1. On Linux, you need to add these udev rules to /etc/udev/rules.d/.

  2. Run sudo gpg --card-edit

  3. Get your key stubs: fetch

  4. Quit: q

  5. May need to change the keyring owner to yourself if it was just created with sudo above:

     sudo chown -R $USER ~/.gnupg/*
    
  6. Check your work by running gpg --list-secret-keys. If you see ssb> for the subkeys, then all is good.

Using OpenPGP with git

Configure git to sign all commits with an OpenPGP key

git config --global user.email [EMAIL ADDRESS OF YOUR PGP IDENTITY]
git config --global user.signingkey [YOUR KEY HERE]
git config --global commit.gpgsign true  # Only works in git >= 2

You should also add your OpenPGP public key to GitHub so that verification info is displayed to users.

NOTE: Both git and GitHub will show that code was signed with your signing subkey (rather than primary key). This may be confusing for users because normally the primary key is used / publicly shared by devs and subkeys are selected quietly in the background as needed. See example here and click on the green "Verified" button.

Show commit signature info (more info)

git log --show-signature -1               # Details of last commit sig.
git log --pretty="format:%h %G? %aN  %s"  # Log of last commits. The "G" means good signature, "N" means no sig.

Permissions problems (YubiKey)

Symptom: gpg --card-status works as root, but not as an unprivileged user.

gpg --card-status
gpg: selecting openpgp failed: unknown command
gpg: OpenPGP card not available: general error

Workaround: use sudo:

sudo gpg --card-status

Same with signing, but you need to explicitly add -S

sudo git commit -a -S

Linux git commit signing

I have been able to fix gpg and git signing in Linux Mint 17.3 using udev rules:

sudo sh -c 'wget -q -O - https://raw.githubusercontent.com/Yubico/yubikey-neo-manager/master/resources/linux-fix-ccid-udev | python'

I can then use git commit -a -S to sign my commit. NOTE: If using git version >= 2, you can make this the default via:

git config --global commit.gpgsign true

Unfortunately gpg2 still reports an error unless sudo is used:

gpg2 --card-status
gpg: selecting openpgp failed: Unsupported certificate
gpg: OpenPGP card not available: Unsupported certificate

Additional tools / scripts / documentation

I have written a few scripts to help with various PGP / GPG related tasks:

GUI Tools

Mac

Thunderbird (Linux / Windows / Mac)

Android

Additional Software

Disclaimer

This document comes with no guarantees, do your own homework. Feedback is welcome.

License

WTFPL - See LICENSE for more info.

See original source document on GitHub.
Last modified: 2020-05-25
© Jonathan Cross 2019-2020