翻译披露:本页为对 IETF RFC 3156《MIME Security with OpenPGP》 的中文翻译,原文著作权归 IETF/原作者所有,内容以人类原始 RFC 为准。本译本由 ztpop.net 整理,仅供学习参考;RFC 受 BCP 78 与 IETF 信托法律条款约束,译本保留原文编号与结构,权威性以英文原文为准。英文原文见 rfc-editor.org/rfc/rfc3156。
RFC 3156:使用 OpenPGP 的 MIME 安全机制
本备忘录的状态
本文档为互联网社区规定了一项互联网标准跟踪(standards track)协议,并征求改进意见与建议。有关本协议的标准化状态与状况,请参阅《互联网官方协议标准》(STD 1)的当前版本。本备忘录的分发不受限制。
版权声明
Copyright (C) The Internet Society (2001). All Rights Reserved.
摘要
本文档描述如何利用 RFC 1847 所述的多用途互联网邮件扩展(MIME)安全内容类型,使用 OpenPGP 消息格式来提供隐私保护与认证。
1. 引言
在 RFC 2015 之前,将 PGP(Pretty Good Privacy)与 MIME [3] 相集成的工作(包括其后被撤回的 "application/pgp" 内容类型)存在若干问题,其中最严重的是:若不解析 PGP 专有的数据结构,就无法还原出被签名的邮件正文。RFC 2015 采用了 RFC 1847 提出的优雅方案——该文档为 MIME 定义了安全多部分(security multipart)格式。安全多部分把被签名的邮件正文与签名清晰地分离开来,并具备若干其他理想特性。本文档修订 RFC 2015,使 PGP 与 MIME 的集成方式适配 OpenPGP 规范制定过程中出现的新需求。
本文档定义了三种用于以 OpenPGP 实现安全与隐私的内容类型:"application/pgp-encrypted"、"application/pgp-signature" 与 "application/pgp-keys"。
本文档中的关键词 "MUST"(必须)、"MUST NOT"(不得)、"REQUIRED"(需要)、"SHALL"(应)、"SHALL NOT"(不应)、"SHOULD"(应当)、"SHOULD NOT"(不应)、"RECOMMENDED"(推荐)、"MAY"(可以)与 "OPTIONAL"(可选),应按 RFC 2119 中的描述来解释。
2. OpenPGP 数据格式
OpenPGP 实现在加密数据、生成数字签名或提取公钥数据时,既可以产生 ASCII armor(见 [1] 所述)输出,也可以产生 8 位二进制输出。ASCII armor 输出是数据传输所需要采用的方法。这使得那些无法解释本文档所述格式的用户,仍然能够提取并使用邮件中的 OpenPGP 信息。
当待传输的数据量大到必须分成多个部分发送时,应当使用 MIME 的 message/partial 机制,而不是使用多部分 ASCII armor 的 OpenPGP 格式。
3. Content-Transfer-Encoding 限制
multipart/signed 与 multipart/encrypted 应被各类代理视为不透明的(opaque),即其数据不得以任何方式改动 [2]、[7]。然而,许多现有的邮件网关会检测下一跳是否支持 MIME 或 8 位数据,并据此转换为 Quoted-Printable 或 Base64。这对 multipart/signed 造成了严重问题——一旦发生此类操作,签名即告失效。
因此,按本协议签名的所有数据必须限制为 7 位(8 位数据必须使用 Quoted-Printable 或 Base64 编码)。注意这也包括被签名对象同时又被加密的情形(见第 6 节)。该限制将提高签名在接收时仍然有效的可能性。
此外,各实现必须确保在应用 MIME 编码之后不存在行尾空白。
注:多数情况下,行尾空白既可以被移除,也可以通过施加适当的 content-transfer-encoding 加以保护。但当出现仅由空白构成的头部行时(无论是 MIME 实体头部还是内嵌的 RFC 822 头部)必须特别小心:此类行必须被整行删除,因为把它们替换为空行会使其变成头部分隔符,从而改变邮件的语义。对空白的这些限制是必要的,其目的是使所计算的散列值在 OpenPGP [1] 提供的文本模式与二进制模式签名机制下保持一致;同时也有助于避免与早于 OpenPGP 规范的 PGP 实现之间出现兼容性问题。
注:如果某行以字符串 "From " 开头,强烈建议施加 Quoted-Printable 或 Base64 MIME 编码。若使用 Quoted-Printable,该字符串中至少应有一个字符采用十六进制编码规则进行编码。原因是:许多邮件传输与投递代理把 "From "(单词 "from" 紧跟一个空格字符)视为一封新邮件的开始,因而会在任何以 "From " 开头的行前插入一个右尖括号(>)以区分该情形,从而使签名失效。
仅需加密的数据允许包含 8 位字符与行尾空白,因此无需进行到 7 位格式的转换,也无需剥离空白。
实现者注记:再怎么强调也不过分——使用本标准的应用应遵循 MIME 的建议:"生成时保守,接受时宽容"。在本例中,这意味着实现明智的做法是:接受采用任何 content-transfer-encoding 的邮件,但把自身的生成限制在本备忘录要求的 7 位格式。这将在互联网 SMTP 框架变得对 8 位友好时保证未来的兼容性。
4. OpenPGP 加密数据
在进行 OpenPGP 加密之前,数据先以 MIME 规范形式(正文与头部)写出。
OpenPGP 加密数据以 [2] 所述的 "multipart/encrypted" 内容类型标识,并且其 "protocol" 参数值必须为 "application/pgp-encrypted"。注意该参数值必须用引号括起。
multipart/encrypted 的 MIME 正文必须恰好由两个正文部分组成。第一部分的内容类型为 "application/pgp-encrypted",其中承载控制信息;符合本标准的邮件必须在该正文中包含 "Version: 1" 字段。由于 OpenPGP 分组格式已包含解密所需的其余全部信息,此处不再需要其他信息。
第二个 MIME 正文部分必须包含实际的加密数据,并必须标注内容类型为 "application/octet-stream"。
邮件结构示例(正文中的 PGP 数据块以省略号代替):
Content-Type: multipart/encrypted; boundary=foo; protocol="application/pgp-encrypted" --foo Content-Type: application/pgp-encrypted Version: 1 --foo Content-Type: application/octet-stream -----BEGIN PGP MESSAGE----- Version: 2.6.2 (此处为 ASCII armor 形式的加密数据块) -----END PGP MESSAGE----- --foo--
5. OpenPGP 签名数据
OpenPGP 签名邮件以 [2] 所述的 "multipart/signed" 内容类型标识,其 "protocol" 参数值必须为 "application/pgp-signature"(必须加引号)。
"application/pgp-signature" 协议的 "micalg" 参数必须恰好包含一个格式为 "pgp-<hash-identifier>" 的散列符号,其中 <hash-identifier> 标识用于生成该签名的消息完整性校验(MIC)算法。散列符号由 [1] 中注册的文本名称、或按该文档定义的机制构造而成:把文本名称转为小写,并加上四字符前缀 "pgp-"。
当时已定义的取值为:"pgp-md5"、"pgp-sha1"、"pgp-ripemd160"、"pgp-md2"、"pgp-tiger192" 与 "pgp-haval-5-160"。
multipart/signed 正文必须恰好由两部分组成。第一部分以 MIME 规范形式包含被签名的数据,并含有一组描述该数据的适当内容头部。第二部分必须包含 OpenPGP 数字签名,并必须标注内容类型为 "application/pgp-signature"。
注:各实现既可以生成 [1] 中定义的"规范文本文档的签名",也可以生成"二进制文档的签名"。第 3 节与本节对被签名材料所作的限制,将确保 [1] 与 [5] 中规定的各种 MIC 算法变体都产生相同结果。
生成 OpenPGP 数字签名时:
- 待签名数据必须先转换为其内容类型对应的规范形式。对 text/plain 而言,这意味着转换为适当的字符集,并将行结束符转换为规范的 <CR><LF> 序列。
- 随后施加适当的 Content-Transfer-Encoding,见第 3 节。特别地,编码后数据中的行结束符在适当之处必须使用规范的 <CR><LF> 序列(注意:编码数据的最后一行可能有也可能没有规范行结束符;若不存在,则不得将其计入签名)。
- 然后向正文添加 MIME 内容头部,每个头部均以规范的 <CR><LF> 序列结束。
- 如本文档第 3 节所述,随后必须从被签名材料中移除所有行尾空白。
- 如 [2] 所述,数字签名必须覆盖待签名数据及其内容头部集合一并计算。
- 签名必须以与被签名数据相分离(detached)的方式生成,使该过程不以任何方式改动被签名数据。
注:OpenPGP 公认的约定是被签名数据以 <CR><LF> 序列结束。注意,紧邻 MIME 边界分隔行之前的 <CR><LF> 序列在 [3] 第 5.1 节中被视为分隔符的一部分,因此它不属于该分隔行之前的被签名数据。选择遵循 OpenPGP 约定的实现,必须确保在"待签名并传输的数据"的最后一行插入一个 <CR><LF> 对(被签名邮件与被传输邮件必须完全一致)。
邮件结构示例(原文中以 "&" 标记出签名所覆盖的数据范围):
Content-Type: multipart/signed; boundary=bar; micalg=pgp-md5; protocol="application/pgp-signature" --bar & Content-Type: text/plain; charset=iso-8859-1 & Content-Transfer-Encoding: quoted-printable & & (被签名的正文内容) --bar Content-Type: application/pgp-signature -----BEGIN PGP MESSAGE----- Version: 2.6.2 (此处为 ASCII armor 形式的签名数据块) -----END PGP MESSAGE----- --bar--
上例中的 "&" 标示出签名所计算覆盖的数据部分。
收到签名邮件时,应用必须:
- 在验证签名之前,先把行结束符转换为规范的 <CR><LF> 序列。这是必要的,因为本地 MTA 可能已将其转换为本地的行结束约定。
- 把被签名数据及其关联的内容头部,连同 OpenPGP 签名一并交给签名验证服务。
6. 既加密又签名的数据
有时既需要对待发送的邮件进行数字签名、又需要对其加密。本协议允许用两种方法完成该任务。
6.1 RFC 1847 式封装
[2] 中规定:数据先被签名为一个 multipart/signed 正文,然后再被加密以形成最终的 multipart/encrypted 正文。该方式对于标准的、符合 MIME 的邮件转发最为有用。
结构示例(以 "&" 标记的部分实际上处于加密态,此处为清晰起见以文本呈现):
Content-Type: multipart/encrypted; protocol="application/pgp-encrypted"; boundary=foo --foo Content-Type: application/pgp-encrypted Version: 1 --foo Content-Type: application/octet-stream -----BEGIN PGP MESSAGE----- & Content-Type: multipart/signed; micalg=pgp-md5 & protocol="application/pgp-signature"; boundary=bar & & --bar & Content-Type: text/plain; charset=us-ascii & & (先被签名、随后被加密的正文内容) & & --bar & Content-Type: application/pgp-signature & & (此处为 ASCII armor 形式的签名数据块) & & --bar-- -----END PGP MESSAGE----- --foo--
6.2 合并方法
OpenPGP 分组格式 [1] 描述了在单个 OpenPGP 消息中同时完成签名与加密的方法。允许使用该方法,以减少处理开销并提高与 OpenPGP 非 MIME 实现之间的兼容性。所得数据按第 4 节所述格式化为 "multipart/encrypted" 对象。
以此合并方式加密并签名的邮件,需要遵循与 multipart/signed 对象相同的规范化规则。
明确允许代理对合并式邮件进行解密,并利用加密版本中内嵌的签名数据将其改写为 multipart/signed 对象。
7. OpenPGP 公钥的分发
内容类型:application/pgp-keys;必需参数:无;可选参数:无。
内容类型为 "application/pgp-keys" 的 MIME 正文部分,包含 [1] 第 10.1 节所定义的、经 ASCII armor 处理的可传输公钥分组(transferable Public Key Packets)。
8. 安全考量
[1] 中定义的"规范文本文档的签名"会忽略被签名材料中的行尾空白。选择使用规范文本文档签名的实现,将无法检测出传输途中被添加的空白。
关于底层协议的更多安全考量,参见 [3]、[4]。
9. IANA 考量
本文档定义了三种媒体类型:"application/pgp-encrypted"、"application/pgp-signature" 与 "application/pgp-keys"。以下各节给出这些类型的 IANA 注册信息。
9.1 application/pgp-encrypted 媒体类型的注册
| 字段 | 内容 |
|---|---|
| MIME 媒体类型名 | application |
| MIME 子类型名 | pgp-encrypted |
| 必需参数 / 可选参数 | 无 / 无 |
| 编码考量 | 当前该媒体类型始终由单个 7 位文本字符串构成 |
| 安全考量 | 见第 8 节与 RFC 2440 第 13 节 |
| 互操作性考量 | 无 |
| 已发布规范 | 本文档 |
| 幻数 / 文件扩展名 / Macintosh 文件类型码 | 无 / 无 / 无 |
| 预期用途 | common(常用) |
9.2 application/pgp-signature 媒体类型的注册
| 字段 | 内容 |
|---|---|
| MIME 媒体类型名 | application |
| MIME 子类型名 | pgp-signature |
| 必需参数 / 可选参数 | 无 / 无 |
| 编码考量 | 该媒体类型的内容始终由 7 位文本构成 |
| 安全考量 | 见第 8 节与 RFC 2440 第 13 节 |
| 互操作性考量 | 无 |
| 已发布规范 | RFC 2440 与本文档 |
| 文件扩展名 | asc、sig |
| Macintosh 文件类型码 | pgDS |
| 预期用途 | common(常用) |
9.3 application/pgp-keys 媒体类型的注册
| 字段 | 内容 |
|---|---|
| MIME 媒体类型名 | application |
| MIME 子类型名 | pgp-keys |
| 必需参数 / 可选参数 | 无 / 无 |
| 编码考量 | 该媒体类型的内容始终由 7 位文本构成 |
| 安全考量 | 见第 8 节与 RFC 2440 第 13 节 |
| 互操作性考量 | 无 |
| 已发布规范 | RFC 2440 与本文档 |
| 文件扩展名 | asc |
| 预期用途 | common(常用) |
以上三项注册中,"供进一步咨询的联系人 / 作者与变更控制者"均为 Michael Elkins(邮箱:me@cs.hmc.edu)。
作者
Michael Elkins(Network Associates, Inc.)、Dave Del Torto(CryptoRights Foundation)、Raph Levien(加州大学伯克利分校)、Thomas Roessler。完整作者地址见英文原文"Authors' Addresses"一节。
完整版权声明
Copyright (C) The Internet Society (2001). All Rights Reserved.
本文档及其译本可以被复制并提供给他人;对其进行注释或以其他方式解释、或协助其实现的衍生作品,也可以被全部或部分地准备、复制、发布与分发,不受任何形式的限制,前提是在所有此类副本与衍生作品上都包含上述版权声明与本段文字。但本文档本身不得以任何方式修改;除非是出于制定互联网标准的需要,或者是将其翻译为英语以外的语言所必需。
上述授予的有限许可是永久性的,不会被互联网协会或其继任者或受让人撤销。
本文档及其中所含信息以"按现状"(AS IS)的方式提供,互联网协会与互联网工程任务组不作任何明示或默示的担保。
来源(Source)
本页译自 IETF 人类原始文本,英文原文与权威版本:
- RFC 原文(IETF Datatracker):https://datatracker.ietf.org/doc/html/rfc3156
- RFC 原文(RFC Editor):https://www.rfc-editor.org/rfc/rfc3156
- 文档状态与勘误:https://www.rfc-editor.org/info/rfc3156
如中文表述与英文原文存在歧义,一律以 ietf.org / rfc-editor.org 英文原文为准。
