delphij's Chaos

选择chaos这个词是因为~~实在很难找到一个更合适的词来形容这儿了……

13 Aug 2023

采用 Ed25519 的 DKIM 签名

Ed25519 是一种高性能的公钥签名系统。和 RSA 相比, 同等强度的 Ed25519 的密钥长度要比 RSA 短很多,此外,软件实现的 Ed25519 的验证速度也比同等强度的 RSA 快很多。

尽管早在2018年 RFC 8463 Section 5 就已经将 RFC 6376 Section 3.3 修正为要求验证者必须支持 Ed25519 验证,然而时至今日主要的邮件服务提供商中, 包括 Google 的 Gmail 和 Microsoft 的 Outlook.com 以及 Apple 的 iCloud 都还不支持验证 Ed25519 DKIM 签名。ProtonMail 支持 Ed25519 的 DKIM 签名,但它并不使用 Ed25519 签名向外发出的邮件。

经测试,同时采用 RSA 和 Ed25519 签名发出的邮件可以让那些只支持 RSA 签名的邮件运营者正确验证邮件, 显然,这样做会增加邮件尺寸,也会增加 DNS 流量,这些都和采用 Ed25519 签名的希望背道而驰, 但我觉得总得做点什么来让互联网巨头开始面对这一现实,因此我打算从今天开始将我自己域名发出的邮件同时采用 RSA 和 Ed25519 签名,直到三大主要的邮件服务提供商(Google、 Microsoft 和 Apple)都支持它为止。

我目前采用的是 dkimpy-milter。 和之前使用的 OpenDKIM 相比,它的开发更为活跃(后者在2018年发布了一版beta之后就没有再发布新的版本了)。 其配置大致如下:

首先是生成签名用的密钥对:

dknewkey --ktype ed25519 ed25519-2023
dknewkey rsa-2023

这其中 ed25519-2023rsa-2023 是计划使用的 selector 名字。程序会生成 .key (私钥)和 .dns (公钥,用来添加到域名 zone 中)两个文件。

注意 dkimpy 并未考虑 TXT 记录只能有255个字符的限制,对于 2048-bit 的 RSA 公钥,必须将其切开。 对于 Ed25519 公钥,由于其长度很短,因此没有这个问题。

接下来要更新域名的 DNS zone 来添加新的记录。为了方便回退,暂时不要删除旧的公钥。

dkimpy-milter.conf 的配置主要是以下几方面:

  1. Domain。这是希望签名(自己的)域名。
  2. KeyFileSelector。这是 RSA key 的私钥(PEM格式)和 selector。除此之外也可以用 OpenDKIM 风格的 KeyTable
  3. KeyFileEd25519SelectorEd25519。这是 Ed25519 的私钥和 selector。除此之外也可以用 OpenDKIM 风格的 KeyTable25519
  4. Socket。我使用的是本地的 Unix socket (local:/var/spool/postfix/private/dkimpy-milter
  5. UserID。抛弃特权后的身份。注意 socket 必须可以被 Postfix 读写,可以设置为 postfix:dkimpy-milter

启动之后将 Postfix 的 master.cfsubmission 服务(或者其他希望接收往外发邮件的 smtpd 的服务马甲)上的 smtpd_milters 改为 -o smtpd_milters=unix:private/dkimpy-milter 就可以了。

同时使用两种签名算法时,邮件中会出现两个 DKIM-Signature: 信头。 对方邮件服务器收到之后通常会增加对应的信头说明验证情况。