Ben Hardill<p><strong>Sharing PGP keys</strong></p><p>A recent boosted <a href="https://social.coop/@fnat/113543896849600364" rel="nofollow noopener" target="_blank">toot</a> from <a rel="nofollow noopener" class="u-url mention" href="https://mastodon.neilzone.co.uk/@neil" target="_blank">@<span>neil</span></a> combined with the <a href="https://keybase.io/" rel="nofollow noopener" target="_blank">keybase.io </a>Linux desktop widget causing me grief (it’s virtual filesystem stuff messing with Gnome file manage) made me think about how folks could, if they needed, find a public PGP key for me.</p><p>Keybase.io was a nice idea, you could tie a PGP key to all your other web persona, this was done by publishing a signed hash e.g. as a tweet, in a DNS record, or at a known location on a web host. This meant that anybody who knew where to find you online could then “prove” that the public PGP key hosted on Keybase.io belonged to you. It was sort of like a modern take on the old <a href="https://en.wikipedia.org/wiki/Key_signing_party" rel="nofollow noopener" target="_blank">key signing parties</a>. But in the end they got <a href="https://keybase.io/blog/keybase-joins-zoom" rel="nofollow noopener" target="_blank">bought by Zoom</a>, and also started handing out crypto tokens…</p><p>Distributing encryption keys is one of the well known <strong>hard</strong> problems in computer science, public key encryption makes it easier in that bit that needs distributing is something that can be shared with everybody, but there is still the discovery problem. E.g. how do I find the right public key of somebody you have never talked to before.</p><p><strong>Public Key Servers</strong></p><p>This is a original way to share keys without having to meet up in person. You uploaded the keys to one of a few key server and tools like gpg/pgp could search for a public key using an email address.</p><p>Servers like:</p><ul><li><a href="https://keys.openpgp.org" rel="nofollow noopener" target="_blank">keys.openpgp.org</a></li><li><a href="https://pgp.mit.edu" rel="nofollow noopener" target="_blank">pgp.mit.edu</a></li><li><a href="https://keys.openpgp.org" rel="nofollow noopener" target="_blank">keys.openpgp.org</a></li></ul><p>I did find longer lists online, but many of the servers didn’t respond when I tried to reach them. There was also a <a href="https://www.vice.com/en/article/someone-is-spamming-and-breaking-a-core-component-of-pgps-ecosystem/" rel="nofollow noopener" target="_blank">concerted effort</a> to spam some of these servers submitting lots of signatures attesting the validity of existing public keys.</p><p>There are several problem with using a 3rd party server </p><ul><li>The person looking up your key needs to know which Key Server to use</li><li>If the Key Server goes down, you are unlikely to get notified</li><li>It’s hard/impossible to remove a key if you have lost access to the matching private key (removal requests need to be signed with the private key to prove you own it)</li></ul><p><strong>Self Hosting</strong></p><p>What we need is a way to self host a discoverable and verifiable public key. There are a few options out there.</p><p><strong>Autocrypt</strong></p><p>This is a little different to other options. Here your email client attaches your public key to all outbound email in the <code>Autocrypt</code> header. e.g.</p> <pre>From: Ben Hardill <ben@hardill.me.uk>X-Clacks-Overhead: GNU Terry PratchettSubject: AutoCrypt TestAutocrypt: addr=ben@hardill.me.uk; keydata= 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Content-Type: text/plain; charset=UTF-8; format=flowed</pre> <p>Modern versions Thunderbird supports this feature and you can pick which key to attach to each account under the “End-To-End Encryption” section of each account.</p><p>Thunderbird doesn’t automatically import these keys to the local keystore, but it can.</p><p>This also relies on protocols such as SPF and DKIM to ensure the email arrived from a trusted source for the email address in question.</p><p>More details can be found <a href="https://docs.autocrypt.org/" rel="nofollow noopener" target="_blank">here</a>.</p><p><strong>Web Key Service</strong></p><p><a href="https://wiki.gnupg.org/WKS" rel="nofollow noopener" target="_blank">Web Key Service</a> (WKS) is a way to host public keys on a web server, discovery of the web server is done via DNS and has a couple of different options.</p><p>This is what was mentioned in the <a href="https://fabionatali.com/posts/make-your-gnupg-key-discoverable-via-web-key-directory/" rel="nofollow noopener" target="_blank">post</a> linked to in the original toot, but it missed out a couple of details, so I’ll cover all the options here.</p><p>This makes use of the <code>.well-known</code> directory that is used for many other discovery protocols. In this case the location will be <code>.well-known/openpgpkey</code> what comes after that depends on which of the other options is used.</p><p>Firstly the <code>gpg-wks-server</code> tool is used to create the required files and directory structure, but there is a minor niggle with the <code>gpg-wks-server</code> tool, it will only work with a output directory that has the following permissions <code>rwxr-x---</code> which makes it accessible to the owner and people in the same group as the owner, but these files will most likely need to be world readable when deployed to the web server, especially as the intention is to make them available to anybody that needs them.</p> <pre>$ mkdir output-dir$ chmod 740 output-dir$ gpg-wks-server --directory output-dir --install-key 4F19C128BB4DC20AA5E564D8FC2D3FB5080CFED8 ben@hardill.me.uk</pre> <p>This will create a directory under <code>output-dir</code> with the domain name of the email address, in this case <code>hardill.me.uk</code>, under here there will be a <code>hu</code> directory and a policy file. Under the <code>hu</code> directory will be file with name which is a 32bit hex string. This is a SHA1 hash of the local part of the email address in <a href="https://www.rfc-editor.org/rfc/rfc6189.html#section-5.1.6" rel="nofollow noopener" target="_blank">Z-base-32</a> encoding.</p> <pre>output-dir |-hardill.me.uk | |-hu | | |-qpui546ptjbsz3rqaetbdz8wj9op6nur | |-policy</pre> <p>If you have a Web Server running on the same domain as the email domain (e.g. <code>hardill.me.uk</code>) then you can copy the <code>hu</code> directory and <code>policy</code> file to <code>.well-known/openpgpkey</code> directory</p> <pre>/var/www/html/.well-known |-openpgpkey | |-hu | | |-qpui546ptjbsz3rqaetbdz8wj9op6nur | |-policy</pre> <p>If you are not running a Web Server on the same domain, you can create a cname of <code>openpgpkey.[domain]</code> e.g. <code>openpgpkey.hardill.me.uk</code> and point that at a Web Server that will respond to that hostname and in this case you need to include the domain name in the directory structure</p> <pre>/var/www/html/.well-known |-openpgpkey | |-hardill.me.uk | | |-hu | | | |-qpui546ptjbsz3rqaetbdz8wj9op6nur | | |-policy</pre> <p>Thunderbird’s built in PGP support can use this mechanism to look up public keys for email addresses.</p><p>There is a constraint that look ups will only be done over valid HTTPS to prevent man-in-the-middle tampering.</p><p>Also I’ve not mentioned the <code>policy</code> file, this appears to be more aimed at mail service providers, as it dictates how a user should submit their keys via email to the provider for hosting on their WKS instance. It involves a 2 way encrypted email handshake. Since I have direct access to both my Web Server and the keys I want to publish, I’ve not explored setting this up.</p><p>The specification can be found <a href="https://datatracker.ietf.org/doc/draft-koch-openpgp-webkey-service/" rel="nofollow noopener" target="_blank">here</a>.</p><p><strong>DANE</strong></p><p><a href="https://en.wikipedia.org/wiki/DNS-based_Authentication_of_Named_Entities" rel="nofollow noopener" target="_blank">DNS-based Authentication of Named Entities</a> (DANE) was originally a way to do a form of HTTPS certificate pinning via DNS, which when combined with DNSSEC provides assurance that the certificate presented by a Web Server is the one the owner intended.</p><p>It has since been extended to also support providing PGP keys for email users. </p><p>This works by adding <code>OPENPGPKEY</code> records in the <code>_openpgpkey</code> sub domain e.g. <code>_openpgpkey.hardill.me.uk</code>. It uses a SHA256 hash of the local part of the email address as the hostname in the sub domain. This can be generated as follows:</p> <pre>$ echo -n 'ben' | sha256sum | head -c566700869c8ff7480e34a70a708b028700dbaa3a033b5652b903afe89f</pre> <p>(this does make it possible to pre-compute a list of local part’s and then use DNS to iterate these to generate a list of valid email addresses)</p><p>The value of the record is just the ascii armoured version of the key with the <code>-----BEGIN PGP PRIVATE KEY BLOCK-----</code> header and <code>-----END PGP PRIVATE KEY BLOCK-----</code> (and the size) removed, but also with all the line breaks removed.</p><p>The tricky bit is formatting the record correctly, I found a <a href="https://www.huque.com/bin/openpgpkey" rel="nofollow noopener" target="_blank">website</a> that would do it for bind, but this implies they you are editing the zone files by hand, rather than using something like <code>nsupdate</code> to make updates dynamically (this also helps if you have auto DNSSEC signing enabled). So I wrote the following script that will generate the correct <code>nsupdate</code> command to insert the key into DNS in the correct way.</p> <pre>#!/bin/bashMAIL=$1LOCAL=$(echo "${MAIL}" | sed 's/@.*$//')DOMAIN=$(echo "${MAIL}" | sed 's/^.*@//')FQD="$(echo -n $LOCAL | sha256sum | head -c56)._openpgpkey.${DOMAIN}."KEY=$(gpg --export --export-options export-minimal --armor $1 | head -n-2 | tail -n+3 | tr -d '\n')echo "update add $FQD 3600 IN OPENPGPKEY $KEY"</pre> <p>One thing of note is that these records will need to be accessed using DNS over TCP as all secure keys are likely to be too big to fit in a single UDP response packet.</p><p>You can search and import a key using gpg</p> <pre>$ gpg --auto-key-locate clear,nodefault,dane --locate-keys ben@hardill.me.ukgpg: checking the trustdbgpg: marginals needed: 3 completes needed: 1 trust model: pgpgpg: depth: 0 valid: 1 signed: 0 trust: 0-, 0q, 0n, 0m, 0f, 1ugpg: key FC2D3FB5080CFED8: public key "Ben Hardill <ben@hardill.me.uk>" importedgpg: Total number processed: 1gpg: imported: 1pub rsa4096 2024-11-25 [SC] 4F19C128BB4DC20AA5E564D8FC2D3FB5080CFED8uid [ unknown] Ben Hardill <ben@hardill.me.uk>sub rsa4096 2024-11-25 [E]</pre> <p>The RFC is <a href="https://datatracker.ietf.org/doc/html/rfc8162" rel="nofollow noopener" target="_blank">here</a>.</p><p><a rel="nofollow noopener" class="hashtag u-tag u-category" href="https://blog.hardill.me.uk/tag/keys/" target="_blank">#keys</a> <a rel="nofollow noopener" class="hashtag u-tag u-category" href="https://blog.hardill.me.uk/tag/pgp/" target="_blank">#pgp</a></p>