TLS 握手协议(handshake protocol)
握手是TLS协议中最精密复杂的部分。在这个过程中,通信双方协商连接参数(沟通双方各有什么加密算法,选择一个最合适的算法),并且完成身份验证。根据使用的功能的不同,整个过程通常需要交换6~10次信息。根据配置和支持的协议扩展的不同,交换过程可能有许多变种。在使用中经常可以观察到以下三种流程:
(一) 完整的握手,对服务器进行身份验证;
(二) 短握手(恢复以前某个会话 根据session id);
(三) 对客户端和服务器都进行身份验证的握手。
握手协议消息的标头信息包含消息类型(1字节)和长度(3字节),余下的信息则取决于消息类型。
一个系统介绍TLS协议,加密算法,以及使用 openssl 建立私有CA的课程:http://edu.51cto.com/sd/89f15
(一) 完整的握手
TLS连接都会以握手开始。如果客户端此前并未与服务器建立会话,那么双方会执行一次完整的握手流程来协商TLS会话。握手过程中,客户端和服务器将进行以下四个主要步骤。
(1) 交换各自所支持的加密算法(密钥套件),如果需要其他参数,参数也要达成一致。
(2) 验证对方的证书,或使用其他方式进行身份验证。
(3) 对主密钥达成一致。
(4) 验证握手消息的完整性(看是否被第三方修改)。
在实际使用中,第2步和第3步都是密钥交换(更通用的说法是密钥生成)的一部分,如果没有身份验证,主动攻击者就可以将自身嵌入会话,并冒充会话的另一端。
一个TLS握手需要2个RTT (round trip time),一个RTT通俗的说就是一个来回,一来一往就是一个RTT。红色部分是服务器端发送的数据,黑色是客户端。
(1) 客户端开始新的握手( ClientHello),将自身支持的加密功能(Cipher Suites)提交给服务器。
(2) 服务器( ServerHello),选择Cipher Suite。
(3) 服务器发送其证书(Certificate)(当需要服务器身份验证时)。
(4) 根据选择的密钥交换方式,服务器发送生成主密钥的额外信息。
(5) 服务器通知客户端自己完成了协商过程。
(6) 客户端发送生成主密钥所需的额外信息(ClientKeyExchange)。
(7) 客户端切换到加密方式并通知服务器。
(8) 客户端计算发送和接收到的握手消息的MAC并发送。
(9) 服务器切换加密方式并通知客户端。
(10) 服务器计算发送和接收到的握手消息的MAC并发送。
我们逐一讲解每个步骤:
1. ClientHello
在一次新的握手流程中, ClientHello 消息总是第一条消息。这条消息将客户端的功能和首选项传送给服务器。客户端会在新建连接后,希望重新协商或者响应服务器发起的重新协商请求(由 HelloRequest 消息指示)时,发送这条消息。在握手时,客户端和服务器都会提供随机数。这种随机性对每次握手都是独一无二的,在身份验证中起着举足轻重的作用。它可以防止重放攻击,并确认初始数据交换的完整性。
传输的数据:
Handshake protocol: ClientHello
Version: TLS 1.2
Random
Client time: May 22, 2030 02:43:46 GMT
Random bytes: b76b0e61829557eb4c611adfd2d36eb232dc1332fe29802e321ee871
Session ID: (empty)
Cipher Suites
Suite: TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
Suite: TLS_DHE_RSA_WITH_AES_128_GCM_SHA256
Suite: TLS_RSA_WITH_AES_128_GCM_SHA256
Suite: TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA
Suite: TLS_DHE_RSA_WITH_AES_128_CBC_SHA
Suite: TLS_RSA_WITH_AES_128_CBC_SHA
Suite: TLS_RSA_WITH_3DES_EDE_CBC_SHA
Suite: TLS_RSA_WITH_RC4_128_SHA
Compression methods
Method: null
Extensions
Extension: server_name
Hostname: www.feistyduck.com
Extension: renegotiation_info
Extension: elliptic_curves
Named curve: secp256r1
Named curve: secp384r1
Extension: signature_algorithms
Algorithm: sha1/rsa
Algorithm: sha256/rsa
Algorithm: sha1/ecdsa
Algorithm: sha256/ecdsa
?
2. ServerHello
ServerHello 消息的意义是将服务器选择的连接参数传送回客户端。这个消息的结构与ClientHello 类似,只是每个字段只包含一个选项。
Handshake protocol: ServerHello
Version: TLS 1.2
Random
Server time: Mar 10, 2059 02:35:57 GMT
Random bytes: 8469b09b480c1978182ce1b59290487609f41132312ca22aacaf5012
Session ID: 4cae75c91cf5adf55f93c9fb5dd36d19903b1182029af3d527b7a42ef1c32c80
Cipher Suite: TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
Compression method: null
Extensions
Extension: server_name
Extension: renegotiation_info
服务器无需支持客户端支持的最佳版本。如果服务器不支持与客户端相同的版本,可以提供某个其他版本,只要这个版本客户端也支持。
?
3. Certificate
典型的 Certificate 消息用于携带服务器X.509证书链。证书链是以ASN.1 DER编码的一系列证书,一个接着一个组合而成。主证书必须第一个发送,中间证书按照正确的顺序跟在主证书之后。根证书可以并且应该省略掉,因为在这个场景中它没有用处。
服务器必须保证它发送的证书与选择的算法套件一致。比方说,公钥算法与套件中使用的必须匹配。除此以外,一些密钥交换算法依赖嵌入证书的特定数据,而且要求证书必须以客户端支持的算法签名。所有这些都表明服务器需要配置多个证书(每个证书可能会配备不同的证书链)。
Certificate 消息是可选的,因为并非所有套件都使用身份验证,也并非所有身份验证方法都需要证书。更进一步说,虽然消息默认使用X.509证书,但是也可以携带其他形式的标志;一些套件就依赖PGP密钥。
4. ServerKeyExchange
ServerKeyExchange 消息的目的是携带密钥交换的额外数据。消息内容对于不同的协商算法套件都会存在差异。在某些场景中,服务器不需要发送任何内容,这意味着在这些场景中根本不会发送 ServerKeyExchange 消息。
5. ServerHelloDone
ServerHelloDone 消息表明服务器已经将所有预计的握手消息发送完毕。在此之后,服务器会等待客户端发送消息。
6. ClientKeyExchange
ClientKeyExchange 消息携带客户端为密钥交换提供的所有信息。这个消息受协商的密码套件的影响,内容随着不同的协商密码套件而不同。
7. ChangeCipherSpec
ChangeCipherSpec 消息表明发送端已取得用以生成连接参数的足够信息,已生成加密密钥,并且将切换到加密模式。客户端和服务器在条件成熟时都会发送这个消息。
?
8. Finished
Finished 消息意味着握手已经完成。消息内容将加密,以便双方可以安全地交换验证整个握手完整性所需的数据。这个消息包含 verify_data 字段,它的值是握手过程中所有消息的散列值。这些消息在连接两端都按照各自所见的顺序排列,并以协商新得到的主密钥计算散列。这个过程是通过一个伪随机函数(pseudorandom function,PRF)来完成的,这个函数可以生成任意数量的伪随机数据。
我将在本章的后续部分中对其进行介绍。散列函数与PRF一致,除非协商的套件指定使用其他算法。两端的计算方法一致,但会使用不同的标签:客户端使用client finished,而服务器则使用serverfinished。verify_data = PRF(master_secret, finished_label, Hash(handshake_messages))因为 Finished 消息是加密的,并且它们的完整性由协商MAC算法保证,所以主动网络攻击者不能改变握手消息并对 vertify_data 的值造假。
理论上攻击者也可以尝试找到一组伪造的握手消息,得到的值与真正消息计算出的verity_data 的值完全一致。这种攻击本身就非常不容易,而且因为散列中混入了主密钥(攻击者不知道主密钥),所以攻击者根本不会尝试。
在TLS 1.2版本中, Finished 消息的长度默认是12字节(96位),并且允许密码套件使用更长的长度。在此之前的版本,除了SSL 3使用36字节的定长消息,其他版本都使用12字节的定长消息。
?
(二) 短握手
完整的握手需要发送多次信息,是一个耗时的操作。服务器为会话指定唯一会话ID。服务器在ServerHello 消息中将会话ID发给客户端。希望恢复之前会话的客户端将会话ID放入 ClientHello 消息。服务器如果愿意恢复会话,就将相同的会话ID放入 ServerHello 消息返回,切换到加密模式,发送 Finished 消息。
?
(1) 客户端恢复握手( ClientHello),session id
(2) 服务器ServerHello , session id
(3) 服务器切换加密方式并通知客户端。
(4) 服务器计算之前发送和接收到的所有有关握手的消息,形成MAC并发送(签名)
(5) 客户端切换到加密方式并通知服务器。
(6) 客户端计算发送和接收到的握手消息的MAC并发送。
?
(三) 对客户端和服务器都进行身份验证的握手
服务器发送 CertificateRequest 消息请求对客户端进行身份验证。客户端发送自己的 Certificate 消息(使用与服务器发送证书相同的格式),并附上证书。此后,客户端发送 CertificateVerify 消息,证明自己拥有对应的私钥。其中的5,7,9三个步骤是比普通的完整握手多出来的。
?
(1) 客户端开始新的握手( ClientHello),将自身支持的加密功能(Cipher Suites)提交给服务器。
(2) 服务器选择Cipher Suite。
(3) 服务器发送其证书(当需要服务器身份验证时)。
(4) 根据选择的密钥交换方式,服务器发送生成主密钥的额外信息。
(5) 服务器发送 CertificateRequest
(6) 服务器通知自己完成了协商过程。
(7)客户端发送自己的 Certificate
(8) 客户端发送生成主密钥所需的额外信息。
(9) 客户端发送 CertificateVerify 消息,证明自己拥有对应的私钥
(10) 客户端切换到加密方式并通知服务器。
(11) 客户端计算发送和接收到的握手消息的MAC并发送。
(12) 服务器切换加密方式并通知客户端。
(13) 服务器计算发送和接收到的握手消息的MAC并发送
?
?
?
?