Go中TLS源码学习(4)之Server端第一次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详解”

5.3.2 TLS第一次握手

先看看ClientHello报文内容,再看代码处理逻辑:
请添加图片描述
Server端的tls握手流程中,第一项工作便是读取ClientHello报文然后通过ClientHello确定当前TLS版本(目前有TLS1.0, TLS1.1, TLS1.2,TLS1.3),当下主流浏览器(Chrome, FireFox, IE等)都已经支持TLS1.3,不过网络上的大多数TLS服务还是TLS1.2, 以及少量的TLS1.1和TLS1.3。

服务端的TLS握手读取ClientHello报文,并通过“双方同时支持的最高版本”的原则确定TLS采用的版本,然后根据协商出的版本进入相应TLS版本处理函数:
请添加图片描述下面对代码中的关键部分做介绍。其中主要包括:

  • 1)读取ClientHello报文
  • 2)解析ClientHello报文,TLS版本协商
  • 3)TLS快速协商
  • 4)算法套件协商

1. 读取Client Hello报文

tls握手报文读取,全部是通过readHandshake()接口来完成的。readClientHello()接口对readHandshake()接口再次封装,只获取ClientHello报文。 在readClientHello成功获取到tls的clientHello协商报文之后,便是解析报文中的TLS版本信息
请添加图片描述
关于TLS的版本选择,需要做个重点说明: 在 ClientHello报文中,有两个与版本有关的字段:记录层的version, 扩展字段supported_version。记录层的version用来标明当前客户端tls握手时采用的版本;supported_version来用标明客户端支持的所有版本。由于TLS版本需要握手双方进行协商确定,clientHello报文时,version字段只不过是临时采用的一个版本而已。

🎁 对于TLS1.0, TLS1.1,TLS1.2, 可以通过记录层中的版本字段来获取(不发送supported_version),此时supported_version默认支持包括此版本在内的之前所有的TLS版本;

🎁 但是TLS1.3有点特殊:TLS1.2与TLS1.3 的握手报文中version字段都是0x0303,也就是TLS1.2版本。TLS1.3则是通过扩展字段supported_version来特别说明

  • TLS1.2截图
    请添加图片描述
  • TLS1.3截图
    请添加图片描述因此,确定客户端支持的TLS版本时,需要通过记录层中的Version以及扩展字段中的SupportedVersion共同确定服务端支持的TLS版本则是通过配置来确定(c.config.mutualVersion(clientVersions))。

💥💥💥:Go中TLS的版本可以在创建HTTPS服务时进行配置:例如下面代码中TLS版本限定为TLS1.2版本。
请添加图片描述分别获取到客户端和服务端的TLS版本后,便需要确定当前握手需要采用的TLS版本。协商的原则是:从客户端支持的版本中选择一个双方都支持的版本,版本越高优先级越高。长江后浪推前浪,前浪拍死在沙滩上。Go中协商TLS版本的函数如下:
请添加图片描述
确定TLS的版本后,根据当前协商的版本进入对应TLS握手流程。后面主要学习TLS1.2版本的握手流程。

通过上面的流程,便成功协商出要采用的TLS版本,后面便是解析ClientHello报文。

2. 解析ClientHello报文

TLS握手的核心处理函数!!!,关键操作都在此函数中实现。 后面主要介绍此函数及其子函数的实现。请添加图片描述这里先介绍ClientHello解析函数相关部分:processClientHello(),其他的函数在后面TLS交互报文中再介绍。processClientHello函数中有几个关键操作:

  • 确定clientHello中支持的压缩算法(compressionNone)
  • 分配Server Random随机数空间,并填充;如果TLS版本降级,则需要特殊处理ServerRandom
  • 检查是否支持client hello中的椭圆曲线组以及基点
  • 证书采用的解密算法和签名算法(搞什么鬼,没看懂)
  • 填充ServerHello报文的部分字段

源码实现如下:
请添加图片描述从上面可以看出:此函数并未解析完整的ClientHello报文,只解析了其中的压缩算法和椭圆曲线部分,以及生成了ServerHello中的Random的值;其他部分的解析仍在后面的流程中完成。以下对代码中关键部分做一个说明:

🔆🔆关于server random的说明:

TLS协商过程中有两个重要的随机数:client random,server random;分别位于ClientHello,ServerHello报文中。random的大小为32字节,填充的内容由Client和Server各自随机产生。
请添加图片描述
如果TLS协商过程中,存在降级情况(双方协商出的TLS版本不是服务端最高版本,一般是协商出的版本为TLS1.1或者TLS1.0时存在降级现象),在这种情况下,为了安全起见,在Server Random随机数据的后8个字节填充上降级信息,前24字节填充随机数。降级时填充的信息如下:
请添加图片描述

🔆🔆关于椭圆曲线和基点

报文中的椭圆曲线和基点载荷信息如下:
请添加图片描述

目前TLS支持的椭圆曲线共有四组,而基点统一采用0。因此这两个载荷的校验包括:1)椭圆曲线ID是否为四者之一;2)基点是否为0
请添加图片描述

🔆🔆TODO: 证书相关、签名算法、解密算法

在解析ClientHello报文过程中,会加载本端的证书、以及证书中采用的加解密算法、签名算法信息。其中加载证书时,服务端证书配置存在三种情况:

  • 未配置证书

    这种情况需要从对端的ClientHello中获取证书。

  • 配置一个证书请添加图片描述 一般情况下都是配置一个证书,此时直接返回该证书即可

  • 配置多个证书

    此时需要根据ClientHello中的ServerName载荷或者SupportsCertificates载荷来确定最终采用的证书。

针对上述三种情况,目前我只见过第二种;其他两种情况权当扩展了。Go中实现如下:

在processClientHello()最后便是获取证书中的签名算法和解密算法,供后续报文交互时使用。

3. TLS快速协商

func (hs *serverHandshakeState) handshake()中,有一部分是关于TLS复用当前链接从而实现TLS快速协商的流程,这里暂不介绍。后期如果需要,单独介绍TLS快速协商流程。

4. 算法套件选择

下面是分别获取客户端和服务端支持的算法列表,并确定优先采用的算法列表,采取的原则是:如果本端配置了算法信息,则优先采用本端算法;如果本端未配置算法参数,则对端算法优先。
请添加图片描述在优先算法列表中,从头开始遍历,找到客户端和服务端都支持的一个算法即为最终协商后的算法。具体的算法选择函数如下:
请添加图片描述Go中目前包括的算法有(部分算法信息):
请添加图片描述
至此,server端的ClientHello报文便处理完了;上文中主要介绍了ClientHello报文中的版本、ClientRandom、算法套件、支持的椭圆曲线算法和基点这几个主要载荷。Session ID载荷也非常重要,不过在协商流程中,它主要是为了复用其他session信息完成快速协商时使用,这里暂未介绍。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

叨陪鲤

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

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

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

打赏作者

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

抵扣说明:

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

余额充值