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:
cert
: a DNS CERT PGP record as defined in RFC-4398pka
: a DNS CERT IPGP record, also defined in RFC-4398 or a DNS TXT record, depending on the version of GnuPG. This uses an HTTP request to a location defined in the record to retrieve the key.dane
: a DNS OPENPGPKEY record, as defined in RFC-7929.wkd
: via an HTTP GET to a file in the.well-known
(RFC-5785) directory. This is experimental and defined in a RFC draft.keyserver
: The common way to retrieve keys via keyservers.
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:
- Easy to set up
Cons:
- Large record which needs to be transferred over TCP
- Not located at a nice place in the DNS
- Only retrieves public keys from a single record (but a single record can contain multiple keys)
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:
- Easy to setup with software that accepts the output of
gpg2
- Well defined location
Cons:
- Large record which needs to be transferred over TCP
- Only retrieves public keys from a single record (but a single record can contain multiple keys)
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:
- Easy to setup with software that accepts the output of
gpg2
- Can automatically improve trust
- Small DNS record
- Well defined location
Cons
- Does not retrieve the key from the specified location but from a keyserver instead.
- Only retrieves the key for a single record
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:
- Easy to setup
- No cumbersome DNS record
- Well defined location
Cons
- Only retrieves the identity for which a lookup was done
Conclusion
All of the provided methods have drawbacks. Here is what I recommend:
Primarily use WKD, it is easy to maintain and works the best. Additional security can be provided by using DNSSEC and HTTPS (and DANE/TLSA).
Use OPENPGPKEY over CERT PGP. OPENPGPKEY does everything that CERT PGP does, but better. Security is provided by DNSSEC.
Use PKA only for storing fingerprints. Using it when verifying keys might be useful.
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 becausefoo.org
andexample.net
do not matchexample.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 theSRV
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.