原文 rfc5246 (ietf.org) The Transport Layer Security (TLS) Protocol Version 1.2

【会注明缩译部分】

概要
本文档为 Internet 社区指定了 Internet 标准跟踪协议,并请求讨论和改进建议。本协议的标准化状态和现状请参考当前版本的《互联网官方协议标准》(STD 1)。
本文档规定了传输层安全 (TLS) 协议的 1.2 版本。 TLS 协议提供 Internet 上的通信安全。该协议允许客户端/服务器应用程序以一种旨在防止窃听、篡改或消息伪造的方式进行通信。

目录

1.  简介
      1.1.需求术语(略)
      1.2.与 TLS 1.1 的主要区别
   2. 目标
   3. 本文的目标
   4. 演示语言
      4.1.基本块大小
      4.2.Miscellaneous
      4.3.向量
      4.4.数字
      4.5.枚举
      4.6.构造类型
           4.6.1.变体(省略)
      4.7.密码属性(省略)
      4.8.常数(省略)
   5. HMAC 和伪随机函数
   6. TLS 记录协议
      6.1.连接状态
      6.2.记录层
           6.2.1.分片
           6.2.2.记录压缩和解压
           6.2.3.记录有效负载保护
                  6.2.3.1.空或标准流密码
                  6.2.3.2. CBC 块密码
                  6.2.3.3. AEAD 密码
      6.3.密钥计算
   7. TLS 握手协议
      7.1.更改密码规范协议
      7.2.警报协议
           7.2.1.关闭警报
           7.2.2.错误警报
      7.3.握手协议概述
      7.4.握手协议
           7.4.1. Hello消息
                  7.4.1.1. Hello请求
                  7.4.1.2. 客户端Hello
                  7.4.1.3. 服务器Hello
                  7.4.1.4. Hello扩展
                           7.4.1.4.1. 签名算法
           7.4.2.服务器证书
           7.4.3.服务器密钥交换消息
           7.4.4.证书申请
           7.4.5.服务器Hello完成
           7.4.6.客户端证书
           7.4.7.客户端密钥交换消息
                  7.4.7.1. RSA 加密的 Premaster 秘密消息
                  7.4.7.2.客户端 Diffie-Hellman 公共值
           7.4.8.证书验证
           7.4.9.完成
   8. 密码计算
      8.1.计算主密钥
           8.1.1. RSA
           8.1.2. Diffie-Hellman
   9. 强制密码套件 (Cipher Suite)
   10. 应用数据协议
   11. 安全考虑
   12. IANA 考虑
附录 A. 协议数据结构和常量值 (后文暂略)
      A.1.记录层
      A.2.更改密码规范消息
      A.3.警报消息
      A.4.握手协议
           A.4.1.Hello消息
           A.4.2.服务器身份验证和密钥交换消息
           A.4.3.客户端身份验证和密钥交换消息
           A.4.4.握手结束消息
      A.5.密码套件(Cipher Suite)
      A.6.安全参数
      A.7.对 RFC 4492 的更改
   附录 B. 词汇表
   附录 C. 密码套件定义
   附录 D. 实施说明
      D.1.随机数生成和播种
      D.2.证书和认证
      D.3.密码套件
      D.4.实施陷阱
   附录 E. 向后兼容性
      E.1.与 TLS 1.0/1.1 和 SSL 3.0 的兼容性
      E.2.与 SSL 2.0 的兼容性
      E.3.避免中间人版本回滚
   附录 F. 安全分析
      F.1.握手协议
           F.1.1.身份验证和密钥交换
                  F.1.1.1.匿名密钥交换
                  F.1.1.2. RSA 密钥交换和认证
                  F.1.1.3.带有身份验证的 Diffie-Hellman 密钥交换
           F.1.2.版本回滚攻击
           F.1.3.检测对握手协议的攻击
           F.1.4.恢复会话
      F.2.保护应用程序数据
      F.3.显式向量
      F.4.复合密码模式的安全性
      F.5.拒绝服务
      F.6.最后笔记
   规范参考
   参考资料
   工作组信息
   贡献者

1. 简介

TLS 协议的主要目标是在两个通信应用程序之间提供隐私和数据完整性。该协议由两层组成:TLS 记录协议和 TLS 握手协议。在最低级别,位于某些可靠传输协议(例如 TCP [TCP])之上的是TLS 记录协议。TLS 记录协议提供了具有两个基本属性的连接安全性:

- 连接是私有的。对称加密用于数据加密(例如,AES [AES]、RC4 [SCH] 等)。这种对称加密的密钥是为每个连接唯一生成的,并且基于另一个协议(例如 TLS 握手协议)协商的密钥。记录协议也可以在不加密的情况下使用。

- 连接可靠。消息传输包括使用密钥 MAC 的消息完整性检查。安全哈希函数(例如,SHA-1 等)用于 MAC 计算。记录协议可以在没有 MAC 的情况下运行,但通常仅用于此模式,而另一个协议使用记录协议作为协商安全参数的传输。

TLS Record Protocol 用于封装各种更高级别的协议。一个这样的封装协议,即 TLS 握手协议,允许服务器和客户端在应用程序协议传输或接收其第一个数据字节之前相互验证并协商加密算法和密钥。 TLS 握手协议提供了具有三个基本属性的连接安全性:

- 可以使用非对称或公钥,密码学(例如,RSA [RSA]、DSA [DSS] 等)验证对等方的身份。这种身份验证可以是可选的,但通常需要至少一个对等端。

- 共享密钥(shared secret)的协商是安全的:窃听者无法获得协商的密钥,并且对于任何经过身份验证的连接,即使攻击者可以将自己置于连接中间,也无法获得该密钥。

- 协商是可靠的:任何攻击者都不能在不被通信双方检测到的情况下修改协商通信。

TLS 的优势之一是它独立于应用程序协议。更高级别的协议可以透明地叠加在 TLS 协议之上。然而,TLS 标准并没有指定协议如何通过 TLS 增加安全性;关于如何启动 TLS 握手以及如何解释交换的身份验证证书的决定留给了运行在 TLS 之上的协议的设计者和实现者的判断。

1.1 需求术语(略)

1.2.与 TLS 1.1 的主要区别

本文档是 TLS1.1 [TLS1.1] 协议的修订版,其中包含改进的灵活性,特别是对于加密算法的协商,密码学算法。主要的变化是:
- 伪随机函数 (PRF) 中的 MD5/SHA-1 组合已替换为密码套件指定的 PRF。本文档中的所有密码套件都使用 P_SHA256。
- 数字签名元素中的 MD5/SHA-1 组合已替换为单个哈希。签名元素现在包含一个明确指定使用的哈希算法的字段。
- 对客户端和服务器指定他们将接受哪些散列和签名算法的能力进行大量清理。请注意,这也放宽了先前版本的 TLS 对签名和哈希算法的一些限制。
- 增加了对具有附加数据模式的认证加密的支持。
- TLS 扩展定义和 AES 密码套件从外部 [TLSEXT] 和 [TLSAES] 合并。
- 更严格地检查 EncryptedPreMasterSecret 版本号。
- 收紧了多项要求。
- verify_data 长度现在取决于密码套件(默认仍然是 12)。
- 清理了 Bleichenbacher/Klima 攻击防御的描述。
- 在许多情况下,必须当下发送警报。
- 在certificate_request 之后,如果没有可用的证书,客户端现在必须发送一个空的证书列表。
- TLS_RSA_WITH_AES_128_CBC_SHA 现在是实现密码套件的必备条件。
- 添加了 HMAC-SHA256 密码套件。
- 删除了 IDEA 和 DES 密码套件。它们现在已被弃用,并将在单独的文档中记录。
- 对 SSLv2 向后兼容的 hello 的支持现在是 MAY,而不是 SHOULD,向它发送 SHOULD NOT。支持将来可能会变成不应该。
- 向演示语言添加了有限的“失败”,以允许多个外壳臂具有相同的编码。
- 添加了实施陷阱部分
- 通常的澄清和编辑工作。

2. 目标

TLS 协议的目标按优先级顺序如下:
1. 密码安全性:应该使用 TLS 来建立两方之间的安全连接。
2. 互操作性:独立程序员应该能够开发利用 TLS 的应用程序,这些应用程序可以在不了解彼此代码的情况下成功交换加密参数。
3. 可扩展性:TLS 寻求提供一个框架,可以根据需要将新的公钥和批量加密方法合并到其中。这也将实现两个子目标:防止需要创建新协议(并冒着引入可能的新弱点的风险)和避免需要实施全新的安全库。
4. 相对效率:加密操作往往是高度 CPU 密集型的,尤其是公钥操作。为此,TLS 协议包含了一个可选的会话
缓存方案以减少需要从头开始建立的连接数。此外,还注意减少网络活动。

3. 本文的目标

本文档和 TLS 协议本身基于 Netscape 发布的 SSL 3.0 协议规范。此协议与 SSL 3.0 之间的差异并不显着,但它们足够重要,以至于 TLS 和 SSL 3.0 的各种版本无法互操作(尽管每个协议都包含一种机制,通过该机制,实现可以回退到以前的版本)。本文档主要面向将要实施该协议的读者以及对其进行加密分析的读者。编写规范时考虑到了这一点,旨在反映这两个群体的需求。出于这个原因,许多与算法相关的数据结构和规则都包含在正文中(而不是在附录中)【此处代码部分较多,进行缩译】,以便于访问它们。

本文档不打算提供服务定义或接口定义的任何细节,尽管它确实涵盖了某些策略领域,因为它们是维护可靠安全性所必需的。

4. 演示语言

本文档处理外部表示中的数据格式。 将使用以下非常基本且有点随意定义的表示语法。 语法在其结构中来自多个来源。 尽管它在语法上类似于编程语言“C”,在语法和意图上类似于 XDR [XDR],但绘制太多相似之处是有风险的。 这种表示语言的目的只是为了记录 TLS; 没有超出该特定目标的一般应用。

4.1. 基本块大小

明确指定了所有数据项的表示。 基本数据块大小为 1 个字节(即 8 位)。 多字节数据项是字节的串联,从左到右,从上到下。 从字节流中,一个多字节项(示例中的数字)由以下方式形成(使用 C 符号):

这种多字节值的字节顺序是常见的网络字节顺序或大端格式。

4.2. Miscellaneous

注释以“/*”开头,以“*/”结尾。
可选组件通过将它们括在“[[ ]]”双括号中来表示。

包含未解释数据的单字节实体属于不透明类型。

4.3. 向量

向量(单维数组)是同构数据元素的流。 向量的大小可以在文档时指定,也可以在运行时未指定。 在任何一种情况下,长度都声明了向量中的字节数,而不是元素数。 指定新类型 T'(即 T 类型的固定长度向量)的语法是

这里,T'在数据流中占据n个字节,其中n是T大小的倍数。向量的长度不包含在编码流中。

在下面的例子中,Datum被定义为协议不解释的三个连续字节,而Data是三个连续的Datum,总共消耗九个字节。

可变长度向量是通过使用符号 <floor..ceiling> 指定合法长度的子范围来定义的。 当这些被编码时,实际长度在字节流中向量的内容之前。 长度将采用数字的形式,消耗尽可能多的字节以保持向量的指定最大(上限)长度。 实际长度字段为零的可变长度向量称为空向量。

在以下示例中,mandatory 是一个必须包含 300 到 400 个字节的 opaque 类型的向量。 它永远不能是空的。
实际长度字段占用两个字节,一个 uint16,足以表示值 400(参见第 4.4 节)。 另一方面,longer 可以表示最多 800 个字节的数据,或 400 个 uint16 元素,并且可能为空。 它的编码将包括一个预先添加到向量的两字节实际长度字段。 编码向量的长度必须是单个元素长度的偶数倍(例如,uint16 的 17 字节向量将是非法的)。

4.4. 数字

基本数字数据类型是无符号字节 (uint8)。所有较大的数字数据类型都由固定长度的字节序列组成,如第 4.1 节所述,并且也是无符号的。以下数字类型是预定义的。

规范中这里和其他地方的所有值都以网络字节(大端)顺序存储;由十六进制字节 01 02 03 04 表示的 uint32 等效于十进制值 16909060。

请注意,在某些情况下(例如,DH 参数)需要将整数表示为不透明向量。在这种情况下,它们被表示为无符号整数(即,即使设置了最高有效位,也不需要前导零八位字节)。

4.5. 枚举

另一种稀疏数据类型称为枚举。枚举类型的字段只能采用定义中声明的值。
每个定义都是不同的类型。只能分配或比较相同类型的枚举。枚举的每个元素都必须分配一个值,如以下示例所示。
由于枚举的元素没有排序,因此可以按任何顺序为它们分配任何唯一值。

枚举在字节流中占据的空间与其最大定义的序数值一样多。以下定义将导致使用一个字节来承载颜色类型的字段。
枚举 { 红色(3),蓝色(5),白色(7)} 颜色;
可以选择指定一个没有关联标签的值来强制定义宽度而不定义多余的元素。

在以下示例中,Taste 将消耗数据流中的两个字节,但只能假定值 1、2 或 4。
枚举 { 甜(1),酸(2),苦(4),(32000)} 味道;
枚举元素的名称在定义的类型范围内。在第一个示例中,对枚举的第二个元素的完全限定引用将是 Color.blue。如果任务的目标明确指定,则不需要此类资格。

颜色颜色 = Color.blue; /* 过度指定,合法 */
      颜色颜色=蓝色; /* 正确,类型隐式 */

对于从未转换为外部表示的枚举,可以省略数字信息。

枚举{低,中,高}数量;

4.6.构造类型

为方便起见,可以从原始类型构造结构类型。每个规范都声明了一个新的、唯一的类型。定义的语法很像 C 的语法。

结构中的字段可以使用类型的名称进行限定,其语法与可用于枚举的语法非常相似。 例如,T.f2 指的是前面声明的第二个字段。 可以嵌入结构定义。

此处省略(代码请详见原文)

5. HMAC 和伪随机函数

TLS 记录层使用密钥消息身份验证代码 (MAC) 来保护消息完整性。本文档中定义的密码套件使用称为 HMAC 的结构,在 [HMAC] 中进行了描述,该结构基于散列函数。如果需要,其他密码套件可以定义它们自己的 MAC 结构。

此外,为了密钥生成或验证的目的,需要一种结构来将密钥扩展为数据块。
这个伪随机函数 (PRF) 将密钥、种子和识别标签作为输入,并产生任意长度的输出。

在本节中,我们定义了一个基于 HMAC 的 PRF。当协商 TLS 1.2 时,此具有 SHA-256 散列函数的 PRF 用于本文档和本文档之前发布的 TLS 文档中定义的所有密码套件。新的密码套件必须明确指定一个 PRF,并且通常应该使用带有 SHA-256 或更强大的标准哈希函数的 TLS PRF。

首先,我们定义了一个数据扩展函数 P_hash(secret, data),它使用单个散列函数将秘密和种子扩展为任意数量的输出:

P_hash(secret, seed) = HMAC_hash(secret, A(1) + seed) + HMAC_hash(secret, A(2) + seed) + HMAC_hash(secret, A(3) + seed) + ...

其中 + 表示串联。

A() 定义为:
      A(0) = 种子
      A(i) = HMAC_hash(secret, A(i-1))

P_hash 可以根据需要迭代多次,以产生所需数量的数据。例如,如果使用 P_SHA256 创建 80 字节的数据,则必须迭代 3 次(通过 A(3)),创建 96 字节的输出数据;最终迭代的最后 16 个字节将被丢弃,留下 80 个字节的输出数据。

TLS 的 PRF 是通过将 P_hash 应用于秘密来创建的:
PRF(秘密,标签,种子)= P_<hash>(秘密,标签+种子)

标签是一个 ASCII 字符串。它应该以给出的确切形式包含,没有长度字节或尾随空字符。
例如,标签“slithy toves”将通过散列以下字节来处理:

73 6C 69 74 68 79 20 74 6F 76 65 73

6. TLS 记录协议

TLS 记录协议是一个分层协议。在每一层,消息可能包括长度、描述和内容字段。记录协议接收要传输的消息,将数据分段为可管理的块,可选地压缩数据,应用 MAC,加密并传输结果。接收到的数据经过解密、验证、解压缩、重组,然后传送到更高级别的客户端。

本文档描述了四种使用记录协议的协议:握手协议、警报协议、更改密码规范协议和应用程序数据协议。为了允许 TLS 协议的扩展,记录协议可以支持额外的记录内容类型。如第 12 节所述,新记录内容类型值由 IANA 在 TLS 内容类型注册表中分配。

除非由某些扩展协商,否则实现不得发送本文档中未定义的记录类型。如果 TLS 实现接收到意外的记录类型,它必须发送一个unexpected_message 警报。

任何设计用于 TLS 的协议都必须经过精心设计,以应对针对它的所有可能的攻击。实际上,这意味着协议设计者必须了解 TLS 提供和不提供哪些安全属性,并且不能安全地依赖后者。

请特别注意,记录的类型和长度不受加密保护。如果此信息本身很敏感,应用程序设计人员可能希望采取措施(填充、覆盖流量)以最大程度地减少信息泄漏。

6.1.连接状态

TLS 连接状态是 TLS 记录协议的运行环境。它指定了压缩算法、加密算法和 MAC 算法。此外,这些算法的参数是已知的:MAC 密钥和用于在读取和写入方向上的连接的批量加密密钥。
从逻辑上讲,始终有四种未完成的连接状态:当前的读写状态和待处理的读写状态。所有记录都在当前读写状态下进行处理。挂起状态的安全参数可以由 TLS 握手协议设置,ChangeCipherSpec 可以选择性地使任一挂起状态成为当前状态,在这种情况下,适当的当前状态被处理并替换为挂起状态;然后挂起状态被重新初始化为空状态。将尚未使用安全参数初始化的状态设为当前状态是非法的。初始当前状态始终指定不使用加密、压缩或 MAC。

通过提供以下值来设置 TLS 连接读写状态的安全参数:

连接端
      在此连接中,该实体是被视为“客户端”还是“服务器”。

PRF算法
      一种用于从主密钥生成密钥的算法(参见第 5 节和第 6.3 节)。

批量加密算法
      用于批量加密的算法。该规范包括该算法的密钥大小,无论是块、流还是 AEAD 密码,密码的块大小(如果适用),以及显式和隐式初始化向量(或随机数)的长度。

MAC算法
      用于消息认证的算法。该规范包括 MAC 算法返回值的大小。

压缩算法
      一种用于数据压缩的算法。该规范必须包括算法进行压缩所需的所有信息。

主密钥
      在连接中的两个对等方之间共享的 48 字节机密。

客户端随机
      客户端提供的 32 字节值。

服务器端随机
      服务器提供的 32 字节值。

记录层将使用安全参数生成以下六项(其中一些不是所有密码都需要的,因此为空):

客户端写入 MAC 密钥
      服务器写入 MAC 密钥
      客户端写入加密密钥
      服务器写入加密密钥
      客户端写IV
      服务器写IV

服务器在接收和处理记录时使用客户端写入参数,反之亦然。用于从安全参数生成这些项目的算法在第 6.3 节中描述。

一旦设置了安全参数并生成了密钥,就可以通过使它们成为当前状态来实例化连接状态。必须为每个处理的记录更新这些当前状态。每个连接状态包括以下元素:

压缩状态
      压缩算法的当前状态。

密码状态
      加密算法的当前状态。这将由该连接的预定密钥组成。对于流密码,这还将包含允许流继续加密或解密数据所需的任何状态信息。

MAC密钥
      此连接的 MAC 密钥,如上生成。

序列号
      每个连接状态都包含一个序列号,对于读取和写入状态分别维护。每当连接状态变为活动状态时,序列号必须设置为零。序列号是 uint64 类型,不能超过 2^64-1。序列号不换行。如果一个 TLS
实现需要包装一个序列号,它必须重新协商。每条记录后都会增加一个序列号:具体来说,在特定连接状态下传输的第一个记录必须使用序列号 0。

6.2. 记录层

TLS 记录层从任意大小的非空块中的更高层接收未解释的数据。

6.2.1.分片

记录层将信息块分段为 TLSPlaintext 记录,以 2^14 字节或更少的块为单位承载数据。客户端消息边界不保留在记录层中(即,相同 ContentType 的多个客户端消息可以合并为单个 TLSPlaintext 记录,或者单个消息可以跨多个记录分段)。

类型
      用于处理封闭片段的高级协议。

版本
      正在使用的协议版本。本文档描述了 TLS 版本 1.2,它使用版本 { 3, 3 }。版本值 3.3 是历史的,源自对 TLS 1.0 的 {3, 1} 的使用。 (请参阅附录 A.1。)请注意,支持多个 TLS 版本的客户端在收到 ServerHello 之前可能不知道将使用哪个版本。有关 ClientHello 应采用哪个记录层版本号的讨论,请参见附录 E。

长度
      以下 TLSPlaintext.fragment 的长度(以字节为单位)。长度不得超过 2^14。

分段
      应用数据。该数据是透明的,并被视为一个独立的块,由类型字段指定的更高级别的协议处理。

实现不得发送 Handshake、Alert 或 ChangeCipherSpec 内容类型的零长度片段。可以发送应用程序数据的零长度片段,因为它们可能用作流量分析对策。

注意:不同 TLS 记录层内容类型的数据可以交错。与其他内容类型相比,应用程序数据的传输优先级通常较低。但是,记录必须以与记录层保护的顺序相同的顺序传送到网络。接收者必须在连接上的第一个握手之后的握手期间接收和处理交错的应用层流量。

6.2.2.记录压缩和解压

所有记录都使用当前会话状态中定义的压缩算法进行压缩。总有一种主动压缩算法;但是,最初它被定义为 CompressionMethod.null。压缩算法将 TLSPlaintext 结构转换为 TLSCompressed 结构。每当连接状态处于活动状态时,压缩函数都会使用默认状态信息进行初始化。 [RFC3749] 描述了 TLS 的压缩算法。

压缩必须是无损的,并且增加的内容长度不得超过 1024 字节。如果解压函数遇到 TLSCompressed.fragment 会解压到长度超过
2^14 字节,它必须报告一个致命的解压失败错误。

长度
       以下 TLSCompressed.fragment 的长度(以字节为单位)。 长度不得超过 2^14 + 1024。

分段
       TLSPlaintext.fragment 的压缩形式。
       注意:CompressionMethod.null 操作是标识操作; 没有字段被改变。
       实现说明:解压函数负责确保消息不会导致内部缓冲区溢出。

6.2.3. 记录有效负载保护

加密和 MAC 函数将 TLSCompressed 结构转换为 TLSCiphertext。 解密函数逆转了这个过程。 记录的 MAC 还包括一个序列号,以便可以检测到丢失、额外或重复的消息。

类型
       type 字段与 TLSCompressed.type 相同。

版本
       version 字段与 TLSCompressed.version 相同。

长度
       以下 TLSCiphertext.fragment 的长度(以字节为单位)。 长度不得超过 2^14 + 2048。

分段
       TLSCompressed.fragment 的加密形式,带有 MAC。

6.2.3.1. 空或标准流密码

流密码(包括 BulkCipherAlgorithm.null;见附录 A.6)
将 TLSCompressed.fragment 结构与流 TLSCiphertext.fragment 结构相互转换。

序列号
       此记录的序列号。
MAC
       SecurityParameters.mac_algorithm 指定的 MAC 算法。

请注意,MAC 是在加密之前计算的。 流密码加密整个块,包括 MAC。 对于不使用同步向量的流密码(例如 RC4),来自一条记录末尾的流密码状态仅用于后续数据包。 如果密码套件是 TLS_NULL_WITH_NULL_NULL,则加密由身份操作组成(即,数据未加密,MAC 大小为零,这意味着未使用 MAC)。
对于空密码和流密码,TLSCiphertext.length 是 TLSCompressed.length 加上 SecurityParameters.mac_length。

6.2.3.2. CBC 块密码

对于块密码(例如 3DES 或 AES),加密和 MAC 函数将 TLSCompressed.fragment 结构与块 TLSCiphertext.fragment 结构相互转换。

MAC 的生成如第 6.2.3.1 节所述。

初始化向量
      初始化向量 (IV) 应该随机选择,并且必须是不可预测的。请注意,在 1.1 之前的 TLS 版本中,没有初始化向量字段,并且使用前一条记录的最后一个密文块(“CBC 残基”)作为 IV。这已被更改以防止 [CBCATT] 中描述的攻击。对于分组密码,IV 长度的长度为 SecurityParameters.record_iv_length,等于 SecurityParameters.block_size。

填充
      添加的填充以强制明文的长度为块密码块长度的整数倍。填充可以是最多 255 个字节的任何长度,只要它导致 TLSCiphertext.length 是块长度的整数倍。可能需要比必要的长度更长的长度来阻止对基于交换消息长度分析的协议的攻击。填充数据向量中的每个 uint8 必须填充填充长度值。接收者必须检查这个填充并且必须使用 bad_record_mac 警报来指示填充错误。

填充长度
      填充长度必须使得 GenericBlockCipher 结构的总大小是密码块长度的倍数。合法值的范围是从 0 到 255(含)。该长度指定了不包括 padding_length 字段本身的填充字段的长度。

加密数据长度(TLSCiphertext.length)比SecurityParameters.block_length、TLSCompressed.length、SecurityParameters.mac_length和padding_length之和大1。

示例:如果块长度为 8 字节,内容长度(TLSCompressed.length)为 61 字节,MAC 长度为 20 字节,则填充前的长度为 82 字节(这不包括 IV。因此,填充length modulo 8 必须等于 6 才能使总长度是 8 字节(块长度)的偶数倍。填充长度可以是 6、14、22 等,到 254。如果填充长度是必要的最小值 6,填充将是 6 个字节,每个字节包含值 6。因此,块加密之前 GenericBlockCipher 的最后 8 个八位字节将是 xx 06 06 06 06 06 06 06,其中 xx 是最后一个八位字节MAC。

注意:对于 CBC 模式下的分组密码(密码分组链接),在传输任何密文之前知道记录的整个明文是至关重要的。否则,攻击者有可能发起 [CBCATT] 中描述的攻击。

实施说明:Canvel 等。 [CBCTIME] 已经展示了基于计算 MAC 所需时间对 CBC 填充的定时攻击。为了防御这种攻击,实现必须确保记录处理时间本质上是相同的,无论填充是否正确。一般来说,最好的方法是即使填充不正确也计算 MAC,然后才拒绝数据包。例如,如果填充看起来不正确,则实现可能会假设填充长度为零,然后计算 MAC。这留下了一个小的时序信道,因为 MAC 性能在某种程度上取决于数据片段的大小,但由于现有 MAC 的块大小很大,并且定时信号。

6.2.3.3. AEAD 密码

对于 AEAD [AEAD] 密码(例如 [CCM] 或 [GCM]),AEAD 函数将 TLSCompressed.fragment 结构与 AEAD TLSCiphertext.fragment 结构相互转换。

AEAD 密码将单个密钥、随机数、明文和“附加数据”作为输入,以包含在身份验证检查中,如 [AEAD] 的第 2.1 节所述。密钥是 client_write_key 或 server_write_key。不使用 MAC 密钥。

每个 AEAD 密码套件必须指定提供给 AEAD 操作的随机数是如何构造的,以及 GenericAEADCipher.nonce_explicit 部分的长度是多少。在许多情况下,使用 [AEAD] 的第 3.2.1 节中描述的部分隐式随机数技术是合适的; record_iv_length 是显式部分的长度。在这种情况下,隐式部分应该从 key_block 派生为 client_write_iv 和 server_write_iv(如第 6.3 节所述),显式部分包含在 GenericAEAEDCipher.nonce_explicit 中。

明文是 TLSCompressed.fragment。
额外的认证数据,我们表示为 additional_data,定义如下:

additional_data = seq_num + TLSCompressed.type + TLSCompressed.version + TLSCompressed.length;

其中“+”表示连接。

aead_output 由 AEAD 加密操作输出的密文组成。长度通常会大于 TLSCompressed.length,但大小随 AEAD 密码而变化。由于密码可能包含填充,因此开销量可能会随不同的 TLSCompressed.length 值而变化。每个 AEAD 密码不得产生大于 1024 字节的扩展。
象征性地,

AEADEncrypted = AEAD-Encrypt(write_key, nonce, plaintext, additional_data)

为了解密和验证,密码将密钥、nonce、“additional_data”和 AEADEncrypted 值作为输入。输出是明文或指示解密失败的错误。没有单独的完整性检查。那是:

TLSCompressed.fragment = AEAD-Decrypt(write_key, nonce, AEADEncrypted, additional_data)

如果解密失败,则必须生成致命的 bad_record_mac 警报。

6.3.密钥计算

记录协议需要一种算法来根据握手协议提供的安全参数生成当前连接状态(见附录 A.6)所需的密钥。

主密钥被扩展为一系列安全字节,然后拆分为客户端写入 MAC 密钥、服务器写入 MAC 密钥、客户端写入加密密钥和服务器写入加密密钥。这些中的每一个都是按照该顺序从字节序列生成的。未使用的值为空。一些 AEAD 密码可能另外需要客户端写入 向量(IV)和服务器写入向量(IV)(参见第 6.2.3.3 节)。

生成密钥和 MAC 密钥时,主密钥用作熵源。

要生成密钥材料,请计算

key_block = PRF(SecurityParameters.master_secret,
                      “密钥扩展”,
                      SecurityParameters.server_random + SecurityParameters.client_random);

直到产生足够的输出。然后,key_block 分区如下:
  client_write_MAC_key[SecurityParameters.mac_key_length] server_write_MAC_key[SecurityParameters.mac_key_length] client_write_key[SecurityParameters.enc_key_length] server_write_key[SecurityParameters.enc_key_length] client_write_IV[SecurityParameters.fixed_iv_length] server_write_IV[Security_Parameters.fixedlength]
目前,client_write_IV 和 server_write_IV 仅针对隐式随机数技术生成,如 [AEAD] 的第 3.2.1 节中所述。

实现说明:目前定义的需要最多材料的密码套件是AES_256_CBC_SHA256。它需要 2 x 32 字节密钥和 2 x 32 字节 MAC 密钥,总共 128 字节的密钥材料。

7. TLS 握手协议

TLS 具有三个子协议,用于允许对等方就记录层的安全参数达成一致、对自己进行身份验证、实例化协商的安全参数以及向彼此报告错误情况。

握手协议负责协商一个会话,它由以下几项组成:

会话标识符
      服务器选择的任意字节序列,用于标识活动或可恢复的会话状态。

对等证书
      对等方的 X509v3 [PKIX] 证书。该状态元素可能为空。

压缩方式
      用于在加密之前压缩数据的算法。

密码规范
      指定用于生成密钥材料的伪随机函数 (PRF)、批量数据加密算法(如 null、AES 等)和 MAC 算法(如 HMAC-SHA1)。它还定义了加密属性,例如 mac_length。 (正式定义见附录 A.6。)

掌握秘密
      客户端和服务器之间共享的 48 字节机密。

可恢复的
      指示会话是否可用于启动新连接的标志。

然后,这些项目用于创建安全参数,供记录层在保护应用程序数据时使用。通过 TLS 握手协议的恢复功能,可以使用同一个会话实例化许多连接。

7.1.更改密码规范协议

更改密码规范协议的存在是为了指示加密策略中的转换。该协议由单个消息组成,该消息在当前(非挂起)连接状态下被加密和压缩。该消息由值为 1 的单个字节组成。

结构{
          枚举 { change_cipher_spec(1), (255) } 类型;
      更改密码规范;

ChangeCipherSpec 消息由客户端和服务器发送,以通知接收方后续记录将受到新协商的 CipherSpec 和密钥的保护。该消息的接收导致接收器指示记录层立即将读取未决状态复制到读取当前状态。
发送此消息后,发送方必须立即指示记录层将写挂起状态设为写活动状态。
(参见第 6.1 节。) ChangeCipherSpec 消息在安全参数达成一致之后的握手期间发送,但在发送验证完成消息之前。

注意:如果数据在连接上流动时发生重新握手,通信方可能会继续使用旧的 CipherSpec 发送数据。然而,一旦发送了 ChangeCipherSpec,必须使用新的 CipherSpec。发送 ChangeCipherSpec 的第一方不知道另一方已经完成了新密钥材料的计算(例如,如果它必须执行耗时的公钥操作)。因此,可能存在一小段时间窗口,在此期间接收方必须缓冲数据。实际上,对于现代机器,这个间隔可能相当短。

7.2.警报协议

TLS 记录层支持的一种内容类型是警报类型。警报消息传达消息的严重性(警告或致命)和警报的描述。具有致命级别的警报消息会导致立即终止连接。在这种情况下,会话对应的其他连接可以继续,但会话标识符必须无效,防止失败的会话被用于建立新的连接。与其他消息一样,警报消息按照当前连接状态的规定进行加密和压缩。

7.2.1.关闭警报

客户端和服务器必须共享连接正在结束的知识,以避免截断攻击。任何一方都可以发起关闭消息的交换。

关闭通知
      此消息通知收件人,发件人将不再在此连接上发送任何消息。请注意,从 TLS 1.1 开始,无法正确关闭连接不再需要不恢复会话。这是对 TLS 1.0 的更改,以符合广泛的实现实践。

任何一方都可以通过发送 close_notify 警报来启动关闭。关闭警报后收到的任何数据都将被忽略。

除非传输了其他一些致命警报,否则每一方都需要在关闭连接的写入端之前发送 close_notify 警报。另一方必须用自己的 close_notify 警报响应并立即关闭连接,丢弃任何挂起的写入。在关闭连接的读取端之前,关闭的发起者不需要等待响应的 close_notify 警报。

如果使用 TLS 的应用程序协议规定在 TLS 连接关闭后可以通过底层传输传输任何数据,则 TLS 实现必须在向应用程序层指示 TLS 连接已结束之前收到响应的 close_notify 警报。如果应用协议不会传输任何额外的数据,而只会关闭底层传输连接,那么实现可以选择关闭传输而不等待响应的 close_notify。本标准的任何部分都不应被用来规定 TLS 的使用配置文件管理其数据传输的方式,包括何时打开或关闭连接。
注意:假设在破坏传输之前关闭连接可靠地传送挂起的数据。

7.2.2.错误警报

TLS 握手协议中的错误处理非常简单。当检测到错误时,检测方向另一方发送消息。在传输或接收到致命警报消息后,双方立即关闭连接。服务器和客户端必须忘记与失败连接相关的任何会话标识符、密钥和秘密。因此,任何以致命警报终止的连接不得恢复。

每当实现遇到定义为致命警报的情况时,它必须在关闭连接之前发送适当的警报。对于未明确指定警报级别的所有错误,发送方可以自行决定是否将其视为致命错误。如果实现选择发送警报但打算在之后立即关闭连接,则它必须以致命警报级别发送该警报。

如果发送和接收到具有警告级别的警报,通常连接可以继续正常进行。如果接收方决定不继续连接(例如,在收到它不愿意接受的 no_renegotiation 警报之后),它应该发送一个致命警报来终止连接。鉴于此,发送方通常无法知道接收方的行为。因此,当发送方想要继续连接时,警告警报不是很有用,因此有时会被省略。例如,如果对等方决定接受过期的证书(可能在与用户确认后)并希望继续连接,则它通常不会发送 certificate_expired 警报。

定义了以下错误警报:
意外消息
      收到一条不适当的消息。此警报始终是致命的,不应在正确实现之间的通信中观察到。

bad_record_mac
      如果接收到 MAC 不正确的记录,则会返回此警报。如果由于 TLSCiphertext 以无效方式解密而发送警报,则也必须返回此警报:它不是块长度的偶数倍,或者其填充值在检查时不正确。此消息始终是致命的,在正确实现之间的通信中永远不应观察到(除非消息在网络中损坏)。

解密_失败_保留
      此警报用于某些早期版本的 TLS,并且可能允许对 CBC 模式 [CBCATT] 进行某些攻击。它不得由兼容的实现发送。

记录溢出
      接收到长度超过 2^14+2048 字节的 TLSCiphertext 记录,或被解密为超过 2^14+1024 字节的 TLSCompressed 记录的记录。此消息始终是致命的,在正确实现之间的通信中永远不应观察到(除非消息在网络中损坏)。

解压_失败
      解压函数接收到不正确的输入(例如,会扩展到过长的数据)。此消息始终是致命的,不应在正确实现之间的通信中观察到。

握手失败
      收到handshake_failure 警报消息表明发送方无法协商一组可接受的安全参数给定可用选项。这是一个致命的错误。

no_certificate_RESERVED
      此警报用于 SSLv3,但未用于任何版本的 TLS。它不得由兼容的实现发送。

坏证书
      证书已损坏,包含未正确验证的签名等。

unsupported_certificate
      证书的类型不受支持。

证书_撤销
      证书已被其签名者吊销。

证书_过期
      证书已过期或当前无效。

证书_未知
      处理证书时出现了其他一些(未指明的)问题,使其无法接受。

非法参数
      握手中的字段超出范围或与其他字段不一致。此消息始终是致命的。

未知_ca
      收到了有效的证书链或部分链,但证书未被接受,因为无法找到 CA 证书或无法与已知的受信任 CA 匹配。此消息始终是致命的。

拒绝访问
      收到了有效的证书,但在应用访问控制时,发件人决定不继续协商。此消息始终是致命的。

解码错误
      无法对消息进行解码,因为某些字段超出了指定范围或消息长度不正确。此消息始终是致命的,在正确实现之间的通信中永远不应观察到(除非消息在网络中损坏)。

解密错误
      握手加密操作失败,包括无法正确验证签名或验证 Finished 消息。
此消息始终是致命的。

export_restriction_RESERVED
      此警报用于某些早期版本的 TLS。它不得由兼容的实现发送。

协议版本
      客户端尝试协商的协议版本被识别但不受支持。 (例如,出于安全原因,可能会避免使用旧的协议版本。)此消息始终是致命的。

安全性不足
      当协商失败时返回而不是 handshake_failure 特别是因为服务器需要比客户端支持的密码更安全的密码。此消息始终是致命的。

内部错误
      与对端或协议正确性无关的内部错误(例如内存分配失败)导致无法继续。此消息始终是致命的。

用户_取消
      由于与协议失败无关的某种原因,此握手被取消。如果用户在握手完成后取消一个操作,那么直接通过发送 close_notify 来关闭连接更合适。此警报之后应紧跟 close_notify。此消息通常是警告。

不重新谈判
      由客户端发送以响应 hello 请求或由服务器在初始握手后响应客户端 hello 发送。这些中的任何一个通常都会导致重新谈判;当这不合适时,接收者应响应此警报。此时,原始请求者可以决定是否继续进行连接。一种合适的情况是服务器产生了一个进程来满足请求;该进程可能会在启动时接收安全参数(密钥长度、身份验证等),并且在此之后可能难以传达对这些参数的更改。此消息始终是一个警告。

unsupported_extension
      由接收扩展服务器问候的客户端发送,其中包含他们没有放入相应客户端问候的扩展。此消息始终是致命的。

新警报值由 IANA 分配,如第 12 节所述。

7.3.握手协议概述

会话状态的加密参数由 TLS 握手协议生成,该协议在 TLS 记录层之上运行。当 TLS 客户端和服务器第一次开始通信时,他们就协议版本达成一致,选择加密算法,可选地相互验证,并使用公钥加密技术生成共享秘密。

TLS 握手协议包括以下步骤:

- 交换 hello 消息以就算法达成一致、交换随机值并检查会话恢复。

- 交换必要的加密参数以允许客户端和服务器就预主密钥达成一致。

- 交换证书和加密信息以允许客户端和服务器进行身份验证。

- 从预主密码生成主密码并交换随机值。

- 向记录层提供安全参数。

- 允许客户端和服务器验证他们的对等方是否计算了相同的安全参数,并且握手没有被攻击者篡改。

请注意,高层不应过度依赖 TLS 是否总是在两个对等方之间协商最强的连接。中间人攻击者可以通过多种方式尝试使两个实体下降到它们支持的最不安全的方法。该协议旨在最大限度地减少这种风险,但仍然存在可用的攻击:例如,攻击者可以阻止对运行安全服务的端口的访问,或试图让对等方协商未经身份验证的连接。基本规则是更高级别必须意识到他们的安全要求是什么,并且永远不要通过比他们要求的安全性低的渠道传输信息。 TLS 协议是安全的,因为任何密码套件都提供了其承诺的安全级别:如果您通过 1024 位 RSA 密钥交换与已验证其证书的主机协商 3DES,您可以期望是安全的。

这些目标都是通过握手协议来实现的,可以总结如下:客户端发送ClientHello消息,服务器必须响应ServerHello消息,否则会发生致命错误,连接失败。 ClientHello 和 ServerHello 用于在客户端和服务器之间建立安全增强功能。 ClientHello 和 ServerHello 建立以下属性:协议版本、会话 ID、密码套件和压缩方法。此外,还会生成和交换两个随机值:ClientHello.random 和 ServerHello.random。

实际的密钥交换最多使用四个消息:服务器证书、ServerKeyExchange、客户端证书和 ClientKeyExchange。可以通过为这些消息指定格式并通过定义消息的使用来允许客户端和服务器就共享秘密达成一致来创建新的密钥交换方法。这个秘密一定很长;当前定义的密钥交换方法交换范围从 46 字节以上的秘密。

在 hello 消息之后,如果要进行身份验证,服务器将在证书消息中发送其证书。此外,如果需要(例如,如果服务器没有证书,或者其证书仅用于签名),可以发送 ServerKeyExchange 消息。如果服务器通过身份验证,它可能会从客户端请求证书,如果这适合所选的密码套件。接下来服务端会发送ServerHelloDone消息,表示握手的hello-message阶段完成。然后服务器将等待客户端响应。如果服务器发送了 CertificateRequest 消息,客户端必须发送证书消息。现在发送 ClientKeyExchange 消息,该消息的内容将取决于在 ClientHello 和 ServerHello 之间选择的公钥算法。如果客户端发送了具有签名能力的证书,则发送数字签名的 CertificateVerify 消息以明确验证证书中私钥的拥有情况。

此时,客户端发送ChangeCipherSpec消息,客户端将挂起的Cipher Spec复制到当前Cipher Spec中。然后,客户端立即根据新算法、密钥和秘密发送 Finished 消息。作为响应,服务器将发送自己的 ChangeCipherSpec 消息,将待处理的消息转移到当前的密码规范,并在新的密码规范下发送其已完成的消息。至此,握手完成,客户端和服务器可以开始交换应用层数据。 (参见下面的流程图。)在第一次握手完成之前(在建立 TLS_NULL_WITH_NULL_NULL 以外的密码套件之前)不得发送应用程序数据。

* 表示不总是发送的可选或视情况而定的消息。
注意:为了帮助避免管道停顿,ChangeCipherSpec 是一种独立的 TLS 协议内容类型,实际上并不是 TLS 握手消息。

当客户端和服务器决定恢复之前的会话或复制现有会话(而不是协商新的安全参数)时,消息流如下:

客户端使用要恢复的会话的会话 ID 发送 ClientHello。然后服务器检查其会话缓存是否匹配。如果找到匹配项,并且服务器愿意在指定的会话状态下重新建立连接,它将发送一个具有相同会话 ID 值的 ServerHello。此时,客户端和服务器都必须发送 ChangeCipherSpec 消息并直接处理 Finished 消息。一旦重建完成,客户端和服务器可以开始交换应用层数据。 (参见下面的流程图。)如果没有找到匹配的会话 ID,服务器会生成一个新的会话 ID,并且 TLS 客户端和服务器执行一次完整的握手。

每条消息的内容和意义将在以下各节中详细介绍。

7.4. 握手协议

TLS 握手协议是 TLS 记录协议定义的更高级别的客户端之一。 该协议用于协商会话的安全属性。 握手消息被提供给 TLS 记录层,在那里它们被封装在一个或多个 TLSPlaintext 结构中,这些结构按照当前活动会话状态的规定进行处理和传输。

握手协议消息按必须发送的顺序显示如下;以意外的顺序发送握手消息会导致致命错误。但是,可以省略不需要的握手消息。请注意排序的一个例外:证书消息在握手中使用了两次(从服务器到客户端,然后是从客户端到服务器),但仅在其第一个位置进行描述。一个不受这些排序规则约束的消息是 HelloRequest 消息,它可以随时发送,但如果它在握手过程中到达,客户端应该忽略它。

新的握手消息类型由 IANA 分配,如第 12 节所述。

7.4.1.Hello消息

hello 阶段消息用于在客户端和服务器之间交换安全增强功能。当新会话开始时,记录层的连接状态加密、散列和压缩算法被初始化为空。当前连接状态用于重新协商消息。

7.4.1.1.Hello请求

何时发送此消息:
      HelloRequest 消息可以由服务器随时发送。
此消息的含义:
      HelloRequest 是一个简单的通知,客户端应该重新开始协商过程。作为响应,客户端应该在方便时发送 ClientHello 消息。此消息不旨在确定哪一方是客户端或服务器,而只是发起新的协商。服务器不应该在客户端初始连接后立即发送 HelloRequest。此时发送 ClientHello 是客户端的工作。

如果客户端当前正在协商会话,则客户端将忽略此消息。如果客户端不希望重新协商会话,则该消息可以被客户端忽略,或者客户端可以(如果希望)以 no_renegotiation 警报响应。由于握手消息的传输优先于应用程序数据,因此预计协商将在从客户端接收到的记录不超过几条之前开始。如果服务器发送了 HelloRequest 但没有收到 ClientHello 作为响应,它可能会关闭连接并发出致命警报。

发送 HelloRequest 后,服务器不应重复该请求,直到后续的握手协商完成。

此消息不得包含在整个握手过程中维护的消息散列中,并用于 Finished 消息和证书验证消息中。

7.4.1.2. 客户端Hello

何时发送此消息:
       当客户端第一次连接到服务器时,需要发送 ClientHello 作为它的第一条消息。 客户端还可以发送 ClientHello 以响应 HelloRequest 或主动发送,以便重新协商现有连接中的安全参数。

此消息的结构:
       ClientHello 消息包含一个随机结构,稍后在协议中使用。

gmt_unix_time
         标准 UNIX 32 位格式的当前时间和日期(自 1970 年 1 月 1 日午夜开始的秒数,UTC,忽略闰秒)根据发送方的内部时钟。基本 TLS 协议不需要正确设置时钟;更高级别的或应用程序协议可以定义额外的要求。请注意,由于历史原因,数据元素使用 GMT(当前全球时基 UTC 的前身)命名。

随机字节
         由安全随机数生成器生成的 28 个字节。

ClientHello 消息包括一个可变长度的会话标识符。如果不为空,则该值标识客户端希望重用其安全参数的同一客户端和服务器之间的会话。会话标识符可以来自较早的连接、此连接或来自另一个当前活动的连接。如果客户端只希望更新连接的随机结构和派生值,则第二个选项很有用,第三个选项可以在不重复完整握手协议的情况下建立多个独立的安全连接。这些独立的连接可以依次或同时发生;当协商它的握手完成并交换完成消息时,SessionID 变得有效,并且一直持续到它由于老化或因为与会话相关的连接上遇到致命错误而被删除。 SessionID 的实际内容由服务器定义。

警告:因为 SessionID 是在没有加密或立即 MAC 保护的情况下传输的,服务器不得将机密信息放在会话标识符中,或者让虚假会话标识符的内容导致任何安全漏洞。 (注意整个握手的内容,包括 SessionID,都受到握手结束时交换的 Finished 消息的保护。)

在 ClientHello 消息中从客户端传递到服务器的密码套件列表包含客户端支持的加密算法的组合,按客户端的偏好排列(最喜欢的选择在前)。每个密码套件定义了一个密钥交换算法、一个批量加密算法(包括密钥长度)、一个 MAC 算法和一个 PRF。服务器将选择一个密码套件,或者,如果没有出现可接受的选择,则返回握手失败警报并关闭连接。如果列表包含服务器无法识别、支持或希望使用的密码套件,则服务器必须忽略这些密码套件,并照常处理其余的密码套件。

ClientHello 包含客户端支持的压缩算法列表,根据客户端的偏好排序。

TLS 允许扩展遵循扩展块中的 compression_methods 字段。可以通过判断ClientHello 末尾的compression_methods 后面是否有字节来检测extension 的存在。请注意,这种检测可选数据的方法与具有可变长度字段的普通 TLS 方法不同,但它用于在定义扩展之前与 TLS 兼容。

客户端版本
      客户端希望在此会话期间进行通信的 TLS 协议版本。这应该是客户端支持的最新(最高值)版本。对于此版本的规范,版本将为 3.3(有关向后兼容性的详细信息,请参阅附录 E)。

随机的
      客户端生成的随机结构。

session_id
      客户端希望用于此连接的会话 ID。
      如果没有可用的 session_id,或者客户端希望生成新的安全参数,则此字段为空。

密码套件
      这是客户端支持的加密选项列表,首先是客户端的第一个偏好。如果 session_id 字段不为空(暗示会话恢复请求),则该向量必须至少包括来自该会话的 cipher_suite。值在附录 A.5 中定义。

压缩方法
      这是客户端支持的压缩方法列表,按客户端首选项排序。如果 session_id 字段不为空(暗示会话恢复请求),则它必须包含来自该会话的压缩方法。该向量必须包含并且所有实现都必须支持 CompressionMethod.null。因此,客户端和服务器将始终能够就压缩方法达成一致。

扩展
      客户端可以通过在扩展字段中发送数据来从服务器请求扩展功能。实际的“扩展”格式在第 7.4.1.4 节中定义。

如果客户端使用扩展请求附加功能,而服务器未提供此功能,则客户端可以中止握手。服务器必须接受带有和不带有扩展字段的 ClientHello 消息,并且(对于所有其他消息)它必须检查消息中的数据量是否与这些格式之一精确匹配;如果没有,那么它必须发送一个致命的“decode_error”警报。

客户端发送 ClientHello 消息后,等待 ServerHello 消息。服务器返回的任何握手消息(HelloRequest 除外)都被视为致命错误。

7.4.1.3. 服务器端Hello

何时发送此消息:
       当它能够找到一组可接受的算法时,服务器将发送此消息以响应 ClientHello 消息。 如果它找不到这样的匹配项,它将响应握手失败警报。

此消息的结构:

可以通过判断ServerHello末尾的compression_method字段后面是否有字节来检测extensions的存在。

服务器版本
      此字段将包含客户端在客户端 hello 中建议的较低值和服务器支持的最高值。对于此版本的规范,版本为 3.3。 (有关向后兼容性的详细信息,请参阅附录 E。)

随机的
      此结构由服务器生成,并且必须独立于 ClientHello.random 生成。

session_id
      这是与此连接对应的会话的标识。如果 ClientHello.session_id 非空,服务器将在其会话缓存中查找匹配项。如果找到匹配项并且服务器愿意使用指定的会话状态建立新连接,则服务器将使用与客户端提供的值相同的值进行响应。这表示恢复会话并规定各方必须直接处理已完成的消息。否则,该字段将包含标识新会话的不同值。服务器可能会返回一个空的 session_id 以指示会话不会被缓存,因此无法恢复。如果恢复会话,则必须使用最初与之协商的相同密码套件恢复会话。请注意,即使服务器以前提供了 session_id,也不需要服务器恢复任何会话。客户端必须准备好在任何握手期间进行完整的协商——包括协商新的密码套件。

密码套件
      服务器从 ClientHello.cipher_suites 中的列表中选择的单个密码套件。对于恢复的会话,该字段是恢复会话状态的值。

压缩方法
      服务器从 ClientHello.compression_methods 中的列表中选择的单一压缩算法。对于恢复会话,此字段是恢复会话状态的值。

扩展
      扩展名列表。请注意,只有客户端提供的扩展才能出现在服务器列表中。

7.4.1.4. Hello扩展

扩展格式为:

初始扩展集在配套文档 [TLSEXT] 中定义。扩展类型列表由 IANA 维护,如第 12 节所述。

扩展类型不得出现在 ServerHello 中,除非相同的扩展类型出现在相应的 ClientHello 中。如果客户端在 ServerHello 中接收到它没有在关联的 ClientHello 中请求的扩展类型,它必须使用 unsupported_extension 致命警报中止握手。

尽管如此,未来可能会在此框架内提供“面向服务器”的扩展。这样的扩展(例如,类型为 x)将要求客户端首先在带有空 extension_data 的 ClientHello 中发送类型为 x 的扩展,以表明它支持扩展类型。在这种情况下,客户端提供了理解扩展类型的能力,而服务器则接受了客户端的提议。

当 ClientHello 或 ServerHello 消息中存在多个不同类型的扩展时,扩展可以按任何顺序出现。不得有多个相同类型的扩展。

最后,请注意,在开始新会话和请求恢复会话时都可以发送扩展。事实上,请求会话恢复的客户端通常不知道服务器是否会接受这个请求,因此它应该发送与它不尝试恢复时发送的相同的扩展。

一般来说,每个扩展类型的规范需要描述扩展在完全握手和会话恢复期间的效果。大多数当前 TLS 扩展仅在会话启动时相关:当恢复旧会话时,服务器不会在 Client Hello 中处理这些扩展,也不会将它们包含在 Server Hello 中。但是,某些扩展可能会在会话恢复期间指定不同的行为。

在此协议中,新功能和现有功能之间可能会发生微妙(而不是那么微妙)的交互,这可能会导致整体安全性的显着降低。设计新扩展时应考虑以下因素:

- 服务器不同意扩展的某些情况是错误条件,有些只是拒绝支持特定功能。通常,前者应使用错误警报,后者应使用服务器扩展响应中的字段。

- 应尽可能设计扩展以防止任何通过操纵握手消息强制使用(或不使用)特定功能的攻击。无论该功能是否被认为会导致安全问题,都应遵循此原则。

通常将扩展字段包含在 Finished 消息散列的输入中这一事实就足够了,但是当扩展更改握手阶段发送的消息的含义时需要格外小心。设计者和实现者应该意识到这样一个事实,在握手通过身份验证之前,主动攻击者可以修改消息并插入、删除或替换扩展。

- 在技术上可以使用扩展来改变 TLS 设计的主要方面;例如密码套件协商的设计。不推荐这样做;定义一个新版本的 TLS 会更合适——特别是因为 TLS 握手算法具有针对基于版本号的版本回滚攻击的特定保护,并且版本回滚的可能性应该是任何重大设计更改中的一个重要考虑因素。

7.4.1.4.1. 签名算法

客户端使用“signature_algorithms”扩展来向服务器指示哪些签名/散列算法对可以用于数字签名。 此扩展的“extension_data”字段包含“supported_signature_algorithms”值。

每个 SignatureAndHashAlgorithm 值列出客户端愿意验证的单个哈希/签名对。这些值按偏好的降序表示。

注意:因为并不是所有的签名算法和哈希算法都可以被一个实现接受(例如,带有 SHA-1 的 DSA,但不是 SHA-256),这里的算法是成对列出的。

散列
      该字段指示可能使用的散列算法。这些值分别表示支持未散列数据、MD5 [MD5]、SHA-1、SHA-224、SHA-256、SHA-384 和 SHA-512 [SHS]。 “none”值是为将来的可扩展性提供的,以防签名算法在签名前不需要散列。

签名
      该字段指示可能使用的签名算法。这些值分别表示匿名签名 RSASSA-PKCS1-v1_5 [PKCS1] 和 DSA [DSS] 以及 ECDSA [ECDSA]。 “匿名”值在此上下文中没有意义,但在第 7.4.3 节中使用。它不得出现在此扩展中。

这个扩展的语义有些复杂,因为密码套件指示允许的签名算法而不是散列算法。第 7.4.2 和 7.4.3 节描述了适当的规则。

如果客户端只支持默认的散列和签名算法(在本节中列出),它可以省略 signature_algorithms 扩展。如果客户端不支持默认算法,或者支持其他散列和签名算法(并且愿意使用它们来验证服务器发送的消息,即服务器证书和服务器密钥交换),它必须发送 signature_algorithms 扩展,列出它愿意接受的算法。

如果客户端不发送 signature_algorithms 扩展,则服务器必须执行以下操作:

- 如果协商的密钥交换算法是 (RSA, DHE_RSA, DH_RSA, RSA_PSK, ECDH_RSA, ECDHE_RSA) 之一,表现得好像客户端发送了值 {sha1,rsa}。
- 如果协商的密钥交换算法是 (DHE_DSS, DH_DSS) 之一,则表现得好像客户端发送了值 {sha1,dsa}。
- 如果协商的密钥交换算法是 (ECDH_ECDSA, ECDHE_ECDSA) 之一,则表现得好像客户端发送了值 {sha1,ecdsa}。

注意:这是对 TLS 1.1 的一个更改,其中没有明确的规则,但实际上可以假设对等方支持 MD5 和 SHA-1。

注意:此扩展对于 1.2 之前的 TLS 版本没有意义。如果客户提供以前的版本,则客户不得提供它。但是,即使客户端确实提供了它,[TLSEXT] 中指定的规则也要求服务器忽略它们不理解的扩展。

服务器不得发送此扩展。 TLS 服务器必须支持接收这个扩展。

执行会话恢复时,此扩展不包含在 Server Hello 中,服务器会忽略 Client Hello 中的扩展(如果存在)。

7.4.2.服务器证书

何时发送此消息:
      每当商定的密钥交换方法使用证书进行身份验证时,服务器必须发送证书消息(这包括本文档中定义的所有密钥交换方法,除了 DH_anon)。此消息将始终紧跟在 ServerHello 消息之后。

此消息的含义:
      此消息将服务器的证书链传送到客户端。
      证书必须适用于协商密码套件的密钥交换算法和任何协商扩展。

证书列表
      这是证书序列(链)。发件人的证书必须排在列表的首位。后面的每个证书必须直接证明它前面的证书。因为证书验证需要独立分发根密钥,指定根证书颁发机构的自签名证书可以从链中省略,假设远程端必须已经拥有它以便在任何情况下验证它。

客户端对证书请求消息的响应将使用相同的消息类型和结构。请注意,如果客户端没有适当的证书来响应服务器的身份验证请求,则它可以不发送任何证书。

注意:PKCS #7 [PKCS7] 未用作证书向量的格式,因为未使用 PKCS #6 [PKCS6] 扩展证书。此外,PKCS #7 定义了 SET 而不是 SEQUENCE,这使得解析列表的任务更加困难。

以下规则适用于服务器发送的证书:
- 证书类型必须是 X.509v3,除非另有明确协商(例如,[TLSPGP])。
- 最终实体证书的公钥(和相关限制)必须与选择的密钥交换算法兼容。

密钥交换算法证书密钥类型

RSA RSA 公钥;证书必须允许
      用于加密的 RSA_PSK 密钥(
                         keyEncipherment 位必须被设置,如果密钥
                         存在使用扩展)。
                         注意:RSA_PSK 在[TLSPSK]中定义。

DHE_RSA RSA 公钥;证书必须允许
      用于签名的 ECDHE_RSA 密钥(
                         如果密钥,必须设置 digitalSignature 位
                         使用扩展名存在)与签名
                         将采用的方案和哈希算法
                         在服务器密钥交换消息中。
                         注意:ECDHE_RSA 在 [TLSECC] 中定义。

DHE_DSS DSA 公钥;证书必须允许
                         用于使用哈希签名的密钥
                         将在服务器中使用的算法
                         密钥交换消息。

DH_DSS Diffie-Hellman 公钥; keyAgreement 位
      如果密钥使用扩展是,则必须设置 DH_RSA
                         展示。

ECDH_ECDSA 支持 ECDH 的公钥;公钥必须
      ECDH_RSA 使用的曲线和点格式支持
                         客户端,如 [TLSECC] 中所述。

ECDHE_ECDSA 支持 ECDSA 的公钥;证书必须
                         允许使用密钥与
                         哈希算法将用于
                         服务器密钥交换消息。公钥
                         必须使用支持的曲线和点格式
                         客户端,如 [TLSECC] 中所述。

- “server_name”和“trusted_ca_keys”扩展 [TLSEXT] 用于指导证书选择。

如果客户端提供了“signature_algorithms”扩展,则服务器提供的所有证书必须由出现在该扩展中的哈希/签名算法对签名。请注意,这意味着包含一个签名算法密钥的证书可以使用不同的签名算法(例如,使用 DSA 密钥签名的 RSA 密钥)进行签名。这与 TLS 1.1 不同,后者要求算法相同。请注意,这也意味着 DH_DSS、DH_RSA、ECDH_ECDSA 和 ECDH_RSA 密钥交换算法不限制用于签署证书的算法。固定 DH 证书可以使用扩展中出现的任何哈希/签名算法对进行签名。名称 DH_DSS、DH_RSA、ECDH_ECDSA 和 ECDH_RSA 是历史名称。

如果服务器有多个证书,它会根据上述标准(除了其他标准,如传输层端点、本地配置和首选项等)选择其中一个。如果服务器只有一个证书,它应该尝试验证它是否满足这些标准。

请注意,有些证书使用了当前无法与 TLS 一起使用的算法和/或算法组合。例如,不能使用带有 RSASSA-PSS 签名密钥(SubjectPublicKeyInfo 中的 id-RSASSA-PSS OID)的证书,因为 TLS 没有定义相应的签名算法。

由于为 TLS 协议指定了指定新密钥交换方法的密码套件,它们将暗示证书格式和所需的编码密钥信息。

7.4.3.服务器密钥交换消息

何时发送此消息:
      此消息将在服务器证书消息(或 ServerHello 消息,如果这是匿名协商)之后立即发送。

仅当服务器证书消息(如果发送)不包含足够的数据以允许客户端交换预主密钥时,服务器才会发送 ServerKeyExchange 消息。这适用于以下密钥交换方法:
         DHE_DSS
         DHE_RSA
         DH_anon
为以下密钥交换方法发送 ServerKeyExchange 消息是不合法的:
         RSA
         DH_DSS
         DH_RSA
其他密钥交换算法,例如[TLSECC]中定义的那些,必须指定是否发送ServerKeyExchange消息;如果消息被发送,它的内容。

此消息的含义:
      此消息传达加密信息以允许客户端传达预主密钥:客户端可以使用它完成密钥交换的 Diffie-Hellman 公钥(结果是预主密钥)或某些其他算法的公钥。

参数
         服务器的密钥交换参数。
签名参数
         对于非匿名密钥交换,服务器的密钥交换参数上的签名。

如果客户端提供了“signature_algorithms”扩展,则签名算法和哈希算法必须是该扩展中列出的一对。请注意,这里可能会出现不一致的情况。例如,客户端可能提供 DHE_DSS 密钥交换,但从其“signature_algorithms”扩展中省略任何 DSA 对。为了正确协商,服务器必须在选择它们之前根据“signature_algorithms”扩展检查任何候选密码套件。这有点不雅,但它是一种折衷方案,旨在最大限度地减少对原始密码套件设计的更改。

此外,散列和签名算法必须与服务器端实体证书中的密钥兼容。 RSA 密钥可以与任何允许的哈希算法一起使用,但受证书中的限制(如果有)的约束。

因为 DSA 签名不包含任何散列算法的安全指示,如果多个散列可以与任何密钥一起使用,则存在散列替换的风险。目前,DSA [DSS] 只能与 SHA-1 一起使用。预计 DSS [DSS-3] 的未来修订版将允许将其他摘要算法与 DSA 一起使用,并就每种密钥大小应使用哪种摘要算法提供指导。此外,[PKIX] 的未来修订版可能会指定证书机制以指示哪些摘要算法将与 DSA 一起使用。

由于为包含新密钥交换算法的 TLS 定义了额外的密码套件,当且仅当与密钥交换算法关联的证书类型没有为客户端提供足够的信息来交换预主密钥时,才会发送服务器密钥交换消息。

7.4.4.证书申请

何时发送此消息:
       如果适用于所选密码套件,非匿名服务器可以选择从客户端请求证书。如果发送此消息,将立即跟随 ServerKeyExchange 消息(如果已发送;否则,此消息跟随服务器的证书消息)。

supported_signature_algorithms
      服务器能够验证的散列/签名算法对列表,按优先级降序列出。

certificate_authorities
      可接受的certificate_authorities 的专有名称[X501] 列表,以DER 编码格式表示。这些专有名称可以为根 CA 或从属 CA 指定所需的专有名称;因此,该消息可用于描述已知的根以及所需的授权空间。如果certificate_authorities 列表为空,则客户端可以发送任何适当ClientCertificateType 的证书,除非有一些相反的外部安排。

certificate_types 和 supported_signature_algorithms 字段的交互有些复杂。从 SSLv3 开始,certificate_types 就出现在 TLS 中,但有些未指定。它的大部分功能被supported_signature_algorithms 取代。以下规则适用:

- 客户端提供的任何证书必须使用在 supported_signature_algorithms 中找到的散列/签名算法对进行签名。

- 客户端提供的终端实体证书必须包含一个与certificate_types 兼容的密钥。如果密钥是签名密钥,则它必须与 supported_signature_algorithms 中的某些哈希/签名算法对一起使用。

- 由于历史原因,某些客户端证书类型的名称包含用于签署证书的算法。例如,在早期版本的 TLS 中,rsa_fixed_dh 表示使用 RSA 签名并包含静态 DH 密钥的证书。在 TLS 1.2 中,此功能已被 supported_signature_algorithms 废弃,证书类型不再限制用于签署证书的算法。例如,如果服务器发送 dss_fixed_dh 证书类型和 {{sha1, dsa}, {sha1, rsa}} 签名类型,客户端可以回复一个包含静态 DH 密钥的证书,使用 RSA-SHA1 签名。

新的 ClientCertificateType 值由 IANA 分配,如第 12 节所述。

注意:不能使用列为 RESERVED 的值。它们用于 SSLv3。

注意:匿名服务器请求客户端认证是一个致命的handshake_failure警报。

7.4.5.服务器Hello完成

何时发送此消息:
      ServerHelloDone 消息由服务器发送,用于指示 ServerHello 和相关消息的结束。发送此消息后,服务器将等待客户端响应。

此消息的含义:
      此消息意味着服务器已完成发送消息以支持密钥交换,并且客户端可以继续其密钥交换阶段。

收到 ServerHelloDone 消息后,如果需要,客户端应该验证服务器是否提供了有效的证书,并检查服务器 hello 参数是否可接受。

此消息的结构:
      struct { } ServerHelloDone;

7.4.6.客户端证书

何时发送此消息:
      这是客户端收到 ServerHelloDone 消息后可以发送的第一条消息。此消息仅在服务器请求证书时发送。如果没有合适的证书可用,客户端必须发送不包含证书的证书消息。也就是说,certificate_list 结构的长度为零。如果客户端不发送任何证书,服务器可以自行决定在没有客户端身份验证的情况下继续握手,或者以致命的握手失败警报进行响应。此外,如果证书链的某些方面是不可接受的(例如,它不是由已知的、受信任的 CA 签名),服务器可以自行决定继续握手(考虑到客户端未经身份验证)或发送致命警报。

客户端证书使用第 7.4.2 节中定义的证书结构发送。

此消息的含义:
      此消息将客户端的证书链传送到服务器;服务器将在验证 CertificateVerify 消息(当客户端身份验证基于签名时)或计算预主密钥(对于非临时性 Diffie-Hellman)时使用它。证书必须适用于协商密码套件的密钥交换算法和任何协商扩展。

特别是:
- 证书类型必须是 X.509v3,除非另有明确协商(例如,[TLSPGP])。
- 最终实体证书的公钥(和相关限制)必须与 CertificateRequest 中列出的证书类型兼容:

客户证书类型;证书密钥类型

rsa_sign
RSA公钥;证书必须允许使用将在证书验证消息中使用的签名方案和哈希算法使用密钥进行签名。

dss_sign
DSA 公钥;证书必须允许密钥用于使用将在证书验证消息中使用的哈希算法进行签名。

ecdsa_sign
支持 ECDSA 的公钥;证书必须允许使用将在证书验证消息中使用的哈希算法使用密钥进行签名;公钥必须使用服务器支持的曲线和点格式。

rsa_fixed_dh
Diffie-Hellman 公钥;必须使用相同的

dss_fixed_dh
参数作为服务器的密钥。

rsa_fixed_ecdh
支持 ECDH 的公钥;必须使用与服务器密钥相同的 ecdsa_fixed_ecdh 曲线,并且必须使用服务器支持的点格式。

- 如果证书请求消息中的certificate_authorities 列表非空,证书链中的证书之一应该由列出的CA 之一颁发。

- 证书必须使用可接受的哈希/签名算法对进行签名,如第 7.4.4 节所述。请注意,这放宽了对先前版本 TLS 中的证书签名算法的限制。

请注意,与服务器证书一样,有些证书使用了当前无法与 TLS 一起使用的算法/算法组合。

7.4.7.客户端密钥交换消息

何时发送此消息:
      此消息始终由客户端发送。如果它被发送,它必须立即跟随客户端证书消息。否则,它必须是客户端收到 ServerHelloDone 消息后发送的第一条消息。

此消息的含义:
      使用此消息,通过直接传输 RSA 加密的秘密或通过传输 Diffie-Hellman 参数来设置预主密码,这将允许每一方就相同的预主密码达成一致。
      当客户端使用临时 Diffie-Hellman 指数时,此消息包含客户端的 Diffie-Hellman 公共值。如果客户端正在发送包含静态 DH 指数的证书(即,它正在执行 fixed_dh 客户端身份验证),则必须发送此消息,但必须为空。

此消息的结构:
      消息的选择取决于选择的密钥交换方法。有关 KeyExchangeAlgorithm 的定义,请参阅第 7.4.3 节。

7.4.7.1. RSA 加密的 Premaster 密钥消息

此消息的含义:
如果 RSA 用于密钥协商和身份验证,则客户端生成一个 48 字节的预主密钥,使用服务器证书中的公钥对其进行加密,并将结果以加密的预主密钥消息的形式发送。 此结构是 ClientKeyExchange 消息的变体,本身不是消息。

pre_master_secret
该随机值由客户端生成,用于生成主密钥,如第 8.1 节所述。

注意:PreMasterSecret中的版本号是ClientHello.client_version中客户端提供的版本,不是为连接协商的版本。此功能旨在防止回滚攻击。不幸的是,一些旧的实现改为使用协商版本,因此检查版本号可能会导致无法与此类不正确的客户端实现进行互操作。

客户端实现必须始终在 PreMasterSecret 中发送正确的版本号。如果 ClientHello.client_version 是 TLS 1.1 或更高版本,服务器实现必须检查版本号,如下面的注释所述。如果版本号是 TLS 1.0 或更早版本,服务器实现应该检查版本号,但可以有一个配置选项来禁用检查。请注意,如果检查失败,则 PreMasterSecret 应按如下所述进行随机化。

注意:Bleichenbacher [BLEI] 和 Klima 等人发现的攻击。 [KPR03] 可用于攻击 TLS 服务器,该服务器揭示特定消息在解密时是否为正确的 PKCS#1 格式、是否包含有效的 PreMasterSecret 结构或是否具有正确的版本号。

正如 Klima [KPR03] 所描述的那样,可以通过以与正确格式化的 RSA 块无法区分的方式处理格式不正确的消息块和/或不匹配的版本号来避免这些漏洞。换句话说:
      1.生成46个随机字节的字符串R
      2. 解密消息恢复明文M
      3. 如果 PKCS#1 填充不正确,或者消息的长度
         M 不完全是 48 个字节:
            pre_master_secret = ClientHello.client_version ||电阻
         else If ClientHello.client_version <= TLS 1.0, and version
         号码检查被明确禁用:
            pre_master_secret = M
         别的:
            pre_master_secret = ClientHello.client_version || M[2..47]

请注意,如果客户端在原始 pre_master_secret 中发送了错误的版本,则使用 ClientHello.client_version 显式构造 pre_master_secret 会产生无效的 master_secret。

另一种方法是将版本号不匹配视为 PKCS-1 格式错误并完全随机化预主密钥:
      1.生成48个随机字节的字符串R
      2. 解密消息恢复明文M
      3. 如果 PKCS#1 填充不正确,或者消息的长度
         M 不完全是 48 个字节:
            pre_master_secret = R
         else If ClientHello.client_version <= TLS 1.0, and version
         号码检查被明确禁用:
            预主秘密 = M
         否则如果 M[0..1] != ClientHello.client_version:
            预主秘密 = R
         别的:
            预主秘密 = M

尽管没有针对这种结构的实际攻击是已知的,但 Klima 等人。 [KPR03] 描述了一些理论攻击,因此所描述的第一个结构是推荐的。

在任何情况下,如果处理 RSA 加密的 premaster 秘密消息失败,或者版本号不符合预期,TLS 服务器不得生成警报。相反,它必须使用随机生成的预主密钥继续握手。记录故障的真正原因以进行故障排除可能很有用;但是,必须小心避免将信息泄露给攻击者
 (例如,通过计时、日志文件或其他渠道。)

[PKCS1] 中定义的 RSAES-OAEP 加密方案对 Bleichenbacher 攻击更安全。但是,为了与早期版本的 TLS 最大程度地兼容,本规范使用 RSAES-PKCS1-v1_5 方案。如果遵循上述建议,则已知不存在 Bleichenbacher 攻击的变体。

实现说明:公钥加密数据表示为不透明向量 <0..2^16-1>(参见第 4.7 节)。因此,ClientKeyExchange 中 RSA 加密的 PreMasterSecret 前面有两个长度字节。在 RSA 的情况下,这些字节是多余的,因为 EncryptedPreMasterSecret 是 ClientKeyExchange 中唯一的数据,因此可以明确确定其长度。 SSLv3 规范并不清楚公钥加密数据的编码,因此许多 SSLv3 实现不包括长度字节——它们直接在 ClientKeyExchange 消息中对 RSA 加密数据进行编码。

该规范要求对 EncryptedPreMasterSecret 进行正确编码,并带有长度字节。生成的 PDU 与许多 SSLv3 实现不兼容。从 SSLv3 升级的实现者必须修改他们的实现以生成并接受正确的编码。希望与 SSLv3 和 TLS 兼容的实现者应该使他们的实现行为依赖于协议版本。

实施说明:现在已知对 TLS 的远程基于时间的攻击是可能的,至少当客户端和服务器在同一个 LAN 上时。因此,使用静态 RSA 密钥的实现必须使用 RSA 盲法或其他一些反定时技术,如 [TIMING] 中所述。

7.4.7.2.客户端 Diffie-Hellman 公共值

此消息的含义:
      如果客户端的证书中尚未包含客户端的 Diffie-Hellman 公共值 (Yc),则该结构会传达客户端的 Diffie-Hellman 公共值 (Yc)。用于 Yc 的编码由枚举的 PublicValueEncoding 确定。此结构是客户端密钥交换消息的变体,而不是消息本身。

此消息的结构:
      枚举 { 隐式,显式 } PublicValueEncoding;
      隐含的
         如果客户端发送的证书包含合适的 Diffie-Hellman 密钥(用于 fixed_dh 客户端身份验证),则 Yc 是隐式的,不需要再次发送。在这种情况下,将发送客户端密钥交换消息,但它必须为空。
      明确的
         需要发送 Yc。
     

dh_Yc
         客户的 Diffie-Hellman 公共价值 (Yc)。

7.4.8.证书验证

何时发送此消息:
      此消息用于提供对客户端证书的显式验证。此消息仅在具有签名功能的客户端证书之后发送(即,除包含固定 Diffie-Hellman 参数的证书之外的所有证书)。发送时,它必须立即遵循客户端密钥交换消息。

这里的handshake_messages是指发送或接收的所有握手消息,从client hello开始直到但不包括这个消息,包括握手消息的类型和长度字段。这是迄今为止交换的所有握手结构(如第 7.4 节中定义的)的串联。请注意,这需要双方缓冲消息或计算所有潜在哈希算法的运行哈希,直到 CertificateVerify 计算。
      服务器可以通过在 CertificateRequest 消息中提供一组受限的摘要算法来最小化此计算成本。
      签名中使用的散列和签名算法必须是出现在 CertificateRequest 消息的 supported_signature_algorithms 字段中的算法之一。此外,散列和签名算法必须与客户端的最终实体证书中的密钥兼容。 RSA 密钥可以与任何允许的哈希算法一起使用,但受证书中的限制(如果有)的约束。

因为 DSA 签名不包含任何散列算法的安全指示,如果多个散列可以与任何密钥一起使用,则存在散列替换的风险。目前,DSA [DSS] 只能与 SHA-1 一起使用。预计 DSS [DSS-3] 的未来修订版将允许将其他摘要算法与 DSA 一起使用,并就每种密钥大小应使用哪种摘要算法提供指导。此外,[PKIX] 的未来修订版可能会指定证书机制以指示哪些摘要算法将与 DSA 一起使用。

7.4.9. 完成

何时发送此消息:
       Finished 消息总是在更改密码规范消息之后立即发送,以验证密钥交换和身份验证过程是否成功。 在其他握手消息和完成消息之间接收更改密码规范消息是必不可少的。

此消息的含义:
       Finished 消息是第一个用刚刚协商的算法、密钥和秘密保护的消息。 Finished 消息的接收者必须验证内容是否正确。 一旦一方发送了它的 Finished 消息并从其对等方接收并验证了 Finished 消息,它就可以开始通过连接发送和接收应用程序数据。

哈希表示握手消息的哈希。对于第 5 节中定义的 PRF,散列必须是用作 PRF 基础的散列。任何定义不同 PRF 的密码套件还必须定义用于完成计算的哈希。

在以前版本的 TLS 中,verify_data 总是 12 个八位字节长。在当前版本的 TLS 中,它取决于密码套件。任何未明确指定 verify_data_length 的密码套件的 verify_data_length 等于 12。这包括所有现有的密码套件。请注意,此表示与以前的版本具有相同的编码。未来的密码套件可以指定其他长度,但此类长度必须至少为 12 个字节。

握手消息
         来自此握手中所有消息(不包括任何 HelloRequest 消息)的所有数据,直到但不包括此消息。这只是握手层可见的数据,不包括记录层头。这是第 7.4 节中定义的所有握手结构的串联,到目前为止已交换。

如果在握手中的适当点,一个 Finished 消息之前没有一个 ChangeCipherSpec 消息,那么这是一个致命错误。

值 handshake_messages 包括从 ClientHello 开始到但不包括此 Finished 消息的所有握手消息。这可能与第 7.4.8 节中的 handshake_messages 不同,因为它将包含 CertificateVerify 消息(如果已发送)。此外,客户端发送的 Finished 消息的 handshake_messages 将与服务器发送的 Finished 消息的握手消息不同,因为第二个发送的将包括前一个。

注意:ChangeCipherSpec 消息、警报和任何其他记录类型都不是握手消息,也不包括在哈希计算中。此外,握手哈希中省略了 HelloRequest 消息。

8. 密码计算

为了开始连接保护,TLS 记录协议需要指定一套算法、一个主密钥以及客户端和服务器随机值。认证、加密和 MAC 算法由服务器选择的 cipher_suite 决定,并在 ServerHello 消息中显示。压缩算法在hello消息中协商,随机值在hello消息中交换。剩下的就是计算主秘密。

8.1.计算主密钥

对于所有密钥交换方法,使用相同的算法将 pre_master_secret 转换为 master_secret。一旦计算出 master_secret,就应该从内存中删除 pre_master_secret。

主密钥的长度始终恰好为 48 个字节。预主密钥的长度将根据密钥交换方法而有所不同。

8.1.1. RSA

当RSA用于服务器认证和密钥交换时,客户端生成一个48字节的pre_master_secret,在服务器的公钥下加密,然后发送到服务器。服务器使用其私钥解密 pre_master_secret。双方然后将 pre_master_secret 转换为 master_secret,如上所述。

8.1.2.Diffie-Hellman

执行传统的 Diffie-Hellman 计算。协商密钥 (Z) 用作 pre_master_secret,并转换为 master_secret,如上所述。包含所有零位的 Z 的前导字节在用作 pre_master_secret 之前被剥离。

注意:Diffie-Hellman 参数由服务器指定,可能是临时的,也可能包含在服务器的证书中。

9. 强制密码套件

在没有应用程序配置文件标准另外指定的情况下,符合 TLS 的应用程序必须实现密码套件 TLS_RSA_WITH_AES_128_CBC_SHA(定义见附录 A.5)。

10. 应用数据协议

应用数据消息由记录层承载,并根据当前连接状态进行分片、压缩和加密。消息被视为记录层的透明数据。

11. 安全考虑

本文通篇讨论了安全问题,尤其是在附录 D、E 和 F 中。

12. IANA 考虑

本文档使用了最初在 [TLS1.1] 中创建的几个注册表。 IANA 已更新这些内容以引用本文档。下面列出了注册表及其分配策略(与 [TLS1.1] 保持不变)。

- TLS ClientCertificateType 标识符注册表:通过标准操作 [RFC2434] 分配 0-63(十进制)范围内的未来值。 64-223(十进制)范围内的值通过规范要求 [RFC2434] 分配。包含 224-255(十进制)的值保留供私人使用 [RFC2434]。

- TLS 密码套件注册表:通过标准操作 [RFC2434] 分配第一个字节在 0-191(十进制)范围内的未来值。第一个字节在 192-254(十进制)范围内的值通过规范要求 [RFC2434] 分配。
第一个字节为 255(十进制)的值保留供私有使用 [RFC2434]。
- 本文档定义了几个新的基于 HMAC-SHA256 的密码套件,其值(在附录 A.5 中)已从 TLS 密码套件注册表中分配。
- TLS ContentType Registry:未来的值通过标准行动 [RFC2434] 分配。
- TLS 警报注册表:通过标准操作 [RFC2434] 分配未来值。
- TLS 握手类型注册表:未来值通过标准操作 [RFC2434] 分配。

本文档还使用了最初在 [RFC4366] 中创建的注册表。 IANA 已更新它以引用此文档。注册表及其分配策略(与 [RFC4366] 保持不变)如下所列:
- TLS 扩展类型注册表:未来值通过 IETF 共识 [RFC2434] 分配。 IANA 已更新此注册表以包含 signature_algorithms 扩展及其相应值(请参阅第 7.4.1.4 节)。

此外,本文档定义了两个由 IANA 维护的新注册管理机构:

- TLS SignatureAlgorithm 注册表:注册表最初填充了第 7.4.1.4.1 节中描述的值。 0-63(十进制)范围内的未来值通过分配
标准行动 [RFC2434]。 64-223(十进制)范围内的值通过规范要求 [RFC2434] 分配。包含 224-255(十进制)的值保留供私人使用 [RFC2434]。

- TLS HashAlgorithm 注册表:注册表最初已使用第 7.4.1.4.1 节中描述的值填充。 0-63(十进制)范围内的未来值通过分配
标准行动 [RFC2434]。 64-223(十进制)范围内的值通过规范要求 [RFC2434] 分配。包含 224-255(十进制)的值保留供私人使用 [RFC2434]。

【RFC5246 TLS 协议1.2】(全文翻译+小部分缩译)相关推荐

  1. WPF:全文翻译小工具

    我一直使用灵格斯电子词典,里面有个全文翻译的功能,能选择Google,Yahoo等等很多翻译的功能.觉得Google翻译得最好.找了一点资料,利用WPF实现类似的功能,支持52种语言. 灵格斯全文翻译 ...

  2. 知云文献翻译打不开_论文翻译小工具,一键即可免费翻译全文| 知云文献翻译、彩云小译(附安装包)...

    Ⅰ 最近正在秃头写论文,需要可以自动一键全文翻译的工具,一番询问和测试之后,强烈推荐知云文献和彩云小译. 知云文献翻译是一个软件,使用时,只需要将需要翻译的文件拉入软件页面,点击需要翻译的内容,即可以 ...

  3. TLS协议分析 与 现代加密通信协议设计

    本文目标: 学习鉴赏TLS协议的设计,透彻理解原理和重点细节 跟进一下密码学应用领域的历史和进展 整理现代加密通信协议设计的一般思路 本文有门槛,读者需要对现代密码学有清晰而系统的理解,建议花精力补足 ...

  4. 《WSN》无线传感器网络全文翻译

    前言 该篇文章的全文翻译是由敖琳.綦正民.钱金柱.陈见埔.刘仁宇.胡雪亮六位同学完成.其中敖琳负责摘要.第1节.第2节的翻译,綦正民负责第3节的翻译,钱金柱负责第4节的翻译,刘仁宇负责第5节的翻译,陈 ...

  5. 解密TLS协议全记录之Openssl的使用与Nginx Server的配置

    引言 Openssl是TLS协议进行报文加密,安全通讯而用到的开源代码包,代码主要由C语言编写,我个人也只看了其中一部分代码,当作工具使用,没有深入分析. 其维基百科的链接:https://zh.wi ...

  6. GDPR全文翻译(一)

    General Data Protection Regulation <一般数据保护法案>全文翻译(一) 编者按 2016年4月14日,欧洲议会投票通过了商讨四年的<一般数据保护法案 ...

  7. CutPaste: Self-Supervised Learning for Anomaly Detection and Localization 全文翻译+详细解读

    CutPaste: Self-Supervised Learning for Anomaly Detection and Localization 全文翻译+详细解读 文章速览 全文翻译及详细解释 0 ...

  8. AN IMAGE IS WORTH 16X16 WORDS: TRANSFORMERS FOR IMAGE RECOGNITION AT SCALE——ViT全文翻译

    一文读懂ViT:ViT 快速理解 Vision in Transformer 文章目录 全文翻译- Vision in Transformer- 相关说明 基本信息介绍 ABSTRACT 1 INTR ...

  9. 全文翻译(全文合集):TVM: An Automated End-to-End Optimizing Compiler for Deep Learning

    全文翻译(全文合集):TVM: An Automated End-to-End Optimizing Compiler for Deep Learning 摘要 人们越来越需要将机器学习应用到各种各样 ...

最新文章

  1. 中国团队新型类脑芯片登上《自然》封面
  2. CTreeCtrl标签的编辑
  3. vuex - 基础篇
  4. python基础(part15)--迭代
  5. SpringBoot邮件服务
  6. 《疯狂Java讲义》(十五)---- 内部类
  7. python接口自动化(八)--发送post请求的接口(详解)
  8. Oralce 导入dpm 文件数据
  9. susmote个人网站博客论坛(TexTec | 关注互联网技术,传播极客精神)
  10. 精益创业实战 - 第3章 制作自己的精益画布
  11. jquery html5 ui框架,有哪些常用jQuery UI框架?
  12. 赶超磁盘的磁带备份技术
  13. 数字IC设计verilog编写——6脉冲同步器
  14. 怎么引入oracle驱动包,Maven引入oracle驱动包
  15. 高手支招:免费拥有QQ魔法表情(转)
  16. 霍纳法则c语言算法代码,霍纳法则(Horner's rule)
  17. linear regreesion 线性回归
  18. html圆柱体制作方法,如何制作圆柱体
  19. Android 程序员的技术栈大全(1),中高级Android面试题目汇总解答
  20. Java调用aliyun OCR图文识别

热门文章

  1. input标签的tabindex属性
  2. SYD8811 ADC注意点
  3. 一个名叫草泥马的项目:thefuck
  4. Android的Toolbar(含溢出菜单设置[弹出菜单的使用])的使用PopMenu的样式
  5. Windows系统和Linux系统下安装MySQL
  6. 常用正则:手机号码、中文名字、邮箱、身份证号码、网站URL
  7. yii之PHPExcel导出
  8. 化妆品行业如何在微信朋友圈获客
  9. Servlet的生命周期及调用方法
  10. 从0到1打造高成功率的食品品牌系列(一)食品企业从0到1创建品牌的20大误区