Go中TLS源码学习(6)之Server端第3次TLS握手


💖SSL/TLS专栏导航💖
请添加图片描述
💥1. SSL/TLS原理知识
💥2. Go源码中TLS实现
💥3. openssl中TLS实现
💥4. SSL卸载
💥5. SSL代理
💥6. SSL V.P.N
💥7. SSL 与 IPSec
💥8. 其他
获取PDF版本请搜索关键字:“TLS详解”


通常情况下,第三次握手报文的载荷包括:

  • 可选的Certificate载荷
  • ClientKeyExchange载荷
  • 可选的CertificateVerify载荷
  • ChangeCipherSpec载荷
  • Finished载荷
    但是在ECDHE方式的TLS握手流程中,主要有:ClientKeyExchange、ChangeCipherSpec、Finished载荷。第三次握手报文如下:

请添加图片描述
ClientKeyExchange载荷无论在ECDHE密钥交换流程中,还是在RSA密钥交换流程中,都是个非常重要的交互载荷:在RSA流程中,ClientKeyExchange用来传递经过服务端公钥加密的预主密钥; 在ECDHE流程中,ClientKeyExchange载荷用来传递客户端的公钥信息。在ECDHE密钥交换过程中,正是通过该载荷的交换,服务端和客户端同时拥有了两个随机数、两个公钥以及各自的私钥,这便具备了生成TLS密钥的所有材料。之后便是预主密钥、主密钥、会话密钥,最后进行加密通讯。

1. 验证客户端证书

2. 计算预主密钥、主密钥

预主密钥和主密钥的计算方式涉及如下几个参数,通过TLS的握手报文,客户端和服务端都已经拥有下面的密钥材料,客户端和服务端各自计算出相同的预主密钥、主密钥以及会话密钥。
请添加图片描述
预主密钥的计算有两种方式:

🏆 当采用RSA算法进行密钥交换时,则在客户端通过随机产生;然后通过服务端证书的公钥进行加密,最后通过ClientKeyExchange载荷发送到服务端;

🏆 当采用ECDHE算法进行密钥交换时,则需要使用对端的公钥、本端的私钥、以及采用的椭圆曲线函数分别计算生成预主密钥。

Go中生成预主密钥的流程如下:
请添加图片描述
通过第Client Hello和Server Hello报文的交互,客户端和服务端已经确定了采用的算法套件,进而也就是确定了ServerKeyExchange和ClientKeyExchange载荷的内容以及处理方式。在第二个握手报文的“疑问”小结中,已经列出了算法套件与对应的密钥交换结构。由于此次TLS握手采用的是ECDHE的方式进行密钥配送,因此对应的密钥交换结构为ecdheKeyAgreement

ecdheKeyAgreement结构的SharedKey()方法中可以看出,预主密钥的计算涉及:对端的公钥,本端的私钥,以及采用的椭圆曲线
请添加图片描述
预主密钥计算完毕后,便可以生成主密钥。主密钥的计算方式比较简单:

请添加图片描述
到目前为止,预主密钥、主密钥都已经得到。后面便是可以生成6把会话密钥了

3. 制作会话密钥

会话密钥有3类共计6把:

密钥名称作用
client MAC客户端消息认证码密钥
server MAC服务端消息认证码密钥
client KEY客户端对称加密密钥
server KEY服务端对称加密密钥
client IV客户端初始向量,对称加密时使用
server IV服务端支持向量,对称加密时使用

会话密钥的制作是在RFC2246(TLS1.0)中**“6.3. Key calculation”**定义的,它的计算方式如下:

请添加图片描述
Go中计算会话密钥的函数如下:
请添加图片描述
6把会话密钥计算完毕后,后面便应该将生成的密钥存储到对应的连接上供业务通讯时使用。这里还有需要注意的地方:

TLS协议可以实现对报文机密性、完整性、认证的功能;机密性则是通过使用对称密码加密来实现的(此时会使用到6把密钥中的后4把);完整性和认证功能则是通过消息认证码来实现的(此时会用到6把密钥的前2把)。但是除此之外,还有一种更加高级的算法:AE(Authenticated Encryption)或者AEAD(Authenticated Encryption with Associated Data ),中文成为认证加密认证加密是一种将消息认证码和对称加密算法相结合,可以同时满足机密性、完整性、认证三大功能的机制。关于认证加密相关知识在“密码学知识”中进行介绍,这里不再赘述。

Go中的TLS源码当然也支持这种比较新颖的方式(2000年以后开始出现认证加密机制)。

请添加图片描述
如果加密套件中存在AEAD(认证加密)算法,则只需要使用到6把密钥中的后4把,MAC密钥不再需要。如果不存在AEAD则采用独立加密算法和消息认证算法,此时6把密钥会全部参与后续加密通讯。

对于TLS服务端而言,ClientCipher套件用来解析使用;ServerCipher套件用来加密使用。分别存在TLS连接的两个半连接上(in半连接用来读取客户端加密信息,存储ClientCipher套件; out半连接用来加密服务端信息,存储ServerCipher套件)

密钥信息目前并不能立刻投入使用,而是在收到对方的ChangeCipherSpec报文后,再切换使用新协商的密钥。在go源码的实现中,将cipher, mac分别对应的nextCipher,nextMac结构中。

请添加图片描述

4. 读取Change Cipher Spec报文

client的Client Key Exchange载荷处理完毕后,协商双方已经完成了互相认证,预主密钥和会话密钥都已经计算完毕,之后便可以进行加密通讯。但是在加密通讯之前,TLS协议有着更加完备的处理机制:通过Change Cipher Spec载荷来通知协商双方同时完成密钥切换;通过Finished报文来检验协商出的密钥是否可以正常通讯

CCS载荷的作用就是通知对方开始切换密钥,以后通讯均使用新协商的密钥进行加密通讯。CCS载荷内容很简单:只有1字节长度,值为1。
请添加图片描述
go源码中使用readChangeCipherSpec()函数处理CCS报文。在函数中经过一系列的校验之后,最后调用如下函数完成密钥的切换:

请添加图片描述

5. 读取Finished报文

Finished报文主要用来检验双方协商的密钥信息是否可以进行正常通讯。Finished载荷计算方式如下(RFC5246:"7.4.9. Finished"小节):

PRF(master_secret, finished_label, Hash(handshake_messages))

从这里可以看出:参与Finished载荷内容计算的包括:主密钥、Finish标签、所有的握手消息的摘要。之前每一个握手函数都会存储到到hs.finishedHash上,便是为了此刻使用。 关于finished_label,客户端为“client finished”;服务端为"server finished"。这三个数据协商双方都全部拥有,各自独立计算,然后比较是否相同;如果相同,则双方协商出的密钥均准确无误,可以用来加密通讯;如果校验失败,说明协商有误,应立即停止协商。

请添加图片描述
通过该载荷完成对双方协商出的密钥的校验。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

叨陪鲤

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值