PGP and DNS

6 minutes read time

Recently, I looked at all the ways GnuPG can retrieve PGP keys from the internet to see which of these methods are actually useful. This blog post describes a summary of my conclusions.

GnuPG modern (2.1.16) can retrieve keys from the internet using the following mechanisms:

So next to the common way to retrieve keys (which I will not discuss) there are four other mechanisms: two fully relying on DNS, one using a mix of DNS and HTTP(S) and one only using HTTP(S).

For testing the DNS records I used a PowerDNS (4.0.1) server on a DNSSEC signed domain (which I recommend). Note that DNSSEC is not required (not even for the DANE mechanism).

CERT record

The CERT record is quite straightforward: it is a data record in which one can place the base64 encoded information for a public key. This data (which I will call [DATA]) can be generated with:

gpg --export-options export-minimal --export F4DFA1D665C135D6 | base64 -w0

Which results in the same data as what is contained in an ASCII-armored key (except for line endings), which is formatted like:

-----BEGIN PGP PUBLIC KEY BLOCK-----

[DATA]
=[checksum]
-----END PGP PUBLIC KEY BLOCK-----

The DNS record for the identity asdf at slxh.eu looks like any the following:

asdf.slxh.eu. 86400 IN CERT PGP 0 0 [DATA]

Where PGP can be replaced by the number 3. This is required for PowerDNS.

The record is quite straight forward and it works, but only for a single key:

$  gpg2 -v --auto-key-locate=clear,cert,local --locate-keys <address>
...
gpg: auto-key-locate found fingerprint 646B0F089DD5022CF5BA29F9F4DFA1D665C135D6
gpg: automatically retrieved '<address>' via DNS CERT

Pros:

Cons:

DANE: OPENPGP record

The dane mechanism works in a similar way to CERT, but it uses a well-defined location. The record looks like (see the CERT section for generating [DATA]):

7a5b775b45836845e91cb23b59ed7ff45d1732c7aa8415952beeb7d2._openpgpkey.slxh.eu 86400 IN OPENPGPKEY [DATA]

The compatibility format can also be generated by gpg2:

gpg --export-options export-dane --export F4DFA1D665C135D6

Which results in:

$ORIGIN _openpgpkey.slxh.eu.
7a5b775b45836845e91cb23b59ed7ff45d1732c7aa8415952beeb7d2 TYPE61 \# 1695 (
	98330457e504ee16092b06010401da470f01010740752c0c3aa3bf6841a33076
	...
	34d3c8c4f8aaa94f53e10daff07633d2a3eea38dbd409d44d9600d9a755a0e
	)

Pros:

Cons:

PKA: Public Key Association

The PKA record in GnuPG 2.1.16 uses the CERT IPGP record to store the fingerprint of the public key and a location where the key can be retrieved. The record has its own location and local part of the email address is hashed. There is also a TXT variant, but GnuPG does not use this for lookups any more.

GnuPG also has options for automatically doing lookups and increasing trust if the fingerprint matches on verification:

--verify-options parameters
  ...
  pka-lookups
         Enable PKA lookups to verify sender addresses. Note that PKA is based on DNS, and
         so  enabling this option may disclose information on when and what signatures are
         verified or to whom data is encrypted. This is similar to the "web bug" described
         for the --auto-key-retrieve option.

  pka-trust-increase
         Raise  the  trust  in a signature to full if the signature passes PKA validation.
         This option is only meaningful if pka-lookups is set.

GnuPG can also create the DNS record for you:

gpg --export-options export-pka --export F4DFA1D665C135D6

Which shows the required records for zone files:

$ORIGIN _pka.slxh.eu
yyjm39f54qomwmcejnmojaspwa86esqj TYPE37 \# 26 0006 0000 00 14 646B0F089DD5022CF5BA29F9F4DFA1D665C135D6

This output, however, is only for compatibility purposes and does not contain a URL for key retrieval.

The actual format can be generated from this information (I have made a script that does just that). The regular record looks like:

yyjm39f54qomwmcejnmojaspwa86esqj._pka.slxh.eu 3600 IN CERT 6 0 0 FGRrDwid1QIs9bop+fTfodZlwTXW

With a provided URL, in this case https://slxh.eu/keys/pgp/65C135D6, it becomes:

yyjm39f54qomwmcejnmojaspwa86esqj._pka.slxh.eu 3600 IN CERT 6 0 0 FGRrDwid1QIs9bop+fTfodZlwTXWaHR0cHM6Ly9zbHhoLmV1L2tleXMvcGdwLzY1QzEzNUQ2

The 6 may be replaced with IPGP.

The lookup of the fingerprint works. The retrieval of the key, however, does not: instead of using the provided URL it asks the server for a key with a specific URL (a PKS lookup), resulting in a Page Not Found error. This means that gpg does use the server specified in the record but ignores the URL, resulting in gpg claiming there are no keys to be retrieved. A solution to this is to simply use a keyserver (like https://sks-keyservers.net) in the record.

In my opinion this record is most useful for simply verifying the fingerprint, in which case the URL is not needed.

Pros:

Cons

WKD: Web Key Directory

The Web Key Directory mechanism leverages the .well-known directory to store keys. Exporting to this location is relatively easy:

$ gpg2 --with-wkd-hash -k F4DFA1D665C135D6
pub   ed25519/F4DFA1D665C135D6 2016-09-23 [SC] [expires: 2018-09-23]
      646B0F089DD5022CF5BA29F9F4DFA1D665C135D6
uid                 [  full  ] ...
                    yyjm39f54qomwmcejnmojaspwa86esqj@slxh.eu
...
$ gpg --export F4DFA1D665C135D6 > yyjm39f54qomwmcejnmojaspwa86esqj

Note that the key cannot be ASCII-armored.

The created file (yyjm39f54qomwmcejnmojaspwa86esqj) then needs to be placed on the webserver for slxh.eu, so that it is accessible at: https://slxh.eu/.well-known/openpgpkey/hu/yyjm39f54qomwmcejnmojaspwa86esqj

The export can contain multiple public keys, but in that case gpg2 will throw an error (No fingerprint) while still importing the keys. Also: only the identities for which a lookup was done are imported.

Pros:

Cons

Conclusion

All of the provided methods have drawbacks. Here is what I recommend:

Update 2017-02-16

GnuPG 2.1.18 added a DNS lookup to WKD via a SRV record. The given example is:

_openpgpkey._tcp  IN  SRV  0 0 0    wkd.foo.org.
                  IN  SRV  0 0 0    wkd.example.net.
                  IN  SRV  0 0 4711 wkd.example.org.

Which would fetch from:

https://wkd.example.org:4711/.well-known/openpgpkey/submission-address

Explained as follows:

Note that the first two SRV records won’t be used because foo.org and example.net do not match example.org. We require that the target host is identical to the domain or be a subdomain of it. This is so that an attacker modifying the SRV records needs to setup a server in a sub-domain of the actual domain and can’t use an arbitrary domain. Whether this is a sufficient requirement is not clear and needs further discussion.

These changes add some flexibility to WKD lookups. The requirement to have the server as subdomain makes sense, but note that when an attacker has full control of the DNS this is circumvented without much hassle.