首页 关于 微信公众号
欢迎关注我的微信公众号

SSL/TLS协议

SSL/TLS协议介绍

SSL(Secure Sockets Layer)协议由Netscape公司开发,是一种安全协议。历了 SSL 1.0、2.0、3.0 版本后发展成了标准安全协议 - TLS(Transport Layer Security) 传输层安全性协议。TLS 有 1.0 (RFC 2246)、1.1(RFC 4346)、1.2(RFC 5246)、1.3(RFC 8446) 版本。

2008年8月, TLS 1.2发布。该版本添加了对已验证加密的支持,并且基本上删除了协议说明中所有硬编码的安全基元,使协议完全弹性化。

宏观上,TLS以记录协议( record protocol)实现。记录协议负责在传输连接上交换的所有底 层消息,并可以配置加密。每一条TLS记录以一个短标头起始。标头包含记录内容的类型(或子 协议)、协议版本和长度。消息数据紧跟在标头之后,如下图所示。

记录协议从多个重要的宏观角度对通信进行考量,是一个很有用的协议抽象。

TLS协议包含了四个核心子协议:握手协议(handshake protocol)、秘钥规格变更协议(change cipher spec protocol)、应用数据协议(application data protocol)和警报协议(alert protocol)。

握手过程

握手是TLS协议中最精密复杂的部分。在这个过程中,通信双方协商连接参数,并且完成身份验证。根据使用的功能的不同,整个过程通常需要交换6~10条消息。根据配置和支持的协议扩展的不同,交换过程可能有许多变种。在使用中经常可以观察到以下三种流程: (1) 完整的握手,对服务器进行身份验证; (2) 恢复之前的会话采用的简短握手; (3) 对客户端和服务器都进行身份验证的握手。

完整握手过程

每一个TLS连接都会以握手开始。如果客户端此前并未与服务器建立会话,那么双方会执行一次完整的握手流程来协商TLS会话。握手过程中,客户端和服务器将进行以下四个主要步骤。

  1. 交换各自支持的功能,对需要的连接参数达成一致
  2. 验证出示的证书,或使用其它方式进行身份验证
  3. 对将用于保护回话的共享主密钥达成一致
  4. 验证握手消息并未被第三方团体修改

下图所示的是不需要身份验证的客户端与需要身份验证的服务器之间的握手过程:

  1. 客户端开始新的握手,并将自身支持的功能提交给服务器
  2. 服务器选择连接参数
  3. 服务器发送其证书链(仅当需要服务器身份验证时)。
  4. 根据选择的密钥交换方式,服务器发送生成主密钥的额外信息。
  5. 服务器通知自己完成了协商过程。
  6. 客户端发送生成主密钥所需的额外信息。
  7. 客户端切换加密方式并通知服务器。
  8. 客户端计算发送和接收到的握手消息的MAC并发送。
  9. 服务器切换加密方式并通知客户端。
  10. 服务器计算发送和接收到的握手消息的MAC并发送。

假设没有出现错误,到这一步,连接就建立起来了,可以开始发送应用数据。下面我们了解一下更多细节。

ClientHello

在一次新的握手流程中, ClientHello消息总是第一条消息。下图是其报文中的关键信息:

ServerHello

ServerHello消息的意义是将服务器选择的连接参数传送回客户端。这个消息的结构与ClientHello类似,只是每个字段只包含一个选项。

Certificate

典型的Certificate消息用于携带服务器X.509证书链。证书链是以ASN.1 DER编码的一系列证书,一个接着一个组合而成。主证书必须第一个发送,中间证书按照正确的顺序跟在主证书之后。根证书可以并且应该省略掉,因为在这个场景中它没有用处。

服务器必须保证它发送的证书与选择的算法套件一致。比方说,公钥算法与套件中使用的须匹配。除此以外,一些密钥交换算法依赖嵌入证书的特定数据,而且要求证书必须以客户端支持的算法签名。所有这些都表明服务器需要配置多个证书(每个证书可能会配备不同的证书链)。

Certificate消息是可选的,因为并非所有套件都使用身份验证,也并非所有身份验证方法都 需要证书。更进一步说,虽然消息默认使用X.509证书,但是也可以携带其他形式的标志;一些 套件就依赖PGP密钥。

ServerKeyExchange

ServerKeyExchange消息的目的是携带密钥交换的额外数据。消息内容对于不同的协商算法套件都会存在差异。在某些场景中,服务器不需要发送任何内容,这意味着在这些场景中根本不会发送ServerKeyExchange消息

ServerHelloDone

ServerHelloDone消息表明服务器已经将所有预计的握手消息发送完毕。在此之后,服务器会等待客户端发送消息。

ClientKeyChange

ClientKeyExchange消息携带客户端为密钥交换提供的所有信息。这个消息受协商的密码套件的影响,内容随着不同的协商密码套件而不同。

ChangeCipherSpec

ChangeCipherSpec消息表明发送端已取得用以生成连接参数的足够信息,已生成加密密钥,并且将切换到加密模式。客户端和服务器在条件成熟时都会发送这个消息。

Finished

Finished消息意味着握手已经完成。消息内容将加密,以便双方可以安全地交换验证整个握手完整性所需的数据。

这个消息包含verify_data字段,它的值是握手过程中所有消息的散列值。这些消息在连接两端都按照各自所见的顺序排列,并以协商新得到的主密钥计算散列。

客户端身份验证

尽管可以选择对任意一端进行身份验证,但人们几乎都启用了对服务器的身份验证。如果服务器选择的套件不是匿名的,那么就需要在Certificate消息中跟上自己的证书。

相比之下,服务器通过发送CertificateRequest消息请求对客户端进行身份验证。消息中列出所有可接受的客户端证书。作为响应,客户端发送自己的Certificate消息(使用与服务器发送证书相同的格式),并附上证书。此后,客户端发送CertificateVerify消息,证明自己拥有对应的私钥。完整的握手如图所示。

只有已经过身份验证的服务器才被允许请求客户端身份验证。基于这个原因,这个选项被称为相互身份验证( mutual authentication)。

cERtificateRequest

服务器使用CertificateRequest消息请求对客户端进行身份验证,并将其接受的证书的公钥和签名算法传送给客户端。它也可以选择发送一份自己接受的证书颁发机构列表,这些机构都用 其可分辨名称来表示:

struct{
	ClientCertificateType certificate_types;
	SignatureAndHashAlgorithm supported_signature_algorithms;
	DistinguishedName certificate_authorities;
} CertificateRequest;

CertificateVerfy

客户端使用CertificateVerify消息证明自己拥有的私钥与之前发送的客户端证书中的公钥相对应。消息中包含一条到这一步为止的所有握手消息的签名。

会话恢复

最初的会话恢复机制是,在一次完整协商的连接断开时,客户端和服务器都会将会话的安全参数保存一段时间。希望使用会话恢复的服务器为会话指定唯一的标识,称为会话ID。服务器在ServerHello消息中将会话ID发回客户端。

希望恢复早先会话的客户端将适当的会话ID放入ClientHello消息,然后提交。服务器如果 愿意恢复会话,就将相同的会话ID放入ServerHello消息返回,接着使用之前协商的主密钥生成 一套新的密钥,再切换到加密模式,发送Finished消息。客户端收到会话已恢复的消息以后,也 进行相同的操作。这样的结果是握手只需要一次网络往返。简短握手如图所示。

用来替代服务器会话缓存和恢复的方案是使用会话票证( sesession ticket)。它是2006年引入 的(参见RFC 4507),随后在2008年进行了更新(参见RFC 5077)。使用这种方式,除了所有的 状态都保持在客户端(与HTTP Cookie的原理类似)之外,其消息流与服务器会话缓存是一样的。

秘钥交换

在TLS中,会话安全性取决于称为主密钥( master secret)的48字节共享密钥。密钥交换的目的是计算另一个值,即预主密钥( premaster secret)。这个值是组成主密钥的来源。

TLS支持许多密钥交换算法,能够支持各种证书类型、公钥算法和密钥生成协议。它们之中有一些在TLS协议主规格书中定义,但更多的则是在其他规格说明中定义。

使用哪一种密钥交换由协商的套件所决定。一旦套件决定下来,两端都能了解按照哪种算法 继续操作。实际使用的密钥交换算法主要有以下4种。

RSA秘钥交换

RSA密钥交换的过程十分直截了当。客户端生成预主密钥( 46字节随机数),使用服务器公钥对其加密,将其包含在ClientKeyExchange消息中,最后发送出去。服务器只需要解密这条消息就能取出预主密钥。 TLS使用的是RFC 3447定义的RSAES-PKCS1-v1_5加密方案。

RSA密钥交换的简单性也是它最大的弱点。用于加密预主密钥的服务器公钥,一般会保持多年不变。任何能够接触到对应私钥的人都可以恢复预主密钥,并构建相同的主密钥,从而危害到会话安全性。

对目标的攻击并不需要实时进行,强大的对手可以制定长期行动。攻击者会记录所有加密的流量,耐心等待有朝一日可以得到密钥。比如,计算机能力的进步使暴力破解成为可能;也可以通过法律强制力、政治高压、贿赂或强行进入使用该密钥的服务器来取得密钥。只要密钥泄露,就可以解密之前记录的所有流量了。

TLS中其他常见的密钥交换方式都不受这个问题的影响,被称为支持前向保密。使用那些密钥交换时,每个连接使用的主密钥相互独立。泄露的服务器密钥可以用于冒充服务器,但不能用于追溯解密任何流量。

Diffie-Hellman秘钥交换

Diffie-Hellman( DH)密钥交换是一种密钥协定的协议,它使两个团体在不安全的信道上生成共享密钥成为可能。

抛开算法的细节, DH的诀窍是使用了一种正向计算简单、逆向计算困难的数学函数,即使交换中某些因子已被知晓,情况也是一样。最恰当的类比示例是混色:如果有两种颜色,那么很容易将其混在一起得到第三种颜色;但是如果只有第三种颜色的话,就很难确定究竟它是由哪两种颜色混合而成的。

DH密钥交换需要6个参数:其中两个( dh_p和dh_g)称为域参数,由服务器选取。协商过程中,客户端和服务器各自生成另外两个参数,相互发送其中一个参数( dh_Ys和dh_Yc)到对端,再经过计算,最终得到共享密钥。

临时Diffie-Hellman( ephemeral Diffie-Hellman, DHE)密钥交换中没有任何参数被重复使用。与之相对,在一些DH密钥交换方式中,某些参数是静态的,并被嵌入到服务器和客户端的证书中。这样的话,密钥交换的结果是一直不变的共享密钥,就无法具备前向保密的能力。

椭圆曲线 Diffie-Hellman 密钥交换

临时椭圆曲线Diffie-Hellman( elliptic curve Diffie-Hellman, ECDH)密钥交换原理与DH相似,但它的核心使用了不同的数学基础。正如名称所示, ECDHE基于椭圆曲线( elliptic curve, EC)加密。

ECDH密钥交换发生在一条由服务器定义的特定的椭圆曲线上。这条曲线代替了DH中域参数的角色。 理论上, ECDH支持静态的密钥交换,但实际使用时,只使用了这种临时的变种( ECDHE)。密钥交换由服务器发起,它选择一条椭圆曲线和公开参数( EC point)并提交。

身份验证

在TLS中,为了避免重复执行密码操作造成巨大开销,身份验证与密钥交换紧紧捆绑在一起。大多数场景中,身份验证的基础是证书支持的公钥密码(最常见的是RSA,有时也用ECDSA)。一旦证书验证通过,客户端就知道了使用的公钥。在此之后,客户端将公钥交给指定的密钥交换算法,并由它负责以某种方式使用公钥验证另一端。

在RSA密钥交换的过程中,客户端生成一个随机值作为预主密钥,并以服务器公钥加密后发送出去。拥有对应私钥的服务器解码消息得到预主密钥。身份验证原理很清楚:只有拥有对应私钥的服务器才能取得预主密钥,构造正确的会话密钥,并生成正确的Finished消息。

在DHE和ECDHE的交换过程中,服务器为密钥交换提供自己的参数,并使用自己的私钥签名。客户端持有对应的公钥(从已验证的证书中获得),可以验证参数是否真正出自期望的服务器。

Blog

Opinion

Project