TLS是一种复杂的协议,旨在发展和应对主机独立部署的进步。如果互联网上的所有主机都支持完全相同的加密算法,并在锁步(lockstep)TLS中部署补丁,那么事情可能会简单得多。在现实世界中,TLS服务器和客户端必须在每次连接时相互协商。双方可以使用哪些算法?哪些TLS版本?每一方都可以请求或要求特定的协议选项。服务器和客户端提供他们最好的算法,提出他们的请求和需求,并试图达成一致。
你需要有能力观察一个连接,看看会发生什么。启用和禁用哪些TLS功能?如果连接因特定协议细节而失败,您可以在一侧或另一侧启用该功能吗?或者,这种失败是可取的(desirable),因为一方或另一方只接受原始SSL吗?我们将通过 s_client
连接检查TLS连接。一旦你熟悉了这个过程是如何运作的,你就可以使用任何你喜欢的工具。
无论您使用的是TLS 1.2还是1.3,您都会看到连接的三个主要部分:证书验证、协议设置和恢复。我们将使用第2章中的命令,使用TLS 1.2检查与我的web服务器的连接,并使用TLS 1.3检查与Gmail服务器的连接。
xxxxxxxxxx
$ openssl s_client -crlf -tls1_2 -connect www.mwl.io:443
$ openssl s_client -connect imap.gmail.com:995
让我们比较一下这两个版本。
每次TLS协商都从验证所有相关证书开始。您的证书可能通过广泛的信任树锚定到受信任的根证书,但TLS客户端只需要在信任锚和主机证书之间找到一个有效路径。OpenSSL套件在发现的第一个有效路径处停止,并显示该路径。
无论您使用的是TLS 1.2还是1.3,验证过程看起来都是相同的,因此我们将使用我的web服务器作为示例。
xxxxxxxxxx
depth=2 O = Digital Signature Trust Co., CN = DST Root CA X3
verify return:1
depth=1 C = US, O = Let's Encrypt, CN = Let's Encrypt Authority X3
verify return:1
depth=0 CN = mwl.io
verify return:1
首先, s_client
验证链(chain)中的所有证书。这里的“depth”是指每个证书在证书链上有多少个链接。在depth=2时,我们有根CA。O是X.500组织(Organization)的简写:在这种情况下是“数字签名信任公司(Digital Signature Trust Co)”。CN,通用名(CommonName),是“DST根CA X3”。如果此证书不是受信任的根证书,则验证将在此处失败。请注意,这些证书中的每一个都有不同风格的可分辨名称(Distinguished Name)。那很好。
verify return:1
语句表示OpenSSL正常执行了此操作。它指的是OpenSSL代码,而不是证书。
在depth=1时,我们有一个名为“Let's Encrypt”的组织,其通用名称为“Let’s Encrypt Authority X3”。
该网站的证书始终位于深度0。此证书只包含一条信息,即主机的主机名。主机名来自证书的服务器替代名称(Server Alternative Name)部分,其中包括主机 mwl.io
等。TLS根据任何名称约束验证主机名。
xxxxxxxxxx
---
Certificate chain
0 s:CN = mwl.io
i:C = US, O = Let's Encrypt, CN = Let's Encrypt Authority X3
1 s:C = US, O = Let's Encrypt, CN = Let's Encrypt Authority X3
i:O = Digital Signature Trust Co., CN = DST Root CA X3
---
Server certificate
-----BEGIN CERTIFICATE-----
MIIFXDCCBESgAwIBAgISA6Gn7sL7taoAbCDwb8hL8aKGMA0GCSqGSIb3DQ
…
-----END CERTIFICATE-----
subject=CN = mwl.io
issuer=C = US, O = Let's Encrypt, CN = Let's Encrypt Authority X3
---
我们再次看到信任链,这次是从主机到CA的顺序。证书前面的 s 表示X.509证书主体,而 i 是颁发者——签署证书的实体。证书 0
的主题为 mwl.io
,此证书由Let's Encrypt颁发。证书 1
具有Let's Encrypt的可分辨名称(Distinguished Name),该证书由数字签名信托公司(Digital Signature Trust Co)颁发。
然后我们就有了实际的服务器证书。证书颁发后,我们会得到证书的CN声明,以及谁颁发了证书。是的, s_client
在不同的地方重复相同的信息。
接下来,我们将了解到目前为止会话的基本信息。
xxxxxxxxxx
---
No client certificate CA names sent
Peer signing digest: SHA256
Peer signature type: RSA-PSS
Server Temp Key: X25519, 253 bits
---
“no client certificate CA names sent(未发送客户端证书CA名称)”消息告诉我们客户端尚未发送客户端证书,或者,如果发送了,证书却无法识别。服务器使用SHA256和带有概率签名方案的RSA(RSA with Probabilistic Signature Scheme —— RSA-PSS)。
服务器临时密钥(Server Temp Key)用于完全前向保密(Perfect Forward Secrecy)(第1章)。X25519是椭圆曲线Diffie-Hellman瞬时(Elliptic Curve Diffie-Hellman Ephemeral —— ECDHE)密钥协商的曲线类型和算法。当客户端看到这一点时,它将生成自己的X25519密钥对并将其公钥发送回。他们使用这些ECDHE密钥来商定一个对称密钥(symmetric key),该密钥将用于保护传输中的数据。
xxxxxxxxxx
---
SSL handshake has read 3230 bytes and written 314 bytes
Verification: OK
---
我们已经验证了所有证书,可以继续执行协议。
接下来,我们将共同商定此TLS会话的设置。
xxxxxxxxxx
---
New, TLSv1.2, Cipher is ECDHE-RSA-AES256-GCM-SHA384
Server public key is 2048 bit
Secure Renegotiation IS NOT supported
Compression: NONE
Expansion: NONE
我们使用TLS 1.2,密码(cipher)为ECDHE-RSA-AES256-GCM-SHA384。该密码使用256位ECDH进行密钥协商,使用带伽罗瓦/计数器模式(Galois/Counter Mode —— GCM)的256位AES进行加密,使用SHA384进行MAC。这是一个标准的TLS 1.2密码,随OpenSSL的命名系统一起提供,每个TLS 1.2主机都应该支持它。
TLS 1.2支持安全重新协商(Secure Renegotiation)。我们在第一章讨论了安全重新协商以及为什么它不好。
几乎每个协议和应用程序都支持压缩。SSL尝试了压缩,TLS的早期版本继承了这种支持。在TLS中压缩数据会危及机密性和完整性,并在TLS 1.3中被删除。您可以使用 -comp
参数在 s_client
中手动启用压缩。
Expansion (扩展)是指AEAD密码套件。AEAD密钥可以扩展到正常限制之外,最高可达TLS设置的限制。
应用层协议协商(Application Layer Protocol Negotiation —— ALPN)是一个TLS插件,允许应用程序将TLS设置集成到其协议设置的其余部分中。它在HTTP/2中使用最广泛。使用 alpn
标志在 s_client
中启用ALPN。有关如何使用 -alpn
的说明,请参阅 s_client(1)
。
如果您使用的是TLS 1.3,您将在此处获得更多字段。
xxxxxxxxxx
Early data was not sent
Verify return code: 0 (ok)
Early Data 允许您将应用程序请求捆绑到恢复的TLS连接中。您还将看到这被描述为 0-RTT data 。通过在包含要提前发送的数据的文件的参数中添加 -early_data
选项,您可以使用 s_client
发送早期数据。
Verify return code 将我们带回证书验证。返回代码为 0
表示OpenSSL可以验证它。如第3章所述,OpenSSL未能验证证书并不一定意味着证书无效。OpenSSL不断更新,以跟上信任生态系统的变化。每隔几年,就会有人发现OpenSSL无法验证合法证书的错误,每个人都需要更新他们的软件。
TLS会话(session)和恢复(resumption)细节在TLS 1.2和1.3之间变化刚好足够,我们必须分别考虑。
以下是您将在TLS 1.2会话中看到的内容:
xxxxxxxxxx
SSL-Session:
Protocol : TLSv1.2
Cipher : ECDHE-RSA-AES256-GCM-SHA384
Session-ID: E22E5B9717BED0047C0E9C896D6107CB1C8EA11C7E29B43621B3B3762CEA88B9
Session-ID-ctx:
Master-Key: 8320F39FF558B5567874761A1769F85D6B2AE96C1BF604C818A14AFE590FCA80ABE…
PSK identity: None
PSK identity hint: None
SRP username: None
...
会话信息以TLS版本和密码开头。
Session-ID 标识特定的TLS会话。每个会话都存在于特定的会话上下文(session context)或Session-ID-ctx中。通过设置上下文,服务器可以声明“此会话可用于web服务器,但不可用于数据库。”上下文通常用于网络负载平衡。
Master-Key 是密钥协商的结果。
PSK identity 和 PSK identity hint 通过预共享密钥(pre-shared keys)或TLS-PSK用于TLS。这种TLS变体是一种标准,但几乎从未使用过。这与TLS 1.3恢复中使用的预共享密钥不同。
安全远程密码协议将用户名和密码集成到TLS中。与此会话关联的任何用户名都会填充到 SRP username 字段中。
接下来,我们将看到会话票证(session tickets)。TLS 1.2会话票证包含会话恢复所需的信息:
xxxxxxxxxx
TLS session ticket lifetime hint: 86400 (seconds)
TLS session ticket:
0000 - 6d 83 a5 67 31 b5 bb 0a-e0 c3 72 6c b8 62 d6 63 m..g1.....rl.b.c
…
Start Time: 1603377596
Timeout : 7200 (sec)
Verify return code: 0 (ok)
Extended master secret: yes
---
TLS session ticket lifetime hint 告诉客户端应该缓存此票证多长时间。
在 TLS session ticket 中,我们有几行数据,组成了实际的票证。
Start Time 是协商TLS连接的划时代(epochal)时间。将划时代时间转换为日期和时间的方法不仅在操作系统之间有所不同,而且在版本之间也有所不同,因此您需要为您的系统查找该方法。它用于Timeout (超时),显示会话票证的有效期。
Extended master secret 声明票证是否包含额外的完整性MAC。
此时,您有一个功能正常的TLS连接,您的应用程序将接管。
TLS 1.3会话和恢复信息看起来非常像TLS 1.2。它甚至包括已弃用组件的字段,如会话票证恢复数据的一部分。这种盈余是对网络安全设备供应商的回应。
许多企业部署了拦截硬件、代理或其他工具,执行他们所谓的“深度检查”,验证所有TLS流量都是合法的TLS,而不是其他一些流量。可以预见的是,其中一些检查是草率的,写得很差。一些供应商没有跟上新兴的标准。即使供应商在协议发布时提供了TLS 1.3支持,也不是所有组织都能及时应用更新。
使用此类设备的组织无法访问使用TLS 1.3的应用程序。标准机构没有让升级到TLS 1.3的网站在设计不佳的中间件设备后面变得不可用,而是允许TLS 1.3戴上遮罩(mask),伪装成TLS 1.2。某些TLS 1.3功能被定义为TLS 1.2扩展。如果你检查TLS 1.3对话,你会看到过时的TLS 1.2字段,这些字段有助于维护伪装。
下面我们有TLS 1.3会话的开始和恢复信息:
xxxxxxxxxx
Post-Handshake New Session Ticket arrived:
SSL-Session:
Protocol : TLSv1.3
Cipher : TLS_AES_256_GCM_SHA384
Session-ID: 314E771488008EBF29001D48AC6173D7A4D2695AC99549058D6CC3955076…
Session-ID-ctx:
Resumption PSK: 0AB8007A67DB78EA27688BBBEE438CB48749315F15E416F9E0C1C437…
PSK identity: None
PSK identity hint: None
SRP username: None
TLS session ticket lifetime hint: 172800 (seconds)
TLS session ticket:
0000 - 01 fc d2 64 5f 16 46 43-83 18 8b 7b 71 7f 73 35 ...d_.FC...{q.s5
…
Start Time: 1598635979
Timeout : 7200 (sec)
Verify return code: 0 (ok)
Extended master secret: no
Max Early Data: 0
---
票证以TLS版本和密码开头。
提供会话ID和会话ID上下文以作为TLS 1.2传递。TLS 1.3不使用它们。
Resumption PSK 不是前一个TLS会话的私钥,而是证明它有会话的密钥。服务器使用此信息和会话票证中的其他信息来计算之前的预共享密钥。
PSK标识、PSK标识提示和SRP用户名与TLS 1.2相同,但仍然很少使用。
TLS session ticket lifetime hint 表示此信息的有效期(秒)。它由服务器设置。客户可以选择提前丢弃它,但很少这样做。
TLS session ticket 是用于TLS 1.3的实际票证。TLS 1.3会话票证仅适用于一次使用,这消除了TLS 1.2中会话票证的大部分问题。
Start Time 是发布此信息的划时代时间。转换划时代时间的方式不仅在操作系统之间有所不同,而且在操作系统版本之间也有所不同,因此您需要自己查找。
所有这些数据都按照 Verify Return Code 为零进行验证。
TLS 1.2使用的 Extended Master Secret 已经过时,但提供用于伪装。在TLS 1.3中总是 no 。
一个小请求,如HTTP GET,可能与TLS恢复请求一起放入一个数据包中。 Max Early Data 字段显示恢复的TLS会话中可以包含多少早期数据。零表示早期数据已禁用。
现代TLS连接失败的主要原因要么是TLS客户端不接受证书,要么是客户端和服务器找不到一组双方都同意的TLS选项、算法和协议。 s_client
和浏览器错误消息的输出可以提供有关这些协商失败位置的指导。如果你犯了手工筛选服务器提供的密码套件的错误,那就从那里开始。
这些错误通常是由于服务器配置错误造成的。客户端拒绝过期、自签名、吊销或无效的证书是绝对正确的。作为用户,您可以覆盖这些警告,但这取决于您。有些错误更阴险。最近在互联网上搜索时,我发现了一个支持最高TLS 1.1的“安全专家”网站。任何安全博客仍然没有提供比TLS 1.1更好的东西,这都是一个糟糕的例子。
如果你想要坏的例子,最好的地方是BadSSL。现场 https://badssl.com
链接到一大堆已知良好且故意破坏TLS配置的子域。许多配置错误的站点都是无法验证的证书。其他的有验证证书,但只说过时的TLS版本。一些好的网站尽可能地推动可接受的标准。如果你想看看特定的故障是什么样子的,可以在其中一些域上运行 s_client
。请确保包含 -verify_return_error
,以便 s_client
能够处理和捕获TLS级别的错误。
网站常犯的一个错误是不提供证书链文件。在这里,我戳了一下BadSSL网站 incomplete-chain.BadSSL.com
:
xxxxxxxxxx
$ openssl s_client -verify_return_error -crlf incomplete-chain.badssl.com:443
CONNECTED(00000003)
depth=0 C = US, ST = California, L = Walnut Creek, O = Lucas Garron Torres, CN = *.badssl.com
verify error:num=20:unable to get local issuer certificate
…
我们立即看到错误:“无法获取本地颁发者证书。”它就在前面。删除 -verify_return-error
并允许TLS在证书无效的情况下继续运行,可以为我们提供更多详细信息:
xxxxxxxxxx
$ openssl s_client -crlf incomplete-chain.badssl.com:443
CONNECTED(00000003)
depth=0 C = US, ST = California, L = Walnut Creek, O = Lucas Garron Torres, CN = *.badssl.com
verify error:num=20:unable to get local issuer certificate
verify return:1
depth=0 C = US, ST = California, L = Walnut Creek, O = Lucas Garron Torres, CN = *.badssl.com
verify error:num=21:unable to verify the first certificate
verify return:1
---
Certificate chain
0 s:C = US, ST = California, L = Walnut Creek, O = Lucas Garron Torres, CN = *.badssl.com
i:C = US, O = DigiCert Inc, CN = DigiCert SHA2 Secure Server CA
---
Server certificate
-----BEGIN CERTIFICATE-----
MIIGqDCCBZCgAwIBAgIQCvBs2jemC2QTQvCh6x1Z/TANBgkqhkiG9w0BAQsFADBN
…
即使你不知道“无法获取本地颁发者证书”的错误是什么意思,你也可以看到证书链中只有一个证书。即使是信任锚也不能这样工作:这些证书缺少与服务器匹配的SAN和CN。它正指向问题所在。
诚然,TLS很复杂。X.509扩展很多。一旦你理解了将答案放在上下文中,将错误消息复制到搜索引擎中的技能是无价的。我将“无法获得本地颁发者证书”复制到四个主要搜索引擎中,在所有这些引擎中,正确的解决方案都是第一个成功的。诚然,并不是所有的错误都是可以访问的,但它们是一个开始的地方。
接下来,我们将获得自己的证书。