文章目录
什么是 SSL/TLS
使用 SSL/TLS 保护其他协议
SSL 与 TLS 的区别
SSL(Secure Socket Layer,安全套接层)是 1994 年由网景(Netscape)公司设计的一种协议,并在该公司的 Web 浏览器中进行了实现。
TLS(Transport Layer Security,传输层安全)是 IETF 在 SSL3.0 的基础上设计的协议。在 1999 年作为 RFC 2246 发布的 TLS1.0,实际上相当于 SSL3.1。
2006 年,TLS1.1 以 RFC 4346 的形式发布。该版本中增加了针对 CBC 攻击的对策,并加入了 AES 对称密码算法。
2008 年,TLS1.2 以 RFC 5246 的形式发布。该版本中增加了对 GCM、CCM 认证加密的支持,此外,还增加了 HMAC-SHA256,并删除了 IDEA 和 DES,将伪随机函数改为基于 SHA-256 来实现。
2018 年,TLS1.3 以 RFC 8446 的形式发布。
使用 SSL/TLS 进行通信
TLS 协议是由 TLS 记录协议(TLS record protocol) 和 TLS 握手协议(TLS handshake protocol) 这两层协议叠加而成的。位于底层的 TLS 记录协议负责进行加密,而位于上层的 TLS 握手协议则负责除加密以外的其他各种操作。上层的 TLS 握手协议又可以分为 4 个子协议。
length:TLS 负载数据长度,负载数据长度不应超过 214字节。
TLS 记录协议
TLS 记录协议负责消息的压缩、加密以及数据的认证。
首先,消息被分割成多个较短的片段,然后分别对每个片段进行压缩。压缩算法需要与通信对象协商决定。
接下来,经过压缩的片段会被加上消息认证码,这是为了保证完整性,并进行数据的认证。
经过压缩的片段再加上消息认证码会一起通过对称密码进行加密。
最后,经过加密的数据再加上数据类型、版本号、压缩后的长度组成的报头就是最终的报文数据。
TLS 握手协议
握手协议
握手协议是 TLS 握手协议的一部分,负责生成共享密钥以及交换证书。其中,生成共享密钥是为了进行密码通信,交换证书是为了通信双方相互进行认证。
握手协议的过程如下图所示:
- ClientHello(client -> server)
Transport Layer Security
TLSv1.2 Record Layer: Handshake Protocol: Client Hello
Content Type: Handshake (22)
Version: TLS 1.0 (0x0301)
Length: 512
Handshake Protocol: Client Hello
Handshake Type: Client Hello (1)
Length: 508
Version: TLS 1.2 (0x0303)
Random: ca47e86018adad2695a3934a240a425b07dfc1a02deb97f583a88ab8b85c17d5
Session ID Length: 32
Session ID: 121d5bc0339798de72f760cc19d5e39761119347dacd01613baa610959f287a5
Cipher Suites Length: 32
Cipher Suites (16 suites)
Compression Methods Length: 1
Compression Methods (1 method)
Extensions Length: 403
Extension: Reserved (GREASE) (len=0)
Extension: server_name (len=20)
Extension: extended_master_secret (len=0)
Extension: renegotiation_info (len=1)
Extension: supported_groups (len=10)
Extension: ec_point_formats (len=2)
Extension: session_ticket (len=192)
Extension: application_layer_protocol_negotiation (len=14)
Extension: status_request (len=5)
Extension: signature_algorithms (len=18)
Extension: signed_certificate_timestamp (len=0)
Extension: key_share (len=43)
Extension: psk_key_exchange_modes (len=2)
Extension: supported_versions (len=11)
Extension: compress_certificate (len=3)
Extension: Reserved (GREASE) (len=1)
Extension: padding (len=13)
- Version:版本编号,客户端所支持的 TLS 最高版本。
- Random: 随机数序列,随机数序列由 4 字节时间戳和 28 字节安全随机数组成,该部分总长为 32 字节。在握手时客户端和服务器都会提供随机数。该随机数一般由随机数生成器生成,可以防止重放攻击。
- Session ID:会话 ID,客户端首次建立连接时该字段一般为空,为空时表示客户端并不希望恢复某个已经存在的会话。在后续的连接过程中,该字段将会保存会话的唯一标识符。服务器可以借助该会话 ID 在服务器缓存中找到对应的会话状态。
- Cipher Suites:密码套件,客户端与服务器建立连接时,将向服务器提供自身所支持的密码套件。
- Extensions:扩展选项,扩展选项以扩展块的形式出现在 ClientHello 或 ServerHello 消息结尾,扩展块由多个扩展项堆叠组成。
- server_name: 客户端期望访问的虚拟主机名称。
- signature_algorithms: 客户端通知服务器自身支持的签名算法和单向散列函数,TLS1.2 协议中支持的签名算法包括 RSA 和 ECDSA,支持的单向散列函数包括 SHA1、SHA256 和 SHA512 等。
- session_ticket:客户端支持无状态会话恢复。
- ServerHello(server -> client)
Transport Layer Security
TLSv1.2 Record Layer: Handshake Protocol: Server Hello
Content Type: Handshake (22)
Version: TLS 1.2 (0x0303)
Length: 74
Handshake Protocol: Server Hello
Handshake Type: Server Hello (2)
Length: 70
Version: TLS 1.2 (0x0303)
Random: 08ed9e5e8baececa01333ee251ddcc76b92970fd345f06f4fba5c4d8ca73cc0d
Session ID Length: 0
Cipher Suite: TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 (0xc02f)
Compression Method: null (0)
Extensions Length: 30
Extension: renegotiation_info (len=1)
Extension: ec_point_formats (len=4)
Extension: session_ticket (len=0)
Extension: application_layer_protocol_negotiation (len=5)
Extension: extended_master_secret (len=0)
ServerHello 消息的字段描述与 ClientHello 类似,主要包括以下两个:
- Random:随机数序列,服务器向客户端提供 32 字节随机数序列。
- Cipher Suite:协商之后的密码套件,TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
- Certificate(server -> client)
Transport Layer Security
TLSv1.2 Record Layer: Handshake Protocol: Certificate
Content Type: Handshake (22)
Version: TLS 1.2 (0x0303)
Length: 2627
Handshake Protocol: Certificate
Handshake Type: Certificate (11)
Length: 2623
Certificates Length: 2620
Certificates (2620 bytes)
当客户端需要对服务器的身份进行验证时,服务器发送 Certificate 消息。该消息中包含证书清单,证书清单是一组 X.509 v3 证书列表。证书列表包含服务器证书、中间证书和根证书。通常情况下,服务器不会发送根证书,这就需要客户端提前导入根证书。
通过 Certificate 消息,客户端将获得服务器的公钥,并通过根证书中的公钥验证服务器公钥的合法性。
- ServerKeyExchange(server->client)
Transport Layer Security
TLSv1.2 Record Layer: Handshake Protocol: Server Key Exchange
Content Type: Handshake (22)
Version: TLS 1.2 (0x0303)
Length: 300
Handshake Protocol: Server Key Exchange
Handshake Type: Server Key Exchange (12)
Length: 296
EC Diffie-Hellman Server Params
Curve Type: named_curve (0x03)
Named Curve: x25519 (0x001d)
Pubkey Length: 32
Pubkey: f33afa6eee27e63233c0a000d6121e6ab8fcb22aed1c0cd793c02030ca89867f
Signature Algorithm: rsa_pkcs1_sha256 (0x0401)
Signature Length: 256
Signature: 5431d90a0e04ace7e3b88e97ea798b5508bdb93097c57b71869d41b905db7e4daa1f7666…
Server Key Exchange 可携带密钥交换过程的额外数据。某些场景下,服务器并不会发送 Server Key Exchange 消息,以椭圆曲线密钥交换算法为例:
- 若密钥协商采用 ECDH,客户端将使用证书中的服务器公钥,服务器不发送 Server Key Exchange。
- 若密钥协商采用 ECDHE,服务器将通过 Server Key Exchange 消息告之客户端临时 ECDH 公钥,并使用服务器私钥对该临时公钥进行签名。
- CertificateRequest(server->client)
当服务器需要对客户端的身份进行验证时,服务器发送 CertificateRequest 消息,消息中包括以下信息:
- 服务器可理解的证书类型清单(certificate_types)
- 服务器可理解的签名算法清单(supported_signature_algorithms)
- 服务器可理解的认证机构清单(certificate_authorities)
- ServerHelloDone(server->client)
Transport Layer Security
TLSv1.2 Record Layer: Handshake Protocol: Server Hello Done
Content Type: Handshake (22)
Version: TLS 1.2 (0x0303)
Length: 4
Handshake Protocol: Server Hello Done
Handshake Type: Server Hello Done (14)
Length: 0
服务器已将所有预计的握手消息发送完毕。
-
Certificate(client->server)
当客户端收到服务器的 CertificateRequest 消息后,客户端将会发送 Certificate 消息,消息中将包含客户端证书清单,该过程与服务器证书消息类似。
服务器读取客户端的证书并进行验证。 -
ClientKeyExchange(client->server)
Transport Layer Security
TLSv1.2 Record Layer: Handshake Protocol: Client Key Exchange
Content Type: Handshake (22)
Version: TLS 1.2 (0x0303)
Length: 37
Handshake Protocol: Client Key Exchange
Handshake Type: Client Key Exchange (16)
Length: 33
EC Diffie-Hellman Client Params
Pubkey Length: 32
Pubkey: 518cd0b856c35ee9505eaf67c7bda17559937c2890f4f9b70740dbed710db614
当密钥套件中包含 RSA 时,会随 ClientKeyExchange 消息一起发送经过加密的预备主密码。
当密码套件中包含 Diffie-Hellman 密钥交换时,会随 ClientKeyExchange 消息一起发送 Diffie-Hellman 的公开值。根据这个值,客户端和服务器会各自生成预备主密码。
预备主密码(pre-master secret)是由客户端生成的随机数,之后会被用作生成主密码的种子。这个值会在使用服务器的公钥进行加密后发送给服务器。
根据预备主密码,服务器和客户端会计算出相同的主密码,然后再根据主密码生成下列比特序列(密钥素材)。
- 对称密码的密钥
- 消息认证码的密钥
- 对称密码的 CBC 模式中使用的初始化向量(IV)
- CertificateVerify(client->server)
客户端只有在服务器发送 CertificateRequest 消息时才会发送 CertificateVerify 消息。这个消息的目的是向服务器证明自己的确持有客户端证书的私钥。 - ChangeCipherSpec(client->server)
TLSv1.2 Record Layer: Change Cipher Spec Protocol: Change Cipher Spec
Content Type: Change Cipher Spec (20)
Version: TLS 1.2 (0x0303)
Length: 1
Change Cipher Spec Message
实际上,ChangeCipherSpec 消息并不是握手协议的消息,而是密码规格变更协议的消息。
在 ChangeCipherSpec 消息之前,客户端和服务器已经交换了所有关于密码套件的信息,因此在收到这一消息时,客户端和服务器会同时切换密码。
在这一消息之后,TLS 记录协议就开始使用双方协商决定的密码通信方式进行通信。
- Finished(client->server)
TLSv1.2 Record Layer: Handshake Protocol: Encrypted Handshake Message
Content Type: Handshake (22)
Version: TLS 1.2 (0x0303)
Length: 40
Handshake Protocol: Encrypted Handshake Message
由于已经完成了密码切换,因此 Finished 消息是使用切换后的密码套件来发送的。实际负责加密操作的是 TLS 记录协议。
Finished 消息的内容是固定的,因此服务器可以将收到的密文解密,来确认所收到的 Finished 消息是否正确。通过这一消息,就可以确认握手协议是否正常结束,密码套件的切换是否正确。
-
ChangeCipherSpec(server->client)
服务器发送 ChangeCipherSpec 消息,表示服务器期望切换密码套件。 -
Finished(server->client)
服务器发送 Finished 消息,表示握手过程已经完成。 -
切换至应用数据协议
Transport Layer Security
TLSv1.2 Record Layer: Application Data Protocol: http2
Content Type: Application Data (23)
Version: TLS 1.2 (0x0303)
Length: 94
Encrypted Application Data: 0000000000000001166ff6a10d8ae008f8b5e260b74f4933e1f28d72e8f03bfcf9373dee…
[Application Data Protocol: http2]
在此之后,客户端和服务器会使用应用数据协议和 TLS 记录协议进行密码通信。
从结果来看,握手协议完成了以下操作。
- 客户端获得了服务器的合法公钥,完成了服务器认证。
- 服务器获得了客户端的合法公钥,完成了客户端认证(当需要客户端认证时)
- 客户端和服务器生成了密码通信中使用的共享密钥
- 客户端和服务器生成了消息认证码(MAC)中使用的共享密钥
密码规格变更协议
用于通知接收方,将使用协商后密码套件对后续数据报文进行加密。
需要注意的是,如果在通信期间发生了重新握手,通信双方可能需要继续使用旧的密码规范发送数据。如果密码规格发生了变更,则需要使用新的密码规格发送数据。
发送 ChangeCipherSpec 的一方不确定另一方是否完成了主密钥的计算,所以在一个小的时间窗口内接收方必须接收并缓存数据。
警告协议
用于将通信异常告知对端。TLS 警告协议由两部分组成,非别为警告等级和警告描述。
警告等级分为警告(warning)和致命错误(fatal)。当警告等级为 fatal 时,会立即终止连接。
应用数据协议
用于和通信对象之间传送应用数据。
当 TLS 承载 HTTP 时,HTTP 的请求和响应就会通过 TLS 的应用数据协议和 TLS 记录协议来进行传送。
会话恢复
完整的握手过程非常复杂,为了降低 TLS 连接时的开销,TLS 协议引入了一个可选的会话缓存功能。如果客户端希望恢复之前的某次会话,可以将会话 ID 放入 ClientHello 消息中,服务器如果同样愿意恢复会话,则将相同的 ID 放入 ServerHello 消息中返回至客户端,然后使用之前协商的主密钥生成新的会话密钥,再发送密码规格变更协议切换到加密模式,最后发送 Finished 消息。客户端收到 Finished 后进行相同的操作,完成握手过程。通过缓存会话 ID 的方法可以减少握手过程中的交互次数。