2020-05-08 Replacing Keybase

OK, so Keybase was bought by Zoom and I deleted my Keybase identity. @wiktor@metacode.biz said he had a decentralized alternative.

@wiktor@metacode.biz

You can find a simple description here: OpenPGP Proofs.

OpenPGP Proofs

Here’s how I understand it:

1. on an online service, mention your fingerprint in a particular way

2. add that link to your key in a particular way

3. potentially use some software to verify it, or do it manually

Let’s do this.

Determine my fingerprint:

alex@melanobombus:~$ **gpg --fingerprint alex@gnu.org**
pub   rsa8192 2015-03-01 [SC] [expires: 2021-05-07]
      DF94 46EB 7B78 4638 7CCC  018B C78C A29B ACEC FEAE
uid           [ unknown] Alex Schroeder <alex@gnu.org>
uid           [ unknown] Alex Schroeder <kensanata@gmail.com>
uid           [ unknown] [jpeg image of size 5665]
uid           [ unknown] Alex Schroeder <alex@alexschroeder.ch>
sub   elg3072 2019-01-20 [E] [expires: 2021-01-30]

(and many other expired and revoked keys)

The fingerprint in question, with no spaces and converted to lower case: `df9446eb7b7846387ccc018bc78ca29bacecfeae`

Make sure you’re using the keys.openpgp.org keyserver. For a modern GPG installation, your `~/.gnupg/gpg.conf` file should have this line:

keys.openpgp.org

keyserver hkps://keys.openpgp.org

Send your key to keyserver:

alex@melanobombus:~$ **gpg --send-key df9446eb7b7846387ccc018bc78ca29bacecfeae**
gpg: sending key C78CA29BACECFEAE to hkps://keys.openpgp.org

GitHub

I’m going to create a proof for my GitHub account.

Create a new Gist. Use `openpgp.md` as the filename. Write whatever but somewhere in that text, use the String `Verifying my OpenPGP key: openpgp4fpr:{FINGERPRINT}`. Here’s the Gist I created.

Gist

the Gist I created

Now, edit your key, adding a *notation* pointing to the Gist, save it, and send the key to the keyservers.

alex@melanobombus:~$ **gpg --edit-key df9446eb7b7846387ccc018bc78ca29bacecfeae**
Secret key is available.

sec  rsa8192/C78CA29BACECFEAE
     created: 2015-03-01  expires: 2021-05-07  usage: SC
ssb  rsa4096/0C8706F1F6881931
     created: 2015-03-01  expired: 2019-02-28  usage: S
ssb  rsa8192/11C583644529A45C
     created: 2015-03-01  expired: 2019-02-28  usage: E
ssb  elg3072/DE6718E639D2D11F
     created: 2019-01-20  expires: 2021-01-30  usage: E
[ unknown] (1). Alex Schroeder <alex@gnu.org>
[ unknown] (2)  Alex Schroeder <kensanata@gmail.com>
[ unknown] (3)  [jpeg image of size 5665]
[ unknown] (4)  Alex Schroeder <alex@alexschroeder.ch>

gpg> **notation**
Enter the notation: **proof@metacode.biz=https://gist.github.com/kensanata/ffb8ecad8d48c9091ad63fb767534340**
No notations on user ID "Alex Schroeder <alex@gnu.org>"
Adding notation: proof@metacode.biz=https://gist.github.com/kensanata/ffb8ecad8d48c9091ad63fb767534340
No notations on user ID "Alex Schroeder <kensanata@gmail.com>"
Adding notation: proof@metacode.biz=https://gist.github.com/kensanata/ffb8ecad8d48c9091ad63fb767534340
No notations on user ID "[jpeg image of size 5665]"
Adding notation: proof@metacode.biz=https://gist.github.com/kensanata/ffb8ecad8d48c9091ad63fb767534340
No notations on user ID "Alex Schroeder <alex@alexschroeder.ch>"
Adding notation: proof@metacode.biz=https://gist.github.com/kensanata/ffb8ecad8d48c9091ad63fb767534340

sec  rsa8192/C78CA29BACECFEAE
     created: 2015-03-01  expires: 2021-05-07  usage: SC
ssb  rsa4096/0C8706F1F6881931
     created: 2015-03-01  expired: 2019-02-28  usage: S
ssb  rsa8192/11C583644529A45C
     created: 2015-03-01  expired: 2019-02-28  usage: E
ssb  elg3072/DE6718E639D2D11F
     created: 2019-01-20  expires: 2021-01-30  usage: E
[ unknown] (1). Alex Schroeder <alex@gnu.org>
[ unknown] (2)  Alex Schroeder <kensanata@gmail.com>
[ unknown] (3)  [jpeg image of size 5665]
[ unknown] (4)  Alex Schroeder <alex@alexschroeder.ch>

gpg> **save**
alex@melanobombus:~$ **gpg --send-key df9446eb7b7846387ccc018bc78ca29bacecfeae**
gpg: sending key C78CA29BACECFEAE to hkps://keys.openpgp.org

If you’re wondering about the `proof@metacode.biz` key used, there’s an explanation in the FAQ:

FAQ

This e-mail-like string is actually notation key. RFC 4880 specifies this kind of format as a way to namespace custom notations. You need to create notations under the domain that you own to avoid conflicts. I used my own domain for this protocol. Ideally the notation key would be just proof. Using this kind of keys (without @ namespacing) is only allowed for IETF-approved extensions though (I did not approach them).

So, one day it might be just `proof`. But we need to agree on a key for tools to work and so `proof@metacode.biz` is as good as any.

Here’s how to manually verify the key:

alex@melanobombus:~$ **gpg --list-options show-notations --list-sigs df9446eb7b7846387ccc018bc78ca29bacecfeae | grep proof**
   Signature notation: proof@metacode.biz=https://gist.github.com/kensanata/ffb8ecad8d48c9091ad63fb767534340
   Signature notation: proof@metacode.biz=https://gist.github.com/kensanata/ffb8ecad8d48c9091ad63fb767534340
   Signature notation: proof@metacode.biz=https://gist.github.com/kensanata/ffb8ecad8d48c9091ad63fb767534340
   Signature notation: proof@metacode.biz=https://gist.github.com/kensanata/ffb8ecad8d48c9091ad63fb767534340

Visit the URL and check that the fingerprint mentioned is in fact the fingerprint you used in your query. If so, verified! ✔

And here’s how to do it automatically.

You can host the web app somewhere, or use Wiktor’s installation, passing along the fingerprint in question as part of the URL:

the web app

Click for the live version

Click for the live version

This is soooo beautiful! 😍

Thanks, Wiktor!

That’s all I ever wanted Keybase to do for me. And now there’s a way to do this, but decentralized. This is awesome.

Mastodon

I’m adding my fingerprint as one of the four profile metadata elements available to me on Mastodon, followed by:

on Mastodon

gpg --edit-key df9446eb7b7846387ccc018bc78ca29bacecfeae
notation
proof@metacode.biz=https://octodon.social/@kensanata
save
gpg --send-key df9446eb7b7846387ccc018bc78ca29bacecfeae

Reddit

I’m posting the same text I used above to Reddit, followed by:

to Reddit

gpg --edit-key df9446eb7b7846387ccc018bc78ca29bacecfeae
notation
proof@metacode.biz=https://www.reddit.com/user/kensanata/comments/gfzrkn/proof_of_identity_decentralized/
save
gpg --send-key df9446eb7b7846387ccc018bc78ca29bacecfeae

Email

Remember, we’re using keys.openpgp.org. They don’t publish email addresses unless you’ve agreed to it. That means a confirmation mail per email. We need to do the following for every email address we want to make available:

keys.openpgp.org

1. submit it to `keys.openpgp.org`

2. get the confirmation link

3. click the link to request a confirmation mail

4. click the link in the confirmation mail

In order to get started, you have to submit your key *without* using `--send-key`. I know, it’s weird. But that’s the way to get the confirmation link:

alex@melanobombus:~$ **gpg --export alex@alexschroeder.ch | curl -T - https://keys.openpgp.org**
Key successfully uploaded. Proceed with verification here:
https://keys.openpgp.org/upload/...

Click the link to request the confirmation mail, wait for the confirmation mail, click the link in the confirmation mail, and now your address is listed!

Verify this by search for your email addresses on keys.openpgp.org.

keys.openpgp.org

Do this for every email address you want to see listed (possibly all of them).

Searching for emails

Remember how I said above that you can pass the fingerprint of a key to the web app, like this:

https://alexschroeder.ch/openpgp/​#0xdf9446eb7b7846387ccc018bc78ca29bacecfeae

If you’re self-hosting your email, there’s the option of allowing an email address instead of the fingerprint, using a Web Key Directory. One day, tools will be able to handle encryption without having to know about fingerprints. 🙂 The same is true for the web app:

Web Key Directory

https://alexschroeder.ch/openpgp/​#alex@alexschroeder.ch

If you have control over a domain but don’t use it for email, there’s still a way to get this to work using a subdomain under your control and `keys.openpgp.org` but I’m not going to cover that. I would have to do that for my GNU and GMail addresses. The following section just covers the email address I receive under my own domain, `alex@alexschroeder.ch`.

In order for this to work, we need to do the following:

1. export our key

2. rename it so it matches the hash of the local part (`alex` in my case)

3. serve it from the same domain from a well-known location

Let’s determine the hash using `--with-wkd`:

alex@melanobombus:~$ **gpg --list-keys --with-wkd alex@alexschroeder.ch**
pub   rsa8192 2015-03-01 [SC] [expires: 2021-05-07]
      DF9446EB7B7846387CCC018BC78CA29BACECFEAE
uid           [ unknown] Alex Schroeder <alex@gnu.org>
              cddpr77ezsy7h967hgjydxhhmnt76n8w@gnu.org
uid           [ unknown] Alex Schroeder <kensanata@gmail.com>
              cps1z1ccmfq5zj33zg7z3s49sehtefwz@gmail.com
uid           [ unknown] [jpeg image of size 5665]
uid           [ unknown] Alex Schroeder <alex@alexschroeder.ch>
              cddpr77ezsy7h967hgjydxhhmnt76n8w@alexschroeder.ch
sub   elg3072 2019-01-20 [E] [expires: 2021-01-30]

Thus, I need to export my public key using `gpg --export alex@alexschroeder.ch > cddpr77ezsy7h967hgjydxhhmnt76n8w` and serve it from `https://alexschroeder.ch/.well-known/openpgpkey/hu/`.

In addition to that, I created a `.htaccess` file in my `openpgpkey` directory containing the following:

Options -Indexes
Header set Access-Control-Allow-Origin "*"

The first line disables the listing of directory contents and the second line sets the Access-Control-Allow-Origin such that this information may be retrieved from elsewhere, not just my own server.

Access-Control-Allow-Origin

You can test the setup using Wiktor’s Web Key Directory page.

Web Key Directory

Sadly, when testing it from the command line, it doesn’t work as expected. Here I am, using `--locate-keys` from a different account where I don’t have access to my key:

alex@sibirocobombus:~$ **gpg --locate-keys alex@alexschroeder.ch**
gpg: error retrieving 'alex@alexschroeder.ch' via WKD: No data
gpg: error reading key: No data

Oops! 😭

Something’s missing. But what is it?

Self Hosting the Application

On your webserver, create a directory called `openpgp` with a copy of the files in the openpgp-proofs repository. The directory I’m using is accessible from the web as `https://alexschroeder.ch/openpgp`. This is important later because the script expects `proofs.json` at this location.

openpgp-proofs repository

Run `npm install --production` in this directory. You’ll get a bunch of dependencies installed into the `node_modules` directory.

If you’re like me and you’ve set a Content Security Policy, you need to allow clients to make requests to the keyserver and to all the sites hosting the proofs. Thus, we really need to relax our CSP, unfortunately. But there’s no way around it!

Content Security Policy

In my `.htaccess` file, I put:

DirectoryIndex index.html
Header set Content-Security-Policy "default-src https: data:; object-src 'none'; script-src https: 'unsafe-inline'; style-src https: 'unsafe-inline'"

And here it is! 😀

here it is

Note that my primary browser is Firefox which blocks a bunch of requests so that the proofs cannot be fetched. When I use Chromium, which is less paranoid, all my proofs are verified. 👍

​#Cryptography