密码学 E01:TLS 1.2 的 RSA 密钥传输与 ECDHE——历史资料为什么容易混淆
读到一篇旧文章:“服务器用 RSA 证书,所以 HTTPS 把会话密钥用服务器 RSA 公钥加密发送。”另一篇说:“服务器仍是 RSA 证书,却使用了 ECDHE。”两者不必矛盾:证书公钥的算法、服务器握手认证用的签名算法、双方建立共同秘密用的密钥交换算法,是三个问题。尤其不能把 TLS 1.2 的两种方案不加区分地复述成 TLS 1.3 的流程。
谁算秘密,谁验身份
历史 TLS 1.2 RSA key transport 中,客户端生成 pre-master secret,用服务器叶证书中的 RSA 公钥按相应握手规则加密发送;拥有 RSA 私钥的服务器解开。证书和主机名检查必须先说明客户端为什么接受这把公钥,否则攻击者换自己的公钥就能解出秘密。若当时的加密流量被记录,且后来服务器证书 RSA 私钥泄漏,历史握手所依赖的这份私钥可能使旧连接被解开;这个方案缺乏由独立临时 DH 秘密带来的前向保密边界。
TLS 1.2 的 ECDHE_RSA 则使用双方的临时椭圆曲线 DH 点计算共同秘密,用服务器 RSA 密钥对关键握手参数做身份认证;不能说“RSA 公钥加密了共同秘密”。如果只跑 ECDHE 而不把参数绑定到可信服务器身份,攻击者可以分别同客户端和服务器建立秘密并转发/修改通信。临时密钥及时擦除等条件下,将来证书私钥泄漏不应单独解开过去仅凭 ECDHE 形成的会话;不能用本地握手成功模拟私钥泄漏后的取证结果。
1 | |
examples/cryptography/E01_tls12_suites.py 在一次性临时 CA 下签发仅用于本地的 RSA 2048 服务证书,限定客户端与服务器只协商 TLS 1.2。分别选旧 AES128-SHA(Kx=RSA)和 ECDHE-RSA-AES128-GCM-SHA256(Kx=ECDHE/Au=RSA),核对实际握手返回的协议版本/套件名称;两个套件里更换预期服务名 orders.test 为 other.test 均被拒。证书同时带 digitalSignature 与 keyEncipherment,否则错误用途的证书会使 RSA 传输测试失败,但这种为了说明历史机制生成的双用途证书不是现代部署建议。
先按仓库内 examples/cryptography/README.md 完成环境准备;以下命令从仓库根目录执行。
1 | |
使用 @SECLEVEL=1 才能允许旧 RSA/SHA1/CBC 套件,只能在回环实验里使用。两种真实 TLS 握手及错名失败通过;实验没有记录/解密真实会话、没有复现私钥在未来泄漏的完整攻击,也没有多实现互通,所以 forward_secrecy_from_key_compromise_measured=false。实际 Web 服务应按当前规范/平台安全策略配置,不要把旧套件当作“性能优化”。
练习及答案
画图题: 画出 RSA transport 和 ECDHE_RSA 各自的服务证书、临时公钥、共同秘密来源。只删除“按预期服务名验证证书”后,能阻止带另一服务名但由同一测试 CA 签发的冒充者吗?
答案: RSA 传输由客户端产生 pre-master,用服务器证书公钥加密;ECDHE_RSA 由临时 DH 计算秘密,RSA 证书密钥签握手参数。若不检验名字,攻击者可用同一 CA 为另一服务签发的证书冒充期望服务;正确加密也只会把秘密安全地交给那个冒充端点。
实验变更题: 在 ECDHE_RSA 这段仅将 RSA 证书换成另一把经同一 CA 签发、名字仍为 orders.test 的有效 RSA 证书,是否必然改变“有临时 ECDHE”的事实?把套件换为纯 RSA,又怎样改变历史秘密受私钥泄漏的影响?
答案: 有效证书更换影响客户端所信身份钥匙,ECDHE 共同秘密来源仍是临时 DH;若私钥对应关系错误,握手应失败。换为纯 RSA 则没有独立的临时 ECDHE 为过往流量提供该类前向保密;不能再引用 ECDHE 的泄漏边界。任何换证都须核对 CA、SAN、用途和实际握手套件。






