Skip to main content

2. Protocol Overview (协议概述)

安全通道使用的加密参数由TLS握手协议 (Handshake Protocol) 生成。TLS的这个子协议在客户端和服务器首次相互通信时使用。握手协议允许对等体协商协议版本、选择加密算法、可选地相互认证,并建立共享密钥材料。一旦握手完成,对等体使用建立的密钥来保护应用层流量。

握手失败或其他协议错误会触发连接终止,可选地在之前发送警报消息 (Alert Message) (第6节)。

TLS支持三种基本的密钥交换模式 (Key Exchange Modes):

  • (EC)DHE (在有限域或椭圆曲线上的Diffie-Hellman)
  • PSK-only (仅预共享密钥)
  • PSK with (EC)DHE (预共享密钥与(EC)DHE结合)

图1显示了基本的完整TLS握手:

       Client                                           Server

Key ^ ClientHello
Exch | + key_share*
| + signature_algorithms*
| + psk_key_exchange_modes*
v + pre_shared_key* -------->
ServerHello ^ Key
+ key_share* | Exch
+ pre_shared_key* v
{EncryptedExtensions} ^ Server
{CertificateRequest*} v Params
{Certificate*} ^
{CertificateVerify*} | Auth
{Finished} v
<-------- [Application Data*]
^ {Certificate*}
Auth | {CertificateVerify*}
v {Finished} -------->
[Application Data] <-------> [Application Data]

+ 表示在先前提到的消息中发送的值得注意的扩展。

* 表示并非总是发送的可选或情况依赖的
消息/扩展。

{} 表示使用从[sender]_handshake_traffic_secret
派生的密钥保护的消息。

[] 表示使用从[sender]_application_traffic_secret_N
派生的密钥保护的消息。

图1: 完整TLS握手的消息流

握手可以被认为具有三个阶段 (在上图中标明):

  • 密钥交换 (Key Exchange): 建立共享密钥材料并选择加密参数。此阶段之后的所有内容都已加密。

  • 服务器参数 (Server Parameters): 建立其他握手参数 (客户端是否经过认证、应用层协议支持等)。

  • 认证 (Authentication): 认证服务器 (以及可选地认证客户端) 并提供密钥确认和握手完整性。

密钥交换阶段,客户端发送ClientHello (第4.1.2节) 消息,其中包含随机数 (ClientHello.random)、提供的协议版本、对称密码/HKDF哈希对列表、Diffie-Hellman密钥共享集合 (在"key_share" (第4.2.8节) 扩展中)、预共享密钥标签集合 (在"pre_shared_key" (第4.2.11节) 扩展中)、或两者都有,以及可能的其他扩展。为了中间盒兼容性,可能还存在其他字段和/或消息。

服务器处理ClientHello并确定连接的适当加密参数。然后它用自己的ServerHello (第4.1.3节) 响应,指示协商的连接参数。ClientHello和ServerHello的组合决定了共享密钥。如果使用(EC)DHE密钥建立,则ServerHello包含带有服务器临时Diffie-Hellman共享的"key_share"扩展;服务器的共享必须 (MUST) 与客户端的共享之一在同一组中。如果使用PSK密钥建立,则ServerHello包含指示选择了客户端提供的哪个PSK的"pre_shared_key"扩展。请注意,实现可以同时使用(EC)DHE和PSK,在这种情况下将提供两个扩展。

然后服务器发送两条消息以建立服务器参数:

EncryptedExtensions: 对不需要确定加密参数的ClientHello扩展的响应,除了特定于各个证书的扩展之外。[第4.3.1节]

CertificateRequest: 如果需要基于证书的客户端认证,则该证书所需的参数。如果不需要客户端认证,则省略此消息。[第4.3.2节]

最后,客户端和服务器交换认证消息。每当需要基于证书的认证时,TLS都使用同一组消息。(基于PSK的认证作为密钥交换的副作用发生。) 具体来说:

Certificate: 端点的证书和任何每证书扩展。如果服务器不使用证书进行认证,则服务器省略此消息;如果服务器未发送CertificateRequest (从而指示客户端不应使用证书进行认证),则客户端省略此消息。请注意,如果使用原始公钥 [RFC7250] 或缓存信息扩展 [RFC7924],则此消息将不包含证书,而是包含与服务器长期密钥对应的其他值。[第4.4.2节]

CertificateVerify: 使用Certificate消息中公钥对应的私钥对整个握手的签名。如果端点不通过证书进行认证,则省略此消息。[第4.4.3节]

Finished: 对整个握手的MAC (消息认证码)。此消息提供密钥确认,将端点的身份绑定到交换的密钥,并在PSK模式下还认证握手。[第4.4.4节]

收到服务器的消息后,客户端响应其认证消息,即Certificate和CertificateVerify (如果请求),以及Finished。

此时,握手完成,客户端和服务器派生记录层交换通过认证加密保护的应用层数据所需的密钥材料。在发送Finished消息之前,不得 (MUST NOT) 发送应用数据 (Application Data),除非第2.3节中规定的情况。请注意,虽然服务器可能在收到客户端的认证消息之前发送应用数据,但此时发送的任何数据当然是发送给未经认证的对等体。

2.1 Incorrect DHE Share (不正确的DHE共享)

如果客户端未提供足够的"key_share"扩展 (例如,它仅包含服务器不可接受或不支持的DHE或ECDHE组),则服务器使用HelloRetryRequest纠正不匹配,客户端需要使用适当的"key_share"扩展重新启动握手,如图2所示。如果无法协商通用的加密参数,服务器必须 (MUST) 使用适当的警报中止握手。

        Client                                               Server

ClientHello
+ key_share -------->
HelloRetryRequest
<-------- + key_share
ClientHello
+ key_share -------->
ServerHello
+ key_share
{EncryptedExtensions}
{CertificateRequest*}
{Certificate*}
{CertificateVerify*}
{Finished}
<-------- [Application Data*]
{Certificate*}
{CertificateVerify*}
{Finished} -------->
[Application Data] <-------> [Application Data]

图2: 参数不匹配的完整握手消息流

注意: 握手记录 (Handshake Transcript) 包含初始的ClientHello/HelloRetryRequest交换;它不会使用新的ClientHello重置。

TLS还允许基本握手的几种优化变体,如以下各节所述。

2.2 Resumption and Pre-Shared Key (PSK) (恢复和预共享密钥)

虽然TLS PSK可以在带外建立,但PSK也可以在先前的连接中建立,然后用于建立新连接 ("会话恢复 (Session Resumption)" 或使用PSK"恢复")。一旦握手完成,服务器可以向客户端发送PSK身份 (PSK Identity),该身份对应于从初始握手派生的唯一密钥 (参见第4.6.1节)。然后,客户端可以在未来的握手中使用该PSK身份来协商使用相关的PSK。如果服务器接受PSK,则新连接的安全上下文在加密上绑定到原始连接,并且从初始握手派生的密钥用于引导加密状态,而不是完整握手。在TLS 1.2及以下版本中,此功能由"会话ID (Session IDs)"和"会话票据 (Session Tickets)" [RFC5077] 提供。这两种机制在TLS 1.3中都已废弃。

PSK可以与(EC)DHE密钥交换一起使用,以便在共享密钥的基础上提供前向保密 (Forward Secrecy),或者可以单独使用,代价是失去应用数据的前向保密。

图3显示了一对握手,其中第一次握手建立PSK,第二次握手使用它:

          Client                                               Server

Initial Handshake:
ClientHello
+ key_share -------->
ServerHello
+ key_share
{EncryptedExtensions}
{CertificateRequest*}
{Certificate*}
{CertificateVerify*}
{Finished}
<-------- [Application Data*]
{Certificate*}
{CertificateVerify*}
{Finished} -------->
<-------- [NewSessionTicket]
[Application Data] <-------> [Application Data]


Subsequent Handshake:
ClientHello
+ key_share*
+ pre_shared_key -------->
ServerHello
+ pre_shared_key
+ key_share*
{EncryptedExtensions}
{Finished}
<-------- [Application Data*]
{Finished} -------->
[Application Data] <-------> [Application Data]

图3: 恢复和PSK的消息流

由于服务器通过PSK进行认证,因此不发送Certificate或CertificateVerify消息。当客户端通过PSK提供恢复时,它也应该 (SHOULD) 向服务器提供"key_share"扩展,以允许服务器在需要时拒绝恢复并回退到完整握手。服务器使用"pre_shared_key"扩展响应以协商使用PSK密钥建立,并可以 (如此处所示) 使用"key_share"扩展响应以执行(EC)DHE密钥建立,从而提供前向保密。

当PSK在带外配置时,也必须 (MUST) 配置PSK身份和要与PSK一起使用的KDF哈希算法。

注意: 当使用带外配置的预共享密钥时,关键考虑因素是在密钥生成期间使用足够的熵,如 [RFC4086] 中所讨论的。从密码或其他低熵源派生共享密钥是不安全的。低熵密钥或密码容易受到基于PSK绑定器 (PSK Binder) 的字典攻击。即使与Diffie-Hellman密钥建立一起使用,指定的PSK认证也不是强密码基础的认证密钥交换。具体来说,它不能防止可以观察握手的攻击者对密码/预共享密钥执行暴力攻击。

2.3 0-RTT Data (零往返时间数据)

当客户端和服务器共享PSK (外部获得或通过先前的握手获得) 时,TLS 1.3允许客户端在第一次传输中发送数据 ("早期数据 (Early Data)")。客户端使用PSK认证服务器并加密早期数据。

如图4所示,0-RTT数据只是在第一次传输中添加到1-RTT握手中。握手的其余部分使用与具有PSK恢复的1-RTT握手相同的消息。

         Client                                               Server

ClientHello
+ early_data
+ key_share*
+ psk_key_exchange_modes
+ pre_shared_key
(Application Data*) -------->
ServerHello
+ pre_shared_key
+ key_share*
{EncryptedExtensions}
+ early_data*
{Finished}
<-------- [Application Data*]
(EndOfEarlyData)
{Finished} -------->
[Application Data] <-------> [Application Data]

+ 表示在先前提到的消息中发送的值得注意的扩展。

* 表示并非总是发送的可选或情况依赖的
消息/扩展。

() 表示使用从client_early_traffic_secret
派生的密钥保护的消息。

{} 表示使用从[sender]_handshake_traffic_secret
派生的密钥保护的消息。

[] 表示使用从[sender]_application_traffic_secret_N
派生的密钥保护的消息。

图4: 0-RTT握手的消息流

重要提示: 0-RTT数据的安全属性比其他类型的TLS数据弱。具体来说:

  1. 此数据不具有前向保密性 (Forward Secret),因为它仅使用从提供的PSK派生的密钥加密。

  2. 连接之间不保证防重放 (Non-Replay)。普通TLS 1.3 1-RTT数据的防重放保护通过服务器的Random值提供,但0-RTT数据不依赖于ServerHello,因此具有较弱的保证。如果数据使用TLS客户端认证或在应用协议内进行认证,这一点尤其相关。相同的警告适用于early_exporter_master_secret的任何使用。

0-RTT数据不能在连接内重复 (即,服务器不会为同一连接处理相同的数据两次),并且攻击者将无法使0-RTT数据看起来像1-RTT数据 (因为它使用不同的密钥保护)。附录E.5包含对潜在攻击的描述,第8节描述了服务器可以用来限制重放影响的机制。