细读HTTPS -- SSL/TLS协议

细读HTTPS – SSL/TLS协议

TLS的主规格说明书定义了四个核心子协议:握手协议(handshake protocol)、密钥规格变更协议(change cipher spec protocol)、应用数据协议(application data protocol)和警报协议(alert protocol)。

握手协议

在使用中经常可以观察到以下三种流程:

  • 对服务器进行身份验证;
  • 恢复之前的会话采用的简短握手;
  • 对客户端和服务器都进行身份验证的握手。

握手之对服务器进行身份验证

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

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

具体流程如下图:
wos1

  • ClientHello:客户端开始新的握手,并将自身支持的功能提交给服务器。
    ch

    • Version:版本信息
    • Random:随机数(random)字段包含32字节的数据,在握手时,客户端和服务器都会提供随机数。这种随机性对每次握手都是独一无二的,在身份验证中起着举足轻重的作用。它可以防止重放攻击,并确认初始数据交换的完整性。
    • Session ID:在第一次连接时,会话ID(session ID)字段是空的,这表示客户端并不希望恢复某个已存在的会话。在后续的连接中,这个字段可以保存会话的唯一标识。服务器可以借助会话ID在自己的缓存中找到对应的会话状态。典型的会话ID包含32字节随机生成的数据,这些数据本身并没有什么价值。
    • Cipher Suites:密码套件(cipher suite)块是由客户端支持的所有密码套件组成的列表,该列表是按优先级顺序排列的。
    • Compression:客户端可以提交一个或多个支持压缩的方法。默认的压缩方法是null,代表没有压缩。
    • Extensions:扩展(extension)块由任意数量的扩展组成。这些扩展会携带额外数据。
  • ServerHello
    ServerHello消息的意义是将服务器选择的连接参数传送回客户端。这个消息的结构与ClientHello类似,只是每个字段只包含一个选项。服务器无需支持客户端支持的最佳版本。如果服务器不支持与客户端相同的版本,可以提供某个其他版本以期待客户端能够接受。
    是

  • Certificate
    典型的Certificate消息用于携带服务器X.509证书链。证书链是以ASN.1 DER编码的一系列证书,一个接着一个组合而成。主证书必须第一个发送,中间证书按照正确的顺序跟在主证书之后。根证书可以并且应该省略掉,因为在这个场景中它没有用处。
    服务器必须保证它发送的证书与选择的算法套件一致。比方说,公钥算法与套件中使用的必须匹配。除此以外,一些密钥交换算法依赖嵌入证书的特定数据,而且要求证书必须以客户端支持的算法签名。所有这些都表明服务器需要配置多个证书(每个证书可能会配备不同的证书链)。
    Certificate消息是可选的,因为并非所有套件都使用身份验证,也并非所有身份验证方法都需要证书。更进一步说,虽然消息默认使用X.509证书,但是也可以携带其他形式的标志;一些套件就依赖PGP密钥。

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

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

    扫描二维码关注公众号,回复: 9006194 查看本文章
  • ClientKeyExchange
    ClientKeyExchange消息携带客户端为密钥交换提供的所有信息。这个消息受协商的密码套件的影响,内容随着不同协商密码套件而不同。

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

  • Finished
    Finished消息意味着握手已经完成。消息内容将加密,以便双方可以安全地交换验证整个握手完整性所需的数据。这个消息包含verify_data字段,它的值是握手过程中所有消息的散列值。

握手之客户端身份验证&服务器身份验证

窝222
相比如对服务器的验证,双向验证中多了CertificateRequest,CertificateVerify,Certificate.而Certificate与服务器验证过程中的含义相同.所以主要来看下CertificateRequest,CertificateVerify的含义.

  • CertificateRequest
    服务器使用CertificateRequest消息请求对客户端进行身份验证,并将其接受的证书的公钥和签名算法传送给客户端。它也可以选择发送一份自己接受的证书颁发机构列表,这些机构都用其可分辨名称来表示:
    struct {
    ClientCertificateType certificate_types;
    SignatureAndHashAlgorithm supported_signature_algorithms;
    DistinguishedName certificate_authorities;
    } CertificateRequest;
    
  • CertificateVerify
    客户端使用CertificateVerify消息证明自己拥有的私钥与之前发送的客户端证书中的公钥相对应。消息中包含一条到这一步为止的所有握手消息的签名:
    struct {
    Signature handshake_messages_signature;
    } CertificateVerify;
    

握手之会话恢复

恢复早先会话的步骤如下:

  • 客户端将适当的会话ID放入ClientHello消息,然后提交。
  • 服务器如果愿意恢复会话,就将相同的会话ID放入ServerHello消息返回
  • 服务器接着使用之前协商的主密钥生成一套新的密钥,再切换到加密模式,发送Finished消息。
  • 客户端收到会话已恢复的消息以后,也进行相同的操作。
    jianduan

密钥交换

在TLS中,会话安全性取决于称为主密钥(master secret)的48字节共享密钥。密钥交换的目的是计算另一个值,即预主密钥(premaster secret)。这个值是组成主密钥的来源。
实际使用的密钥交换算法主要有以下4种:RSA,DHE_RSA,ECDHE_RSA和ECDHE_ECDSA.

RSA 密钥交换

RSA密钥交换的过程十分直截了当。客户端生成预主密钥(46字节随机数),使用服务器公钥对其加密,将其包含在ClientKeyExchange消息中,最后发送出去。服务器只需要解密这条消息就能取出预主密钥。主密钥如何生成后续会有介绍。

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中域参数的角色。

身份验证

在TLS中,为了避免重复执行密码操作造成巨大开销,身份验证与密钥交换紧紧捆绑在一起。大多数场景中,身份验证的基础是证书支持的公钥密码(最常见的是RSA,有时也用ECDSA)。一旦证书验证通过,客户端就知道了使用的公钥。在此之后,客户端将公钥交给指定的密钥交换算法,并由它负责以某种方式使用公钥验证另一端。
身份验证原理很清楚:只有拥有对应私钥的服务器才能取得预主密钥,构造正确的会话密钥,并生成正确的Finished消息。

  • 在RSA密钥交换的过程中,客户端生成一个随机值作为预主密钥,并以服务器公钥加密后发送出去。拥有对应私钥的服务器解码消息得到预主密钥。
  • 在DHE和ECDHE的交换过程中,服务器为密钥交换提供自己的参数,并使用自己的私钥签名。客户端持有对应的公钥(从已验证的证书中获得),可以验证参数是否真正出自期望的服务器。

加密

TLS可以使用各种方法加密数据,比如使用3DES、AES、ARIA、CAMELLIA、RC4或者SEED等算法。目前使用最为广泛的加密算法是AES。TLS支持三种加密类型:序列密码、分组密码和已验证的加密。

序列加密

  • 计算MAC值,范围包含记录序列号、标头、明文。MAC包含标头能确保未进行加密的标头不会遭受篡改。MAC包括序列号,能确保消息不被重放
  • 加密明文和MAC,生成密文。
    xulie

分组加密

  • 计算序列号、标头和明文的MAC。
  • 构造填充,确认加密前的数据长度是分组大小(通常16字节)的整数倍。
  • 生成一个长度与分组大小一致的不可预期的初始向量(initialization vector,IV)。IV能保证加密是不确定的。
  • 使用CBC分组模式加密明文、MAC和填充。
  • 将IV和密文一起发送。
    Tips:上述专有名词可查看前一篇博客:密码学基础
    fenzu

已验证的加密

已验证的密码将加密和完整性验证合二为一,全名是使用关联数据的已验证加密(authenticated encryption with associated data,AEAD)。表面上,它看起来是序列密码和分组密码的交叉。它不用填充②,也不用初始向量,而是使用一个特殊的值,称为nonce(在加密通信中仅使用一次的密钥)。这个值必须唯一。加密过程比使用分组密码要简单一些:

  • 生成一个唯一的64位nonce。
  • 使用已验证加密算法加密明文;同时也将序列号和记录标头作为完整性验证依据的额外数据交给算法。
  • 将nonce和密文一起发送。
    yiyanzheng

应用数据协议

应用数据协议携带着应用消息,只以TLS的角度考虑的话,这些就是数据缓冲区。记录层使用当前连接安全参数对这些消息进行打包、碎片整理和加密。

警报协议

警报的目的是以简单的通知机制告知对端通信出现异常状况。它通常会携带close_notify异常,在连接关闭时使用,报告错误。警报非常简单,只有两个字段:

	struct {
	AlertLevel level;
	AlertDescription description;
	} Alert;

AlertLevel字段表示警报的严重程度,可取值warning或者fatal。AlertDescription直接表示警报代码。不论这种设计是好是坏,警报都没有表达任意信息的能力,比如实际的错误提示。
严重程度为fatal的消息会立即终止当前连接并使会话失效(相同会话的其他正在进行的连接会继续,但会话绝不可能恢复了)。发送警告通知的一端不会主动终止连接,而是交由接收端通过发送它自己的严重警报对该警告自行作出反应。

协议中的密码操作

伪随机函数

在TLS中,伪随机函数(pseudorandom function,PRF)用于生成任意数量的伪随机数据。
PRF使用一条秘密、一颗种子和一个唯一标签。

主密钥

密钥交换过程的输出是预主密钥。对这个值进行进一步加工,就是使用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)
密钥块的长度根据协商的参数而有所不同。密钥块分为六个密钥:两个MAC密钥、两个加密密钥和两个初始向量(只在必要时生成;序列密码不会使用IV)。

TLS中的密码套件

TLS为实现所需的安全属性提供了非常大的灵活性。它是一个创造实际密码协议的框架。虽然以往版本将某些加密基元硬编码到了协议中,但TLS 1.2是完全可配置的。密码套件是一组选定的加密基元和其他参数,它可以精确定义如何实现安全。套件大致由以下这些属性定义。

  • 身份验证方法
  • 密钥交换方法
  • 加密算法
  • 加密蜜钥大小
  • 密码模式(可应用时)
  • MAC算法(可应用时)
  • PRF(只有TLS 1.2一定使用,其他版本取决于各自协议)
  • 用于Finished消息的散列函数(TLS 1.2)
  • verify_data结构的长度(TLS 1.2)
    密码套件都倾向于使用较长的描述性名称,并且相当一致:它们都由密钥交换方法、身份验证方法、密码定义以及可选的MAC或PRF算法组合而成,如图所示:
    taojian
    taojian2

TLS扩展

TLS扩展是一种通用目的的扩展机制,使用这种机制可以在不修改协议本身的条件下为TLS协议增加功能。
扩展以扩展块的形式加在ClientHello和ServerHello消息的末尾:

	Extension extensions;

扩展块由所需数量的扩展一个个堆叠而成。每一个扩展标头是2字节扩展类型(唯一标志),
后接扩展数据:

	struct {
	ExtensionType extension_type;
	opaque extension_data;
	} Extension;

扩展的格式和期望的行为由每个扩展自己决定。在实践中,扩展通常用于通知支持某些新功能(因此改变了协议),以及用于在握手阶段传递所需的额外数据。自从扩展被引入TLS,它就成为了TLS演进的主要载体。
changyong

TLS扩展:证书透明度

证书透明度(certificate transparency)还是一个提案,目的是通过保持所有公开的服务器证书来改进互联网PKI。它的基本想法是CA将每一张证书都提交给一组公开的日志服务器,反过来,这些CA将收到提交的证明,称为已签名证书时间戳(signed certificate timestamp,SCT),并中继给最终用户。有一些选项用来传送SCT,其中之一就是新的TLS扩展signed_certificate_timestamp。

TLS扩展:签名算法

signature_algoritms扩展是在TLS 1.2中定义的。它使客户端可以通告自己支持的各种签名和散列算法。TLS规格说明书中列出了RSA、DSA和ECDSA签名算法,以及MD5、SHA1、SHA224、SHA256、SHA384和SHA512这些散列算法。使用signature_algorithms扩展,客户端可以提交其支持的签名—散列算法对。

发布了20 篇原创文章 · 获赞 0 · 访问量 553

猜你喜欢

转载自blog.csdn.net/weixin_38537730/article/details/104165914