该笔记将记录:简述 TLS handshake 过程,以及熟悉调试处理 TLS 问题的方法。
握手流程概述
握手过程可以分为以下步骤:
第一步、协议协商
Client 与 Server 将协商要使用的协议版本。例如:决定使用 TLSv1.1 协议,还是 TLSv1.3 协议
第二步、选择算法
选择加密算法。
第三步、证书验证
通过 Server 的公钥 和 SSL 证书的 CA 的数字签名 来验证 Server 的身份。
第四步、数据传输
使用「非对称加密」技术生成「共享密钥」,避免密钥分发问题。然后使用「共享密钥」进行消息的「对称加密」,因为「对称加密」比「非对称加密」更快。
两种类型握手
有两种类型握手,本文将分别讨论这两种握手过程(只涉及过程,不涉及过多细节)。
第一种、基本 TLS 握手(Basic TLS handshake)
这种最常见的,在建立 HTTPS 连接中使用“基本 TLS 握手”。
第二种、认证客户端的 TLS 握手(Client-authenticated TLS handshake)
这种握手需要客户端持有证书,例如在使用证书连接 MySQL 数据库、访问 K8S API Server 时,会使用“认证客户端的 TLS 握手”。
基本 TLS 握手(Basic TLS handshake)
The 'client hello' message
通过发送 Client Hello 消息,Client 发起握手,消息包含如下内容:
1)Client 支持的 TLS 版本;
2)Client 支持的加密方法(Cipher Suite);
3)被称为 Client Random 的随机字节串(由 Client 生成)
The 'server hello' message
为响应 Client Hello 消息,Server 发送 Server Hello 消息,消息内容如下:
1)Server 的 SSL Certificate
2)Server 选择的加密方法(从 Client 支持的加密算法中选择)
3)被称为 Server Random 的随机字节串(由 Server 生成)
Authentication
Client 使用颁发 Server SSL Certificate 的 CA 验证证书,以确定服务器身份。
The premaster secret
Client 再发送壹个随机的字节字符串,Premaster Secret,并使用公钥(来自 SSL Certificate 内部)加密,并且这只能由拥有私钥的 Server 解密。
Private key used
Server 解密 Premaster Secret
Session keys created
利用 Client Random / Server Random / Premaster Secret 字节串,Client 与 Server 会计算出相同的 Session Key
Client is ready
Client 使用 Session Key 发送 Finished 消息
Server is ready
Server 使用 Session Key 发送 Finished 消息
Secure symmetric encryption achieved
至此,握手已经完成,后续通信使用 Session Key 进行对称加密。
# 事情从来都不可能这么简单
如果使用 Diffie-Hellman 握手,那过程还会有所出入,这里不再展开,可以参考 HTTPS: The TLS Handshake Using Diffie-Hellman Ephemeral 页面。
认证客户端的 TLS 握手(Client-authenticated TLS handshake)
#1 Client -> Server: "client hello"
Client 发送「client hello」消息,该消息列出加密信息(例如,按 Client 的优先顺序TLS版本、 Client 支持的CipherSuite)。该消息还包含用于后续计算的随机字节字符串。该协议允许「client hello」包含 Client 支持的数据压缩方法。
#2 Client <- Server: "server hello"
Server 以「server hello」消息响应,该消息包含 Server 所选择的CipherSuite(从Client提供的列表中)、会话ID、另一个随机字节字符串。Server还发送其「数字证书」。
如果 Server 需要「数字证书」进行 Client 身份验证,则 Server 会发送“client certificate request”,其中包括所支持的证书类型列表和可接受的证书颁发机构(CA)的可识别名称。
#3 Client: verify server certificate
Client 验证 Server 的数字证书,以此确认 Server 是可信的。
参考「How SSL and TLS provide identification, authentication, confidentiality, and integrity」一文。
#4 Client -> Server: Client key exchange
Client 发送「随机字节字符串」,使 Client 和 Server 都能够计算用于加密后续消息数据的密钥。
「随机字节字符串」本身使用「Server的公钥」进行加密。
#5 Client -> Server: send client certificate(if required)
如果 Server 发送了“client certificate request”,则 Client 会发送使用「Client私钥」加密的「随机字节字符串」,以及「Client的数字证书」。
或者发送“无数字证书警报”。 此警报仅是警告,但在某些实现中,如果 Client 身份验证是必需的,没有证书则会握手会失败。
#6 Server: Verify client certificate(if required)
Server 验证 Client 的证书。
参考「How SSL and TLS provide identification, authentication, confidentiality, and integrity」手册。
#7 Client -> Server: Client "finished"
Client 向 Server 发送已完成的消息,该消息使用密钥加密,表示握手的 Client 部分已完成。
#8 Client <- Server: Server "finished"
Server 向 Client 发送已完成的消息,该消息使用密钥加密,表示握手的 Server 部分已完成。
#9 Client <> Server: Exchange messages
现在 Server 和 Client 现在可以交换使用「共享密钥」进行「对称加密」的消息。
常用调试方法
通常我们只会触发“普通错误”,例如证书过期、协议版本、配置错误等等。本部分我们将整理常见调试方法,以排查,例如站点无法访问、无法建立安全连接等等,问题。
测试端口开放
#!/bin/sh # 测试端口开放 nc -v -z example.com 443 telnet example.com 443 # 尝试建立连接 openssl s_client -connect example.com:443 openssl s_client -connect example.com:443 -CAfile /etc/ssl/certs/ca-certificates.crt openssl s_client -connect example.com:443 -servername example.com
检测协议版本
在IE 11中,默认设置只支持TLSv1协议握手。如果服务器只支持TLSv1.3协议,则无法通过IE访问该HTTPS站点。因此我们可以检测服务器是否支持特定版本TLS协议:
#!/bin/sh openssl s_client -connect foo.example.com:443 -tls1 # TLSv1 openssl s_client -connect foo.example.com:443 -tls1_1 # TLSv1.1 openssl s_client -connect foo.example.com:443 -tls1_2 # TLSv1.2 openssl s_client -connect foo.example.com:443 -tls1_3 # TLSv1.3 # 有时可以使用NMAP进行扫描,但是有时候会出现无结果(原因未知) nmap --script ssl-enum-ciphers -p 443 www.example.com
证书过期时间
#!/bin/sh openssl s_client -connect example.com:443 2>/dev/null | openssl x509 -noout -dates
相关链接
SSL Handshake explained - Kasun Dharmadasa - Medium
相关文章
「SSL」- 常见错误汇总
「TLS」- 与 IE 有关的问题
参考文献
An overview of the SSL or TLS handshake
The SSL/TLS Handshake: an Overview
Testing with OpenSSL
What Happens in a TLS Handshake? | SSL Handshake | Cloudflare