0-RTT#

0-RTT: Zero round-trip time

这是 TLS1.3 新加的一个特性.

用途: 可以用于快速的发送一部分数据

“快速” 的含义:通常的 TLS 连接, 只有 TLS 握手成功之后, 才能开始发送应用层数据。但是当使用 0-RTT 特性发送消息时, 不需要等待握手结束,便可以提交发送一小部分数据。 因为不需要等待 TLS 握手流程进行完毕,因此比较快。

代价是牺牲部分 TLS 的安全性。


如何工作的?#


并不是任何情况下都能直接发送 0-RTT 数据包。 客户端需要提前有一个和服务器端共享的 PSK.

这个 PSK 的获取方式可以是: 从之前的链接上获取,或者通过其他外部方式。

这里的 PSK 主要用于 TLS 1.3 会话恢复(session resumption),

也就是意味着客户端和服务器已经有一组共享的密钥,可以用来生成加解密 0-RTT 数据的密钥(0-RTT traffic keys)

如下流程, 0-RTT 数据直接跟在客户端的 ClientHello 之后或者 Change Cipher Spec 之后.()

(Change Cipher Spec 在 TLS1.3 中不是必须的,但是为了兼容旧的版本,允许发送 Change Cipher Spec)

Bash
Client                                               Server ClientHello+ early_data+ key_share*+ psk_key_exchange_modes+ pre_shared_key(Application Data*)(0-RTT Data) -------->                                                         ServerHello                                                    + pre_shared_key                                                        + key_share*                                               {EncryptedExtensions}                                                       + early_data*                                                          {Finished}                                 <--------       [Application Data*](EndOfEarlyData){Finished}              -------->[Application Data]      <------->        [Application Data]                Figure 4: Message Flow for a 0-RTT Handshake

代价#


0-RTT 数据的安全性是明显弱于正常握手后发送的 TLS 数据的。

尤其是以下几点:

  1. 这些数据的不是前向保密的(forward secret)。 因为加密这些数据的密钥是从 PSK 直接生成的。
  2. 不能保证这些数据在不同链接上不会被重播(replay)。 1-RTT 数据的防止重播 的机制是依赖于 ServerHello.Random 的值,而 0-RTT数据的加密不依赖于这个值,因此没有这样的保护。

实例#


image-20241114174708164

1-5 是前一个连接, 主要是为了获取 PSK, 这里的 PSK 由服务器端发送的 New Session Ticket 得到。

6-9 是当前连接(一条新的连接)。 我们注意到红框圈起来的部分便是 0-RTT 数据。 它是直接跟在 Change Cipher Spec 之后的, 也就是我们当前连接的 TCP 连接建立起来之后, 直接便发送 Client Hello, Change Cipher Spec 和 0-RTT 数据, 而不需要等待 TLS 握手完成。

这里我们在第 6 步便把数据发送出去了, 第 8 步才是 TLS 握手成功的节点。

这里依然有一些细节需要注意,我们下面逐一解析:


[5] NewSessionTicket.early_data#


Bash
Transport Layer Security    TLSv1.3 Record Layer: Handshake Protocol: New Session Ticket        Opaque Type: Application Data (23)        Version: TLS 1.2 (0x0303)        Length: 82        Handshake Protocol: New Session Ticket            Handshake Type: New Session Ticket (4)            Length: 61            TLS Session Ticket                Session Ticket Lifetime Hint: 7200 seconds (2 hours)                Session Ticket Age Add: 953680565                Session Ticket Nonce Length: 8                Session Ticket Nonce: 0000000000000001                Session Ticket Length: 32                Session Ticket: ....af85e4152440                Extensions Length: 8                Extension: early_data (len=4)                    Type: early_data (42)                    Length: 4                    Maximum Early Data Size: 16384

第 5 步中的 New Session Ticket 携带了一个扩展 early_data, 用于表明当前 Session ticket 可以用于发送 0-RTT 数据。

并且这个 early_data 中携带一个 Maximum Early Data Size 表明服务器端愿意接收 0-RTT 数据的最大值,超过这个值会被拒绝。 (这也就是我们开始说可以发送“一部分数据”的原因了, 不能像 1-RTT 那样发送任意数量的数据)


[6] ClientHello.early_data#


Bash
Transport Layer Security    TLSv1.3 Record Layer: Handshake Protocol: Client Hello        Content Type: Handshake (22)        Version: TLS 1.0 (0x0301)        Length: 309        Handshake Protocol: Client Hello            Handshake Type: Client Hello (1)            Length: 305            Version: TLS 1.2 (0x0303)            Random: ...1081762b162            Session ID Length: 32            Session ID: ,,,8218132ba7            Cipher Suites Length: 8            Cipher Suites (4 suites)            Compression Methods Length: 1            Compression Methods (1 method)            Extensions Length: 224            ....            Extension: early_data (len=0)                Type: early_data (42)                Length: 0            Extension: pre_shared_key (len=91)                Type: pre_shared_key (41)                Length: 91                Pre-Shared Key extension                    Identities Length: 38                    PSK Identity (length: 32)                    PSK Binders length: 49                    PSK Binders 

early_data 扩展:这个扩展没有实际数据,就是一个标识符,表明当前握手过程中,客户端会发送 0-RTT 数据。

这里同时还要携带 pre_shared_key(这是前提), 并且这是使用的 PSK 必须是从带有 early_data 扩展的 New Session Ticket 中计算得来的。


[7] EncryptedExtensions.early_data#


Bash
Transport Layer Security	TLSv1.3 Record Layer: Handshake Protocol: Encrypted Extensions        Opaque Type: Application Data (23)        Version: TLS 1.2 (0x0303)        Length: 27        [Content Type: Handshake (22)]        Handshake Protocol: Encrypted Extensions            Handshake Type: Encrypted Extensions (8)            Length: 6            Extensions Length: 4            Extension: early_data (len=0)                Type: early_data (42)                Length: 0

early_data 扩展: 用于向客户端表明服务器端接受了客户端的 0-RTT 数据。


[8] EndOfEarlyData#


Bash
Transport Layer Security    TLSv1.3 Record Layer: Handshake Protocol: End of Early Data        Opaque Type: Application Data (23)        Version: TLS 1.2 (0x0303)        Length: 21        [Content Type: Handshake (22)]        Handshake Protocol: End of Early Data            Handshake Type: End of Early Data (5)            Length: 0

EndOfEarlyData 是客户端发送给服务器的一个消息, 用于表明自己的 0-RTT 数据已经发送完毕,解析来的数据将是平常的 TLS 加密的数据了。

这个消息也是空的,只是用于表明自己 0-RTT发送完毕了。


实例: 0-RTT数据被拒绝#


也存在一些场景,客户端发送的 0-RTT 数据不被服务器端接受.这里我们来看看响应的流程.

(这里我是用一个过期的 PSK 来模拟这种场景的)

image-20241115092807300

在步骤 1 中, 我们依然是发送 ClientHello 以及相应的 0-RTT 数据(Application Data 中)

ClientHello 中依然携带 pre_shared_key 和 early_data 扩展. 但是这里的 pre_shared_key 是已经过期了. 因此,此次 TLS 会话恢复(Session resumption) 会失败,因此服务器端无法正常解密我们的 0-RTT 数据,因此拒绝接受它.

在步骤 2中, 服务器回复的 Encrypted Extensions 中便没有携带 early_data 扩展, 以表示不接受我们的 0-RTT 数据.

Bash
Transport Layer Security    TLSv1.3 Record Layer: Handshake Protocol: Encrypted Extensions        Opaque Type: Application Data (23)        Version: TLS 1.2 (0x0303)        Length: 23        [Content Type: Handshake (22)]        Handshake Protocol: Encrypted Extensions            Handshake Type: Encrypted Extensions (8)            Length: 2            Extensions Length: 0

因为,客户端的 0-RTT 已经被明确的拒绝接受了,因此,客户端也不需要再发送 EndOfEarlyData 消息了.


Published at:
October 20, 2026
Keywords:
TLS
Session Ticket
0-RTT
Zero round-trip time
TLS13