.

Writing mostly about computers and math.

📅 

A sign outside a key cutting place.

Original image from Jay Gooby on Flickr. Some rights reserved: cc by.

This is the second article in a series about GPG and public-key encryption. This part doesn't depend on the previous part about generating and using a keypair but you may want to read that first anyway for background.

Now that you've got a keypair there are a couple of issues to address: how do other people find it and how can they verify that it's really your key? Anybody can generate a key for any arbitrary email address so what can you do to make sure you have the real one? It's called the web of trust and it's a pretty neat solution to that problem.

What is a Web of Trust?

The math of asymmetric keys means that we can use them to sign any data — including other keys. In the OpenPGP keysystem, signing a key signifies that we have validated that it belongs to the person whose name is on it. This creates a kind of graph over all of the keys, linking them together in what's called a "web of trust." This is similar to the world wide web in that we can use these links to find paths between nodes that aren't directly connected to each other.

An example web of trust with six members.

Original image from Kku on Wikimedia Commons. Some rights reserved: cc by-sa.

This diagram shows how the web of trust can be used to figure out the validity of an unknown key. If I trust Eva and Eva trusts Manuel, then I can also trust Manuel since there's a path between my key and Manuel's key. This kind of link is not quite as strong as if we personally verified a key so we distinguish between direct links, where we have personally checked that a key belongs to a particular person, and indirect links, where our trust comes from the links between keys.

What's great about this is that it allows us to have some degree of certainty that an unknown key belongs to who it says it belongs to. If I end up with two keys for the same identity and one has been signed by a bunch of people I trust and the other has no signatures then it's easy for me to tell which one I should use. This only works, however, if I have some trusted keys in my keyring. Let's talk about how to get those.

Finding Public Keys

GPG keys can be distributed in any way you want - for example, I have mine listed on my website, on keybase, and uploaded to a bunch of keyservers. The simplest way is to import a key from a file or ASCII-armored string like this:

$ gpg --import ./my_key.pub.asc

That's it. Importing keys from files is super easy and if you see a key posted online somewhere that's probably how you'll do it. If you just know a person's email address however then you'll need to look up their key on a keyserver. Other people will want to be able to look up your keys this way too so you'll want to upload them to a keyserver too. The way to do this with GPG is

$ gpg --keyserver <key server> --send-key <key id>

There are lots of keyservers out there but most of them are federated so that keys uploaded to one of them will eventually end up duplicated on the others. SKS is a popular keyserver network so let's say we want to send the key we generated last time there:

$ gpg --keyserver hkp://pool.sks-keyservers.net --send-key 13D0B439
gpg: sending key 5DF274C713D0B439 to hkp://pool.sks-keyservers.net

Now if we want to get somebody's key, we just ask the keyserver for it using their email address. For example, to get my public key, you could do this:

$ gpg --keyserver hkp://pool.sks-keyservers.net --search-keys peter@peterbeard.co                                                                                                                              [2]
gpg: data source: http://209.244.105.201:11371
(1)     Peter Beard 
          3072 bit RSA key 7BE960323A4FF3E2, created: 2018-04-07 (revoked)
(2)     Peter Beard 
        Peter Beard 
          4096 bit RSA key B4A371011B4ED7ED, created: 2016-11-12, expires: 2021-11-11
Keys 1-2 of 2 for "peter@peterbeard.co".  Enter number(s), N)ext, or Q)uit > 2
gpg: key B4A371011B4ED7ED: "Peter Beard " not changed
gpg: Total number processed: 1
gpg:              unchanged: 1

You can see that there are multiple keys matching my email address but only one of them is active so that's the one we download. Now you can encrypt things you want to send to me and you can verify anything that I've signed with that key, right? Well, almost.

Checking Signatures

Before we start using a key we should take a look at the signatures it has. Let's say we're Ingo and we're trying to set up the web from that Wikipedia example - what might that look like?. Well assuming we've already generated our own keypair we'll need to get the keys for our friends Eva and Axel - let's say they've kindly provided us with files containing these keys:

$ gpg --import ./eva.pub.asc
gpg: key EC180DF84D7A82F0: public key "Eva Friend " imported
gpg: Total number processed: 1
gpg:               imported: 1
gpg: marginals needed: 3  completes needed: 1  trust model: pgp
gpg: depth: 0  valid:  10  signed:   0  trust: 0-, 0q, 0n, 0m, 0f, 10u
gpg: next trustdb check due at 2021-06-13
$ gpg --import ./axel.pub.asc
gpg: key 1DE9888E13316A02: public key "Axel Friend " imported
gpg: Total number processed: 1
gpg:               imported: 1
gpg: marginals needed: 3  completes needed: 1  trust model: pgp
gpg: depth: 0  valid:   9  signed:   0  trust: 0-, 0q, 0n, 0m, 0f, 9u
gpg: next trustdb check due at 2020-12-26
$ gpg --list-keys
./ingo
------
pub   rsa4096 2020-06-13 [SC] [expires: 2021-06-13]
      96DBE852024841C3D7F5076F41CEAC45B766EE00
uid           [ultimate] Ingo Myself 
sub   rsa4096 2020-06-13 [E] [expires: 2021-06-13]

pub   rsa4096 2020-06-13 [SC] [expires: 2021-10-23]
      2458335DB495B689DA1832D8EC180DF84D7A82F0
uid           [ unknown] Eva Friend 
sub   rsa4096 2020-06-13 [E] [expires: 2021-10-23]

pub   rsa2048 2020-06-13 [SC] [expires: 2020-12-26]
      1F02C831CABDAE9A38FA1E7E1DE9888E13316A02
uid           [ unknown] Axel Friend 
sub   rsa2048 2020-06-13 [E] [expires: 2020-12-26]

Before each person's name you can see the current trust level - there are five levels of trust that can be applied to a key:

  1. Unknown - you don't know whether or not you trust this person
  2. None - this person's signatures can't be trusted
  3. Marginal - this person is pretty careful about validating keys before signing them
  4. Full - you trust this person as much as yourself to validate keys properly
  5. Ultimate - even if this key isn't valid you trust its owner's signatures as much as your own (rarely used except for your own keys)

There are no fixed rules as to what the different levels mean, just guidelines. In this case, we have a level 3 signature since we generated the key ourselves. If you have a friend who you know properly validates keys before signing them then you might also trust them at a 3. Most people in your web of trust will probably be level 2.

To see how the web of trust works, let's import a few more keys that have been signed by our friends:

Let's say we know Axel and Eva very well and completely trust them to validate other people's keys - we'll set their trust levels to full and see how that changes things.

$ gpg --edit-key eva
gpg (GnuPG) 2.2.20; Copyright (C) 2020 Free Software Foundation, Inc.
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.


pub  rsa4096/EC180DF84D7A82F0
     created: 2020-06-13  expires: 2021-10-23  usage: SC  
     trust: unknown       validity: unknown
sub  rsa4096/3A255E76281F37CF
     created: 2020-06-13  expires: 2021-10-23  usage: E   
[ unknown] (1). Eva Friend 

gpg> trust
pub  rsa4096/EC180DF84D7A82F0
     created: 2020-06-13  expires: 2021-10-23  usage: SC  
     trust: unknown       validity: unknown
sub  rsa4096/3A255E76281F37CF
     created: 2020-06-13  expires: 2021-10-23  usage: E   
[ unknown] (1). Eva Friend 

Please decide how far you trust this user to correctly verify other users' keys
(by looking at passports, checking fingerprints from different sources, etc.)

  1 = I don't know or won't say
  2 = I do NOT trust
  3 = I trust marginally
  4 = I trust fully
  5 = I trust ultimately
  m = back to the main menu

Your decision? 4

pub  rsa4096/EC180DF84D7A82F0
     created: 2020-06-13  expires: 2021-10-23  usage: SC  
     trust: full          validity: unknown
sub  rsa4096/3A255E76281F37CF
     created: 2020-06-13  expires: 2021-10-23  usage: E   
[ unknown] (1). Eva Friend 
Please note that the shown key validity is not necessarily correct
unless you restart the program.

We then do the same for Axel's key and see how that changes the output of --list-keys: