TLS 1.3 新特性剖析

默认分类 2025-04-13 117 次浏览 次点赞


这里结合 RFC8446MbedTLS 源码, Wireshark 抓包对 TLS 1.3 几个重要特性做深入剖析。

一 特性剖析

1. TLS 1.3 VS 1.2

https://datatracker.ietf.org/doc/html/rfc8446#section-1.2

TLS 1.3 对比 TLS 1.2 的主要差异。

项目条目TLS 1.2TLS 1.3
加密与算法对称加密算法支持多种,包括已废弃的 CBC、RC4仅支持 AEAD 算法(如 AES-GCM、ChaCha20-Poly1305)
密钥派生算法自定义复杂结构 KDF使用统一的 HKDF(HMAC-based Extract-and-Expand)
密钥交换机制支持 RSA、DH、ECDHE,包括静态密钥移除静态 RSA/DH,统一使用 ECDHE,具备前向安全
签名算法支持RSA、DSA、ECDSARSA、DSA、ECDSA
安全改进前向安全(PFS)可选,取决于是否使用 (EC)DHE所有公钥交换均具备前向安全
报文完整性保护加密和 MAC 分离(MAC-then-encrypt)使用 AEAD(集成加密+认证)
证书扩展等隐私保护扩展字段如 SNI 以明文发送扩展通过 EncryptedExtensions 加密传输
握手机制握手消息加密ServerHello 后部分消息仍明文ServerHello 后全部握手消息加密
握手流程结构含 ServerHelloDone、ChangeCipherSpec精简状态机,移除冗余消息
0-RTT 数据支持不支持支持 0-RTT,允许部分早期数据发送(有安全限制)
会话恢复会话恢复机制Session ID / Session ticket 两种方式统一为 PSK-based 会话恢复,使用 SessionTicket + Binder
PSK 模式较少使用明确支持 PSK-only / PSK + ECDHE
兼容性机制版本协商通过 ClientHello.version,存在兼容问题使用 extension 提供版本列表,增强兼容性
压缩与 DSA支持 TLS-level 压缩、支持 DSA移除压缩与 DSA,避免压缩攻击

TLS1.3 完整握手

重点介绍全新特性前。介绍下 TLS 1.3 的完整握手流程。

https://datatracker.ietf.org/doc/html/rfc8446#section-2

如上完整握手流程,包含密钥交换(Key Exchange)和双向认证(Authentication,可选)流程。

  • 对于密钥交换仅支持 ECDHE。
  • 对于认证支持证书认证和 PSK 认证,当然也可以不做认证。

如上 KE 和 Auth 流程组合,TLS 1.3 共支持如下5种模式。

握手模式描述
完整握手ECDHE使用 ECDHE 密钥交换,无认证。
PSK ECHDE使用预设密钥 PSK 快速认证 + ECDHE 密钥交换
证书 ECHDE使用证书进行身份验证 + ECDHE 密钥交换
会话恢复PSK ECDHE基于 Session Ticket 快速恢复会话,流程与 PSK-ECDHE 类似,区别在于 PSK 来源不同:完整 PSK-ECDHE 使用预共享凭据;会话恢复则使用前次握手后协商出的临时 PSK。
PSK Only基于 Session Ticket 快速恢复会话,但是不做 ECHDE。需要说明的是,尽管不做 ECHDE,但是还有一个简单 KE,同 TLS 1.2 PSK KE 原理相似。在后面章节会详细介绍。

2. 安全增强

2.1 PSK KE VS PSK ECHDE

TLS 1.2 PSK KE 对比 TLS 1.3 PSK ECDHE 一个安全特性就是前向安全。 前向安全确保了长期密钥泄露不会影响历史会话的安全性。

以下是 TLS 1.2 PSK KE 与 TLS 1.3 PSK ECDHE 的握手流程对比。在密钥交换过程中,最大的区别在于是否引入了临时椭圆曲线 Diffie-Hellman 的密钥交换。

注意:如上为简化公式。完整的密钥派生会在后面详细介绍。

PSK KE vs PSK ECHDE

  • 在 TLS 1.2 PSK KE 模式下,会话密钥完全依赖预共享密钥(PSK),如果 PSK 泄露,攻击者可以离线解密之前或当前的通信内容。

    提示:ClientRandom 和 ServerRandom 为明文交换,所以 PSK 泄漏,MasterSecret 就会泄漏。

  • 在 TLS 1.3 PSK ECDHE 模式下,引入了临时的 ECDHE ClientShare 和 ServerShare 公钥交换,即使 PSK 被泄露,也无法恢复会话密钥,因此提供了前向安全性。

    提示:尽管 ClientShare、ServerShare、ClientRandom、ServerRandom 都是明文交换,但是 ECDH 共享密钥计算需要私钥参与。所以 MasterSecret 不会直接泄漏。

2.2 密钥派生

https://datatracker.ietf.org/doc/html/rfc8446#section-7.1

如下流程为 TLS 1.3 完整的密钥派生流程。

TLS 1.3 密钥派生

  • HKDF-Extract 为熵压缩器,可以看作是一个安全的“种子生成器” 。需要输入 salt 和 IKM(Input Key Material)。如下框图为从上方获取 Salt 参数,从左侧获取 IKM 参数,输出结果向下,其输出变量名写在右边。

    Derive-Secret 为密钥派生器,可以理解为如上“种子”长出多种不同用途的“树”。需要输入:Secret 和 Label 和 Messages。

    Derive-Secret(Secret, Label, Messages) =
         HKDF-Expand-Label(Secret, Label,
                           Transcript-Hash(Messages), Hash.length)
  • 如下框图为从上方获取 Secret 参数,Label 和 Messages 已经包含在 Derive-Secret() 函数参数中。其中 ClientHello...ServerHello 表示两条消息的 hash 值。ClientHello...server Finished 表示从 ClientHello 到 Finished 所有消息的 hash 值。
  • 0 表示一个长度为 Hash.length 字节的全 0 字节串。

首先需要具体说明每一个密钥的使用场景。

阶段密钥描述
Early Secret 早期密钥binder_key用于验证 PSK 的合法性(在 ClientHello 中计算 binder HMAC)
client_early_traffic_secret用于 加密 0-RTT 数据(仅客户端发送)
early_exporter_master_secret用于早期阶段的数据导出(如 token 等)
Handshake Secret 握手阶段密钥client_handshake_traffic_secret加密客户端握手阶段消息,如 Certificate、Finished
server_handshake_traffic_secret加密服务端握手阶段消息,如 Certificate、Finished
Master Secret 主密钥server_application_traffic_secret_0加密服务端应用层数据
exporter_master_secret用于导出额外密钥材料(给上层协议或 token 用)
resumption_master_secret会话恢复时用于生成 Session Ticket 中的 PSK

如上密钥派生流程,主要输入信息为 PSK 和 ECDHE。上面我们已经讨论了 TLS 1.3 的5种不同模式。接下来我们看看不同模式的 PSK 和 ECDHE 信息。

握手模式描述PSK
完整握手ECDHE使用 ECDHE 密钥交换,无认证。无 PSK,有 ECHDE
PSK ECHDE使用预设密钥 PSK 快速认证 + ECDHE 密钥交换预设 PSK,有 ECHDE
证书 ECHDE使用证书进行身份验证 + ECDHE 密钥交换无 PSK,有 ECDHE
会话恢复PSK ECDHE基于 Session Ticket 快速恢复会话,流程与 PSK-ECDHE 类似,区别在于 PSK 来源不同:常规 PSK-ECDHE 使用预共享凭据;会话恢复则使用前次握手后协商出的临时 PSK。有 PSK,PSK = HKDF-Expand-Label(resumption_master_secret, "resumption", ticket_nonce, Hash.length)PSK 由 resumption_master_secret(上次会话派生出) 和 ticket_nonce(上次会话临时临时生成,通过 NewSessionTicket 发送给客户端)。有 ECDHE
PSK Only基于 Session Ticket 快速恢复会话,但是不做 ECHDE。需要说明的是,尽管不做 ECHDE,但是还有一个简单 KE,同时 TLS 1.2 PSK KE 原理一致。在后面章节会详细介绍。有 PSK,PSK 同上。无 ECDHE。

3. 2-RTT VS 1-RTT

TLS 1.3 的一个重要特性是优化了握手阶段的消息交互效率,将原本的 2-RTT 优化为 1-RTT,主要通过以下两个机制实现:

  • 在 TLS 1.2 中,ClientKeyExchange 和 ServerKeyExchange 是独立消息;而在 TLS 1.3 中,这些密钥交换参数被整合进 ClientHello 和 ServerHello 的 key_share 和 pre_shared_key 扩展中,避免了额外的往返消息。
  • 对于身份验证相关的 Finished 消息,TLS 1.2 是由客户端先发送,TLS 1.3 则调整为服务端先发送,这使得 Finished 可以合并在服务端的响应路径中发出。

另外对于 RTT 计算你可能还会有如下疑问。

  1. TLS 1.3 最后还需要发送 Finished 消息,应该算 1.5 RTT?

    对于客户端 Application Data 可以和 Finished 可以一起发送。

  2. 对于 ServerHello 和 CertificateRequest 以及 Certificate 是单独发送为什么 RTT 算在一起?

    在 TLS 1.3 中,服务端从 ServerHello 开始,接下来可以批量发出:
    EncryptedExtensions → Certificate → CertificateVerify → Finished,中间不需要等待客户端的响应,因此这整个过程都算作第 1 个 RTT 内的服务端响应部分。

  3. 如果 TCP RWND = 1 MSS,并且不支持 Trickle ,RTT 如何计算?

    在特定网络条件下(RWND = 1 MSS,不支持 Trickle),TLS 1.3 中服务端确实无法一次性发完所有握手消息,需要多个 TCP ACK 往返来推动 TLS 消息发出。
    在网络层面上 RTT 被拉长了:虽然 TLS 协议逻辑上是一轮 RTT完成握手,但实际 由于 TCP 的传输能力受限,ServerHello 后的证书链等可能被拆分成多个 TCP 分段发送。这个时候,从“时延体验”上看类似于 2-RTT,但协议本身仍然是 1-RTT 的握手逻辑。

4. 0-RTT Early Data

https://datatracker.ietf.org/doc/html/rfc8446#section-2.3

首先说明应用场景。0-RTT Early Data 只能用以有 PSK 的握手流程。

  • 基于 Resumption PSK 会话恢复流程
  • 基于 External PSK 的完整握手流程

不能在首次基于证书的完整握手流程中使用。

提示:如图所示绿色握手消息表示 Early Data 特定流程。

如上图所示

  1. ClientHello

    客户端发起握手,并尝试发送 Early Data,包含以下关键扩展:

    字段描述
    + early_data告诉服务端:“我打算发送 0-RTT 数据”。仅作为信号,无内容。
    + pre_shared_key包含 PSK identity(用于识别会话)和 binder(对 ClientHello 做 MAC 认证)。用于认证服务器并恢复密钥。
  2. (Application Data*)

    如果客户端在 ClientHello 中附带了 early_data 扩展,它可以立即附加加密的 Early Application Data(比如一个 HTTP 请求或 MQTT CONNECT)。
    该数据使用 client_early_traffic_secret 派生出的密钥进行加密。

  3. ServerHello

    服务端响应握手,并选择一个 PSK:

    字段描述
    + pre_shared_key告诉客户端:“我接受了你提供的哪个 PSK identity”。这一决定决定了后续密钥派生路径。
  4. {EncryptedExtensions}

    这是 TLS 1.3 新增的加密消息,用于传输额外扩展字段:

    字段描述
    + early_data*如果服务端接受了 0-RTT 数据,则必须发送该扩展,告知客户端 early data 被接受;否则不发送,表示拒绝 early data。
  5. (EndOfEarlyData)

    如果客户端确实发送了 Early Data,那么它在收到服务端 EncryptedExtensions 后,必须发送 EndOfEarlyData 消息。
    它是握手中的一个标记,告知服务端:早期应用数据(0-RTT)已经发送完毕。
    它也意味着后续将切换到 Handshake Secret 加密上下文。

  6. [Application Data*]

    这是服务端在握手完成后发送的正常 Application Data:使用 server_application_traffic_secret 加密;它可能包含服务端响应,例如 HTTP 响应或 MQTT CONNACK。

总结:

消息加密上下文作用说明
ClientHello明文携带 PSK、声明 early_data 意图
(Application Data*)使用 early secret 加密早期发送的业务数据
ServerHello明文响应 ClientHello,指定使用哪个 PSK
{EncryptedExtensions}Handshake Secret服务端确认是否接受 early_data
EndOfEarlyDataHandshake Secret客户端结束 early data 发送
[Application Data*]Application Secret正式数据传输阶段开始

5. 会话恢复

https://datatracker.ietf.org/doc/html/rfc8446#section-2.2
https://datatracker.ietf.org/doc/html/rfc5077

会话恢复是基于完整 1-RTT 握手协议进一步优化的机制,旨在减少连接建立时的延迟开销。TLS 1.2 支持两种会话恢复机制:Session ID(服务端有状态)和 Session Ticket(服务端无状态)。TLS 1.3 延续了 Session Ticket 的会话恢复机制,但不再直接恢复 Master Secret,而是将 Resumption Secret 用作 PSK,重新进行密钥派生。该过程支持可选的 ECDHE 交换(PSK+ECDHE),进一步增强前向安全性。

看看3种完整握手流程的在2种会话恢复下的收益。

完整握手握手模式会话恢复恢复模式收益
完整握手ECDHE会话恢复PSK ECDHE无收益
PSK Only省略 ECDHE 流程
PSK ECHDE会话恢复PSK ECDHE无收益,还增加 PSK 解密流程
PSK Only省略 ECDHE 流程
证书 ECHDE会话恢复PSK ECDHE省略证书如流程
PSK Only省略证书认证和 ECDHE 流程

TLS 1.3 会话恢复流程

提示:如图所示绿色握手消息表示 PSK 会话恢复特定流程。
https://datatracker.ietf.org/doc/html/rfc5077#section-4

TLS 1.3 会话恢复的关键路径是:完成完整握手后,服务端通过 NewSessionTicket 向客户端下发一个加密的 Ticket。该 Ticket 由服务端的 Ticket Protection Key 加密,服务端不保存 Ticket 内容,因此这种机制被称为“无状态的会话恢复”。

在后续会话恢复阶段,客户端将该 Ticket 原样通过 ClientHello 的 pre_shared_key 扩展回传,服务端解密后取出其中的 PSK,重新执行密钥派生流程,从而恢复会话。

详细看看 Ticket 数据结构。

https://datatracker.ietf.org/doc/html/rfc8446#section-4.6.1
struct {
    uint32 ticket_lifetime;                   // 客户端可使用该 Ticket 的有效时间(单位:秒)
    uint32 ticket_age_add;                    // 随机扰动值,防止重放攻击,服务端生成
    opaque ticket_nonce<0..255>;              // 用于导出 PSK 的 nonce 值(参与 HKDF)
    opaque ticket<1..2^16-1>;                 // 实际 Ticket 内容(密文)
    Extension extensions<0..2^16-2>;          // 可选扩展,例如 early_data 支持等
} NewSessionTicket;
https://datatracker.ietf.org/doc/html/rfc5077#section-4
struct {
    opaque key_name[16];                      // 标识用于加密该 ticket 的密钥名称
    opaque iv[16];                            // AEAD 加密使用的初始化向量
    opaque encrypted_state<0..2^16-1>;        // 加密的 session state(服务端状态)
    opaque mac[32];                           // AEAD 加密产生的认证标签(MAC)
} ticket;
提示:而对于 PSK 加密的 encrypted_state 数据结构在 RFC 8446RFC 5077 均没有详细定义。需要结合 https://github.com/Mbed-TLS/mbedtls/blob/v3.6.3/library/ssl_tls.c#L3818 代码。
struct {
    uint32_t ticket_age_add;                  // 与 NewSessionTicket 中一致,用于计算实际 age
    uint8_t  ticket_flags;                    // 标志位,如是否支持 0-RTT 等
    uint8_t  resumption_key_len;              // PSK 长度(通常是 32)
    uint8_t  resumption_key[32];              // 客户端用于恢复 early_secret 的 PSK
    uint32_t ticket_lifetime;                 // Ticket 生命周期,服务端控制
    uint16_t ticket_len;                      // ticket ID 长度
    uint8_t  ticket[ticket_len];              // 唯一标识该 Session Ticket 的 ID
    // 以下为可选字段(根据编译选项启用)
    uint64_t ticket_creation_time;            // Ticket 创建时间(用于服务端过期检查)
    uint32_t max_early_data_size;             // 客户端支持的最大 Early Data 大小
    uint16_t record_size_limit;               // 最大记录大小限制
    uint16_t hostname_len;                    // 主机名长度(客户端 SNI)
    uint8_t  hostname[hostname_len];          // 主机名内容(如有)
    uint16_t alpn_len;                        // ALPN 协议长度
    uint8_t  alpn[alpn_len];                  // ALPN 协议内容
} encrypted_state;

TLS 1.3 的会话恢复不同于 TLS 1.2 的直接恢复 Master Secret。其核心增强在使用 resumption_key 作为 PSK,重新执行一轮完整的密钥派生,从而获得前向安全。

分别看看客户端和服务端如何持有 PSK 。

  • 客户端在接收到 NewSessionTicket 后,根据 ticket_nonce 和本地的 resumption_master_secret 派生出会话恢复用的 PSK:

  • 对于 Server 端,并不存储 Ticket,而是等待客户端在 ClientHello 的 pre_shared_key 直接将加密 ticket 回传给服务端,使用 Ticket Protection Key 解密后直接取出 encrypted_state 中的 resumption_key 作为 PSK。

对于 Ticket Protection Key 的管理,不再 RFC 讨论中,Mbed TLS 做了双密钥的轮换管理。

/*
 * Rotate active session ticket encryption key
 */
int mbedtls_ssl_ticket_rotate(mbedtls_ssl_ticket_context *ctx,
                              const unsigned char *name, size_t nlength,
                              const unsigned char *k, size_t klength,
                              uint32_t lifetime)

二 测试分析

1. 编译使用

这里使用 Mbed TLS v3.6.3 官方仓库 programs/ssl/ssl_client2.cprograms/ssl/ssl_server2.c 完成测试。
直接参考工程 README.md 编译 ssl_client2 和 ssl2_server2。例如 Make 直接在根目录运行 make 即可。

git clone https://github.com/Mbed-TLS/mbedtls.git
git submodule update --init
cd mbedtls
make

对于不同测试可以参考 Mbed TLS 的测试用例,比如 0-RTT (Early Data)。测试脚本会告诉你使能哪些宏,使用哪些参数,以及输出日志。

requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_3
requires_config_enabled MBEDTLS_SSL_CLI_C
requires_config_enabled MBEDTLS_SSL_SRV_C
requires_config_enabled MBEDTLS_SSL_SESSION_TICKETS
requires_config_enabled MBEDTLS_HAVE_TIME
requires_config_enabled MBEDTLS_SSL_EARLY_DATA
requires_config_enabled MBEDTLS_DEBUG_C
requires_config_enabled MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_EPHEMERAL_ENABLED
requires_any_configs_enabled MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_PSK_ENABLED \
                             MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_PSK_EPHEMERAL_ENABLED
run_test "TLS 1.3 m->m: resumption with early data" \
         "$P_SRV debug_level=4 early_data=1 crt_file=../framework/data_files/server5.crt key_file=../framework/data_files/server5.key" \
         "$P_CLI debug_level=3 early_data=1 new_session_tickets=1 reco_mode=1 reconnect=1" \
         0 \
         -c "Protocol is TLSv1.3" \
         -c "Saving session for reuse... ok" \
         -c "Reconnecting with saved session" \
         -c "HTTP/1.0 200 OK" \
         -c "received max_early_data_size" \
         -c "NewSessionTicket: early_data(42) extension received." \
         -c "ClientHello: early_data(42) extension exists." \
         -c "EncryptedExtensions: early_data(42) extension received." \
         -c "bytes of early data written" \
         -C "0 bytes of early data written" \
         -s "Protocol is TLSv1.3" \
         -s "key exchange mode: psk" \
         -s "Select PSK ciphersuite" \
         -s "Sent max_early_data_size" \
         -s "NewSessionTicket: early_data(42) extension exists." \
         -s "ClientHello: early_data(42) extension exists." \
         -s "EncryptedExtensions: early_data(42) extension exists." \
         -s "early data bytes read"

如上宏配置可以通过 scripts/config.py 检查和设置当前配置。

scripts/config.py --file include/mbedtls/mbedtls_config.h get MBEDTLS_SSL_EARLY_DATA ;echo $?  #1表示未使能,0表示使能
scripts/config.py --file include/mbedtls/mbedtls_config.h set MBEDTLS_SSL_EARLY_DATA
scripts/config.py --file include/mbedtls/mbedtls_config.h get MBEDTLS_SSL_EARLY_DATA ;echo $?  #1表示未使能,0表示使能

对于当前需要测试的会话恢复。其他宏都默认使能(当前你可以通过 get 检查),你只需要使能如上 MBEDTLS_SSL_EARLY_DATA

scripts/config.py --file include/mbedtls/mbedtls_config.h set MBEDTLS_SSL_EARLY_DATA
make
ls programs/ssl/ssl_*2
  • TLS 1.2 PSK KE 本地连接测试。

    服务端

    programs/ssl/ssl_server2 debug_level=3 nbio=0 min_version=tls12 max_version=tls13 auth_mode="required" tickets=0 server_addr=127.0.0.1 force_ciphersuite=TLS-PSK-WITH-AES-128-GCM-SHA256  psk=6162636465666768696a6b6c6d6e6f70 psk_identity="PSK Identity"

    客户端

    programs/ssl/ssl_client2 nss_keylog=1 nss_keylog_file=tls_client_nss_key.log debug_level=3 nbio=0 server_name="localhost" tickets=0 server_addr=127.0.0.1 force_version=tls12 psk=6162636465666768696a6b6c6d6e6f70 psk_identity="PSK Identity"
  • TLS 1.3 PSK ECDHE 本地连接测试。

    服务端

    programs/ssl/ssl_server2 debug_level=3 nbio=0 min_version=tls12 max_version=tls13 auth_mode="required" force_ciphersuite=TLS1-3-AES-128-GCM-SHA256 tickets=1 server_addr=127.0.0.1 psk=6162636465666768696a6b6c6d6e6f70 psk_identity="PSK Identity"

    客户端

    programs/ssl/ssl_client2 nss_keylog=1 nss_keylog_file=tls_client_nss_key.log debug_level=3 nbio=0 server_name="localhost" tickets=0 new_session_tickets=0 reco_mode=0 server_addr=127.0.0.1 server_addr=127.0.0.1 force_version=tls13 psk=6162636465666768696a6b6c6d6e6f70 psk_identity="PSK Identity"
  • TLS 1.3 双向证书 ECDHE 本地连接测试。

    服务端

    programs/ssl/ssl_server2 debug_level=3 nbio=0 min_version=tls12 max_version=tls13 auth_mode="required" crt_file=framework/data_files/server5.crt key_file=framework/data_files/server5.key

    客户端

    programs/ssl/ssl_client2 nss_keylog=1 nss_keylog_file=tls_client_nss_key.log debug_level=3 nbio=0 server_name="localhost" tickets=0 new_session_tickets=0 reco_mode=0 server_addr=127.0.0.1 server_addr=127.0.0.1 force_version=tls13 auth_mode="required"  crt_file=framework/data_files/server5.crt key_file=framework/data_files/server5.key key_opaque_algs=ecdsa-sign,none
  • TLS 1.3 开启 Session Tickets,进行会话恢复。

    服务端

    programs/ssl/ssl_server2 debug_level=3 nbio=0 min_version=tls12 max_version=tls13 auth_mode="required" force_ciphersuite=TLS1-3-AES-128-GCM-SHA256 tickets=1 server_addr=127.0.0.1 psk=6162636465666768696a6b6c6d6e6f70 psk_identity="PSK Identity"

    客户端

    programs/ssl/ssl_client2 nss_keylog=1 nss_keylog_file=tls_client_nss_key.log debug_level=3 nbio=0 server_name="localhost" tickets=1 new_session_tickets=1 reco_mode=0 server_addr=127.0.0.1 server_addr=127.0.0.1 force_version=tls13 psk=6162636465666768696a6b6c6d6e6f70 psk_identity="PSK Identity" reconnect=1 
  • TLS 1.3 0-RTT Early Data 测试。

    服务端

    programs/ssl/ssl_server2 debug_level=3 nbio=0 min_version=tls12 max_version=tls13 auth_mode="required" force_ciphersuite=TLS1-3-AES-128-GCM-SHA256 tickets=1 server_addr=127.0.0.1 psk=6162636465666768696a6b6c6d6e6f70 psk_identity="PSK Identity" early_data=1 max_early_data_size=200

    客户端

    programs/ssl/ssl_client2 nss_keylog=1 nss_keylog_file=tls_client_nss_key.log debug_level=3 nbio=0 server_name="localhost" tickets=1 new_session_tickets=1 reco_mode=0 server_addr=127.0.0.1 server_addr=127.0.0.1 force_version=tls13 psk=6162636465666768696a6b6c6d6e6f70 psk_identity="PSK Identity" reconnect=1 early_data=1 

2. 测试汇总

如下测试日志汇总通过此脚本自动生成 run_tls_test.sh
测试用例抓包文件客户端日志服务端日志Key Log
TLS 1.2 PSK KEtls12_psk_capture.pcapngtls12_psk_client.logtls12_psk_server.logtls12_psk_nss_key.log
TLS 1.3 PSK ECDHEtls13_psk_ecdhe_capture.pcapngtls13_psk_ecdhe_client.logtls13_psk_ecdhe_server.log
TLS 1.3 证书 ECDHEtls13_cert_capture.pcapngtls13_cert_client.logtls13_cert_server.log
TLS 1.3 会话恢复tls13_session_resumption_capture.pcapngtls13_session_resumption_client.logtls13_session_resumption_server.log
TLS 1.3 0-RTT Early Datatls13_0rtt_capture.pcapngtls13_0rtt_client.logtls13_0rtt_server.log

3. VS Code 调试

为了方便 VS Code 单步调试走断点阅读代码,你需要编译配置优化和调试等级。

scripts/config.py --file include/mbedtls/mbedtls_config.h set MBEDTLS_SSL_EARLY_DATA
make
make CFLAGS='--coverage -g3 -O0' LDFLAGS='--coverage'

参考 Using C++ on Linux in VS Code 或者 Using Clang in Visual Studio Code 进行 VSCode 调试。

这里把如上所有测试命令配置 launch.json。直接保存在 根目录 .vscode 即可以调试。

VS Code 调试

4. Wireshark 抓包分析

因为 Wireshark 暂时还不支持 TLS 1.3 SSLKEYLOGFILE https://wiki.wireshark.org/TLS 解密。所以 TLS 1.3 信息有限。但是对于一些关键扩展和握手消息还是值得分析。

4.1 TLS 1.2 完整握手

因为 TLS 1.3 握手消息都有加密,这里解释 TLS 1.2 PSK KE 抓包分析。

4.2 TLS 1.3 0-RTT Early Data

tls13_0rtt_capture.pcapng
  • Early Data 指示

    TLS 1.3 0-RTT Early Data 指示

  • Early Data 数据

    TLS 1.3 Early Data 数据

4.3 会话恢复

tls13_session_resumption_capture.pcapng
  • 完整握手初次会话,预设 PSK。

    TLS 1.3 PSK ECDHE 初次会话

  • 会话恢复,同时包含预设 PSK 和会话恢复的 PSK,前面一个为 Ticket。

    TLS 1.3 PSK Resumption


本文由 Jay 创作,采用 知识共享署名 3.0,可自由转载、引用,但需署名作者且注明文章出处,点赞1

还不快抢沙发

添加新评论