TLS是一种密码学协议,用于保证两者之间的会话安全。整个SSL/TLS协议内容太多,本文只从握手,加密,套件等方面对TLS 1.2进行简要总结。
协议详细内容,可以参见:
握手是TLS协议中最精密复杂的部分。在这个过程中,通信双方协商连接参数,并且完成身份验证。根据使用的功能的不同,整个过程通常需要交换6~10条消息。根据配置和支持的协议扩展的不同,交换过程可能有许多变种。在使用中经常可以观察到以下三种流程:
也可以参考cloudflare的流程:https://www.cloudflare.com/learning/ssl/keyless-ssl/
上图的流程大概可总结为:
TLS/SSL使用非对称加密提供身份认证和密钥协商(RSA、DH、ECC),使用对称加密完成信息加密(AES、DES、RC4),使用散列算法提供完整校验(MD5、SHA)
接下来将用Wireshark来分析一次真实的握手过程
ClientHello为握手的第一条消息,发送的内容有:
ServerHello消息的意义是将服务器选择的连接参数传送回客户端,结构与ClientHello类似。这里返回了随机数(标记为random_s),选择的套件TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,以及扩展
该部分是服务器返回给客户端的证书链,如果你访问百度,会发现会有两个证书且按照等级高的在前的顺序列出来,由于样例中的证书是自己签发的且不涉及CA,所以只有一个证书。
服务器必须保证它发送的证书与选择的算法套件一致。因为并非所有套件都使用身份验证,也并非所有身份验证方法都需要证书,所以该消息是可选的。
该消息的目的是携带密钥交换的额外数据,消息内容对于不同的协商算法套
件都会存在差异。由于这里采用的是ECDHE算法,类似DH算法,所以需要密钥交换阶段,RSA算法是没有这步的。
ServerHelloDone消息表明服务器已经将所有预计的握手消息发送完毕。在此之后,服务器会等待客户端发送消息
ClientKeyExchange消息携带客户端为密钥交换提供的所有信息,内容随着不同的协商密码套件而不同。
如果是DH算法,则是发送交换密钥,如果是RSA则是使用服务器公钥加密随机数pre-master,与random_c、random_s共同构成协商密钥
本例中的是DH算法的的秘钥
ChangeCipherSpec消息表明发送端已取得用以生成连接参数的足够信息,已生成加密密钥,并且将切换到加密模式,此后客户端的数据均为协商密钥加密的密文。
ChangeCipherSpec不属于握手消息,它是另一种协议,只有一条消息,作为它的子协议进行实现
为结合所有当前的通信参数信息生成一段数据,并使用协商密钥加密后的内容
会话标识符,解决会话缓存问题,这些数据采用一个只有服务器知道的密钥进行加密。Session Ticket由客户端进行存储,并可以在随后的一次会话中添加到 ClientHello消息的SessionTicket扩展中
与客户端发送的意义类似,代表服务器端协商的结束,与加密的开始。
完整的握手协议非常复杂,需要很多握手消息和两次网络往返才能开始发送客户端应用数据。会话的恢复机制可以减少网络的交互以及计算秘钥的资源开销。话恢复机制为:在一次完整协商的连接断开时,客户端和服务器都会将会话的安全参数保存一段时间。
服务器如果愿意恢复会话,就将相同的会话ID放入ServerHello消息返回,接着使用之前协商的主密钥生成一套新的密钥,再切换到加密模式,发送Finished消息。客户端收到会话已恢复的消息以后,也进行相同的操作。这样的结果是握手只需要一次网络往返。
在Wireshark中的流程为:
此时Client Hello的消息已经包含了Session ID.
密钥交换的主要目的是计算预主密钥( premaster secret)。这个值是组成主密钥的来源。
master_secret=PRF(pre_master_secret,"master secret",random_c,random_s)
由客户端生成一个随机值作为预主密钥,并以服务器公钥加密,将其包含在ClientKeyExchange消息中,最后发送出去。服务器只需要解密这条消息
就能取出预主密钥。
优点:简单,快速
缺点:
临时椭圆曲线Diffie-Hellman( ephemeral elliptic curve Diffie-Hellman, ECDHE)密钥交换建立在椭圆曲线加密的基础之上,其有速度快且向前兼容的优点。在TLS中, ECDHE可以与RSA或者ECDSA身份验证
一起使用。
ECDHE密钥交换由服务器发起,它选择一条椭圆曲线和公开参数(EC point),并使用自己的私钥签名:
现在就可以计算预主密钥。
身份验证的目的是来验证双方的身份,基础是证书包含的公钥密码(最常见的是RSA,有时也用ECDSA)。不同的秘钥交换算法,验证的方式存在一点差异:
加密算法主要用来对应用数据进行加密,常见的算法有:3DES、 AES、 ARIA、 CAMELLIA、 RC4。目前最为广泛的是AES
TLS支持的加密类型包括以下三种:
使用序列密码时,加密由两步组成。第一步,计算MAC值,范围包含记录序列号、标头、明文。MAC包含标头能确保未进行加密的标头不会遭受篡改。MAC包括序列号,能确保消息不被重放。第二步,加密明文和MAC,生成密文。
使用分组密码时,加密会涉及更多内容,因为需要为分组加密的特性准备解决方案。具体来 说,需要以下几个步骤:
1. 计算序列号、标头和明文的MAC。
2. 构造填充,确认加密前的数据长度是分组大小(通常16字节)的整数倍。
3. 生成一个长度与分组大小一致的不可预期的初始向量(initialization vector,IV)。IV能保证加密是不确定的。
4. 使用CBC分组模式加密明文、MAC和填充。
5 将IV和密文一起发送。
操作流程如下:
已验证的密码将加密和完整性验证合二为一,全名是使用关联数据的已验证加密。已验证加密被认为是当前TLS中可用的加密模式中最好的一种,因为它可以避免MAC-then-
encrypt方式带来的问题。
虽然TLS当前定义了基于GCM和CCM块模式的已验证套件,实际上仅支持GCM套件。
大部分TLS连接都以握手作为起点,经过应用数据的交换,最后关闭会话。但如果请求重新协 商,就会发起一次新的握手,对新的连接安全参数达成一致。该功能在以下场景很有用:
警报的目的是以简单的通知机制告知对端通信出现异常状况。它通常会携带close_notify异常,在连接关闭时使用,报告错误。警报非常简单,只有两个字段:
在TLS中,伪随机函数(pseudorandom function,PRF)用于生成任意数量的伪随机数据,其中主密钥,最终秘钥都依赖伪随机函数
密钥交换过程的输出是预主密钥。不同的秘钥交换算法采取的方式有所不同:
RSA:RSA密钥交换的过程十分直接。客户端生成预主密钥(46字节随机数),使用服务器公钥对其加密,将其包含在ClientKeyExchange消息发送出去
ECDHE:使用客户端以及服务器端的dh参数生成预主秘钥
对预主密钥进行进一步加工,就是使用PRF生成48字节(384位)主密钥:
master_secret = PRF(pre_master_secret, "master secret",
ClientHello.random + ServerHello.random)
由于PRF输出的长度是固定的,所以即使预主密钥长度可能不同,最终结果的长度也是一致的。
同时,因为客户端和服务器的随机字段被用作种子,所以主密钥实际上也是随机的.
最终用来加密数据的秘钥生成方式如下:
key_block = PRF(master_secret, “key expansion”, server_random + client_random)
由于生成key_block的参数,在server以及client上都是一致的,所以两方生成的key_block也是一致的。
key_block块分为六个密钥:
密码套件定义了秘钥交换,身份验证,加密算法,加密模式等方式。密码套件的构成如下:
密码套件并未完全掌控其安全参数。它们只是定义了最关键的身份验证和密钥交换算法,而 对这些算法的实际参数并没有控制能力(比如密钥和参数强度)。
对于身份验证,其强度主要依靠证书,更确切地说是证书中的密钥长度和签名算法。RSA密 钥交换的强度也依赖证书。可以为DHE和ECDHE密钥交换配置不同的强度,这通常是在服务器 级别的配置中完成的
SSL3(1995年末发布)->TLS 1.0(1999年初)->TLS 1.1(2006.4发布) ->TLS1.2(2008年8月发布,目前使用较广的版本)