# Using WKD to Publish PGP Public Keys John Simpson `` 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 < ForceType application/pgp-key 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 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. * 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 " 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 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 * [Key Discovery Made Simple](https://gnupg.org/blog/20160830-web-key-service.html) - 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](https://wiki.gnupg.org/WKD#Hosting%20a%20Web%20Key%20Directory) - GnuPG's documentation about WKD. * [Original reference](https://gist.github.com/kafene/0a6e259996862d35845784e6e5dbfc79) - This page has a similar walk-through to this one. * Werner Koch, the primary deveoper of GnuPG, [says that the usernames are hashed](https://marc.info/?l=gnupg-devel&m=142488047809150&w=2) in order to allow for email addresses which may contain characters which are not valid in DNS names. * [RFC-4398](https://tools.ietf.org/html/rfc4398) 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.