4

TLS协议深入

 2 years ago
source link: https://xiaochai.github.io/2020/07/05/tls/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client
Back to Posts
Jul 5, 2020

TLS协议深入

Posted in Tech
dir.svg

TLS(Transport Layer Security)协议是位于传输层(TCP)与应用层(HTTP/WebSocket)之间的协议,增加了数据传输之间的安全性及完整性(HTTPS/WSS)。

TLS的前身SSL(Secure Sockets Layer)是由网景开发,应用于HTTPS中,前后经历了SSL 1.0、SSL 2.0、SSL 3.0三个版本(目前均已废弃)。

1999年IETF发布了标准化后的SSL协议,称之为TLS 1.0。TLS 1.0和TSL 1.1于2020年废弃,目前最新版本的TLS 3.0发布于2018年8月。

本文介绍的内容主要以TLS 2.0为主,在最后简单介绍TLS 3.0的改进以及实现原理概要。

TLS的交互流程发生于TCP的三次握手之后,典型的流程(TLS 1.2)如下:

TLS流程

从TCP三次握手成功后,还会有两次的往返交互来达成一致,随后才开始使用对称加密的方式来传输应用层信息:

  1. 客户端会发送ClientHello消息包,说明自己的TLS版本、支持的加密套件等信息;

  2. 服务端发送ServerHello消息包,确认选定的加密套件,是否支持压缩等信息,并在Certificate中添加自己的证书链信息;

  3. 客户端收到证书链后校验证书的有效性,随后生成主密钥,并将所需要的信息通过ClientKeyExchange发送给服务端(主密钥协商过程见密钥交换协议,并声明后续所有的消息都是加密后的内容(ChangeCipherSpec);至此Client端已经完成协商,可以开始发送应用层数据;

  4. 服务端收到客户端的信息,生成主密钥,也声明后续的消息都为加密后的内容(ChangeCipherSpec);

  5. TLS协商结束,开始加密传输应用层消息。

以上这些信息使得对TLS有一些直观的印象,但还会有很多的问题浮现出来,例如这些交互包里都包括哪些内容呢,加密套件具体表示什么?

如果抓包确认一下以上流程,会发现大部分情况下我们抓到的TLS的交互流程与这张图上还是有一些区别的,这其中的区别又有什么说道呢?

以上抓包的流程中多了Server Key Exchange和New Session Ticket这两个消息包

接下来从各个方面来深入理解一下TLS的握手过程。

密钥交换协议

我们知道TLS握手的目的之一是协商一个对称密钥。基于非对称加密以及证书机制,我们可以很容易想到如下流程:

  1. 客户端发起请求;

  2. 服务端回复自己的证书;

  3. 客户端使用证书链机制验证有效性,生成对称密钥S,使用证书中包含的公钥进行加密,发送给服务端;

  4. 服务端收到密文后使用私钥解密,得到密钥S,至此两端就可以使用S进行对称加密传输了。

这种方式可以保证密钥S只有通信双方知道,在私钥不泄漏的情况下,第三方无法解密内容。

但如果私钥泄漏了呢?一旦私钥泄漏,之前的转输内容将全部被解密,这是由于私钥参与了密钥交换,不满足前向安全性(Forward Secrecy)

DH密钥交换

为了解决这个问题,产生了DH密钥交换协议(Diffie–Hellman key exchange),其流程如下:

  1. 客户端发起请求;

  2. 服务端生成一个私钥aa,并选定pp,gg,计算A=ga mod pA=gamodp,发送p,g,Ap,g,A到客户端;

  3. 客户端生成一个私钥bb, 计算B=gbmodpB=gbmodp,主密钥K=Ab mod pK=Abmodp,发送BB;

  4. 服务端生成主密钥K=Ba mod pK=Bamodp;

这样双方即协商生成了主密钥KK,这是基于这样一个等式: (ga)b mod p=(gb)a mod p(ga)bmodp=(gb)amodp,证明从略。

DH协商中服务端私钥aa可以使用证书中的私钥,也可以使用临时生成一个私钥。第一种由于证书私钥参与了密钥的生成,所以一旦证书的私钥泄漏,之前的传输就有可能被破解,所以是非前向安全性。而使用临时生成的私钥可以解决这个问题,这种方式称之为DHE(Diffie–Hellman ephemeral)。

与此类似的,如果将计算过程替换成椭圆曲线的方式,就产生了ECDH和ECDHE(Elliptic-curve Diffie–Hellman ephemeral),由于ECDH的非前向安全性,目前已经废弃。

在DHE/ECDHE算法中,证书的公私钥不再参与密钥的计算,只是做为服务端的身份认证。

承载协商消息的包包括Server Key Exchange、Client Key Exchange,本文后面详细分析包结构时会再次详细介绍。

CA机构与证书

CA(Certificate Authority),即证书认证机构,通过WebTrust国际安全审计认证,就可以将自己颁发的证书预装到主流浏览器中,成为受信的根证书。

全球的主流的CA机构有Comodo、Symantec、GeoTrust、DigiCert、Thawte、GlobalSign、RapidSSL等;这其中的几家公司又属于DigiCert公司,如Symantec,GeoTrust,Thawte,RapidSSL。

不得不提一下Let’s Encrypt,它提供免费的自动化的证书管理和颁发,降低了证书申请的门槛,推进了全网HTTPS化的进程。

CA的私钥如此重要,关于它的保护措施可以查看此文章:CA 机构是如何保护自己私钥的

证书链与证书内容

Chrome打开任意一个https的网站,在地址栏的最左边可以查看网站的对应证书链:

证书链中最顶端的为根证书(Root Certificates),一般随操作系统分发,自签名,属于Root CA;最底端的为终端用户证书(End-User Certificates),即网站所属者的证书;位于中间的证书可能有多级,都称之为中间证书(Intermediates Certificates)。

可以点击证书图片的位置拖出到文件夹,即可得到cer文件,使用如下命令可以查看证书的内容:

$ openssl x509 -text -inform DER -in baidu.com.cer
Certificate:
    Data:
        Version: 3 (0x2)
        Serial Number:
            72:58:78:36:6e:9f:56:e8:1d:41:88:48
    Signature Algorithm: sha256WithRSAEncryption
        Issuer: C=BE, O=GlobalSign nv-sa, CN=GlobalSign Organization Validation CA - SHA256 - G2
        Validity
            Not Before: Apr  2 07:04:58 2020 GMT
            Not After : Jul 26 05:31:02 2021 GMT
        Subject: C=CN, ST=beijing, L=beijing, OU=service operation department, O=Beijing Baidu Netcom Science Technology Co., Ltd, CN=baidu.com
        Subject Public Key Info:
            Public Key Algorithm: rsaEncryption
                Public-Key: (2048 bit)
                Modulus:
                    00:c1:a9:b0:ae:47:1a:d2:57:eb:1d:15:1f:6e:5c:
                    ...
                    cf:26:a6:08:8e:a5:49:17:92:53:b3:91:a5:cf:53:
                    b0:31
                Exponent: 65537 (0x10001)
        X509v3 extensions:
            X509v3 Key Usage: critical
                Digital Signature, Key Encipherment
            Authority Information Access:
                CA Issuers - URI:http://secure.globalsign.com/cacert/gsorganizationvalsha2g2r1.crt
                OCSP - URI:http://ocsp2.globalsign.com/gsorganizationvalsha2g2

            X509v3 Certificate Policies:
                Policy: 1.3.6.1.4.1.4146.1.20
                  CPS: https://www.globalsign.com/repository/
                Policy: 2.23.140.1.2.2

            X509v3 Basic Constraints:
                CA:FALSE
            X509v3 CRL Distribution Points:

                Full Name:
                  URI:http://crl.globalsign.com/gs/gsorganizationvalsha2g2.crl

            X509v3 Subject Alternative Name:
                DNS:baidu.com, DNS:baifubao.com, DNS:www.baidu.cn, DNS:www.baidu.com.cn, DNS:mct.y.nuomi.com, DNS:apollo.auto, DNS:dwz.cn, DNS:*.baidu.com, DNS:*.baifubao.com, DNS:*.baidustatic.com, DNS:*.bdstatic.com, DNS:*.bdimg.com, DNS:*.hao123.com, DNS:*.nuomi.com, DNS:*.chuanke.com, DNS:*.trustgo.com, DNS:*.bce.baidu.com, DNS:*.eyun.baidu.com, DNS:*.map.baidu.com, DNS:*.mbd.baidu.com, DNS:*.fanyi.baidu.com, DNS:*.baidubce.com, DNS:*.mipcdn.com, DNS:*.news.baidu.com, DNS:*.baidupcs.com, DNS:*.aipage.com, DNS:*.aipage.cn, DNS:*.bcehost.com, DNS:*.safe.baidu.com, DNS:*.im.baidu.com, DNS:*.baiducontent.com, DNS:*.dlnel.com, DNS:*.dlnel.org, DNS:*.dueros.baidu.com, DNS:*.su.baidu.com, DNS:*.91.com, DNS:*.hao123.baidu.com, DNS:*.apollo.auto, DNS:*.xueshu.baidu.com, DNS:*.bj.baidubce.com, DNS:*.gz.baidubce.com, DNS:*.smartapps.cn, DNS:*.bdtjrcv.com, DNS:*.hao222.com, DNS:*.haokan.com, DNS:*.pae.baidu.com, DNS:*.vd.bdstatic.com, DNS:click.hm.baidu.com, DNS:log.hm.baidu.com, DNS:cm.pos.baidu.com, DNS:wn.pos.baidu.com, DNS:update.pan.baidu.com
            X509v3 Extended Key Usage:
                TLS Web Server Authentication, TLS Web Client Authentication
            X509v3 Authority Key Identifier:
                keyid:96:DE:61:F1:BD:1C:16:29:53:1C:C0:CC:7D:3B:83:00:40:E6:1A:7C

            X509v3 Subject Key Identifier:
                9E:C9:79:D7:E9:5B:AB:8A:16:CC:32:8E:C6:99:E6:9F:20:42:35:87
            1.3.6.1.4.1.11129.2.4.2:
                ...j.h.v.\.C....ED.^..V..7...G..s..^........q9.<......G0E. i.h1!.Y]...J.Ef.i.....r..(.......!...._.....ve.W...Jmo..J.....'.E...v.oSv.1.1.....Q..w.......).....7.....q9.<......G0E. TEl0N......hf.A...=.P.F..,.Z|6?^.!../.j..Z...J.5e...Z..J..xw'..C..F.v..\./.w0".T..0.V..M..3.../ ..N.d....q9.<......G0E. E...(Ga.....1A...H..[.?..v....i?.!........% ......o..e.=qY5._..-C.[
    Signature Algorithm: sha256WithRSAEncryption
         bc:dc:02:d0:d9:de:8c:c5:e2:d9:fe:4d:ef:ba:d1:22:8b:34:
         ...
         ee:69:4b:df:e4:ec:cf:f8:f2:ae:a5:5f:55:2b:0f:31:f2:64:
         0a:53:ab:eb

证书的标准为X.509,定义了证书需要包含哪些字段;

有几个比较重要的字段:

颁发者(Issuer):指向证书链的上一级证书,包含国家或地区(C)、组织(O)、名称(CN);根证书的Issuer是自己,所以他的签名也是使用自己的密钥签名的,称之为自签名证书(Self-signed certificate);

有效期(Validity):证书有效期限;

被颁发的对象(Subject):一般是网站所有者,包含国家或地区(C),州或省(ST),地点(L/Locality), 组织单位(OU),组织名(O),名称(CN);

公钥信息(Public Key Info):包括公钥算法、模数(Modulus,2048bit,在输入中有前导0x00,所以看起来像257字节)和指数(Exponent,一般是65537),参考此

签名(Signature):包括签名算法(如sha256WithRSAEncryption)和签名的值,签名的计算公式为RSA(sha256(Data), IssuerPrivateKey);

CRL Distribution Points:CRL列表的访问地址,用于吊销证书使用,参见证书吊销章节

Authority Information Access:这个信息中OCSP是比较重要的信息,用于查看证书是否被吊销,参见证书吊销章节

证书对应又有两种编码格式PEM和DER,PEM格式是使用base64编码,可以用文本程序打开,以-----BEGIN CERTIFICATE-----开头,而DER是二进制编码;可以通过以下命令将DER转成PEM:

openssl x509 -text -inform DER -in baidu.com.cer -out baidu.com.pem

对于证书文件的后缀名有很多,.crt,.cer,.pem,.der等,后缀名与编码格式并没有很大的关系。

证书链的校验

如图中所示

  1. 从终端用户证书开始,取出证书的签名,使用上一级证书(Issuer指定的)中的公钥(Public Key Info)解密得到摘要,将终端用户证书的内容按摘要算法(sha256等)获得的摘要与签名解密的摘要对比,如果一致,即说明内容没有被篡改;这里的解密和摘要生成使用了证书中指定的Signature Algorithm信息,例如sha256WithRSAEncryption,则使用sha256生成摘要,使用RSA和上一级证书公钥解密证书签名;

  2. 依次再取出第二级的证书使用再上一级的公钥解密,并验证摘要;

  3. 以此类推,直到受信任的根证书或者信任锚点(trusted anchor)。

如果在此过程中摘要对不上或者找不到受信的根证书,那么这个网站就会标记为不安全。如原来的12306,只有通过安装根证书才能使浏览器不报警。

以上就是证书链的校验过程。这一套机制通过增加中间证书的方式,使得在某一个证书提供商有问题时,直接吊销中间证书即可,保证了根证书的安全性。

证书吊销的原因有很多,例如私钥泄漏,私钥被破解等。

目前有两种方式可以吊销证书:CRLs证书吊销列表(Certificate Revocation Lists)和OCSP在线证书状态协议(Online Certificate Status Protocol)。

CRLs方式,其实是CA机构会维护一个或者多个CRL列表,包含有被吊销的证书的信息。如之前我们看到的证书信息中就有CRL Distribution Points字段,表示CRL列表的下载地址。但一些证书(大多数是自签名证书)不包含有此信息。

CRLs方式存在性能问题,随着被吊销的证书越来越多,CRL文件越来越大,达到上百兆之多。部分CA通过拆分CRL的方式来缓解这个问题,但拆分之后的大小依然可达到1M。

另外一种方式是通过增量的方式来更新CRL列表,但这需要客户端实现上的支持,目前这种方式并没有广泛地应用。

使用OCSP方式的CA会提供一个实时查询证书有效性的HTTP接口,这个接口的地址一般保存在证书当中。

这种方式会在请求服务端接口前请求一次OCSP接口,一定程度上会将用户的行为隐私暴露给CA。并且OCSP的响应时间也影响客户端页面的加载速度,带来一些性能上的问题。

为了解决这些问题,OCSP Stapling技术出现了。TLS的status_request扩展用来表明客户端支持OCSP stapling的方式来校验证书的有效性。服务端接收到此扩展后,会请求OCSP服务器来确认证书的状态,并在发送服务器状态的同时将证书的状态也下发下去,服务商会缓存叶子证书的OCSP的响应结果,但不允许缓存中间证书的响应结果。不过nginx的ocsp_stapling的选项默认是关闭的,有需要时可以在配置中打开

使用Wireshark可以很方便地识别TLS相关的包,并按其对应的含义识别成易读的结构。再配合RFC5246文档说明,可以很容易地了解交互中的每一个包的作用。

接下会按之前Wireshark截图中的出现的协议包来一个一个说明对应包的结构体,以及每一个字段的含义。

TLS Record Protocol

不过在此之前,我们还需要了解TLS传输的数据结构的基础协议,即TLS Record Protocol。它定义了数据的传输、分片、以及协商中的各种包类型。

它的每一个包的整体结构如下图:

一字节的内容类型,两个字节的版本号(版本号分成两部分:主版本号和子版本号,由于历史原因,TLS v1.0表示为0x0301,v1.1表示为0x0302,以此类推),两个字节剩下的内容长度

其定义如下:

struct {
    uint8 major;
    uint8 minor;
} ProtocolVersion;

enum {
    change_cipher_spec(20), alert(21), handshake(22),
    application_data(23), (255)
} ContentType;

struct {
    ContentType type;
    ProtocolVersion version;
    uint16 length;
    opaque fragment[TLSPlaintext.length];
} TLSPlaintext;

这里的ContentType的定义主要有以下四种,每一种都是子协议,所以会在名称后面添加Protocol字样:

  1. Handshake Protocal(22): 用于协商各种内容,例如加密套件等,常见的像ClientHello、ServerHello都属于这一类型;

  2. Change Cipher Spec Protocol(20):这个类型的消息只有一种子类型change_cipher_spec(1),用于宣告接下来的数据传输都使用协商后的加密方式进行,所以一般在加密信息协商完成之后发送,这包括重新协商的情况;

  3. Alert Protocol(21):用于表示警告或者错误的发生,包含有两个字段,AlertLevel(1)和AlertDescription(1)。需要注意的是,在TLS结束时,双方都需要发送close_notify类型的Alert来告诉对方已经传输完成;

  4. Application Data Protocol(23):携带需要传输的应用层数据。

Handshake Protocal

由于Handshake Protocal中包的类型众多,而且在交互过程中起到关键的作用,所以先来详细介绍一下它的包格式(TLS Record Protocol中Fragment的数据格式):

enum {
    hello_request(0), client_hello(1), server_hello(2),
    certificate(11), server_key_exchange (12),
    certificate_request(13), server_hello_done(14),
    certificate_verify(15), client_key_exchange(16),
    finished(20), (255)
} HandshakeType;

struct {
    HandshakeType msg_type;    /* handshake type */
    uint24 length;             /* bytes in message */
    select (HandshakeType) {
        case hello_request:       HelloRequest;
        case client_hello:        ClientHello;
        case server_hello:        ServerHello;
        case certificate:         Certificate;
        case server_key_exchange: ServerKeyExchange;
        case certificate_request: CertificateRequest;
        case server_hello_done:   ServerHelloDone;
        case certificate_verify:  CertificateVerify;
        case client_key_exchange: ClientKeyExchange;
        case finished:            Finished;
    } body;
} Handshake;

即会以一个字节的类型字段开头,后跟3字节的长度字段标识后续各个类型附属信息的长度,后面介绍每一种类型的时候,还会加深对此的认识。

至此,我们终于要开始分析每一个包了。

ClientHello

在client连接上server时,需要发送ClientHello消息。其结构体如下:

struct {
    ProtocolVersion client_version;
    Random random;
    SessionID session_id;
    CipherSuite cipher_suites<2..2^16-2>;
    CompressionMethod compression_methods<1..2^8-1>;
    select (extensions_present) {
        case false:
            struct {};
        case true:
            Extension extensions<0..2^16-1>;
    };
} ClientHello;

struct {
    uint32 gmt_unix_time;
    opaque random_bytes[28];
} Random;

opaque SessionID<0..32>;

uint8 CipherSuite[2];

enum { null(0), (255) } CompressionMethod;

struct {
    ExtensionType extension_type;
    opaque extension_data<0..2^16-1>;
} Extension;

client_version: 与之前提到的版本号格式一致,表示客户端期望交互的TLS的版本号,如TLS v1.2时,值为0x0303。但其实在TLS v1.3中,这个值也是使用1.2的值(字段名变更为legacy_version),而是使用了supported_versions这个扩展来标识对于TLS v1.3的支持。这块的原因可以参考RFC8446中的以下这段话,主要是为了兼容客户端:

legacy_version:
   In previous versions of TLS, this field was used for version negotiation and represented the highest version number supported by the client.
   Experience has shown that many servers do not properly implement version negotiation, leading to “version intolerance” in which the server rejects an otherwise acceptable ClientHello with a version number higher than it supports.
   In TLS 1.3, the client indicates its version preferences in the “supported_versions” extension (Section 4.2.1) and the legacy_version field MUST be set to 0x0303, which is the version number for TLS 1.2.
   TLS 1.3 ClientHellos are identified as having a legacy_version of 0x0303 and a supported_versions extension present with 0x0304 as the highest version indicated therein.

random:这个结构包括一个32位的时间戳和一个28字节的随机数;

session_id:是一个不定长的id标识,在实现中有一个字节的长度和后面的具体内容组成。session_id一般情况下为空,只有在客户端希望复用session_id(session_id的来源可以是之前连接的,也可以是当前连接的,也可以是当前其它连接)时,才会传这个session_id,传session_id可以减少协商的交互次数,详见后面的session复用章节

cipher_suites:包括两个字节的长度信息,和支持的套件列表(按客户端喜好优先排列),每一个套件占用两字节,定义了以下四个方面:密钥交换算法(key exchange algorithm),批量加密算法(bulk encryption algorithm (including secret key length)),消息认证码算法(MAC algorithm),伪随机算法函数(pseudo-random function/PRF);

compression_methods: 包括一个字节的长度信息和支持的压缩方法列表,列表中必须包含有null(0),表示支持不使用压缩;

extensions: 剩下的都为扩展相关的内容,包括两字节的长度信息和扩展列表;扩展的结构如下,包括两个字节的ExtensionType、两个字节的扩展长度,以及剩下的扩展的具体数据信息,详情参见ClientHello与ServerHello所使用的扩展

Wireshark抓包如下:

TLSv1.2 Record Layer: Handshake Protocol: Client Hello
    Content Type: Handshake (22)
    Version: TLS 1.0 (0x0301)
    Length: 512
    Handshake Protocol: Client Hello
        Handshake Type: Client Hello (1)
        Length: 508
        Version: TLS 1.2 (0x0303)
        Random: 5ed829e87870dd580769d4edeccf8da2629ff6f84856b816…
            GMT Unix Time: Jun  4, 2020 06:53:28.000000000 CST
            Random Bytes: 7870dd580769d4edeccf8da2629ff6f84856b816ed1ccad5…
        Session ID Length: 32
        Session ID: d832f91730c0b419f42e26a7222e5e3a4523db0b34eca86d…
        Cipher Suites Length: 32
        Cipher Suites (16 suites)
            Cipher Suite: Reserved (GREASE) (0x9a9a)
            Cipher Suite: TLS_AES_128_GCM_SHA256 (0x1301)
            Cipher Suite: TLS_AES_256_GCM_SHA384 (0x1302)
            Cipher Suite: TLS_CHACHA20_POLY1305_SHA256 (0x1303)
            Cipher Suite: TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 (0xc02b)
            Cipher Suite: TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 (0xc02f)
            Cipher Suite: TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 (0xc02c)
            Cipher Suite: TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (0xc030)
            Cipher Suite: TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256 (0xcca9)
            Cipher Suite: TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256 (0xcca8)
            Cipher Suite: TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA (0xc013)
            Cipher Suite: TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA (0xc014)
            Cipher Suite: TLS_RSA_WITH_AES_128_GCM_SHA256 (0x009c)
            Cipher Suite: TLS_RSA_WITH_AES_256_GCM_SHA384 (0x009d)
            Cipher Suite: TLS_RSA_WITH_AES_128_CBC_SHA (0x002f)
            Cipher Suite: TLS_RSA_WITH_AES_256_CBC_SHA (0x0035)
        Compression Methods Length: 1
        Compression Methods (1 method)
            Compression Method: null (0)
        Extensions Length: 403
        Extension: Reserved (GREASE) (len=0)
        Extension: server_name (len=18)
        Extension: extended_master_secret (len=0)
        Extension: renegotiation_info (len=1)
        Extension: supported_groups (len=10)
        Extension: ec_point_formats (len=2)
        Extension: session_ticket (len=0)
        Extension: application_layer_protocol_negotiation (len=14)
        Extension: status_request (len=5)
        Extension: signature_algorithms (len=18)
        Extension: signed_certificate_timestamp (len=0)
        Extension: key_share (len=43)
        Extension: psk_key_exchange_modes (len=2)
        Extension: supported_versions (len=11)
        Extension: compress_certificate (len=3)
        Extension: Reserved (GREASE) (len=1)
        Extension: padding (len=207)

ServerHello

用于回复ClinetHello。如果客户端的所有算法套件服务端不支持,则不会回复ServerHello,而会使用FailureAlert消息。

struct {
    ProtocolVersion server_version;
    Random random;
    SessionID session_id;
    CipherSuite cipher_suite;
    CompressionMethod compression_method;
    select (extensions_present) {
        case false:
            struct {};
        case true:
            Extension extensions<0..2^16-1>;
    };
} ServerHello;

字段上与ClientHello基本一样,只是CipherSuite和CompressionMethod不再是变长的字段,而是服务端选定的结果。

session_id字段说明:如果ClientHello传了session_id,并且server端在自己的缓存中找到了这个session_id对应的信息,则可以直接返回client的session_id,表示复用此session。如果没有找到,或者服务端不想使用,则生成一个新的session_id,服务端也可以返回空的session_id表示服务端不希望复用此session_id。

extensions_present: 用于回应ClientHello中的扩展信息,注意ServerHello中的扩展只能出现那些在ClientHello里出现的扩展。

TLSv1.2 Record Layer: Handshake Protocol: Server Hello
    Content Type: Handshake (22)
    Version: TLS 1.2 (0x0303)
    Length: 74
    Handshake Protocol: Server Hello
        Handshake Type: Server Hello (2)
        Length: 70
        Version: TLS 1.2 (0x0303)
        Random: 3392504de3539bf4bb4a8144225493d893ec4bd493d2314d…
        Session ID Length: 0
        Cipher Suite: TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 (0xc02f)
        Compression Method: null (0)
        Extensions Length: 30
        Extension: server_name (len=0)
        Extension: renegotiation_info (len=1)
        Extension: ec_point_formats (len=4)
        Extension: session_ticket (len=0)
        Extension: application_layer_protocol_negotiation (len=5)

ClientHello与ServerHello所使用的扩展

扩展的使用延展了TLS协议的大量能力,所以这里穿插介绍TLS中使用的扩展,以下这些扩展是在chrome里抓包查看到的,也忽略了一些不常用。

Reserved(GREASE)

这个扩展并不是只有指定的一个类型编号,而是有一系列类型编号。它是google提出,用于消除那些服务端在碰到不认识扩展时就中止的不正确服务端实现,这里是对应的介绍。此类型只包含两字节的类型和两字节的内容长度,并且长度为0。其意义如下,定义的这些插件会被随机发送给服务端,使得有问题的服务端实现可以在广泛传播前发现问题:

However, bugs may cause an implementation to reject unknown values. It will interoperate with existing peers, so the mistake may spread through the ecosystem unnoticed. Later, when new values are defined, updated peers will discover that the metaphorical joint in the protocol has rusted shut and that the new values cannot be deployed without interoperability failures. To avoid this problem, this document reserves some currently unused values for TLS implementations to advertise at random. Correctly implemented peers will ignore these values and interoperate. Peers that do not tolerate unknown values will fail to interoperate, revealing the mistake before it is widespread.

Extension: Reserved (GREASE) (len=0)
    Type: Reserved (GREASE) (10794)
    Length: 0
    Data: <MISSING>
sever_name(RFC6066)

对于使用vhost的服务器来说,同一个IP可能对应服务多个域名,并且对应多个证书,所以在http的host头信息没有上传时,server端根据这个server_name扩展字段来识别域名,即大家所说的SNI扩展(server name indication)。

Extension: server_name (len=30)
    Type: server_name (0)
    Length: 30
    Server Name Indication extension
        Server Name list length: 28
        Server Name Type: host_name (0)
        Server Name length: 25
        Server Name: passport.test.huajiao.com
extended_master_secret(RFC7627)

使用增强型主密钥计算方式,client发送的内容为空,而server hello如果返回了这个扩展,表示使用增强型主密钥计算方式。

增强型主密钥是将原来的主密钥算法

master_secret = PRF(pre_master_secret, "master secret", ClientHello.random + ServerHello.random)[0..47]

master_secret = PRF(pre_master_secret, "extended master secret", session_hash)[0..47]

其中server_hash是整个交互过程中提取的信息,包括ClientHello.random和ServerHello.random:

此设计反映了密钥应该绑定到计算它们的安全上下文的建议SP800-108。将密钥交换消息的散列混合到主密钥导出中的技术已经用于其他众所周知的协议,例如Secure Shell(SSH)RFC4251。Client和Server不应接受不使用扩展主密钥的握手,特别是如果它们依赖于复合认证等功能。

Extension: extended_master_secret (len=0)
    Type: extended_master_secret (23)
    Length: 0
renegotiation_info(RFC5746)

重协商扩展,用于解决旧版本中重协商存在中间人攻击的情况,具体这块扩展的内容,见后面的重协商中间人攻击相关的内容。

有时候ClientHello中也存在不发送这个扩展,但服务端返回这个扩展的情况,这是为了监容旧版本服务端不正确的实现,使用了TLS_EMPTY_RENEGOTIATION_INFO_SCSV这一伪密码套件来表示这一扩展,即在ClientHello中的cipher_suites中添加TLS_EMPTY_RENEGOTIATION_INFO_SCSV来表示支持重协商。

Extension: renegotiation_info (len=1)
    Type: renegotiation_info (65281)
    Length: 1
    Renegotiation Info extension
        Renegotiation info extension length: 0
supported_groups(RFC7919)ec_point_formats(RFC8422)

这两个都是关于椭圆曲线相关的: 支持的椭圆曲线的种类以及是否能对椭圆曲线参数进行压缩。

Extension: supported_groups (len=10)
    Type: supported_groups (10)
    Length: 10
    Supported Groups List Length: 8
    Supported Groups (4 groups)
        Supported Group: Reserved (GREASE) (0xbaba)
        Supported Group: x25519 (0x001d)
        Supported Group: secp256r1 (0x0017)
        Supported Group: secp384r1 (0x0018)
Extension: ec_point_formats (len=2)
    Type: ec_point_formats (11)
    Length: 2
    EC point formats Length: 1
    Elliptic curves point formats (1)
        EC point format: uncompressed (0)
session_ticket(RFC5077)

附带之前服务端下发的ticket来加速协商的过程,如果服务端支持ticket需要在回包中带上此扩展,并且在Change Chiper Spec之前发送New Session Ticket类型的Handshake包,详情见

Extension: session_ticket (len=160)
    Type: session_ticket (35)
    Length: 160
    Data (160 bytes)

TLSv1.2 Record Layer: Handshake Protocol: New Session Ticket
    Content Type: Handshake (22)
    Version: TLS 1.2 (0x0303)
    Length: 202
    Handshake Protocol: New Session Ticket
        Handshake Type: New Session Ticket (4)
        Length: 198
        TLS Session Ticket
            Session Ticket Lifetime Hint: 6000 seconds (1 hour, 40 minutes)
            Session Ticket Length: 192
            Session Ticket: d008e85ec8445a77337455e2cf7bfd761fbd4dcfc1294b10…
application_layer_protocol_negotiation(RFC7301)

用于协调应用层的协议,例如使用http1.1还是使用http2,一般称之为ALPN扩展。

Extension: application_layer_protocol_negotiation (len=14)
    Type: application_layer_protocol_negotiation (16)
    Length: 14
    ALPN Extension Length: 12
    ALPN Protocol
        ALPN string length: 2
        ALPN Next Protocol: h2
        ALPN string length: 8
        ALPN Next Protocol: http/1.1

Extension: application_layer_protocol_negotiation (len=5)
    Type: application_layer_protocol_negotiation (16)
    Length: 5
    ALPN Extension Length: 3
    ALPN Protocol
        ALPN string length: 2
        ALPN Next Protocol: h2
status_request(RFC6066)

期望服务端请求OCSP来校验证书是否被吊销,详见证书吊销章节。

    Extension: status_request (len=5)
        Type: status_request (5)
        Length: 5
        Certificate Status Type: OCSP (1)
        Responder ID list Length: 0
        Request Extensions Length: 0

signature_algorithms(RFC5246):
Extension: signature_algorithms (len=18)
    Type: signature_algorithms (13)
    Length: 18
    Signature Hash Algorithms Length: 16
    Signature Hash Algorithms (8 algorithms)
        Signature Algorithm: ecdsa_secp256r1_sha256 (0x0403)
        Signature Algorithm: rsa_pss_rsae_sha256 (0x0804)
        Signature Algorithm: rsa_pkcs1_sha256 (0x0401)
        Signature Algorithm: ecdsa_secp384r1_sha384 (0x0503)
        Signature Algorithm: rsa_pss_rsae_sha384 (0x0805)
        Signature Algorithm: rsa_pkcs1_sha384 (0x0501)
        Signature Algorithm: rsa_pss_rsae_sha512 (0x0806)
        Signature Algorithm: rsa_pkcs1_sha512 (0x0601)
Extension: signed_certificate_timestamp (len=0)
    Type: signed_certificate_timestamp (18)
    Length: 0
supported_versions(RFC8446)

在TLS1.3中,ClientHello中的supported_versions扩展非常重要。因为TLS1.3 是根据这个字段的值来协商是否支持TLS1.3。

在TLS1.3规范中规定,ClientHello中的legacy_version必须设置为0x0303,这个值代表的是TLS1.2。这样规定是为了对网络中间件做的一些兼容。

如果ClientHello中不携带supported_versions这个扩展,那么注定只能协商TLS1.2了。

Extension: supported_versions (len=11)
    Type: supported_versions (43)
    Length: 11
    Supported Versions length: 10
    Supported Version: Unknown (0xeaea)
    Supported Version: TLS 1.3 (0x0304)
    Supported Version: TLS 1.2 (0x0303)
    Supported Version: TLS 1.1 (0x0302)
    Supported Version: TLS 1.0 (0x0301)
padding(RFC7685)

为了解决某些TLS实现在收到特定大小的ClientHello包时会出现问题的情况。

Extension: padding (len=207)
    Type: padding (21)
    Length: 207
    Padding Data: 000000000000000000000000000000000000000000000000…

Server Certificate

这个消息跟在ServerHello之后,用于发送服务端的证书链:

Handshake Protocol: Certificate
    Handshake Type: Certificate (11)
    Length: 3419
    Certificates Length: 3416
    Certificates (3416 bytes)
        Certificate Length: 1293
        Certificate: 30820509308203f1a00302010202100e3cc14994b3e174a6… (id-at-commonName=*.zhihu.com,id-at-organizationalUnitName=IT,id-at-organizationName=智者四海(北京)技术有限公�,id-at-localityName=北京市,id-at-countryName=C
            signedCertificate
                version: v3 (2)
                serialNumber: 0x0e3cc14994b3e174a63454d9906466d7
                signature (sha256WithRSAEncryption)
                    Algorithm Id: 1.2.840.113549.1.1.11 (sha256WithRSAEncryption)
                issuer: rdnSequence (0)
                    rdnSequence: 4 items (id-at-commonName=GeoTrust RSA CA 2018,id-at-organizationalUnitName=www.digicert.com,id-at-organizationName=DigiCert Inc,id-at-countryName=US)
                        RDNSequence item: 1 item (id-at-countryName=US)
                            RelativeDistinguishedName item (id-at-countryName=US)
                                Id: 2.5.4.6 (id-at-countryName)
                                CountryName: US
                        RDNSequence item: 1 item (id-at-organizationName=DigiCert Inc)
                            RelativeDistinguishedName item (id-at-organizationName=DigiCert Inc)
                                Id: 2.5.4.10 (id-at-organizationName)
                                DirectoryString: printableString (1)
                                    printableString: DigiCert Inc
                        RDNSequence item: 1 item (id-at-organizationalUnitName=www.digicert.com)
                            RelativeDistinguishedName item (id-at-organizationalUnitName=www.digicert.com)
                                Id: 2.5.4.11 (id-at-organizationalUnitName)
                                DirectoryString: printableString (1)
                                    printableString: www.digicert.com
                        RDNSequence item: 1 item (id-at-commonName=GeoTrust RSA CA 2018)
                            RelativeDistinguishedName item (id-at-commonName=GeoTrust RSA CA 2018)
                                Id: 2.5.4.3 (id-at-commonName)
                                DirectoryString: printableString (1)
                                    printableString: GeoTrust RSA CA 2018
                validity
                    notBefore: utcTime (0)
                        utcTime: 17-12-25 00:00:00 (UTC)
                    notAfter: utcTime (0)
                        utcTime: 20-12-24 12:00:00 (UTC)
                subject: rdnSequence (0)
                    rdnSequence: 5 items (id-at-commonName=*.zhihu.com,id-at-organizationalUnitName=IT,id-at-organizationName=智者四海(北京)技术有限公�,id-at-localityName=北京市,id-at-countryName=CN)
                        RDNSequence item: 1 item (id-at-countryName=CN)
                            RelativeDistinguishedName item (id-at-countryName=CN)
                                Id: 2.5.4.6 (id-at-countryName)
                                CountryName: CN
                        RDNSequence item: 1 item (id-at-localityName=北京市)
                            RelativeDistinguishedName item (id-at-localityName=北京市)
                                Id: 2.5.4.7 (id-at-localityName)
                                DirectoryString: uTF8String (4)
                                    uTF8String: 北京市
                        RDNSequence item: 1 item (id-at-organizationName=智者四海(北京)技术有限公�)
                            RelativeDistinguishedName item (id-at-organizationName=智者四海(北京)技术有限公司)
                                Id: 2.5.4.10 (id-at-organizationName)
                                DirectoryString: uTF8String (4)
                                    uTF8String: 智者四海(北京)技术有限公司
                        RDNSequence item: 1 item (id-at-organizationalUnitName=IT)
                            RelativeDistinguishedName item (id-at-organizationalUnitName=IT)
                                Id: 2.5.4.11 (id-at-organizationalUnitName)
                                DirectoryString: printableString (1)
                                    printableString: IT
                        RDNSequence item: 1 item (id-at-commonName=*.zhihu.com)
                            RelativeDistinguishedName item (id-at-commonName=*.zhihu.com)
                                Id: 2.5.4.3 (id-at-commonName)
                                DirectoryString: uTF8String (4)
                subjectPublicKeyInfo
                    algorithm (rsaEncryption)
                        Algorithm Id: 1.2.840.113549.1.1.1 (rsaEncryption)
                    subjectPublicKey: 3082010a0282010100a0a87188cf5e1be6c845ed6089ced2…
                        modulus: 0x00a0a87188cf5e1be6c845ed6089ced276a0af03a6c118bb…
                        publicExponent: 65537
                extensions: 9 items
                    Extension (id-ce-authorityKeyIdentifier)
                    Extension (id-ce-subjectKeyIdentifier)
                    Extension (id-ce-subjectAltName)
                    Extension (id-ce-keyUsage)
                    Extension (id-ce-extKeyUsage)
                    Extension (id-ce-cRLDistributionPoints)
                    Extension (id-ce-certificatePolicies)
                    Extension (id-pe-authorityInfoAccess)
                    Extension (id-ce-basicConstraints)
            algorithmIdentifier (sha256WithRSAEncryption)
                Algorithm Id: 1.2.840.113549.1.1.11 (sha256WithRSAEncryption)
            Padding: 0
            encrypted: 5473e602db5d49304d6171acef6df152af45f20f81940b5c…
        Certificate Length: 1167
        Certificate: 3082048b30820373a00302010202100546fe1823f7e1941d… (id-at-commonName=GeoTrust RSA CA 2018,id-at-organizationalUnitName=www.digicert.com,id-at-organizationName=DigiCert Inc,id-at-countryName=US)
        Certificate Length: 947
        Certificate: 308203af30820297a0030201020210083be056904246b1a1… (id-at-commonName=DigiCert Global Root CA,id-at-organizationalUnitName=www.digicert.com,id-at-organizationName=DigiCert Inc,id-at-countryName=US)

Server Key Exchange Message

用于密钥交换时所需要的额外信息,例如在密钥交换使用DHE算法时,就需要发送服务端算出来的值。

TLSv1.2 Record Layer: Handshake Protocol: Server Key Exchange
    Content Type: Handshake (22)
    Version: TLS 1.2 (0x0303)
    Length: 333
    Handshake Protocol: Server Key Exchange
        Handshake Type: Server Key Exchange (12)
        Length: 329
        EC Diffie-Hellman Server Params
            Curve Type: named_curve (0x03)
            Named Curve: secp256r1 (0x0017)
            Pubkey Length: 65
            Pubkey: 048b8789076ab24ec8a4f62276cea6ca302596c725dc87e1…
            Signature Algorithm: rsa_pkcs1_sha512 (0x0601)
                Signature Hash Algorithm Hash: SHA512 (6)
                Signature Hash Algorithm Signature: RSA (1)
            Signature Length: 256
            Signature: 231e98d4d7327615c0623390b5a70c75af452d4f3138516f…

Server Hello Done

用于表明服务端已经在密钥交换环节发送完信息了,现在需要等待客户端发送信息了。

TLSv1.2 Record Layer: Handshake Protocol: Server Hello Done
    Content Type: Handshake (22)
    Version: TLS 1.2 (0x0303)
    Length: 4
    Handshake Protocol: Server Hello Done
        Handshake Type: Server Hello Done (14)
        Length: 0

Client Key Exchange

客户端用于密钥协商所需要提供的信息

TLSv1.2 Record Layer: Handshake Protocol: Client Key Exchange
    Content Type: Handshake (22)
    Version: TLS 1.2 (0x0303)
    Length: 70
    Handshake Protocol: Client Key Exchange
        Handshake Type: Client Key Exchange (16)
        Length: 66
        EC Diffie-Hellman Client Params
            Pubkey Length: 65
            Pubkey: 0417926519bea2958936e4350faa1a3f4271228a97668627…

New Session Ticket

新生成的session ticket,参见session ticket章节

TLSv1.2 Record Layer: Handshake Protocol: New Session Ticket
    Content Type: Handshake (22)
    Version: TLS 1.2 (0x0303)
    Length: 202
    Handshake Protocol: New Session Ticket
        Handshake Type: New Session Ticket (4)
        Length: 198
        TLS Session Ticket
            Session Ticket Lifetime Hint: 6000 seconds (1 hour, 40 minutes)
            Session Ticket Length: 192
            Session Ticket: d008e85ec8445a77337455e2cf7bfd761fbd4dcfc1294b10…

Finished

用于表示协商结束,后续开始传输应用数据,Finished本身使用协商的对称密钥加密,并且包含了整个协商交互过程中内容的Hash校验值,所以Finish信息也是对于交互中是否篡改进行的校验。

struct {
    opaque verify_data[verify_data_length];
} Finished;

verify_data
   PRF(master_secret, finished_label, Hash(handshake_messages))
      [0..verify_data_length-1];

注意这里的verify_data将在重协商的renegotiation_info扩展消息中使用。

Hello Request

Server端随时可以发送,用于告知Client端需要重新协商。此类型没有消息体,所以length为0。

TLS重协商的中间人攻击

重协商是在已经协商好的TLS连接上发起重新协商的机制,用于更换算法、证书、更新密钥等场景。

有两种方式可以发起重协商:1. 客户端发起ClientHello要求重协商 ,2. 服务端发送HelloRequest来发起重协商。当然对方都可以通过Alert来拒绝重协商。

最开始的重协商机制存在安全漏洞,可以通过以下的方式进行中间人攻击:

攻击流程:

  1. Client发起clientHello握手请求,被中间人暂时存下来
  2. 中间人发起握手请求,并发送精心设计的HTTP的请求头:
    GET /attacked.jsp HTTP/1.0
    Dummy: 
    
  3. 中间人将暂存的clientHello发送到服务端,服务端会认为是一个重协商,所以走重协商流程
  4. Client发送真正的HTTP请求
    GET /index.jsp HTTP/1.0
    Cookie: Token=xxx
    
  5. 在服务端看来,会把两段请求合并(如图),变成带着用户的cookie请求attacked.jsp路径,中间人攻击达到目的。

使用这个思路还可以实现用户重定向到恶意网站,POST劫持等各种攻击

以上SSL3.0上的重协商协议之所以是不安全的,主要原因在于服务端无法区分首次的ClientHello包还是重协商的ClientHello包,以及前后的两次协商之间缺少关联性。

为此,RFC5746提出了安全重协商renegotitation_info扩展,ClientHello中发送此扩展来与服务端协商开启安全的重协商策略,其发送的数据如下:

Extension: renegotiation_info (len=1)
    Type: renegotiation_info (65281)
    Length: 1
    Renegotiation Info extension
        Renegotiation info extension length: 0

如果服务端同意开启安全重协商策略,则在server hello也会返回些扩展,数据也是为空;在协商完成发送的Finish包时会各自都带上verify_data,称之为client_verify_data和server_verify_data,两端都将这两个verify_data存储下来。

在重协商时,发送的ClientHello会在Renegotiation Info extension里带有上一次协商时的client_verify_data;ServerHello则会将client_verify_data和server_verify_data都带上。两端对此数据校验通过了才会继续重协商。

Finish包是使用协商完成的密钥加密传输的,所以不用担心verify_data被篡改的问题,这种方式就将两次协商关联在一起了,防止中间人攻击。

有时候ClientHello中也存在不发送这个扩展但服务端返回这个扩展的情况,这是为了兼容旧版本服务端不正确的实现,使用了TLS_EMPTY_RENEGOTIATION_INFO_SCSV这一伪密码套件来表示这一扩展,即在ClientHello中的cipher_suites中添加TLS_EMPTY_RENEGOTIATION_INFO_SCSV来表示支持重协商,这块的理解参见

Cipher Suites (46 suites)
    Cipher Suite: TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (0xc030)
    ...
    Cipher Suite: TLS_EMPTY_RENEGOTIATION_INFO_SCSV (0x00ff)

使用session_id 和session_ticket 减少握手次数

SessionID机制

session_id用于复用连接信息来减少TLS握手的次数,其机制是在ServerHello时返回session_id,客户端在下次建立连接时发送的ClientHello包里可以包含此session_id来恢复之前的会话。

  Client                                                Server

  ClientHello                   -------->
                                                   ServerHello
                                            [ChangeCipherSpec]
                                <--------             Finished
  [ChangeCipherSpec]
  Finished                      -------->
  Application Data              <------->     Application Data

服务端存储session_id并存储与之对应的状态,如加密套件,master key等信息。如果服务端拿客户端传过来的session_id能拿到对应的信息,就表示此session_id有效,并尝试恢复会话。

由于session_id是存储在服务端,所以需要解决多台机器共享session_id的问题,一般来说在分布式系统中增加session_id的共享会带来一些麻烦。

SessionTicket机制

session_ticket用来减少客户端和服务端协商密钥等信息的交互次数(由原来的两次交互减少为一次交互)。与此相关的插件SessionTicket以及NewSessionTicket消息来共同完成此工作。

首先ClientHello会发送空的session_ticket插件来表示支持session_ticket。服务端如果希望使用此机制,会在ServerHello中返回空的session_ticket扩展。

接着在协商完成之后在Change Cipher Spec包之前发送New Session Ticket包:

TLSv1.2 Record Layer: Handshake Protocol: New Session Ticket
    Content Type: Handshake (22)
    Version: TLS 1.2 (0x0303)
    Length: 170
    Handshake Protocol: New Session Ticket
        Handshake Type: New Session Ticket (4)
        Length: 166
        TLS Session Ticket
            Session Ticket Lifetime Hint: 0 seconds
            Session Ticket Length: 160
            Session Ticket: 0014a28214a3b4ad53eb7a7a48abf3df92ac921763557b0e…

其中包含的session_ticket是将本次协商的结果状态(如加密套件,master secret等),使用只有服务端知道的密钥加密(nginx中的ssl_session_ticket_key配置)。

对于这个session_ticket,客户端会与主密钥、加密套件等状态信息保存在一起。

以下是第一次握手以及服务端发送SessionTicket的过程:

Client Server

     ClientHello
    (empty SessionTicket extension)-------->
                                                     ServerHello
                                 (empty SessionTicket extension)
                                                    Certificate*
                                              ServerKeyExchange*
                                             CertificateRequest*
                                  <--------      ServerHelloDone
     Certificate*
     ClientKeyExchange
     CertificateVerify*
     [ChangeCipherSpec]
     Finished                     -------->
                                                NewSessionTicket
                                              [ChangeCipherSpec]
                                  <--------             Finished
     Application Data             <------->     Application Data

下次发起请求时,会在ClientHello的session_ticket插件上带上此ticket,服务端尝试从中解析出对应主密钥,如果此ticket验证通过,则服务端就重用session状态,直接握手完成,开始发送Change cipher spec,当然服务端也可以再发一个新的NewSessionTicket。

     Client                                                Server
     ClientHello
     (SessionTicket extension)      -------->
                                                      ServerHello
                                  (empty SessionTicket extension)
                                                 NewSessionTicket(option)
                                               [ChangeCipherSpec]
                                   <--------             Finished
     [ChangeCipherSpec]
     Finished                      -------->
     Application Data              <------->     Application Data

Ticket是明文传输的,其安全性是通过服务端的加密密钥来保证。如果这个ticket被第三方截获,由于其它无法解密,就无法得知主密钥,所以也就无法恢复会话了。

密钥的生成

在TLS1.2中,密钥分成预备主密钥(premaster secret)和主密钥。

在协商过程中通过两个Key Exchange信息以及DH密钥交换机制协商出预备主密钥,然后根据Client.Random和Server.Random,通过PRF函数,计算出主密钥(会话密钥)。

在使用了增强型主密钥扩展后,需要将Client.Random和Server.Random换成握手过程中内容的值。

在session_id和session_ticket中,各方保存的都是预备主密钥,而每一次会话中所使用的Random是不同的,所以可以保证每一次所使用的主密钥是不同的。

另外由于Finish数据校验的存在,客户端也不能实现重放攻击,因为在不知道主密钥的情况下,无法伪造出Finish的校验数据。

TLS1.3

TLS1.3针对1.2版本进行了相当大的改动,主要是以下这些:(摘自RFC8446TLS 1.3 Introduction)

  1. 移除已经过时的对称加密算法,剩余的都是带有关联数据的认证加密(AEAD)型算法。加密套件的概念也从原来包含着记录保护算法和用于生成密钥以及HMAC的hash分拆成了认证和密钥交换机制。

  2. 增加0次往返模式(0-RTT),节省连接建立的开销,但需要付出一定的安全代价(非前向安全以及重放攻击)。

  3. 移除静态RSA和DH加密套件,所有基于公钥的密钥交换机制都提供前向安全保证。

  4. ServerHello以后的握手信息全部加密。新引入的EncryptedExtensions消息允许之前在ServerHello中传递的各种扩展同样保密性。

  5. 密钥导出函数被重新设计。新的设计使得密码学家能够通过改进的密钥分离特性进行更容易的分析。基于HMAC的提取 — 扩展密钥导出函数(HMAC-based Extract-and-Expand Key Derivation Function,HKDF)被用作一个基础的原始组件(primitive)。

  6. 握手状态机已经进行了重大调整,以便更具一致性,删除多余的消息如ChangeCipherSpec(除了由于中间件兼容性被需要时)。

  7. 椭圆曲线算法已经属于基本的规范,且包含了新的签名算法,如 EdDSA。TLS1.3删除了点格式协商以利于每个曲线使用单点格式。

  8. 其它的密码学改进包括改变 RSA 填充以使用 RSA 概率签名方案(RSASSA-PSS),删除压缩,DSA,和定制 DHE 组。

  9. TLS1.2 的版本协商机制被废弃。支持在扩展中使用版本列表。这增加了与不正确地实现版本协商的 Server 的兼容性。

  10. 带有和不带 Server 端状态的会话恢复以及 TLS 早期版本的基于 PSK 密码套件已经被一个单独的新 PSK 交换所取代。

  11. 酌情更新引用以指向最新版本的 RFC(例如,RFC 5280 而不是 RFC 3280)。

以下是TLS1.3的典型握手过程:

        Client                                           Server

    Key  ^ ClientHello
    Exch | + key_share*
         | + signature_algorithms*
         | + psk_key_exchange_modes*
         v + pre_shared_key*     -------->
                                                      ServerHello  ^ Key
                                                     + key_share*  | Exch
                                                + pre_shared_key*  v
                                            {EncryptedExtensions}  ^  Server
                                            {CertificateRequest*}  v  Params
                                                   {Certificate*}  ^
                                             {CertificateVerify*}  | Auth
                                                       {Finished}  v
                                <--------  [Application Data*]
         ^ {Certificate*}
    Auth | {CertificateVerify*}
         v {Finished}           -------->
        [Application Data]      <------->  [Application Data]

TLS/SSL 协议详解 (30) SSL中的RSA、DHE、ECDHE、ECDH流程与区别

Diffie–Hellman key exchange DH密钥协商

TLS 中的密钥交换

HTTPS 精读之 TLS 证书校验

HTTPS系列1——HTTPS三次握手

RSA Modulus prefaced by 0x00

Java使用模数、公钥指数、私钥指数进行RSA加解密

CA证书相关的一些基础知识

科普一下关于SSL证书颁发机构的相关知识

CA机构介绍(Certificate Authority 域名SSL证书颁发机构)

Let’s Encrypt,免费好用的 HTTPS 证书

SSL/TLS协议安全之:不安全的重协商

白话SSL/TLS默认重协商漏洞原理与安全重协商对抗机制

RFC 5746:Transport Layer Security (TLS) Renegotiation Indication Extension

HTTPS 温故知新(六) —— TLS 中的 Extensions

HTTPS 温故知新(三) —— 直观感受 TLS 握手流程(上)

TLS扩展的那些事

SSL协议安全系列:PKI体系中的证书吊销

Decrypt HTTPS (SSL/TLS) with Wireshark


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK