SSL/TLS

Table of Contents

1. TLS 简介

The Transport Layer Security (TLS) protocol aims primarily to provide secure and data integrity between two communicating computer applications.

TLS 位于 TCP 之上(也有基于 UDP 的,称为DTLS,这里不讨论它),如图 1 所示。

ssl_desc.png

Figure 1: SSL/TLS 协议所在层次

TLS 各个版本提出时间如表 1 所示。

Table 1: TLS version History
Protocol Published
SSL 1.0 Unpublished
SSL 2.0 1995
SSL 3.0 1996
TLS 1.0 1999
TLS 1.1 2006
TLS 1.2 2008
TLS 1.3 2018

1.1. TLS 两个阶段

TLS 协议可分为两个阶段:

  1. 握手(Handshake)阶段,其目的是通信双方约定在数据传输阶段使用的加解密算法及密钥(为效率考虑,在数据传输阶段会使用对称密钥算法);
  2. 数据传输阶段,即发送到网络前加密数据,从网络收到数据后解密数据。

1.2. TLS 报文头

TLS 报文头占 5 字节,第 1 字节是类型(目前有 4 种类型),第 2-3 字节是版本(目前有 4 种版本),第 4-5 字节是长度(不包含报文头本身长度),其格式为:

         record type (1 byte)
        /
       /    version (1 byte major, 1 byte minor)
      /    /
     /    /         length (2 bytes)
    /    /         /
 +----+----+----+----+----+
 |    |    |    |    |    |
 |    |    |    |    |    | TLS Record header (5 bytes)
 +----+----+----+----+----+


 Record Type Values       dec      hex
 -------------------------------------
 CHANGE_CIPHER_SPEC        20     0x14
 ALERT                     21     0x15
 HANDSHAKE                 22     0x16
 APPLICATION_DATA          23     0x17


 Version Values            dec     hex
 -------------------------------------
 SSL 3.0                   3,0  0x0300
 TLS 1.0                   3,1  0x0301
 TLS 1.1                   3,2  0x0302
 TLS 1.2                   3,3  0x0303

2. TLS 1.2 Handshake

2.1. Handshake 具体过程

TLS1.2 使用“两个来回”完成握手过程:

          TLS1.2 Handshake

          +-----+                              +-----+
          |     |                              |     |
          |     |        ClientHello           |     |
          |     o----------------------------> |     |
          |     |                              |     |
          |     |                              |     |
          |     |        ServerHello           |     |
          |     |       [Certificate]          |     |
          |     |    [ServerKeyExchange]       |     |
          |     |    [CertificateRequest]      |     |
          |     |      ServerHelloDone         |     |
          |     | <----------------------------o     |
  CLIENT  |     |                              |     |  SERVER
          |     |                              |     |
          |     |       [Certificate]          |     |
          |     |     ClientKeyExchange        |     |
          |     |    [CertificateVerify]       |     |
          |     |   ** ChangeCipherSpec **     |     |
          |     |         Finished             |     |
          |     o----------------------------> |     |
          |     |                              |     |
          |     |                              |     |
          |     |   ** ChangeCipherSpec **     |     |
          |     |         Finished             |     |
          |     | <----------------------------o     |
          |     |                              |     |
          +-----+                              +-----+

下面来介绍一下 Handshake 的具体过程。
第 1 步、客户端发送 ClientHello 报文。其主要作用是告诉服务器,本客户端所支持的 TLS 协议版本,以及所支持的加密算法等等。
第 2 步、服务器发送 ServerHello 报文。其主要作用是服务器选择一个它认为安全的,且双方都支持的加密算法;如果服务器认为客户端所有支持的加密算法都不安全,则服务器可以发送一个 ALERT 报文(ALERT 报文是 TLS 顶级报文,参见 1.2 )。
第 3 步、服务器发送 Certificate 报文。其主要作用是服务器发送自己的证书给客户端。
第 4 步、服务器发送 ServerKeyExchange 。其主要作用是提供一些信息,以便双方有足够的信息来约定一个数据传输阶段所使用的对称密钥算法的密钥。这个报文是可选的,如果使用 Diffie-Hellman 方式来约定密钥,则这个是必须的;如果是 RSA 方式来约定密钥,它可以省略,参见后面介绍的 ClientKeyExchange 报文。
第 5 步、服务器发送 CertificateRequest 。其作用是开启“双向认证(Mutual authentication)”模式,即不仅客户端要验证服务器,而且服务器还要验证客户端。这种方式在 https 网站中很少使用,如果对 https 网站进行抓包分析,一般都不会有这个报文。
第 6 步,服务器发送 ServerHelloDone 。其作用是告诉客户端
第 7 步、客户端发送 Certificate 报文(仅当客户端收到了 CertificateRequest 时才发送,即服务器开启了双向认证)。其主要作用是客户端发送自己的证书给服务器。
第 8 步、客户端发送 ClientKeyExchange 报文。其主要作用是提供一些信息,以便双方有足够的信息来约定一个数据传输阶段所使用的对称密钥算法的密钥。如果是 RSA 方式,则客户端生成一个对称密钥算法的密钥后,使用服务器的公钥进行加密后传送给服务器。如果是 Diffie-Hellman 方式,则传送必要信息以便双方可以按约定方式生成同一个密钥。
第 9 步、客户端发送 CertificateVerify 报文(仅当客户端收到了 CertificateRequest 时才发送,即服务器开启了双向认证)。主要作用是客户端发送一段它签名的信息给服务器,这样服务器使用客户端的公钥就可以验证签名,从而验证客户端。
第 10 步、客户端发送 ChangeCipherSpec 报文,告诉服务器你可以使用加密模式了。注: ChangeCipherSpec 报文不属于 Handshake 报文,它是 TLS 顶级报文。
第 11 步、客户端发送 Finished 报文,告诉服务器我准备好加密通信了。
第 12 步、服务器发送 ChangeCipherSpec 报文,告诉客户端你可以使用加密模式了。
第 13 步、服务器发送 Finished 报文,告诉客户端我准备好加密通信了。至此,握手结束。

2.1.1. 单向认证和双向认证

握手阶段,如果服务器发送了 CertificateRequest ,就意味着开启“双向认证”。和“单向认证”相比,“双向认证”在握手阶段多了下面 3 种报文:

  • 服务器发送的 CertificateRequest
  • 客户端发送的 CertificateCertificateVerify

参考:An Introduction to Mutual SSL Authentication

2.1.2. 复用 TLS 协商结果:Session Identifier, Session Ticket

当我们打开一个 https 网页时往往会发送几十个请求,难道要重复几十次 TLS 握手协商吗?当然不用, 有两种方案可以复用第一次请求的 TLS 协商结果:Session Identifier 和 Session Ticket。

这里不详细介绍它们,可参考:
https://en.wikipedia.org/wiki/Transport_Layer_Security#Resumed_TLS_handshake
https://stackoverflow.com/questions/19939247/ssl-session-tickets-vs-session-ids

2.2. Handshake 报文格式

Handshake 报文格式如下所示:

                         |
                         |
                         |
       Record Layer      |  Handshake Layer
                         |                              |                              |
                         |                              |                              |
+----+----+----+----+----+----+----+----+----+------ - -+----+----+----+----+------ - -+ ......
| 22 |    |    |    |    |    |    |    |    |          |    |    |    |    |          |
|0x16|    |    |    |    |    |    |    |    |message   |    |    |    |    |message   |
+----+----+----+----+----+----+----+----+----+------ - -+----+----+----+----+------ - -+
  /             /--/--/  | \    \----\-----\            | \    \----\-----\            |
 /                /      |  \         \                    \         \
type: 22         /       |   \     handshake message length \    handshake message length
                /             type                          type
               /
         length: arbitrary (up to 16k)


 Handshake Type Values    dec      hex
 -------------------------------------
 HELLO_REQUEST              0     0x00
 CLIENT_HELLO               1     0x01
 SERVER_HELLO               2     0x02
 CERTIFICATE               11     0x0b
 SERVER_KEY_EXCHANGE       12     0x0c
 CERTIFICATE_REQUEST       13     0x0d
 SERVER_HELLO_DONE         14     0x0e
 CERTIFICATE_VERIFY        15     0x0f
 CLIENT_KEY_EXCHANGE       16     0x10
 FINISHED                  20     0x14

注 1:共有 10 种类型的 Handshake 报文,每种类型的具体格式可参考:Traffic Analysis of an SSL/TLS Session
注 2:多个 Handshake 报文可以组合为一个 TLS Record,上面演示中就有两个 Handshake 报文。

2.2.1. ClientHello

ClientHello 报文如下所示:

     |
     |
     |
     |  Handshake Layer
     |
     |
- ---+----+----+----+----+----+----+------+----+----------+--------+-----------+----------+
     |  1 |    |    |    |    |    |32-bit|    |max 32-bit| Cipher |Compression|Extensions|
     |0x01|    |    |    |  3 |  1 |random|    |session Id| Suites |  methods  |          |
- ---+----+----+----+----+----+----+------+----+----------+--------+-----------+----------+
  /  |  \    \---------\    \----\             \       \
 /       \        \            \                \   SessionId
record    \     length        SSL/TLS            \
length     \                  version         SessionId
            type: 1       (TLS 1.0 here)       length



CipherSuites

+----+----+----+----+----+----+
|    |    |    |    |    |    |
|    |    |    |    |    |    |
+----+----+----+----+----+----+
  \-----\   \-----\    \----\
     \         \          \
      length    cipher Id  cipherId


Compression methods (no practical implementation uses compression)

+----+----+----+
|    |    |    |
|  0 |  1 |  0 |
+----+----+----+
  \-----\    \
     \        \
 length: 1    cmp Id: 0


Extensions

+----+----+----+----+----+----+----- - -
|    |    |    |    |    |    |
|    |    |    |    |    |    |...extension data
+----+----+----+----+----+----+----- - -
  \-----\   \-----\    \----\
     \         \          \
    length    Extension  Extension data
                 Id          length

3. Server Name Indication (SNI)

在 TLS 握手时,客户端发送的 ClientHello 中不包括服务器的域名,这一般不会有问题。但随着 HTTP 服务器开启虚拟主机支持后,每个服务器通过相同的 IP 地址可以为很多个网站提供服务。这样服务器在发送 Certificate 报文时不知道应该向客户端提供哪一个网站的证书。2006 年,TLS 协议增加了 Server Name Indication (SNI) 扩展,允许客户端在 ClientHello 报文中带上它所请求的域名,这样服务器就知道客户端想访问哪个网站了,从而提供对应的证书。

参考:https://blog.csdn.net/makenothing/article/details/53292335

3.1. Encrypted SNI (ESNI)

SNI 是没有加密的,“中间人”可以知道这个请求是发往哪个域名的。在 TLS 1.3 中可以使用 Encrypted SNI (ESNI) 对 SNI 进行加密。

4. Application Layer Protocol Negotiation (ALPN)

Application Layer Protocol Negotiation (ALPN, RFC 7301),旨在将原来应用层协议中的协商,提前合并到 TLS 握手时完成,以减少一次往返时间(即不再需要应用层协议中的协商了)。

ALPN 最初是为 Google SPDY 协议(现已标准化为 HTTP/2)而提出的。我们以 HTTP/2 为实例来说明 ALPN。假设 TLS 握手完成了,接下来客户端和服务端就应该开始进行正常的 HTTP 通信了,但是客户端认为 HTTP 协议比较慢,在请求内容之前先向服务端提出“我们能不能使用 HTTP/2 协议”。服务端会根据自己支持 HTTP/2 的情况给出回答,之后客户端会根据服务端的答复,使用 HTTP 或 HTTP/2 向服务端请求内容。可以看到这个过程中又多了一次协商升级协议的往返,导致客户端拿到返回结果的延迟更大了。

为了优化这一点,在 HTTP 使用 TLS 加密的时候,会使用 ALPN 扩展,把升级 HTTP 协议的请求放在 ClientHello 的 ALPN Extension 字段中,服务端在 ServerHello 的 ALPN Extension 字段中回复说“我支持 HTTP/2”。这样 TLS 握手之后,客户端就可以直接按 HTTP/2 发起请求而不必多一次往返了。

4.1. ALPN 检测服务器是否支持 HTTP 2

前面说过,在 TLS 握手阶段,客户端可通过 ALPN 来检测服务器是否支持 HTTP 2。下面以浏览器访问 “https://tmail.com” (它已经支持了 HTTP 2)为例,使用 Wireshark 进行抓包验证。

浏览器第一次发送 ClientHello 报文时,在 ALPN 中携带了浏览器支持的版本,h2 代表浏览器支持 HTTP 2 协议,如图 2 所示。

ssl_client_hello.gif

Figure 2: ClientHello

服务器在返回 ServerHello 报文时,在 ALPN 中返回了 h2,表示服务器支持 HTTP 2 协议,如图 3 所示。

ssl_server_hello.gif

Figure 3: ServerHello

这样,建立 TLS 连接后,浏览器就知道了服务器已经支持 HTTP 2,下一步,可以直接发送“GET / HTTP/2”这样的 HTTP 报文了。

5. TLS 1.3

2018 年 8 月 10 日,IETF 发布了 TLS 1.3(RFC 8446)。这次是 TLS 协议的第一次重大改革,带来了重大的安全性和性能改进。

TLS 1.3 只需要一个 RTT(来回传输一次的时间)就能完成握手,相比 TLS 1.2 省去了一个 RTT(如图 45 所示,图片摘自:https://www.cloudflare.com/learning-resources/tls-1-3/ )。并且 TLS 1.3 支持“0-RTT”模式,在该模式下客户端可以在握手的同时发送数据,极大地加快了 https 网页的加载速度。

ssl_tls1.2vs1.3_a.png

Figure 4: TLS 1.2 握手完成需要“来回两次”

ssl_tls1.2vs1.3_b.png

Figure 5: TLS 1.3 握手完成仅需“来回一次”

6. 参考

Author: cig01

Created: <2018-03-18 Sun>

Last updated: <2023-02-24 Fri>

Creator: Emacs 27.1 (Org mode 9.4)