Using WKD to Publish PGP Public Keys

John Simpson <jms1@jms1.net> 2018-10-13, last updated 2018-10-14

A Web Key Directory, or WKD, is a way to publish PGP keys so they can be easily located, based on an email address. The idea is, if people know your email address, they can use WKD to find your PGP public key.

WKD requires that the website were you publish the keys, be accessible using the same domain name as the "domain" portion of the email address. For example, keys for any email address ending with "@jms1.net" would need to be published on the jms1.net web server.

Starting with GnuPG 2.1.12, the gpg command knows how to use WKD to automatically locate keys for an email address. And starting with 2.1.23, the automatic searching is enabled by defaut.

This page assumes you're using a non-Windows operating system, and that you are comfortable working on the command line.

Setup for hosting

WKD works by hosting files containing the public keys in a ".well-known/openpgpkey/hu/" directory on the web site. So the first step is to create that directory.

On the web server:

# cd $WEBROOT
# mkdir -pm 0711 .well-known
# mkdir -pm 0711 .well-known/openpgpkey
# mkdir -pm 0711 .well-known/openpgpkey/hu

The other thing we need to do is make sure that the files are served with the correct MIME type. Assuming you are using Apache and allow .htaccess files within the document root, this will accomplish that:

# cd $WEBROOT/.well-known/openpgpkey/hu
# cat > .htaccess <<EOF
<IfModule mod_mime.c>
  ForceType application/pgp-key
</IfModule>
EOF
# chmod 0644 .htaccess

At this point the web server is ready to service WKD requests, now you just need to add some keys.

Add a key

Each key's filename is a hash of the "username part" of the email address. The steps below will produce a file with the correct name and contents.

Identify the WKD hash

On your workstation, whose keyring has the key you want to serve, identify the WKD hash of the email address you're matching.

$ gpg --with-wkd-hash --fingerprint jms1@jms1.net
...
pub   rsa4096/0xA7EC1FBAB3B50007 2017-11-27 [SC] [expires: 2019-11-28]
      Key fingerprint = BDC8 4CA8 78FD 827A 4C0B  B361 A7EC 1FBA B3B5 0007
uid                   [ unknown] John Simpson <jms1@jms1.net>
                      bctwn8rhe4wecqwd349bsjczijf74ouy@jms1.net
...

In this case, "bctwn8rhe4wecqwd349bsjczijf74ouy" is the WDK hash of the username part of the email address I'm publishing.

Export the public key

We need to eport the public key as a binary file, rather than the ASCII-armored export you may already be used to doing. To do this, export just the public key you're looking for, and save the output to a file whose name is the WKD hash. (I have several older keys with the same email address on them, so I used the Key ID value to be sure I was exporting the correct key.)

$ gpg --no-armor --export 0xA7EC1FBAB3B50007 > bctwn8rhe4wecqwd349bsjczijf74ouy

You should be able to use the file command to verify that the file contains a public key.

$ file bctwn8rhe4wecqwd349bsjczijf74ouy
bctwn8rhe4wecqwd349bsjczijf74ouy: GPG key public ring, created Mon Nov 27 00:36:27 2017

Upload the key to your web server

Upload the file to the .well-known/openpgpkey/hu directory on your web site. The mechanics of doing this will depend on your server. (If it helps, I used scp for this.)

Make sure the file is world-readable (i.e. "chmod 0644 bctwn8rhe4wecqwd349bsjczijf74ouy").

Test

Make sure you have a "clean" working environment.

Do a search for the key. The --auto-key-locate clear,wkd option tells gpg to use only WKD to locate the key.

$ gpg --auto-key-locate clear,wkd --locate-keys jms1@jms1.net
gpg: key A7EC1FBAB3B50007: public key "John Simpson <jms1@jms1.net>" imported
gpg: Total number processed: 1
gpg:               imported: 1
gpg: no ultimately trusted keys found
pub   rsa4096 2017-11-27 [SC] [expires: 2019-11-28]
      BDC84CA878FD827A4C0BB361A7EC1FBAB3B50007
uid           [ unknown] John Simpson <jms1@jms1.net>
sub   rsa4096 2017-11-27 [E] [expires: 2019-11-28]
sub   rsa4096 2017-11-27 [S] [expires: 2019-11-28]
sub   rsa4096 2017-11-27 [A] [expires: 2019-11-28]

When you're finished, remove the temporary directory and the GNUPGHOME environment variable.

$ rm -rf /tmp/gpg-work
$ unset GNUPGHOME

Other Information