You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

TLSv1.2 ECDHE_ECDSA_WITH_AES_256_GCM_SHA384握手实现细节问询

TLS v1.2 受限子集实现细节疑问(Erlang sans IO 模式)

我在服务端基于Erlang采用**无IO(sans IO)**技术实现了TLS v1.2的一个受限子集,仅针对ECDHE_ECDSA_WITH_AES_256_GCM_SHA384算法组合。我了解相关理论,但具体实现细节仍有模糊点,查看过Wireshark抓包和RFC5246文档后,仍有三个问题:

  • 握手协议->服务器密钥交换->签名字段:具体包含哪些内容,以及后续处理流程?我了解到使用服务器私钥签名前有一些异或操作。
  • 加密握手消息:具体包含哪些内容?
  • 如何利用客户端的应答生成会话对称密钥?似乎是ClientRandom + ServerRandom + 其他内容,再进行SHA384哈希,之后还有其他操作?还是我的思路有误?有资料称需要拼接包括Server Hello TLS记录在内的完整二进制流量。

额外说明:
采用“无IO(sans IO)”技术实现,即所有TLS交换不使用套接字,仅依赖保存的状态和函数参数。该服务需要与企业网络中已有的.NET/C#客户端完全兼容,抓包确认所有客户端均支持上述算法组合。


问题1:服务器密钥交换签名字段内容及处理流程

针对ECDHE_ECDSA_WITH_AES_256_GCM_SHA384算法,签名字段的构造及处理流程如下:

签名构造代码(Erlang)

SignatureAlgo   = ?ECDSA_SECP384R1_SHA384,
HashAlgo        = sha384,
ClientPubKeyLen = byte_size(ClientPublicKey),

% 构造加密参数(包含曲线标识、公钥)
EncParams = <<?BYTE(?NAMED_CURVE),
            ?UINT16((tls_v1:oid_to_enum(?secp384r1))),
            ?BYTE(ClientPubKeyLen),
                ClientPublicKey/binary>>,
% 拼接待签名的原始数据:ClientRandom + ServerRandom + 加密参数
Erunda = <<ClientRandom/binary, ServerRandom/binary, EncParams/binary>>,
% 使用服务器私钥对拼接后的数据做SHA384哈希签名
Signature = public_key:sign(Erunda, HashAlgo, ServerKey),
...

细节说明

  1. 待签名数据组成:必须包含客户端随机数(ClientRandom)、服务器随机数(ServerRandom),以及本次ECDHE交换的核心参数(命名曲线标识、服务器生成的EC公钥)。这些数据拼接后作为签名的原始输入,确保握手过程的不可否认性和完整性。
  2. 签名流程:先对拼接后的Erunda数据做SHA384哈希,再用服务器的ECDSA私钥对哈希值进行签名。你提到的“异或操作”是误解,ECDHE_ECDSA签名流程中没有异或步骤,直接对哈希结果做签名即可。
  3. 后续处理:生成的签名会封装进ServerKeyExchange握手消息发送给客户端,客户端用服务器的ECDSA公钥验证签名有效性,确认服务器身份和交换参数未被篡改。

问题2:加密握手消息的内容

在TLS v1.2握手阶段,只有Finished消息会被加密传输,其他握手消息(如ClientHello、ServerHello、ServerKeyExchange等)均为明文传输。加密的Finished消息核心内容如下:

  • 基于握手全量消息生成的验证数据(VerifyData),由主密钥(Master Secret)、固定标识字符串和握手消息哈希通过伪随机函数(PRF)生成。
  • 消息类型标识(固定为finished)。

具体生成规则

Finished消息的加密内容是经对称密钥加密后的VerifyData,其生成逻辑为:

VerifyData = PRF(MasterSecret, "client finished" / "server finished", Hash(HandshakeMessages))

其中HandshakeMessages是从握手开始到Finished消息之前的所有握手消息的二进制拼接,哈希算法采用SHA384(对应所选套件)。

问题3:利用客户端应答生成会话对称密钥

你的思路方向正确,需严格遵循TLS v1.2的密钥派生流程,核心步骤如下:

1. 生成预主密钥(Pre-Master Secret)

通过ECDHE密钥交换,客户端和服务器各自计算出相同的预主密钥:服务器用自身EC私钥+客户端EC公钥计算,客户端用自身EC私钥+服务器EC公钥计算,最终得到384位的二进制值。

2. 生成主密钥(Master Secret)

主密钥由预主密钥、ClientRandom、ServerRandom通过PRF派生:

MasterSecret = PRF(PreMasterSecret, "master secret", ClientRandom + ServerRandom)

PRF采用SHA384算法,派生后主密钥长度为48字节(384位)。

3. 生成会话对称密钥

主密钥再通过PRF派生得到所有会话所需的密钥材料,包括:

  • 客户端/服务器发送用的AES-GCM密钥
  • 客户端/服务器发送用的IV(初始化向量)
  • 客户端/服务器发送用的GCM认证密钥

派生规则为:

KeyMaterial = PRF(MasterSecret, "key expansion", ServerRandom + ClientRandom)

随后按顺序从KeyMaterial中截取对应长度的字节:

  • AES-256密钥:每个方向32字节
  • GCM IV:每个方向12字节
  • GCM认证密钥:每个方向16字节

注意点

不需要拼接包括Server Hello在内的完整二进制流量,密钥派生的核心输入是预主密钥、ClientRandom和ServerRandom。你看到的“拼接完整流量”是生成Finished消息时用到的握手消息哈希,和密钥派生无关。


内容的提问来源于stack exchange,提问作者Dimitri

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.12 09:23:12