4. 混合密钥交换在TLS链路中的部署验证

测试环境与部署对象

本节在隔离测试环境中完成一次可复现的混合密钥交换部署验证。测试对象为一台运行 Nginx 1.27 的 Web 服务端与一台使用 OpenSSL 3.5 客户端的测试机,二者通过本地回环或测试网段通信,不涉及生产流量。验证的核心是:在 TLS 1.3 握手中同时启用 X25519MLKEM768(X25519 与 ML-KEM-768 的混合组)与传统 X25519,确认协商结果、抓包可见性以及握手延迟与兼容性表现。

需要先明确两个前提。第一,混合密钥交换只影响 TLS 1.3 的 key_share 与密钥派生,不改变证书签名算法,因此本节不涉及证书链改造。第二,X25519MLKEM768 在 OpenSSL 3.5 中作为命名组存在,服务端与客户端必须同时支持该组才可能协商成功;任一端不支持时会回退到双方共同支持的经典组,这正是兼容性观察的重点。

服务端与客户端配置

服务端在 Nginx 的 server 块中通过 ssl_conf_command 指定组顺序,把混合组放在首位,保留 X25519 作为回退:

server {
    listen 8443 ssl;
    server_name pq-test.local;

    ssl_certificate     /etc/nginx/certs/test.crt;
    ssl_certificate_key /etc/nginx/certs/test.key;

    ssl_protocols TLSv1.3;
    # 混合组优先,X25519 作为回退组
    ssl_conf_command Groups X25519MLKEM768:X25519;

    location / {
        return 200 "pq-kex-ok\n";
    }
}

客户端使用 OpenSSL 命令行发起握手并显式指定组,便于对照实验:

# 混合组优先
openssl s_client -connect 127.0.0.1:8443 -tls1_3 \
  -groups X25519MLKEM768:X25519 -brief

# 仅经典组,用于兼容性对照
openssl s_client -connect 127.0.0.1:8443 -tls1_3 \
  -groups X25519 -brief

配置完成后先做语法检查再重载,避免因组名拼写错误导致服务启动失败:

nginx -t && nginx -s reload

握手协商与抓包确认

用 -brief 模式观察协商结果,输出中会出现协商到的组名。混合组成功时可见 Negotiated TLS1.3 group: X25519MLKEM768;若客户端只提供 X25519,则显示 X25519。这一步是判断“是否真的用上了混合密钥交换”的第一手依据。

抓包确认使用 tcpdump 保存握手报文,再用 Wireshark 或 tshark 查看 ClientHello 的 supported_groups 扩展与 ServerHello 的 key_share 扩展。混合组的 key_share 长度明显大于经典 X25519(ML-KEM-768 公钥约 1184 字节,加上 X25519 的 32 字节),这是抓包层面最直观的区分特征:

sudo tcpdump -i lo -w pq-kex.pcap 'tcp port 8443'
tshark -r pq-kex.pcap -Y 'tls.handshake.extensions_supported_group' \
  -T fields -e tls.handshake.extensions_supported_group

抓包判读要点:ClientHello 中应同时出现混合组与 X25519 的组 ID;ServerHello 的 key_share 若为混合组,其长度字段应显著大于 32 字节。若 ServerHello 只回 X25519,说明服务端未启用混合组或客户端未提供,需要回到配置核对。

TLS 1.3 混合密钥交换握手与协商判读 OpenSSL 3.5 客户端 -groups X25519MLKEM768:X25519 Nginx 1.27 服务端 Groups X25519MLKEM768:X25519 ClientHello:supported_groups = [X25519MLKEM768, X25519] ServerHello:key_share = X25519MLKEM768(长度显著 > 32B) 共享密钥派生:ML-KEM 密文 + X25519 共享值 → 混合密钥 任一算法安全即可保障会话密钥(混合安全假设) Finished:握手完成,应用数据可传输 协商成功判据 s_client 显示 X25519MLKEM768 抓包 ServerHello key_share 长度 > 32B 回退/异常判据 ServerHello 仅回 X25519 → 检查组配置 握手失败 → 核对 OpenSSL 版本与组名

延迟与兼容性记录

握手延迟用 openssl s_client 的 -brief 输出或 time 命令做多次采样,取中位数以减少抖动。教学示例中可记录如下对照(数值为示例假设,需在实际环境复测):

客户端组配置协商结果握手耗时(示例)说明
X25519MLKEM768:X25519X25519MLKEM768约 2.1 ms混合组成功,key_share 更大
X25519X25519约 1.4 ms回退经典组,兼容性正常
仅 ML-KEM 组(不支持)握手失败—无共同组,验证失败路径

兼容性表现需覆盖三类客户端:支持混合组的新版 OpenSSL、仅支持经典组的老客户端、以及组配置不匹配的异常客户端。前两类应分别协商到混合组与 X25519,第三类应明确失败并给出可读错误,而不是静默降级到不安全配置。记录时同时保存 s_client 输出与 pcap 文件,便于后续复核。

验证通过的最低标准:混合组客户端协商到 X25519MLKEM768,抓包 ServerHello 的 key_share 长度与混合组一致,经典组客户端能正常回退,异常组客户端失败且错误信息可定位。三项同时满足才算部署验证完成。
混合密钥交换不改变证书签名算法,因此本节验证通过不代表证书链已抗量子。若后续替换为 ML-DSA 证书,握手报文尺寸与兼容性会再次变化,需要单独测试。