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.
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.
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.
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.
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 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
").
Make sure you have a "clean" working environment.
Create an empty directory and point the GNUPGHOME
environment variable to it. This will make all gpg
commands in this shell use this temp directory for everything it would normally use ~/.gnupg/
for, including keyrings and gpg.conf
files.
$ mkdir -m 0700 /tmp/gpg-work
$ export GNUPGHOME=/tmp/gpg-work
Make sure the keyring is empty.
$ gpg --list-keys
gpg: keybox '/tmp/gpg-work/pubring.kbx' created
gpg: /tmp/gpg-work/trustdb.gpg: trustdb created
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
Key Discovery Made Simple - The original idea for WKD, as part of "Web Key Service". The idea was that users could email their public keys to a special address on the server, and the server would publish those keys automatically. (I'm not a fan of the idea, I prefer knowing which keys are published on my server.)
Web Key Directory - GnuPG's documentation about WKD.
Original reference - This page has a similar walk-through to this one.
Werner Koch, the primary deveoper of GnuPG, says that the usernames are hashed in order to allow for email addresses which may contain characters which are not valid in DNS names.
RFC-4398 describes a way to store "certificates" in DNS data. It supports different types of certificates, two of which are PGP (which stores the public key directly) and IPGP (which stores a fingerprint and/or a URL from which the public key may be downoaded). GnuPG seems to support this, and I was able to build a CERT record from which it got a fingerprint, but ether I built the record incorrectly, or gpg
doesn't know how to use a URL in the same record.
PKA is a way of publishing PGP public keys in DNS data. PKA is very similar to RFC-4398, except that the record names it looks up are hashed using the same method as WKD, and with a "._pka
" between the hashed username and the domain name. gpg
was able to use both the fingerprint and the URL from this record.