WireShark 抓包理解 TLS 建立加密连接的过程

看这里



一、实验环境

服务端:web容器 glassfish 部署了一个可以访问的web包
              keystore.jks里添加的SSL证书,可参见 https://blog.csdn.net/yetugeng/article/details/81416320
客户端:一台笔记本,安装好wireshark

二、服务端的证书

在服务端keystore.jks内容如下,主要省略了Extensions部分内容
我们重点需要看的是别名为s1as的这部分,其中s1as下包含了3条证书
分别是泛域名*.axxxxxxxxing.com的证书以及上两级的签名授权商的证书。

三、TLS握手原理

(1)为了在握手协议解决降级攻击的问题,TLS协议规定:client发送ClientHello消息,server必须回复ServerHello消息,否则就是fatal error,当成连接失败处理。ClientHello和ServerHello消息用于建立client和server之间的安全增强能力,ClientHello和ServerHello消息建立如下属性:
Protocol Version
Session ID
Cipher Suite
Compression Method
(2)另外,产生并交换两个random值 ClientHello.random 和 ServerHello.random
(3)密钥协商使用四条: server的Certificate,ServerKeyExchange,client的Certificate,ClientKeyExchange 。TLS规定以后如果要新增密钥协商方法,可以订制这4条消息的数据格式,并且指定这4条消息的使用方法。密钥协商得出的共享密钥必须足够长,当前定义的密钥协商算法生成的密钥长度必须大于46字节。
(4)原理类似下图(实验步骤中会详细介绍)


图 3-1

表 3-1
握手消息 动作描述 消息内容
1. Client —> Server
    Client Hello
客户端(浏览器)发送一个hello消息给服务端,发起建立SSL会话的请求。并告诉服务端,自己支持哪些加密算法(Cipher Suite List)。除此之外,还需要产生一个随机数(第一个随机数,用于以后生成对称密钥),发送给服务端。 1)支持的协议版本,如TLS 1.0版
2)由客户端生成的随机数,用于生成后面的“对称密钥”
3)支持的加密方法,比如RSA公钥加密
4)支持的压缩方法
5)请求的域名
2. Server —> Client
    Server Hello
服务端的首次响应,会确定加密协议版本,以及加密的算法,也会生成一个随机数(第二个随机数)给客户端。 1)协议的版本
2)加密的算法
3)服务端生成的随机数
3. Server —> Client
    Certificate
还会把自己的证书发送给客户端,让客户端进行校验。服务端证书中的公钥也可被用于加密后面握手过程中生成的对称密钥。 1)服务端证书
证书颁发机构的名称
证书本身的数字签名
证书持有者公钥
证书签名用到的Hash算法
4. Server —> Client
    Server Key Exchange
指定使用哪种密钥协商协议。服务端可以在ServerKeyExchange之后立即发送CertificateRequest消息,要求校验客户端的证书。 1)使用哪种密钥协商方式
2)密钥协商时客户端需要的信息
5. Server —> Client
    Server Hello Done
服务器发送ServerHelloDone消息,告知客户端服务器这边握手相关的消息发送完毕。
6. Client —> Server
    Client Key Exchange
消息中包含客户端这边的EC Diffie-Hellman算法相关参数,然后服务器和客户端都可根据接收到的对方参数和自身参数运算出对称密钥。 1)密钥协商时服务端需要的信息
7. Client —> Server
    Change Cipher Spec
ChangeCipherSpec消息,通知服务器此消息以后客户端会以加密方式发送数据。 准备好了做加密传输的通知
8. Client —> Server
    Finished
客户端计算生成对称密钥,然后使用该对称密钥加密之前所有收发握手消息的Hash值,发送给服务器,服务器将相同的会话密钥(使用相同方法生成)解密此消息,校验其中的Hash值。
9. Server —> Client
    Change Cipher Spec
ChangeCipherSpec消息,通知客户端此消息以后服务器会以加密方式发送数据。 准备好了做加密传输的通知
10. Server —> Client
      Finished
服务器使用对称密钥加密(生成方式与客户端相同)之前所发送的所有握手消息的hash值,发送给客户端去校验。
11. Application Data 真正的数据传输(使用对称加密)

四、操作步骤

1.访问我自己的网站 http://*.axxxxxxxxing.com:8181/,网站IP为 103.110.152.xxx
2.wireshark抓包,使用 ip.src == 103.110.152.xxx && ssl 规则来过滤包。如图 4-1 :


图 4-1

五、握手过程

首先我们了解一下建立握手连接的目的:
(1)身份的验证,client与server确认对方是它相连接的,而不是第三方冒充的,通过证书实现;
(2)client与server交换session key,用于连接后数据的传输加密和hash校验。
其次分析简单的SSL握手连接过程(仅Server端交换证书给client):

1.Client Hello

客户端(浏览器)发送一个hello消息给服务端,发起建立SSL会话的请求。并告诉服务端,自己支持的协议版本和哪些加密算法(Cipher Suite List)。除此之外,还需要产生一个随机数random(第一个随机数,用于以后生成对称密钥),发送给服务端。
如图 5-1中 30号包,


图 5-1-1


  • TLSv1.2 Record Layer: Handshake Protocol: Client Hello 
表明此包为TLS的第一个包,参见图3-1过程。
  • Content Type: Handshake (22) 
显示了本包的类型为 Handshake (22)。
TLS的ContentType有如下一些,详见 https://www.iana.org/assignments/tls-parameters/tls-parameters.xhtml#tls-parameters-5


图 5-1-2

  • Version: TLS 1.2 (0x0303)
协议版本(客户端期望支持的握手协议版本),版本号的编码规则如下
Common Version name Response Major version Response Minor version
SSL 3.0 03 00
TLS 1.0 03 01
TLS 1.1 03 02
TLS 1.2 03 03
  • Handshake Type: Client Hello (1)
握手类型大概有如下一些,详见https://www.iana.org/assignments/tls-parameters/tls-parameters.xhtml#tls-parameters-7


图 5-1-3

  • Random
安全随机数(MasterSecret生成用到,协议文档里面说是28个字节,但是实际抓包看到是32个字节,这里怀疑是各个协议文档版本不同,还有使用加密套件的不同,导致的差异,具体博主就没有在继续深究了,如果有朋友知道可以留言给我)


图 5-1-4

从底部一栏可以看到全部字段 ,5d6dd059b5ad015d25bbba75a4b7913494b31eb34fdbabefa769cd33dc4badd1
4字节:5d6dd059
28字节:b5ad015d25bbba75a4b7913494b31eb34fdbabefa769cd33dc4badd1
5d6dd059 (16进制)-> 1567477849(十进制,时间戳)->  2019-09-03 10:30:49 (日期格式)


图 5-1-5

即客户端将时间戳连同随机字符串放在一起作为一串字符串发送给服务端。
  • Session ID
这个值是被服务端设置的,如果这个值为空,表示客户端与服务端没有存活的https会话,需要与服务端进行完整的握手。
如果这个值存在,则表明客户端期望恢复上一次的https会话,这时候客户端与服务端只需要进行快速的握手过程。
  • Cipher Suites
加密套件(客户端支持的加密套件列表)
如果前面的sessionid不为空,可以不传这个值,服务端可以从上一次会话中恢复这个值。
可以看到,客户端发送了21种可用密码套件给服务端,然后由服务端挑选自己支持的套件。


图 5-1-6

每个加密组件(Cipher Suite)都包括了下面5类算法 , 后面会看到本例中服务端使用的是就是 TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 这个加密套件:
     (1) authentication (认证算法):RSA
     (2) encryption (加密算法 ):AEAD_AES_256_GCM
     (3) message authentication code (消息认证码算法 简称MAC):SHA384
     (4) key exchange (密钥交换算法):ECDHE
     (5) key derivation function (密钥衍生算法)

更多密码套件详见官方文档 TLS Cipher Suite Registry
如下图,wireshark中括号里的十六进制值,就对应下图的Value 。


图 5-1-7

  • Compression Methods
加密前进行数据压缩


图 5-1-8

压缩方式有如下一些,详见 https://www.iana.org/assignments/comp-meth-ids/comp-meth-ids.xhtml


图 5-1-9

因为压缩方法被攻击,在TLS1.3协议版本上已经彻底禁止压缩了。(这里有两种攻击方式BREACH、CRIME,有时间博主会来研究)
  • Extensions
最后我们来看看扩展,本例中客户端发送了8种扩展。
比如第一个扩展 Extension: server_name (len=23) 中,就包含了我们访问的域名。


图 5-1-10

常见扩展类型有50多种,如下图 5-11,更多详见 https://www.iana.org/assignments/tls-extensiontype-values/tls-extensiontype-values.xhtml


图 5-1-11


2.Server Hello

服务端的首次响应,会确定加密协议版本,以及加密的算法,也会生成一个随机数(第二个随机数)给客户端。


图 5-2-1

不过这里我们在如 图 5-2-1 中看起来有些不一样,如 36号包 的Info 字段显示的是Server Hello,Certificate,Server Key Exchange,Server Hello Done 四个过程。
但是绿色框中,[4 Reassembled TCP Segments (4949 bytes): #32(1412), #33(1412), #35(1412), #36(713)] 表明 36号包是整合了32,34,35,36 四个包的内容一起显示的。所以才有红色框里的 Multiple Handshake Messages显示 。
且看图中面黄色框里就是详细展示这四个握手阶段的内容。
现在我们进一步展开 Handshake Protocol: Server Hello 部分。
  • Version
服务端最高支持的握手协议版本,TLS/SSL协议都是向下兼容的。
  • Random      服务端生成32字节安全随机数(MasterSecret生成会用到)


图 5-2-2

现在我们将Client Hello 和Server Hello里面randam进行对比
  1. #Client Hello
  2. Random: 5d6dd059b5ad015d25bbba75a4b7913494b31eb34fdbabefa769cd33dc4badd1
  3. Random Bytes: b5ad015d25bbba75a4b7913494b31eb34fdbabefa769cd33dc4badd1
  4. Session ID: 空
  5. 5d6dd059 -> 1567477849 -> 2019-09-03 10:30:49
  6. #Server Hello
  7. Random: 5d6dd04ae801b092ff9d891027a4f4d76293a29780e86e83996564dbf87fa520 #这就是上文说的第二个随机数吧
  8. Random Bytes: e801b092ff9d891027a4f4d76293a29780e86e83996564dbf87fa520
  9. Session ID: 5d6dd04a4db6e7a76205eb180fe7e1557961b95c8b8a2eb6fbb7e792f242e68d
  10. 5d6dd04a -> 1567477834 -> 2019-09-03 10:30:34
这里多了个Session ID,但是Server Hello中的时间竟然比 Client Hello中的时间更早?这个我还没看懂,忘大神指点。
  • Session ID
如果客户端hello有发送session id,服务端从内存中查找,并尝试恢复之前的会话状态。
          恢复成功,服务端返回同样的session id。
          恢复不成功,服务端此字段返回空。
  • Cipher Suite
服务端从客户端hello的cipher suite列表中选择一个加密套件,如果是恢复上一次的会话,则从会话状态中恢复上一次相同的加密套件。
本次测试,服务端选择的密码套件是 TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (0xc030)
  • Compression Method
服务端从客户端hello的compression_methods列表中选择一个压缩方法,如果是恢复上一次的会话,则从会话状态中恢复上一次相同的压缩方法。
  • Extensions
这里包含了两个扩展


图 5-2-3

注意这里服务端的扩展里面没有包括 session ticket,证明服务端不支持该机制。

3.Certificate

服务端把自己的证书发送给客户端,让客户端进行校验。服务端证书中的公钥也可被用于加密后面握手过程中生成的对称密钥。


图 5-3-1

如图 5-3-1服务端发送的是一个证书链,可能包含多个证书 ,这里有三个证书:
  • 第一个证书为网站的证书。
  • 第二个证书为颁发证书给网站的机构的证书。
  • 在这个例子中第三个证书是CA机构的根证书,可以忽略不用发送,因为这个CA的根证书是CA自己给自己颁发的。
    这里构成了一个证书信任链,也就是 GlobalSign Root CA信任GlobalSign Organization Validation CA,而他又信任baidu.com的证书。
下面,我们使用 https://www.geocerts.com/ssl-checker 这个网站可以测试web服务证书安装情况,检测结果如下图


图 5-3-2

从图 5-3-2 中我们看到,由上往下证书链的关系依次是:
泛域名 *.aixxxxxxxing.com 被 Sectigo RSA Domain Validation Secure Server CA 签发,
Sectigo RSA Domain Validation Secure Server CA 被 USERTrust RSA Certification Authority 签发,
USERTrust RSA Certification Authority  被 AddTrust External CA Root 签发,
AddTrust External CA Root 被自身AddTrust External CA Root签发。
那证书中到底包含了些什么内容呢?
  • 证书版本号(Version)
  • 证书序列号(Serial Number)
  • 签名算法标识符(Signature Algorithm)
    签名算法标识用来指定由CA签发证书时所使用的"签名算法"。算法标识符用来指定CA签发证书时所使用的:
    1) 公开密钥算法
    2) hash算法
    example: sha256WithRSAEncryption
    须向国际知名标准组织(如ISO)注册
  • 签发机构名(Issuer)
  • 有效期(Validity):指定证书的有效期
  • 证书用户名(Subject)
  • 证书持有者公开密钥信息(Subject Public Key Info)
    证书持有者公开密钥信息域包含两个重要信息:
    1) 证书持有者的公开密钥的值
    2) 公开密钥使用的算法标识符。此标识符包含公开密钥算法和hash算法。
  • 扩展项(extension)
  • 签发者唯一标识符(Issuer Unique Identifier)
  • 证书持有者唯一标识符(Subject Unique Identifier)
  • 签名算法(Signature Algorithm)
  • 签名值(Issuer's Signature)
我们再回过头来看看本文第二部分的keystore.jks,里面有三个证书分别如下,只是这里只显示除了前三个证书,最后一个根证书自签名的没有存储在keystore.jks文件里。
  1. ...
  2. Certificate[1]: #第一条证书
  3. Owner: CN=*.axxxxxxxxing.com, OU=PositiveSSL Wildcard, OU=Domain Control Validated
  4. Issuer: CN=Sectigo RSA Domain Validation Secure Server CA, O=Sectigo Limited, L=Salford, ST=Greater Manchester, C=GB
  5. ...
  6. Certificate[2]: #第三条证书
  7. Owner: CN=Sectigo RSA Domain Validation Secure Server CA, O=Sectigo Limited, L=Salford, ST=Greater Manchester, C=GB
  8. Issuer: CN=USERTrust RSA Certification Authority, O=The USERTRUST Network, L=Jersey City, ST=New Jersey, C=US
  9. ...
  10. Certificate[3]: #第三条证书
  11. Owner: CN=USERTrust RSA Certification Authority, O=The USERTRUST Network, L=Jersey City, ST=New Jersey, C=US
  12. Issuer: CN=AddTrust External CA Root, OU=AddTrust External TTP Network, O=AddTrust AB, C=SE
  13. ...
现在,我们再回到wireshark详细地看看第一个证书


图 5-3-4

后面两个证书就不多说了,与第一个证书类似。需要详细研究的可以自己抓包来测试。
如何校验服务端证书呢?


图 5-3-5

  • 签名的生成:CA先将证书信息生成hash摘要,然后再用CA机构的私钥进行加密。
  • 签名的校验:使用CA机构的公钥进行解密签名,得到hash摘要A,再计算证书信息的hash摘要B。比对是否一致。
       #### 详细解释服务端的证书是怎么生成的?
  • 服务端的证书是由CA (Certificate Authority,证书认证中心)颁发的。他是一个负责发放和管理数字证书的第三方权威机构,它负责管理PKI(Public Key Infrastructure,公开密钥基础设施)结构下的所有用户(包括各种应用程序)的证书,把用户的公钥和用户的其他信息捆绑在一起,在网上验证用户的身份。
  • 一般情况下网站方向CA申请一个证书。CA会给网站方生成一对非对称加密的公钥私钥,公钥会做到证书里面,私钥则会给到网站方。
  • CA会先做一个“数字签名”(生成过程:明文 --> hash运算 --> 摘要 --> 私钥加密 --> 数字签名)
    • 就是将网站方的信息网站方的公钥签名算法等信息(就是Wireshark Packet 36中的数据,除了“签名值”),计算一个hash值(图中hash算法是SHA256),然后CA再用自己私钥做加密(图中公开密钥算法是RSA),最后的这个密文就是“数字签名”(也就是我们在图中看到“encrypted”签名值)。
  • CA最后将“网站方信息”、“网站方公钥”、“签名算法”、“签名值”都做到证书里面(就是Wireshark Packet 36中的我们看到那些数据),证书就做好了,CA会把“证书”和“网站方的私钥”给到网站方。
由于我这个证书是在某宝买的,所以公钥私钥这些信息都是由卖家提供的.
CA怎么验证证书是不是自己颁发的呢?以及做证书内容校验?
  • 首先浏览器(校验网站的证书)或操作系统(校验应用的证书),会在操作系统存储的系统信任的根证书里面去查找“证书颁发机构”是否是信任的。如下图系统根证书:  (Windows+R输入 certmgr.msc)


图 5-3-6

浏览器通常也会内置大多数主流权威CA的根证书,如下图


图 5-3-7


如果查找不到对应的可信CA,则判断这个证书是伪造的,不可信的。(浏览器则会提醒该证书不是可信任机构颁发的,并询问是否要继续访问)
  • 如果找到对应的CA机构,则取出CA机构证书里面的公钥信息,将网站方证书中的签名值(也就是数字签名)做解密,得到网站证书信息的hash摘要A。
  • 然后将网站证书中的信息,做hash得到摘要B,比对摘要A和摘要B是否一致。如果不一致,说明网站证书中的信息被修改了。(浏览器则会提醒该证书不是可信任机构颁发的,并询问是否要继续访问)
  • 如果摘要hash一致,则说明证书中的信息未被修改,这时浏览器会比对您现在正在访问的网站与证书中网站信息是否一致,比如域名是否一致、证书是否在有效期内等。(如果出现问题,浏览器将会提醒你,并询问是否要继续访问)
  • 另外大部分浏览器也会在线校验证书,是否在有效期内(将证书序列号通过在线证书状态协议“OCSP”发送给CA做校验)。
  • 证书校验成功,最后将从证书中取出网站方的公钥,用于后面的握手签名。

4.Server Key Exchange

这个步骤是密钥协商的服务端部分,最终的密钥将会用于传输数据对称加密。
服务端需要发送一个Diffie-Hellman算法的公钥,和指定使用哪种椭圆曲线多项式。
我们到Client Key Exchange的时候,再来讲这个密钥协商过程。
这里还有一个签名,校验这个流程的数据是否被篡改。如下图所示,客户端收到Server Key Exchange数据后,可以用上个流程中获得的证书公钥对签名值解密,获得摘要A。并将这次数据明文做SHA512的hash,获得摘要B,做比对。(这里对协商算法做签名校验,目的可能是防止中间人对协商算法方式做篡改,虽然DH算法不担心公钥在不安全的网络中传输,但是其他算法可能需要考虑被篡改的情况。所以猜测服务端密钥协商时做签名是这个目的,因为服务端这时已经确定是DH算法了,所以客户端协商时就不需要做签名了,DH算法不需要考虑这个安全问题)


图 5-4-1


6.Server Hello Done

服务端发送ServerHelloDone消息表示,已经发送完了密钥协商需要的消息,并且客户端可以开始进行客户端的密钥协商处理了,也就是Client Key Exchange。
收到ServerHelloDone后,客户端需要确认服务器是否提供了合法的证书,并且确认服务器的ServerHello消息里面的参数是否可以接受。


图 5-6-2

7.Client Key Exchange

回顾一下图 5-2-1,一个  TLSv1.2 Record Layer: Handshake Protocol: Multiple Handshake Messages下面包含了四个Handshake Protocol,分别是 Server Hello,Certificate,Server Key Exchange,Server Hello Done。
而这里一个包里包含了三个 TLSv1.2 Record Layer,分别是如下图所示


图 5-7-1

展开 Client Key Exchange如下图


图 5-7-2

  • 客户端生成自己用于密钥协商的公私钥,并发送此公钥
  • 这时客户端已经知道了服务端密钥协商的公钥以及自己的公钥
  • 我们以EC Diffie-Hellman密钥协商协议为例,来看看客户端、服务端是怎么协商出相同的密钥的(这里协商出来的是PreMasterSecret,不是最终的对称加密用到的密钥)。
  • EC Diffie-Hellman使用到一个数学难题,就是在给定的椭圆曲线上的一个点P,一个整数k,求Q=kP很容易;但是给定一个点P、Q,知道Q=kP,求整数k确实很难。
  • 服务端确定了密钥协商算法为“EC Diffie-Hellman”,发送给客户端。现在两端都知道了使用的是哪个曲线参数(椭圆曲线E、阶N、基点G)。
  • Server Key Change:服务端随机生成一个整数a,计算A=a*G,生成服务端公钥A,发送给客户端。
  • Client Key Change:客户端随机生成一个整数b,计算B=b*G,生成服务端公钥B,发送给服务端。
  • 客户端计算出PreMasterSecret:Q=bA=b(a*G)
  • 服务端计算出PreMasterSecret:Q'=aB=a(b*G),这两个计算结果是相等的,此时双方协商好对称密钥值。
  • 并且即使攻击者截获到双方公钥A、B,仍然无法计算出PreMasterSecret,因为攻击者需要知道随机整数a、b的其中任意一个,可是之前我们就提到过EC Diffie-Hellman协议中,知道A、G求a是很难的。
  • 真正对称加密使用到的密钥生成(这里使用到了client、server一开始hello中传输的随机数):
    • MasterSecret = PRF(PreMasterSecret, "master secret", Client.random || Server.random)[0..47] -- 固定取前 48 字节
    • KeyBlock = PRF(MasterSecret, "key expansion", Server.random || Client.random) -- 长度为由双方确定的密码算法套件决定
    • KeyBlock才是最终用来做对称加密的密钥块 6.3. Key Calculation

8. (Client) Change Cipher Spec

  • 这个过程就是告诉服务端,他已经准备好MasterSecret了,可以进行数据加密传输了。
  • 这个协议是冗余的,在TLS 1.3里面直接被删除了。
展开Change Cipher Spec如下图


图 5-7-3

9.Encrypted Handshake Message | Client Finished

client发送的encrypted handshake message加密数据非常关键,一是能证明握手数据没有被篡改过,二也能证明自己确实是密钥的拥有者(这里是单边验证,只有server有certificate,server发送的Finished能证明自己含有private key,原理是一样的)。client将之前发送的所有握手消息存入handshake message缓存。


图 5-7-4

9.1.Server New Session Ticket

  • 如果服务端想使用Ticket方式存储session状态,在Server Change Cipher Spec之前就需要发送New Session Ticket消息。
  • New Session Ticket方式与Session ID方式对比:
    • SessionID方式,客户端在ClientHello的时候带着上一次SessionID过来,服务端从自己内存中查找SessionID对应的session状态,并读取session状态快速恢复。
    • SessionTicket方式,则是将session状态加密后,发送给客户端存储。客户端在ClientHello时将SessionTicket带上,服务端就将其解密,读取出里面存储的session状态信息,SessionTicket存储的信息如下:
  1. struct {
  2. ProtocolVersion protocol_version; //协议版本
  3. CipherSuite cipher_suite; //加密套件类型
  4. CompressionMethod compression_method; //压缩方法
  5. opaque master_secret[48]; //对称密钥
  6. ClientIdentity client_identity; //客户端ID
  7. uint32 timestamp;//ticket有效期
  8. } StatePlaintext;
本例中,没有出现 Server New Session Ticket

10.(Server )Change Cipher Spec

  • 告诉客户端,我已经准备好进行加密传输了。


图 5-7-5

11.Server Finished | Encrypted Handshake Message

与9. Client Finished的情况一样,使用对称密钥加密,最后做一次验证,确定双方是否都准备好进行数据传输了。
只是这里加密的数据还不是真正的网站内容数据,而是握手过程的数据。


图 5-7-6


12. Application Data

  • 真正的网站数据传输,但是这里的数据就是经过握手时协商好的对称密钥进行加密的了。


标题

13.Encrypted Alert

  • SSL 警告消息,因为是加密的内容,所以单从 Wireshark 看不出警报的内容。
  • 但因为警报消息经常只是客户端用来提示服务端 SSL 传输结束,对照抓包到的内容确实如此。所以这里只是 SSL 传输结束的一个信号。
  • 发出了 Encryted Alert 后客户端数据传输完毕,准备进入四次挥手断开 TCP 连接。
参考文章:
https://www.cnblogs.com/20179204gege/p/7858070.html
https://www.cnblogs.com/Anker/p/6082966.html
https://blog.csdn.net/liangyihuai/article/details/53098482
http://www.ruanyifeng.com/blog/2014/09/illustration-ssl.html
https://xz.aliyun.com/t/1039
https://blog.helong.info/blog/2015/09/06/tls-protocol-analysis-and-crypto-protocol-design/