跳到主要内容

3. 协议元素

协议元素是协议中的概念性部分, 不特定于 Signer 或 Verifier. Signer 和 Verifier 的协议描述见后续章节 ("Signer Actions" (Section 5) 和 "Verifier Actions" (Section 6)). NOTE: 本节必须结合这些章节阅读.

3.1. Selectors

为支持每个签名域同时存在多个公钥, key 命名空间使用 "selector" 进行细分. 例如, selector 可以指示办公地点名称 (如 "sanfrancisco", "coolumbeach" 和 "reykjavik"), 签名日期 (如 "january2005", "february2005" 等), 甚至可以指示单个用户.

需要 selector 来支持一些重要用例. 例如:

  • 希望在给定时长内把特定地址的签名能力委托给合作方的域, 例如广告提供商或其他外包功能.

  • 希望允许经常出差的用户在本地发送消息, 而无需连接到特定 MSA 的域.

  • 提供入站邮件转发但不运行出站邮件提交代理的 "Affinity" 域 (例如大学校友会).

selector 中允许使用句点, 且句点作为组件分隔符. 从 DNS 取得 key 时, selector 中的句点以类似域名常规用法的方式定义 DNS label 边界. selector 组件可用于组合日期和地点, 例如 "march2005.reykjavik". 在 DNS 实现中, 这可用于允许委托 selector 命名空间的一部分.

ABNF:

selector = sub-domain *( "." sub-domain )

每个域的公钥数量及相应 selector 由域所有者决定. 许多域所有者只需一个 selector 即可满足需求, 而管理上分布式的组织可以选择在不同区域或不同电子邮件服务器上管理不同 selector 和 key pair.

除管理便利性外, selector 还使按常规无缝替换公钥成为可能. 如果某个域希望从使用与 selector "january2005" 关联的公钥切换到使用与 selector "february2005" 关联的公钥, 它只需确保在过渡期间两个公钥同时发布在公钥仓库中, 因为在验证前电子邮件可能仍在传输中. 过渡期开始时, 出站电子邮件服务器配置为使用 "february2005" 私钥签名. 过渡期结束时, 从公钥仓库中移除 "january2005" 公钥.

INFORMATIVE NOTE: key 也可以按下文描述撤销. 撤销 key selector record 与移除它之间的区别很微妙. 当按上述方式逐步淘汰 key 时, 签名域很可能只是在过渡期后移除 key record. 但是, 签名域也可以选择在更长一段时间内撤销该 key (但保留 key record). 已撤销 key 与已移除 key 之间没有已定义的语义差异.

虽然某些域可能希望让 selector 值广为人知, 但其他域会希望谨慎分配 selector 名称, 避免外部方据此收集数据. 例如, 如果签发每用户 key, 域所有者需要决定是把该 selector 直接关联到注册最终用户的名称, 还是使其成为某个无关联随机值, 例如公钥指纹.

INFORMATIVE OPERATIONS NOTE: 使用新 key 复用 selector (例如更改与用户名关联的 key) 会使人无法区分两种情况: 消息因为 key 不再有效而未验证通过, 或者消息实际是伪造的. 因此, 不建议 Signer 为新 key 复用 selector. 更好的策略是为新 key 分配新 selector.

3.2. Tag=Value 列表

DKIM 在多个上下文中使用简单的 "tag=value" 语法, 包括消息和域签名 record.

值是一系列字符串, 包含 plain text, "base64" 文本 (如 [RFC2045, Section 6.8] 所定义), "qp-section" (同上, Section 6.7), 或 "dkim-quoted-printable" (如 Section 2.11 所定义). tag 名称将决定每个值的编码. tag 值中 MUST NOT 出现未编码分号 (";") 字符, 因为它用于分隔 tag-spec.

INFORMATIVE IMPLEMENTATION NOTE: 虽然下文定义的 "plain text" (作为 "tag-value") 只包含 7-bit 字符, 但建议希望预先适应未来标准的实现不要排除在 tag=value 列表中使用 UTF-8 编码 ([RFC3629]) 文本.

形式化地说, ABNF 语法规则如下:

tag-list  = tag-spec *( ";" tag-spec ) [ ";" ]
tag-spec = [FWS] tag-name [FWS] "=" [FWS] tag-value [FWS]
tag-name = ALPHA *ALNUMPUNC
tag-value = [ tval *( 1*(WSP / FWS) tval ) ]
; Prohibits WSP and FWS at beginning and end
tval = 1*VALCHAR
VALCHAR = %x21-3A / %x3C-7E
; EXCLAMATION to TILDE except SEMICOLON
ALNUMPUNC = ALPHA / DIGIT / "_"

注意, tag 周围任何位置都允许 WSP. 特别是, "=" 后的任何 WSP 以及终止 ";" 前的任何 WSP 都不是值的一部分; 但是, 值内部的 WSP 具有意义.

tag MUST 以大小写敏感方式解释. 除非特定 tag 的语义描述指定大小写不敏感, 否则值 MUST 按大小写敏感方式处理.

单个 tag-list 中 MUST NOT 出现名称重复的 tag; 如果某个 tag 名称出现超过一次, 整个 tag-list 无效.

除非特定 tag 描述明确排除, 值内的空白 MUST 保留.

表示默认值的 tag=value 对 MAY 包含在内以提高可读性.

未识别 tag MUST 被忽略.

具有空值的 tag 不同于被省略的 tag. 被省略的 tag 视为具有默认值; 具有空值的 tag 明确指定空字符串为其值.

3.3. 签名和验证算法

DKIM 支持多种数字签名算法. 本规范目前定义两个算法: rsa-sha1 和 rsa-sha256. Signer MUST 实现并 SHOULD 使用 rsa-sha256 签名. Verifier MUST 同时实现 rsa-sha1 和 rsa-sha256.

INFORMATIVE NOTE: 虽然强烈鼓励使用 rsa-sha256, 但某些发送方在权衡安全强度与性能, 复杂度或其他需求时, 可能更倾向使用 rsa-sha1. 不过一般而言, 只要可能就应始终使用 rsa-sha256.

3.3.1. rsa-sha1 签名算法

rsa-sha1 签名算法按 Section 3.7 中的描述计算消息哈希, 使用 SHA-1 [FIPS-180-3-2008] 作为 hash-alg. 随后 Signer 使用 RSA 算法 (在 Public-Key Cryptography Standards (PKCS) #1 version 1.5 [RFC3447] 中定义) 作为 crypt-alg, 并使用 Signer 的私钥对该哈希签名. 签名前, 该哈希 MUST NOT 被截断或转换为原生二进制形式以外的任何形式. 签名算法 SHOULD 使用公指数 65537.

3.3.2. rsa-sha256 签名算法

rsa-sha256 签名算法按 Section 3.7 中的描述计算消息哈希, 使用 SHA-256 [FIPS-180-3-2008] 作为 hash-alg. 随后 Signer 使用 RSA 算法 (在 PKCS#1 version 1.5 [RFC3447] 中定义) 作为 crypt-alg, 并使用 Signer 的私钥对该哈希签名. 签名前, 该哈希 MUST NOT 被截断或转换为原生二进制形式以外的任何形式. 签名算法 SHOULD 使用公指数 65537.

3.3.3. Key 大小

选择适当 key 大小是在成本, 性能和风险之间进行权衡. 由于较短 RSA key 更容易受到离线攻击, Signer MUST 对长期 key 使用至少 1024 bit 的 RSA key. Verifier MUST 能够验证 key 范围为 512 bit 到 2048 bit 的签名, 并且 MAY 能够验证使用更大 key 的签名. Verifier 策略可以把签名 key 的长度作为判断签名是否可接受的一项指标.

应影响 key 大小选择的因素包括:

  • 实际约束: 大 key (例如 4096-bit) 可能无法装入 512-byte DNS UDP 响应包

  • 安全约束: 小于 1024 bit 的 key 会受到离线攻击

  • 更大的 key 会给验证和签署电子邮件带来更高 CPU 成本

  • key 可以定期替换; 因此其生命周期可以相对较短

  • 与使用数字签名的其他系统的典型目标相比, 本规范的安全目标较为适度

关于选择 key 大小的进一步讨论, 见 [RFC3766].

3.3.4. 其他算法

未来 MAY 定义其他算法. Verifier MUST 忽略使用其未实现算法的任何签名.

3.4. 规范化

某些邮件系统会在传输中修改电子邮件, 可能导致签名失效. 对大多数 Signer 而言, 对电子邮件的轻微修改不会影响对 DKIM 域名使用的验证. 对此类 Signer, 更适合使用能够经受适度传输中修改的规范化算法.

其他 Signer 要求电子邮件的任何修改, 无论多小, 都导致签名验证失败. 这些 Signer 偏好不容忍已签名电子邮件在传输中被修改的规范化算法.

某些 Signer 可能愿意接受对 header field 的修改, 只要这些修改处于 [RFC5322] 等电子邮件标准边界内, 但不愿接受对消息正文的任何修改.

为满足所有要求, 分别为 header 和正文定义了两种规范化算法: 几乎不容忍任何修改的 "simple" 算法, 以及容忍常见修改的 "relaxed" 算法, 例如空白替换和 header field 行重新换行. Signer 在签署电子邮件时 MAY 为 header 或正文指定任一算法. 如果 Signer 未指定规范化算法, header 和正文都默认为 "simple" 算法. Verifier MUST 实现两种规范化算法. 注意, header 和正文可以使用不同的规范化算法. 未来 MAY 定义进一步的规范化算法; Verifier MUST 忽略使用未识别规范化算法的任何签名.

规范化只是为把电子邮件提交给签名或验证算法做准备. 它 MUST NOT 以任何方式更改传输数据. header field 和正文的规范化如下所述.

NOTE: 本节假定消息已经采用 "network normal" 格式 (文本为 ASCII 编码, 行由 CRLF 字符分隔, 等等). 关于消息规范化的信息另见 Section 5.3.

3.4.1. "simple" Header 规范化算法

"simple" header 规范化算法不以任何方式更改 header field. Header field MUST 按正在签名或验证的消息中的原样提交给签名或验证算法. 特别是, header field 名称 MUST NOT 进行大小写折叠, 空白也 MUST NOT 更改.

3.4.2. "relaxed" Header 规范化算法

"relaxed" header 规范化算法 MUST 按顺序应用以下步骤:

  • 将所有 header field 名称 (不是 header field 值) 转换为小写. 例如, 将 "SUBJect: AbC" 转换为 "subject: AbC".

  • 按 [RFC5322] 中的描述展开所有 header field 续行; 特别是, 在连续 header field 值中嵌入终止符的行 (即 CRLF 序列后跟 WSP) MUST 按不含 CRLF 的方式解释. 实现 MUST NOT 移除 header field 值末尾的 CRLF.

  • 将一个或多个 WSP 字符的所有序列转换为单个 SP 字符. 此处的 WSP 字符包括行折叠边界前后的字符.

  • 删除每个已展开 header field 值末尾的所有 WSP 字符.

  • 删除分隔 header field 名称和 header field 值的冒号前后剩余的任何 WSP 字符. 冒号分隔符 MUST 保留.

3.4.3. "simple" 正文规范化算法

"simple" 正文规范化算法忽略消息正文末尾的所有空行. 空行是移除行终止符后长度为零的行. 如果没有正文, 或者消息正文末尾没有 CRLF, 则添加一个 CRLF. 它不对消息正文作其他更改. 更形式化地说, "simple" 正文规范化算法把正文末尾的 "*CRLF" 转换为单个 "CRLF".

注意, 完全为空或缺失的正文会规范化为单个 "CRLF"; 也就是说, 规范化后的长度为 2 octet.

空正文 (规范化为 "CRLF") 的 SHA-1 值 (base64) 为:

uoq1oCgLlTqpdDX/iUbLy7J1Wic=

SHA-256 值为:

frcCV1k9oG9oKj3dpUqdJg1PxRT2RSN/XKdLCPjaYaY=

3.4.4. "relaxed" 正文规范化算法

"relaxed" 正文规范化算法 MUST 按顺序应用以下步骤 (a) 和 (b):

a. 缩减空白:

  • 忽略行末所有空白. 实现 MUST NOT 移除行末的 CRLF.

  • 将一行内所有 WSP 序列缩减为单个 SP 字符.

b. 忽略消息正文末尾的所有空行. "Empty line" 在 Section 3.4.3 中定义. 如果正文非空但不以 CRLF 结尾, 则添加一个 CRLF. (对于电子邮件, 这只有在使用 SMTP 扩展或非 SMTP 传输机制时才可能发生.)

空正文 (规范化为空输入) 的 SHA-1 值 (base64) 为:

2jmj7l5rSw0yVb/vlWAYkK/YBwk=

SHA-256 值为:

47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU=

3.4.5. 规范化示例 (INFORMATIVE)

在以下示例中, 实际空白仅用于清晰展示. 实际输入和输出文本使用带方括号的描述符标示: "<SP>" 表示空格字符, "<HTAB>" 表示制表符, "<CRLF>" 表示 carriage-return/line-feed 序列. 例如, "X <SP> Y" 和 "X<SP>Y" 表示相同的三个字符.

Example 1: 一条消息内容为:

A: <SP> X <CRLF>
B <SP> : <SP> Y <HTAB><CRLF>
<HTAB> Z <SP><SP><CRLF>
<CRLF>
<SP> C <SP><CRLF>
D <SP><HTAB><SP> E <CRLF>
<CRLF>
<CRLF>

当 header 和正文都使用 relaxed 规范化时, 得到的 header 为:

a:X <CRLF>
b:Y <SP> Z <CRLF>

正文为:

<SP> C <CRLF>
D <SP> E <CRLF>

Example 2: 同一消息在 header 和正文都使用 simple 规范化时, 得到的 header 为:

A: <SP> X <CRLF>
B <SP> : <SP> Y <HTAB><CRLF>
<HTAB> Z <SP><SP><CRLF>

正文为:

<SP> C <SP><CRLF>
D <SP><HTAB><SP> E <CRLF>

Example 3: 当使用 relaxed header 规范化和 simple 正文规范化处理时, 规范化后的版本具有如下 header:

a:X <CRLF>
b:Y <SP> Z <CRLF>

正文为:

<SP> C <SP><CRLF>
D <SP><HTAB><SP> E <CRLF>