HKDF 是 TLS1.3 中定义的基础组件,该组件主要分为两个部分 HKDF-Extract 和 HKDF-Expand 部分,这两个部分一般情况混合使用。在 TLS1.2 当中,定义了一个叫做 PRK 的组件,做的实际上就是 HKDF-Expand 的作用。HKDF 的基础定义可以去看 RFC5869,具体的实现部分不再赘述。
TLS1.3 中除了使用 HKDF-Extract 和 HKDF-Expand 之外,还定义了其它函数,其数据结构为: HKDF-Expand-Label(Secret, Label, Context, Length) = HKDF-Expand(Secret, HkdfLabel, Length)
Where HkdfLabel is specified as:
struct {
uint16 length = Length;
opaque label<7..255> = "tls13 " + Label;
opaque context<0..255> = Context;
} HkdfLabel;
Derive-Secret(Secret, Label, Messages) =
HKDF-Expand-Label(Secret, Label,
Transcript-Hash(Messages), Hash.length)
可以看出本质上 Derive-Secret 就是把拼接好的 Label(不同的 secret 种类加不同的 Label)当成 info 字段输入到,Message 报文就是我们输入的 ClientHello 等报文当做环境也就是 Context 输入到 HKDF-Expand 里。进而获得我们想要的各种不同 key.
ok,来看看 psk-only 模式下如何获得各种秘钥。
HKDF-Extract(PSK,0)==>Early Secret.
PSK 是 IKM,SALT 是0,计算产生 RKM--Early Secret.Early Secret 参与到不同种类的 secret 当中去,值得注意的是这里 secret 的产生并不像网上说的计算多次,而是根据不同的种类计算不同的 secret.
1
hxndg OP Derive-Secret(.,"ext binder"|"res binder","")= binder_key
binder_key 用于 psk identity 计算,使用类似计算 finished 信息的计算方式,只不过 base key 换成了 binder_key. 所以有一点概念需要明确,binder_key 和 0-rtt data 通信时候的秘钥没有什么关系。这个东西就是来让服务端和客户端标示身份用的,服务端回复 identity index,这个值双方都是共有的。 |
2
hxndg OP Derive-Secret(., "c e traffic",ClientHello)= client_early_traffic_secret
客户端传送 early data 的时候用的传输 secret,首先什么是 early data?early data 本质上就是 application data。换成日常的应用就是 GET / HTTP/1.1 ...等信息。这个信息使用的秘钥是需要拿 clientHello 报文计算出来的。值得注意的是这个时候客户端默认选择了他最终以的 psk 也就是第一个对,把信息传送过去。 |