3. Protocol Elements (协议元素)
3. Protocol Elements (协议元素)
DKIM 的操作涉及 Signer (签名者) 和 Verifier (验证者) 两个角色。Signer 在消息离开 ADMD 时为其创建 DKIM-Signature 头字段, Verifier 在消息到达时对其进行验证。Signer 和 Verifier 可以是 MTA, MSA 或 MUA, 但它们更可能是由其中一个调用的模块。
3.1. Selectors (选择器)
为了支持一个 SDID 下多个并发公钥, 增强密钥管理便利性, DKIM 使用 "selector" 机制。正如 DNS 域名中使用标签一样, selector 被插入到查询字符串中。
例如, 假设 example.com 的管理员安装了两个并行的 DKIM 系统。他们可能会选择使用 "marketing.example.com" 和 "engineering.example.com" 作为两个系统的域名。然而, 这样的方案有一个严重的操作问题: 它要求在两个系统的域名和其名下使用的域名之间建立和维护技术关联。相比之下, 更简单的方案是使用单个域名 "example.com" 作为声称的身份来源, 并区分来自两个系统的公钥。
为此, 引入了 selector 机制。最简单的用法是拥有不同的密钥记录, 每个记录使用不同的 selector。与其有两个不同的域名, 不如使用两个不同的 selector "nyc" 和 "sf" 来区分部门。在这种情况下, 两个密钥记录将在 "nyc._domainkey.example.com" 和 "sf._domainkey.example.com" 中分别被引用。
多个 selector 允许单个域持有多个 DKIM 密钥, 从而实现多个并发的密钥对. Verifier 不关心任何给定域使用多少个 selector; DKIM 架构确保密钥标识是唯一的。用户可以使用多个 selector 的方式示例包括: 维护单独的 MSA 和 MTA 密钥, per-user 密钥, 升级前后的密钥 (key overlap), 以及支持第三方签名。在所有情况下, selector 是随机字符串, 与操作无关, 因此无法对其进行推断。密钥记录可能提供人类可读的注释 (n= 标签) 用于密钥管理目的。
3.2. Tag=Value Lists (标签=值列表)
DKIM 使用简单的 "tag=value" 语法来表达多种结构, 以提供签名和密钥记录。每个 tag-spec 由一个 tag 名称后跟 "=" 和一个值组成。多个 tag-spec 用分号分隔。Tag 名称和值语法遵循 [RFC2822] 的 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 / "_"
3.3. Signing and Verification Algorithms (签名和验证算法)
DKIM 支持多种数字签名算法。支持两类算法: (1) 必须支持的必需算法, 确保互操作性; (2) 可选算法, 允许在需要时实施新算法。
签名者 (Signer) 选择哪个算法来使用。Verifier 必须能够验证使用任何必需算法的签名。
签名算法在 DKIM-Signature 头字段的 "a=" 标签中定义, 其语法为:
sig-a-tag-alg = sig-a-tag-k "-" sig-a-tag-h
sig-a-tag-k = "rsa" / x-sig-a-tag-k
sig-a-tag-h = "sha1" / "sha256" / x-sig-a-tag-h
x-sig-a-tag-k = ALPHA *(ALPHA / DIGIT)
; for future extension
x-sig-a-tag-h = ALPHA *(ALPHA / DIGIT)
; for future extension
"rsa-sha1" 和 "rsa-sha256" 必须支持并实现。其他算法的规范留待后续定义。
3.4. Canonicalization (规范化)
某些 Internet 邮件转发系统会修改消息, 例如将标题行重新格式化或添加/删除前导或尾随空白。此类修改会导致签名验证失败。
为了解决此问题, DKIM 定义了两种规范化算法来对消息进行规范化: "simple" 和 "relaxed"。"simple" 允许很少或不进行修改; "relaxed" 允许常见的修改, 例如空白的重新格式化。Signer 可以选择使用哪种算法。两种算法分别应用于头部和正文。
规范化算法在 DKIM-Signature 头字段的 "c=" 标签中指定, 语法如下:
sig-c-tag = "simple" / "relaxed" /
(sig-c-tag-h "/" sig-c-tag-b)
sig-c-tag-h = "simple" / "relaxed" / x-sig-c-tag
sig-c-tag-b = "simple" / "relaxed" / x-sig-c-tag
x-sig-c-tag = hyphenated-word ; for future extension
3.4.1. simple 头部规范化算法
"simple" 头部规范化算法不会更改头字段, 其方式与验证会产生影响。
3.4.2. relaxed 头部规范化算法
"relaxed" 头部规范化算法必须应用以下步骤依次进行:
- 将所有头字段名 (包括冒号之前) 转换为小写。例如, 将 "SUBJect: AbC" 转换为 "subject: AbC"。
- 删除任何冒号后的所有 WSP 字符。
- 将所有连续的 WSP 字符序列转换为单个 SP 字符。WSP 字符是 SP 和 HTAB 字符, 如 [RFC5234] 的附录 B.1 中定义。
- 删除字段值末尾的所有 WSP。
- 删除任何行尾的 CRLF 序列, 不需要在正文边界追加。
3.4.3. simple 正文规范化算法
"simple" 正文规范化算法:
- 忽略消息正文中尾随的所有空行。空行定义为仅包含 CRLF 的行; 其他 WSP 字符不能单独出现在行中。如果正文完全为空, 则使用单个 CRLF 的规范化版本, 该版本中尾随的空行已被移除。
3.4.4. relaxed 正文规范化算法
"relaxed" 正文规范化算法必须应用以下步骤:
- 将所有连续的 WSP 字符序列 (包括 CRLF 后的) 减少为单个 SP。
- 忽略消息正文中所有 WSP 字符出现在行尾的行。实现不能在最后一个非 WSP 字符之后删除 CRLF。
- 忽略消息正文中尾随的所有空行。
3.4.5. Canonicalization Examples (规范化示例)
以下示例展示了头部和正文的规范化。这里使用 "<SP>" 表示空格字符, 使用 "<HTAB>" 表示水平制表符, 使用 "<CRLF>" 表示回车换行符对。
原始消息:
A: \<SP\>X\<CRLF\>
B\<SP\>:\<SP\>Y\<HTAB\>\<CRLF\>
\<HTAB\>Z\<SP\>\<SP\>\<CRLF\>
\<CRLF\>
\<SP\>C\<SP\>\<CRLF\>
D\<SP\>\<HTAB\>\<SP\>\<CRLF\>
simple 规范化后的消息:
头部:
A: \<SP\>X\<CRLF\>
B\<SP\>:\<SP\>Y\<HTAB\>\<CRLF\>
\<HTAB\>Z\<SP\>\<SP\>\<CRLF\>
正文:
\<SP\>C\<SP\>\<CRLF\>
D\<SP\>\<HTAB\>\<SP\>\<CRLF\>
relaxed 规范化后的消息:
头部:
a:\<SP\>X\<CRLF\>
b:\<SP\>Y\<SP\>Z\<CRLF\>
正文:
\<SP\>C\<CRLF\>
D\<CRLF\>