前言#

Keyoxide 类似于 Keybase.io,用于验证在线账户的身份同一性。

例如,在 Keyoxide.org 上搜索 contact@forgejo.org,你会看见 Forgejo 拥有 Mastodon 实例账户 @forgejo@floss.social, 域名 forgejo.org 和 Forgejo 实例账户 @forgejo@codeberg.org .

你也可以通过 OpenPGP 公钥指纹进行查询。例如,在 Keyoxide.org 上搜索我的指纹(可以在“联系”页面找到),你就能看到 Yuki 声明其拥有的 ActivityPub, Matrix, Forgejo 等账号,还有 obsp.de 这一域名。

每次进行查询时都会进行一次实时验证,验证成功的条目旁边会显示绿色的对钩。这保证了信息的及时更新。

目前 Keyoxide 采用两种身份验证系统,一种是 Ariadne Signature Profile,另一种则是已被广泛采用的 OpenPGP.

Keyoxide 是去中心化的,这不仅仅在于每个人都可以运行自己的 Keyoxide 实例,更在于 OpenPGP 采用了联邦式的信息系统。当你需要获取公钥时,你可以从大型的密钥服务器如 keys.openpgp.org 获取某电子邮件地址所对应的公钥,也可以和你的联系人进行点对点的公钥交换,还可以使用 WKD 获取公钥。

那么什么是 WKD 呢?WKD 的全称是 Web Key Directory,网络密钥目录,顾名思义,它是一种通过 HTTPS 请求网站的某一目录来获取密钥的方法。假如 Alice 的邮件地址是 alice@example.org, Bob 想要获取她的公钥,而他既不能在大型密钥服务器上搜索到有效的结果(因为 Alice 没有公开发布),直接向 Alice 询问又会浪费一定的时间等待她的回复。如果 example.org 具有对 WKD 的支持,那么 Bob 可以运行 gpg --locate-key alice@example.org 来获取她的公钥。这条命令实际上执行了以下的动作:

  • 对 “alice” 这一字符串执行 WKD 哈希,得到哈希字符串 “kei1q4tipxxu1yj79k9kfukdhfy631xe”
    • 你可以在终端运行 gpg-wks-client --print-wkd-hash alice@example.org 验证
  • 将哈希字符串、域名 example.org 与 WKD 的通用格式结合,获得 WKD URL
    • 它应该形如 https://openpgpkey.example.org/.well-known/openpgpkey/example.org/hu/kei1q4tipxxu1yj79k9kfukdhfy631xe?l=alice
    • 或者 https://example.org/.well-known/openpgpkey/example.org/hu/kei1q4tipxxu1yj79k9kfukdhfy631xe?l=alice
    • 第一种,也就是 subdomain method URL,相比起第二种 direct method URL 更受 GnuPG 青睐
  • curl 这一 WKD URL 的内容
    • 它没有经过 ASCII armor,而是 binary,所以是不可读的
  • gpg --import

你可能会发现,不同于在密钥服务器上进行的 --search-key 动作, GnuPG 不会提示你是否选择导入。这是因为发布在 WKD 上的密钥通常被认为是有效而可信的。如果 Alice 是域名 example.org 的所有者,只有她拥有对这一域名下目录的控制权,那么 WKD 发现的密钥可认为是 Alice 亲自发布的。如果 Alice只是 example.org 的用户,那么至少这一密钥是 Alice 的管理员发布的。

目前支持 WKD 的邮件提供商有 systemli.org, posteo.de, Proton, Mailfence 和 ForwardEmail 等,由于我用的 disroot.org 并没有 WKD 支持,所以你在 Keyoxide 上搜到的公钥会显示是 HKP 服务器的,而 Forgejo 为 forgejo.org 提供了 WKD 支持,Keyoxide 会显示这个公钥来自 WKD,你可以点击 WKD 链接进行查看。

如果你使用域名邮箱,你可以自己托管 WKD,如果你使用支持 WKD 的提供商的话,可以把子域名 openpgpkey CNAME 指向提供商的域名。如果提供商不支持的话你也可以直接 CNAME 到 wkd.keys.openpgp.org,这是 openpgp.org 提供的 WKD as a service 服务。

创建 Notation#

假设:

  • 你拥有一个域名 doma.in
  • 你已经为你的电子邮件地址 you@doma.in 创建了一个公钥
  • 你希望证明自己对这个域名的所有权

那么你需要做的事情很简单:

  • 在公钥上创建一个注记:“我拥有 doma.in”
  • 为域名添加一条 TXT 记录:“公钥指纹xxx说得对”(这一条记录可以选择性进行哈希)

聪明的你肯定已经发现了,这两条记录不是等价的。如果仅凭公钥上的注记,我们可以找到 doma.in,而通过 doma.in 上 TXT 记录里的指纹,我们是找不到公钥的。并且由于注记前后的指纹保持不变,你根本不知道公钥指纹xxx说了什么。我们不能也不需要从 doma.in 反推到 you@doma.in,这也就是为什么 TXT 记录可以用哈希值代替(至于为什么有人想要哈希,因为他们可能把公钥发布到了某个密钥服务器,在服务器上可以按指纹搜索反推到公钥)。

公钥上的注记在 Keyoxide 被称为 Identity Claim,这很好理解,它们是对身份所有权的声明。在声明所有权的同时,它会指示在该身份的哪里可以找到证明。 被声明所有权的物品返回的记录被称为 Identity Proof,可以在诸如域名的 TXT 记录,git 实例的仓库或联邦宇宙账户的嘟文等出现。这些地方一定是只有账户所有者才能编辑的,比如你不能 claim 某 GitHub 账户的 proof 在一个不属于你 claim 的 username 下的 gist 里,道理很简单。

我们运行以下命令创建注记:

gpg --edit-key FINGERPRINT
list #列出这一指纹下的所有uid
uid N #选择你要编辑的uid
notation #添加新的注记
proof@ariadne.id=dns:doma.in?type=TXT #声明你拥有 doma.in,证据在它的 TXT 记录里
save

不同的在线身份拥有不同的 claim,你可以自行查看支持的 claim/proof 类型。总的来说 claim 都是 proof@ariadne.id=CLAIM 的格式。

创建 Proof#

我们给 doma.in 加上 proof,创建一条 TXT 记录,格式是:

openpgp4fpr: FINGERPRINT 

TTL 多少都可以。

噢对,你可以用 argon2bcrypt 进行哈希,保证一定程度的匿名性。Keyoxide 的文档里贴心地准备了一个哈希小工具, 直接把 openpgp4fpr: FINGERPRINT这一串输进去,然后把输出粘贴到 TXT 记录里。

现在,把你的密钥上传到 WKD 或 HKP 吧!不出意外,TTL 之内就能在 Keyoxide 搜索邮箱地址或者公钥指纹发现你声明自己拥有 doma.in 并显示验证成功了。

杂项#

如果你不小心把 claim 写错的话(经常发生),重新进入 GnuPG 编辑身份的 notation 部分输入 -你写错的notation 可以删除这条 notation,如果你忘了自己写了哪些 notation,可以编辑身份的时候输入 showpref 查看。

我在大部分 proof 里使用了 argon2 哈希,不过 Matrix 用的是明文。用哈希值总是会显示验证失败,换了 bcrypt 也不行,不知道问题具体出在哪里,过段时间看看能不能复现。(更新:解决了,需要用 /plain 命令确保 Matrix 不会渲染字符串)不过影响不大,这个哈希没什么意义,除非你真的不希望只知道 proof 所在地的人发现你的 claim 所在地,并且你不会从其他渠道泄露这个联系…… 这个概率我觉得还挺小的。如果真是这种情况,最好不要 claim,会破坏你的匿名性。

Ariadne Signature Profile 的使用以及自己托管 Keyoxide 实例我还没试过,以后可能会再写一篇教程。Keyoxide 的官方文档强烈建议阅读,条理清晰,简单易懂。