TLS1.3规范(RFC文档)

来源:互联网 发布:linux如何打开命令行 编辑:程序博客网 时间:2024/04/30 05:03

The Transport Layer Security (TLS) Protocol Version 1.3

draft-ietf-tls-tls13-latest)

2. Protocol Overview


TLS支持三种基本的密钥交换模式:

  • (EC)DHE (Diffie-Hellman both the finite field and elliptic curve varieties),
  • PSK-only, and
  • PSK with (EC)DHE

图1:完整TLS握手的消息流
       Client                                                               ServerKey  ^ ClientHelloExch | + key_share*     | + 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]              +  Indicates noteworthy extensions sent in the previously noted message.              *  Indicates optional or situation-dependent messages/extensions that are not always sent.              {} Indicates messages protected using keys derived from a [sender]_handshake_traffic_secret.              [] Indicates messages protected using keys derived from traffic_secret_N
握手可以被认为具有三个阶段(如上图所示):
  • 密钥交换:建立共享密钥材料并选择加密参数。 此阶段后的所有内容都已加密。
  • 服务器参数:建立其他握手参数(客户端是否认证,应用层协议支持等)。
  • 验证:验证服务器(并且可选地客户端),并提供密钥确认和握手完整性。

如果客户端没有提供足够的“key_share”扩展(例如,它仅包括服务器不接受或不支持的DHE或ECDHE组),则服务器使用HelloRetryRequest来纠正不匹配,客户端需要重新启动握手, “key_share”扩展。

图2:具有不匹配参数的完整握手的消息流

         Client                                               Server         ClientHello         + key_share             -------->                                 <--------         HelloRetryRequest                                                         + key_share         ClientHello         + key_share             -------->                                                         ServerHello                                                         + key_share                                               {EncryptedExtensions}                                               {CertificateRequest*}                                                      {Certificate*}                                                {CertificateVerify*}                                                          {Finished}                                 <--------       [Application Data*]         {Certificate*}         {CertificateVerify*}         {Finished}              -------->         [Application Data]      <------->        [Application Data]

图3:恢复和PSK的消息流:显示出一对握手,其中第一个建立PSK,第二个使用它

       Client                                               ServerInitial Handshake:       ClientHello       + key_share               -------->                                                       ServerHello                                                       + key_share                                             {EncryptedExtensions}                                             {CertificateRequest*}                                                    {Certificate*}                                              {CertificateVerify*}                                                        {Finished}                                 <--------     [Application Data*]       {Certificate*}       {CertificateVerify*}       {Finished}                -------->                                 <--------      [NewSessionTicket]       [Application Data]        <------->      [Application Data]Subsequent Handshake:       ClientHello       + key_share*       + psk_key_exchange_modes       + pre_shared_key          -------->                                                       ServerHello                                                  + pre_shared_key                                                      + key_share*                                             {EncryptedExtensions}                                                        {Finished}                                 <--------     [Application Data*]       {Finished}                -------->       [Application Data]        <------->      [Application Data]
当客户端通过PSK提供恢复时,它还应该向服务器提供“key_share”扩展,以允许服务器拒绝恢复,并在需要时回退到完全握手。 

当服务器通过PSK进行认证时,它不发送证书或CertificateVerify消息。服务器用“pre_shared_key”扩展来响应以协商PSK密钥建立的使用,并且可以(如这里所示)协商PSK密钥建立的使用,并且可以用“key_share”扩展来做出(EC)DHE 密钥建立,从而提供前向保密。



Zero-RTT Data

当客户端和服务器共享PSK(从外部获得或通过先前的握手获得)时,TLS 1.3允许客户端在第一次飞行(“早期数据”)上发送数据。 客户端使用PSK来认证服务器并加密早期数据。
当客户使用从外部获得的PSK时,必须向双方提供以下附加信息:

  • 用于此PSK的密码套件
  • 应用层协议协商(Application-Layer Protocol Negotiation, ALPN)协议,如果有的话将被使用
  • 服务器名称指示(Server Name Indication, SNI),如果有的话将被使用
如图4所示,Zero-RTT数据只是添加到第一次飞行中的1-RTT握手。 握手的其余部分使用与使用PSK恢复的1-RTT握手相同的消息。


图4:0-RTT握手的消息流

 Client                                               Server         ClientHello         + early_data         + key_share*         + psk_key_exchange_modes         + pre_shared_key         (Application Data*)     -------->                                                         ServerHello                                                    + pre_shared_key                                                        + key_share*                                               {EncryptedExtensions}                                                          {Finished}                                 <--------       [Application Data*]         (EndOfEarlyData)         {Finished}              -------->         [Application Data]      <------->        [Application Data]               *  Indicates optional or situation-dependent messages/extensions that are not always sent.               () Indicates messages protected using keys derived from client_early_traffic_secret.               {} Indicates messages protected using keys derived from a [sender]_handshake_traffic_secret.               [] Indicates messages protected using keys derived from traffic_secret_N
重要说明】:

0-RTT数据的安全属性比其他类型的TLS数据的安全属性弱。特别:
1、该数据不是前向保密,因为其仅在使用所提供的PSK导出的密钥下加密。
2、没有连接之间不重放的保证。除非服务器在TLS提供的服务器之外采取特殊措施,否则服务器不能保证相同的0-RTT数据不会在多个0-RTT连接上传输(有关详细信息,请参见第4.2.8.3节)。然而,0-RTT数据不能在连接中重复(即,服务器将不会为相同的连接处理相同的数据两次),并且攻击者将不能使0-RTT数据看起来是1-RTT数据因为它用不同的密钥保护。)

重放攻击(Replay Attacks)是指攻击者发送一个接收方已经正常接收过的包。由于重放的数据包是过去的一个有效数据包,如果没有防重放的处理,接收方是没办法辨别出来的。

3、协议不得使用0-RTT数据,没有定义其使用的配置文件。该配置文件需要确定哪些消息或交互可安全地与0-RTT一起使用。此外,为了避免意外误用,除非特别要求,否则实现不应该启用0-RTT。实现应该为0-RTT数据提供特殊功能,以确保应用程序总是知道它正在发送或接收可能被重放的数据。


4. Handshake Protocol

   enum {       client_hello(1),       server_hello(2),       new_session_ticket(4),       end_of_early_data(5),       hello_retry_request(6),       encrypted_extensions(8),       certificate(11),       certificate_request(13),       certificate_verify(15),       finished(20),       key_update(24),       (255)   } HandshakeType;   struct {       HandshakeType msg_type;    /* handshake type */       uint24 length;             /* bytes in message */       select (Handshake.msg_type) {           case client_hello:          ClientHello;           case server_hello:          ServerHello;           case end_of_early_data:     EndOfEarlyData;           case hello_retry_request:   HelloRetryRequest;           case encrypted_extensions:  EncryptedExtensions;           case certificate_request:   CertificateRequest;           case certificate:           Certificate;           case certificate_verify:    CertificateVerify;           case finished:              Finished;           case new_session_ticket:    NewSessionTicket;           case key_update:            KeyUpdate;       } body;   } Handshake;
协议消息必须按照下面定义的顺序发送(如第2节中的图所示)。 以意外顺序接收握手消息的对等体必须使用“unexpected_message”警报中止握手。

4.1. Key Exchange Messages

4.1.1. Cryptographic Negotiation

TLS加密协商由客户端在其ClientHello中提供以下四组选项进行:
  • 指示客户端支持的AEAD算法/ HKDF哈希对的密码套件列表。
  • 指示客户端支持的(EC)DHE组的“supported_groups”(第4.2.4节)扩展和包含这些组中的一些或全部的(EC)DHE共享的“key_share”扩展(第4.2.5节)。
  • 扩展,指示客户端可以接受的签名算法的“signature_algorithms”(第4.2.3节)扩展。
  • 包含客户端已知的对称密钥身份列表的“pre_shared_key”(第4.2.8节)扩展和指示可与PSK一起使用的密钥交换模式的“psk_key_exchange_modes”扩展(第4.2.6节)。
如果服务器不选择PSK,则这些选项中的前三个是完全正交的:服务器独立地选择密码套件,用于密钥建立的(EC)DHE组和密钥共享,以及签名算法/证书对,以认证本身给客户端。如果在“supported_groups”中没有重叠,则服务器必须中止握手。
如果服务器选择一个PSK,它还必须从客户端的“psk_key_exchange_modes”扩展(PSK单独或与(EC)DHE)指示的集合中选择密钥建立模式。注意,如果PSK可以在没有(EC)DHE的情况下使用,则在“supported_groups”参数中的非重叠不需要是致命的,因为它在前面段落中讨论的非PSK情况下。


如果服务器成功选择参数并且不需要HelloRetryRequest,则它会在ServerHello中指示所选参数,如下所示:

  • 如果正在使用PSK,那么服务器将发送一个“pre_shared_key”扩展,指明所选择的密钥。
  • 如果不使用PSK,则总是使用(EC)DHE和基于证书的认证。
  • 当(EC)DHE正在使用时,服务器还将提供“key_share”扩展。
  • 当通过证书进行认证时(即,当PSK未使用时),服务器将发送证书(第4.4.1节)和CertificateVerify(第4.4.2节)消息。
如果服务器不能协商一组支持的参数(即,客户端和服务器参数之间没有重叠),它必须用“handshake_failure”或“insufficient_security”致命警报中止握手(见第6节)。


4.1.2. Client Hello

当客户端首次连接到服务器时,需要发送ClientHello作为其第一条消息。当服务器使用HelloRetryRequest响应其ClientHello时,客户端还将发送ClientHello。在这种情况下,客户端必须发送相同的ClientHello(不修改),除了:
  • 如果在HelloRetryRequest中提供了“key_share”扩展,用包含来自指定组的单个KeyShareEntry的列表替换共享列表。
  • 删除“early_data”扩展(第4.2.7节)(如果存在)。 HelloRetryRequest后不允许使用早期数据。
  • 包括“Cookie”扩展(如果在HelloRetryRequest中提供了)。
  • 如果存在“pre_shared_key”扩展,则更新PSK绑定器值。
因为TLS 1.3禁止重新协商,如果服务器在任何其他时间接收到ClientHello,它必须终止连接。
如果服务器与先前版本的TLS建立TLS连接并在重新协商中接收到TLS 1.3 ClientHello,则它必须保留先前的协议版本。特别是,它不得协商TLS 1.3。
此消息的结构:

   uint16 ProtocolVersion;   opaque Random[32];   uint8 CipherSuite[2];    /* Cryptographic suite selector */   struct {       ProtocolVersion legacy_version = 0x0303;    /* TLS v1.2 */       Random random;       opaque legacy_session_id<0..32>;       CipherSuite cipher_suites<2..2^16-2>;       opaque legacy_compression_methods<1..2^8-1>;       Extension extensions<8..2^16-1>;   } ClientHello;
所有版本的TLS都允许扩展可选地跟随compression_methods字段作为扩展字段。 TLS 1.3 ClientHellos将至少包含两个扩展名“supported_versions”以及“key_share”或“pre_shared_key”。扩展的存在可以通过确定在ClientHello的结尾处是否存在跟在compression_methods之后的字节来检测。 注意,检测可选数据的这种方法与具有可变长度字段的常规TLS方法不同,但是在定义扩展之前用于与TLS的兼容性。 TLS 1.3服务器将需要首先执行此检查,并且仅当存在“supported_version”扩展时才尝试协商TLS 1.3。

legacy_version
在TLS的先前版本中,此字段用于版本协商,表示客户端支持的最高版本号。在TLS 1.3中,客户端在“supported_versions”扩展中指示其版本首选项(第4.2.1节),并且legacy_version字段必须设置为0x0303,这是TLS 1.2的版本号。 
【random】
32字节由安全随机数生成器生成。
legacy_session_id
TLS在TLS 1.3之前的版本支持会话恢复功能,已在此版本中与预共享密钥合并(见第2.2节)。该字段必须被协商TLS 1.3的服务器忽略,并且必须由不具有由pre-TLS 1.3服务器设置的高速缓存的会话ID的客户端设置为零长度向量(即,单个零字节长度字段)。
【cipher_suites】
这是客户端支持的对称密码选项的列表,特别是记录保护算法(包括秘密密钥长度)和要与HKDF一起使用的哈希,以客户端偏好的降序排列。如果列表包含密码套件,服务器不能识别,支持或希望使用,则服务器必须忽略这些密码套件,并照常处理剩余的套件。值在附录B.4中定义。如果客户端正在尝试PSK密钥建立,则它应当通告至少一个包含与PSK相关联的哈希的加密套件。
legacy_compression_methods
TLS 1.3之前的版本支持压缩,并在此字段中发送支持的压缩方法列表。对于每个TLS 1.3 ClientHello,该向量必须精确地包含一个设置为零的一个字节,其对应于TLS的先前版本中的“null”压缩方法。如果接收到TLS 1.3 ClientHello与此字段中的任何其他值,则服务器必须使用“illegal_parameter”警报中止握手。请注意,TLS 1.3服务器可能接收TLS 1.2或之前的ClientHellos,其中包含其他压缩方法,并且必须遵循TLS的相应先前版本的过程。
【extensions】
客户端通过在扩展字段中发送数据,从服务器请求扩展功能。实际的“扩展”格式在第4.2节中定义。在TLS 1.3中,使用某些扩展是强制性的,因为功能被移动到扩展中以保持ClientHello与先前版本的TLS的兼容性。


如果客户端请求使用扩展的附加功能,并且该功能不是由服务器提供的,则客户端可以中止握手。 请注意,TLS 1.3 ClientHello消息始终包含扩展最低限度必须包含“supported_versions”或它们将被解释为TLS 1.2 ClientHello消息)。 TLS 1.3服务器可能从不包含扩展名的1.3之前的TLS版本接收ClientHello消息。 如果在1.3之前协商TLS的版本,服务器必须检查消息在legacy_compression_methods之后是否包含数据,或者它包含没有数据跟随的有效扩展块。 如果不是,那么它必须用“decode_error”警报来中止握手。

发送ClientHello消息后,客户端等待ServerHello或HelloRetryRequest消息。


4.1.3. Server Hello

能够找到可接受的一组算法并且客户端的“key_share”扩展是可接受的时,服务器将发送此消息以响应ClientHello消息。 如果它不能找到一个可接受的参数集,服务器将响应一个“handshake_failure”致命警报。
此消息的结构:

   struct {       ProtocolVersion version;       Random random;       CipherSuite cipher_suite;       Extension extensions<6..2^16-1>;   } ServerHello;
【version】
此字段包含为此会话协商的TLS的版本。 服务器必须从ClientHello.supported_versions扩展中的列表中选择一个版本。 接收未提供的版本的客户端必须中止握手。 对于此版本的规范,版本为0x0304。 (有关向后兼容性的详细信息,请参阅附录D.)
random
此结构由服务器生成,并且必须独立于ClientHello.random生成。
cipher_suite
服务器从ClientHello.cipher_suites中的列表中选择的单个密码套件。 接收未提供的密码套件的客户端必须中止握手。
extensions
扩展列表。 ServerHello必须只包括建立加密上下文所需的扩展。 目前唯一这样的扩展是“key_share”和“pre_shared_key”。 所有当前的TLS 1.3 ServerHello消息将包含这两个扩展之一


TLS 1.3具有嵌入在服务器的随机值中的降级保护机制。 TLS 1.3服务器协商TLS 1.2或以下响应ClientHello必须专门设置其随机值的最后8个字节。
如果协商TLS 1.2,服务器必须设置其随机值的最后8个字节为字节

  44 4F 57 4E 47 52 44 01
如果协商TLS 1.1,TLS 1.3服务器MUST和TLS 1.2服务器应该将其随机值的最后8个字节设置为字节:

  44 4F 57 4E 47 52 44 00
TLS 1.3客户端接收TLS 1.2或更低版本的ServerHello必须检查最后八个字节不等于这些值之一。 TLS 1.2客户端还应该检查,如果ServerHello指示TLS 1.1或更低版本,最后8个字节不等于第二个值。如果找到匹配,客户端必须用“illegal_parameter”警报中止握手。这种机制提供有限的保护以防止降级攻击超过和完成交换提供:由于ServerKeyExchange,在TLS1.2及以下存在的消息包括两个随机值的签名,活动攻击者不可能修改只要使用短暂密码,就不进行检测。当使用静态RSA时,它不提供降级保护。

在重新协商期间接收TLS 1.3 ServerHello的客户端必须使用“protocol_version”警报中止握手


4.1.4. Hello Retry Request

如果服务器能够找到相互支持的可接受的一组算法和组,但是客户端的ClientHello没有包含足够的信息来继续握手,则服务器发送此消息以响应ClientHello消息。如果服务器无法成功选择算法和组,则必须使用“handshake_failure”警报中止握手。
此消息的结构:

   struct {       ProtocolVersion server_version;       Extension extensions<2..2^16-1>;   } HelloRetryRequest;
server_version和extensions与ServerHello中的相应值具有相同的含义。服务器应该只发送客户端生成正确的ClientHello对所需的扩展。与ServerHello一样,HelloRetryRequest不得包含客户端在其ClientHello中首次提供的任何扩展但可选的“cookie”扩展(见第4.2.2节)除外
在接收到HelloRetryRequest时,客户端必须验证扩展块不为空,否则必须使用“decode_error”警报中止握手。如果HelloRetryRequest不会导致ClientHello的任何更改,客户端必须使用“illegal_parameter”警报中止握手。如果客户端在同一连接中接收到第二个HelloRetryRequest(即,ClientHello本身响应于HelloRetryRequest),则它必须用“unexpected_message”警报中止握手
否则,客户端必须处理HelloRetryRequest中的所有扩展,并发送第二个更新的ClientHello。本规范中定义的HelloRetryRequest扩展包括:
  • cookie(见第4.2.2节)
  • key_share(见第4.2.5节)

4.2. Extensions

许多TLS消息包含 tag-length-value编码的扩展结构。
   struct {       ExtensionType extension_type;       opaque extension_data<0..2^16-1>;   } Extension;   enum {       supported_groups(10),       signature_algorithms(13),       key_share(40),       pre_shared_key(41),       early_data(42),       supported_versions(43),       cookie(44),       psk_key_exchange_modes(45),       certificate_authorities(47),       oid_filters(48),       (65535)   } ExtensionType;
这里:
  • “extension_type”标识特定的扩展类型。
  • “extension_data”包含特定于该特定扩展类型的信息。
扩展通常以请求/响应方式构造,尽管一些扩展仅仅是没有相应响应的指示。客户端在ClientHello消息中发送其扩展请求,服务器在ServerHello,EncryptedExtensions和HelloRetryRequest消息中发送其扩展响应。服务器在CertificateRequest消息中发送扩展请求,可以使用客户端的证书消息进行响应。服务器也可以在NewSessionTicket中发送未经请求的扩展,尽管客户端不直接响应这些。
如果远程端点没有发送相应的扩展请求,除了HelloRetryRequest中的“cookie”扩展之外,实现不得发送扩展响应。在接收到这样的扩展时,端点必须用“unsupported_extension”警报中止握手
下表表示使用以下符号:CH(ClientHello),SH(ServerHello),EE(EncryptedExtensions),CT(Certificate),CR(CertificateRequest),NST(NewSessionTicket)和HRR HelloRetryRequest)。如果实现接收到它识别的扩展,并且没有为它出现的消息指定它,它必须用“illegal_parameter”警报来中止握手

ExtensionTLS 1.3server_name [RFC6066]CH, EEmax_fragment_length [RFC6066]CH, EEclient_certificate_url [RFC6066]CH, EEstatus_request [RFC6066]CH, CTuser_mapping [RFC4681]CH, EEcert_type [RFC6091]CH, EEsupported_groups [RFC7919]CH, EEsignature_algorithms [RFC5246]CH, CRuse_srtp [RFC5764]CH, EEheartbeat [RFC6520]CH, EEapplication_layer_protocol_negotiation [RFC7301]CH, EEsigned_certificate_timestamp [RFC6962]CH, CR, CTclient_certificate_type [RFC7250]CH, EEserver_certificate_type [RFC7250]CH, CTpadding [RFC7685]CHkey_share [[this document]]CH, SH, HRRpre_shared_key [[this document]]CH, SHpsk_key_exchange_modes [[this document]]CHearly_data [[this document]]CH, EE, NSTcookie [[this document]]CH, HRRsupported_versions [[this document]]CHcertificate_authorities [[this document]]CH, CRoid_filters [[this document]]CR

当存在不同类型的多个扩展时,扩展可以以任何顺序出现除了“pre_shared_key”第4.2.8节,它必须是ClientHello中的最后一个扩展不能有多个同一类型的扩展。
在TLS 1.3中,与TLS 1.2不同,即使在恢复PSK模式下,每次握手都重新协商扩展。然而,0-RTT参数是在先前握手中协商的参数;不匹配可能需要拒绝0-RTT(见第4.2.7节)。


4.2.1. Supported Versions

   struct {       ProtocolVersion versions<2..254>;   } SupportedVersions;
客户端使用“supported_versions”扩展来指示它支持哪些版本的TLS。该扩展包含优先顺序中支持的版本列表,首先是最优先的版本。这个规范的实现必须发送这个扩展包含他们准备谈判的TLS的所有版本(对于这个规范,这意味着最低0x0304,但是如果支持TLS的以前的版本,它们必须存在)。
  • 如果不存在此扩展,那么符合本规范的服务器必须按照[RFC5246]中的规定协商TLS 1.2或先前版本,即使ClientHello.legacy_version为0x0304或更高版本。
  • 如果存在此扩展,服务器必须忽略ClientHello.legacy_version值,并且必须仅使用“supported_versions”扩展来确定客户端首选项。服务器必须只选择该扩展中存在的TLS版本,并且必须忽略任何未知版本。注意,如果一方支持稀疏范围,这种机制使得可以在TLS 1.2之前协商版本。选择支持TLS的以前版本的TLS 1.3的实现应支持TLS 1.2。
服务器不得发送“supported_versions”扩展名服务器的所选版本包含在ServerHello.version字段中,与TLS的先前版本中一样。

4.2.2. Cookie

   struct {       opaque cookie<1..2^16-1>;   } Cookie;
Cookie有两个主要目的:
  • 允许服务器强制客户端在其明显的网络地址展示可达性(从而提供DoS保护的度量)。 这主要用于非面向连接的传输(参见[RFC6347])。
  • 允许服务器向客户端卸载状态,从而允许它发送HelloRetryRequest而不存储任何状态。 服务器通过将序列化的哈希状态存储在cookie中(用一些合适的完整性算法保护)来做到这一点。
当发送HelloRetryRequest时,服务器可以向客户端提供“cookie”扩展(这是通常的规则的一个例外,只有可能被发送的扩展是出现在ClientHello中的扩展)。当发送新的ClientHello时,客户端必须回显扩展的值客户不得在后续连接中使用Cookie。

4.2.3. Signature Algorithms

客户端使用“signature_algorithms”扩展来向服务器指示哪些签名算法可以在数字签名中使用。 希望服务器通过证书认证自身的客户端必须发送此扩展。 如果服务器通过证书进行身份验证,并且客户端没有发送“signature_algorithms”扩展,那么服务器必须使用“missing_extension”警报中止握手(见第8.2节)。
ClientHello中此扩展的“extension_data”字段包含SignatureSchemeList值:
   enum {       /* RSASSA-PKCS1-v1_5 algorithms */       rsa_pkcs1_sha1(0x0201),       rsa_pkcs1_sha256(0x0401),       rsa_pkcs1_sha384(0x0501),       rsa_pkcs1_sha512(0x0601),       /* ECDSA algorithms */       ecdsa_secp256r1_sha256(0x0403),       ecdsa_secp384r1_sha384(0x0503),       ecdsa_secp521r1_sha512(0x0603),       /* RSASSA-PSS algorithms */       rsa_pss_sha256(0x0804),       rsa_pss_sha384(0x0805),       rsa_pss_sha512(0x0806),       /* EdDSA algorithms */       ed25519(0x0807),       ed448(0x0808),       /* Reserved Code Points */       private_use(0xFE00..0xFFFF),       (0xFFFF)   } SignatureScheme;   struct {       SignatureScheme supported_signature_algorithms<2..2^16-2>;   } SignatureSchemeList;
注意:此枚举名为“SignatureScheme”,因为TLS 1.2中已经有一个“SignatureAlgorithm”类型,它将替换它。 我们在整个文本中使用术语“签名算法”。
每个SignatureScheme值列出客户端愿意验证的单一签名算法。 这些值以优先级的降序表示。 注意,签名算法输入任意长度的消息,而不是摘要。 传统上作用于摘要的算法应在TLS中定义,以首先使用指定的哈希算法对输入进行哈希,然后照常进行。 上面列出的代码点组具有以下含义:
RSASSA-PKCS1-v1_5算法
表示使用RSASSA-PKCS1-v1_5 [RFC3447]与[SHS]中定义的相应散列算法的签名算法。这些值仅涉及出现在证书中的签名(参见第4.4.1.2节),并且未定义用于签署的TLS握手消息。
ECDSA算法
表示使用ECDSA [ECDSA]的签名算法,在ANSI X9.62 [X962]和FIPS 186-4 [DSS]中定义的相应曲线以及如[SHS]中定义的相应散列算法。签名被表示为DER编码的[X690] ECDSA-Sig-Value结构。
RSASSA-PSS算法
表示使用具有掩码生成功能1的RSASSA-PSS [RFC3447]的签名算法。在掩码生成函数中使用的摘要和被签名的摘要都是如在[SHS]中定义的相应的哈希算法。当在签署的TLS握手消息中使用时,盐的长度必须等于摘要输出的长度。此代码点也定义为与TLS 1.2一起使用。
EdDSA算法
表示使用[I-D.irtf-cfrg-eddsa]或其后继中定义的EdDSA的签名算法。注意,这些对应于“PureEdDSA”算法,而不是“prehash”变体。

rsa_pkcs1_sha1,dsa_sha1和ecdsa_sha1不应该提供。 提供这些值以实现向后兼容性的客户端必须将它们列为最低优先级(在SignatureSchemeList中的所有其他算法之后列出)。TLS 1.3服务器不得提供SHA-1签名的证书,除非没有有效的证书链(见第4.4.1.2节)。
自签名证书或作为信任锚的证书上的签名不会生效,因为它们开始了认证路径(参见[RFC5280],第3.2节)。 开始认证路径的证书可以使用未在“signature_algorithms”扩展中通告为支持的签名算法。
注意,TLS 1.2定义了不同的扩展。 TLS 1.3实现愿意协商TLS 1.2在协商该版本时,必须按照[RFC5246]的要求进行操作。 尤其是:
  • TLS 1.2 ClientHellos可以忽略此扩展。
  • 在TLS 1.2中,扩展包含散列/签名对。 这些对被编码为两个八位字节,因此已分配SignatureScheme值以与TLS 1.2的编码对齐。 一些传统对保留未分配。 这些算法自TLS 1.3起已弃用。 它们不得由任何实施提供或协商。 特别是,不得使用MD5 [SLOTH]和SHA-224。
  • ECDSA签名方案与TLS 1.2的ECDSA哈希/签名对相一致。 然而,旧的语义没有约束签名曲线。 如果协商TLS 1.2,则实现必须准备接受使用它们在“supported_groups”扩展中通告的任何曲线的签名。
  • 支持RSASSA-PSS(在TLS 1.3中是强制性的)的实现必须准备接受使用该方案的签名,即使协商TLS 1.2。 在TLS 1.2中,RSASSA-PSS与RSA密码套件一起使用。

4.2.3.1. Certificate Authorities

“certificate_authorities”扩展用于指示端点支持的证书授权,并且接收端点应该使用它来指导证书选择
“certificate_authorities”扩展的主体由CertificateAuthoritiesExtension结构组成。
   opaque DistinguishedName<1..2^16-1>;   struct {       DistinguishedName authorities<3..2^16-1>;   } CertificateAuthoritiesExtension;
【authorities】
可接受证书颁发机构的可分辨名称[X501]的列表,以DER编码[X690]格式表示。 这些可分辨名称为信任锚或从属CA指定所需的可分辨名称; 因此,该消息可以用于描述已知的信任锚以及期望的授权空间。
客户端可以在ClientHello消息中发送“certificate_authorities”扩展服务器可以在CertificateRequest消息中发送它

4.2.4. Negotiated Groups

当由客户端发送时,“supported_groups”扩展指示客户端支持的用于密钥交换的命名组,从最优选到最不优选。
注意:在TLS 1.3之前的TLS版本中,此扩展名称为“elliptic_curves”,并且只包含椭圆曲线组。 参见[RFC4492]和[RFC7919]。 此扩展也用于协商ECDSA曲线。签名算法现在独立协商(见第4.2.3节)。
此扩展的“extension_data”字段包含“NamedGroupList”值:
   enum {       /* Elliptic Curve Groups (ECDHE) */       secp256r1(0x0017), secp384r1(0x0018), secp521r1(0x0019),       x25519(0x001D), x448(0x001E),       /* Finite Field Groups (DHE) */       ffdhe2048(0x0100), ffdhe3072(0x0101), ffdhe4096 (0x0102),       ffdhe6144(0x0103), ffdhe8192(0x0104),       /* Reserved Code Points */       ffdhe_private_use(0x01FC..0x01FF),       ecdhe_private_use(0xFE00..0xFEFF),       (0xFFFF)   } NamedGroup;   struct {       NamedGroup named_group_list<2..2^16-1>;   } NamedGroupList;
  • Elliptic Curve Groups(ECDHE) 表示支持对应的命名曲线,在FIPS 186-4 [DSS]或[RFC7748]中定义。值0xFE00到0xFEFF保留供私人使用。
  • Finite Field Groups(DHE) 表示支持相应的有限域组,在[RFC7919]中定义。值0x01FC至0x01FF保留供私人使用。
named_group_list中的项根据客户端的首选项排序(最好是首先选择)。
从TLS 1.3开始,服务器允许向客户端发送“supported_groups”扩展。如果服务器有一个组,它喜欢“key_share”扩展中的那些,但仍然愿意接受ClientHello,它应该发送“supported_groups”来更新客户端的偏好视图;此扩展应包含服务器支持的所有组,无论它们当前是否由客户端支持。客户端不能在成功完成握手之前对“supported_groups”中找到的任何信息采取行动,但可以使用从成功完成的握手中获得的信息来更改在后续连接中的“key_share”扩展中使用的组。

4.2.5. Key Share

“key_share”扩展包含端点的加密参数
客户端可以发送空的client_shares向量,以便以额外的往返为代价从服务器请求组选择。 (见第4.1.4节)
   struct {       NamedGroup group;       opaque key_exchange<1..2^16-1>;   } KeyShareEntry;
【group】
要交换的密钥的命名组。 有限域Diffie-Hellman [DH]参数在第4.2.5.1节中描述; 椭圆曲线Diffie-Hellman参数在4.2.5.2节中描述。
key_exchange
密钥交换信息。 此字段的内容由指定的组及其相应的定义确定。
此扩展的“extension_data”字段包含一个“KeyShare”值:
   struct {       select (Handshake.msg_type) {           case client_hello:               KeyShareEntry client_shares<0..2^16-1>;           case hello_retry_request:               NamedGroup selected_group;           case server_hello:               KeyShareEntry server_share;       };   } KeyShare;
client_shares
提供的KeyShareEntry值的列表,按客户机首选项的降序排列。 如果客户端请求HelloRetryRequest,则此向量可以为空。每个KeyShareEntry值必须对应于在“supported_groups”扩展中提供的组,并且必须以相同的顺序出现。 然而,值可以是“supported_groups”扩展的非连续子集,并且可以省略最优选的组。
selected_group
服务器打算协商的相互支持的组,并正在请求重试的ClientHello / KeyShare。
server_share
与客户端共享位于同一组中的单个KeyShareEntry值。

客户端提供任意数量的KeyShareEntry值,每个值表示一组密钥交换参数。例如,客户端可能为几个椭圆曲线或多个FFDHE组提供共享。必须独立生成每个KeyShareEntry的key_exchange值。客户不得为同一组提供多个KeyShareEntry值客户端不得为客户端的“supported_groups”扩展中未列出的组提供任何KeyShareEntry值服务器可以检查是否违反了这些规则,并且如果违反了则使用“illegal_parameter”警报来中止握手。

在HelloRetryRequest中接收到此扩展时,客户端必须验证
(1)selected_group字段对应于在原始ClientHello中的“supported_groups”扩展中提供的组;
(2)selected_group字段不对应于在原始ClientHello中的“key_share”扩展中提供的组。
如果这些检查中的任一个失败,则客户端必须用“illegal_parameter”警报来中止握手。否则,当发送新的ClientHello时,客户端必须用在触发HelloRetryRequest的selected_group字段中指示的组替换原来的“key_share”扩展,其中只包含新的KeyShareEntry。

如果使用(EC)DHE密钥建立,服务器在ServerHello中只提供一个KeyShareEntry。该值必须与服务器为协商的密钥交换选择的客户端提供的KeyShareEntry值相对应。
服务器不得为“supported_groups”扩展中指定的任何组发送KeyShareEntry,并且在使用“psk_ke”PskKeyExchangeMode时不得发送KeyShareEntry。
如果客户端收到HelloRetryRequest,客户端必须验证所选的NamedGroup是否匹配客户端在其supported_groups扩展中发送的一个,否则必须中止具有“illegal_parameter”警报的握手。

4.2.5.1. Diffie-Hellman Parameters

用于客户端和服务器的Diffie-Hellman [DH]参数在KeyShare结构中的KeyShareEntry的不透明key_exchange字段中编码。 不透明值包含编码为大端字节整数的指定组(参见[RFC7919]的组定义)的Diffie-Hellman公开值(Y = g ^ X模p),用零填充,字节大小为p 。
注意:对于给定的Diffie-Hellman组,填充导致所有公钥具有相同的长度。
对等体应该通过确保1 <Y <p-1来验证对方的公钥Y. 此检查确保远程对等体正常运行,并且不强制本地系统进入小子组。

4.2.5.2. ECDHE Parameters

用于客户端和服务器的ECDHE参数在KeyShare结构中的KeyShareEntry的不透明key_exchange字段中编码。
对于secp256r1,secp384r1和secp521r1,内容是ANSI X9.62 [X962]第4.3.6节中的转换程序后的椭圆曲线公共值的字节字符串表示。
虽然X9.62支持多点格式,但任何给定的曲线必须只指定单点格式。本文档中当前指定的所有曲线必须仅使用未压缩点格式(所有ECDH函数的格式均被视为未压缩)。对等体必须通过确保点是椭圆曲线上的有效点来验证彼此的公开值Y.
对于曲线secp256r1,secp384r1和secp521r1,适当的验证程序在[X962]的第4.3.7节中以及[KEYAGREEMENT]的第5.6.2.6节中定义。该过程包括三个步骤:(1)验证Y不是无穷大点(O),(2)验证对于Y =(x,y)两个整数处于正确的间隔,(3) x,y)是椭圆曲线方程的正确解。对于这些曲线,实现者不需要验证正确子组中的成员资格。
对于x25519和x448,公共值的内容是[RFC7748]中定义的相应函数的字节串输入和输出,x25519为32字节,x448为56字节。对等体应该使用[RFC7748]中指定的方法来计算Diffie-Hellman共享密钥,并且必须检查计算的Diffie-Hellman共享密钥是否为全零值,如果是,则必须中止,如[RFC7748] 。如果实现者使用这些椭圆曲线的替代实现,它们应该执行[RFC7748]第7节中规定的附加检查。
注意:在1.3允许点格式协商之前TLS的版本; TLS 1.3删除了此功能,有利于每个曲线的单点格式。

4.2.6. Pre-Shared Key Exchange Modes

为了使用PSK,客户端还必须发送一个“psk_key_exchange_modes”扩展。 此扩展的语义是客户端仅支持使用具有这些模式的PSK,这限制了在此ClientHello中提供的PSK的使用以及服务器可通过NewSessionTicket提供的PSK的使用。
如果它提供了一个“pre_shared_key”扩展,客户端必须提供一个“psk_key_exchange_modes”扩展。如果客户端提供不带“psk_key_exchange_modes”扩展名的“pre_shared_key”,服务器必须中止握手。服务器不得选择客户端未列出的密钥交换模式。 此扩展还限制与PSK恢复使用的模式; 服务器不应发送与所公布的模式不兼容的NewSessionTicket; 但是如果服务器这样做,则影响将是客户端在恢复时的尝试失败。
服务器不得发送“psk_key_exchange_modes”扩展名。
   enum { psk_ke(0), psk_dhe_ke(1), (255) } PskKeyExchangeMode;   struct {       PskKeyExchangeMode ke_modes<1..255>;   } PskKeyExchangeModes;
psk_ke
仅PSK密钥建立在这种模式下,服务器不能提供“key_share”值。
【psk_dhe_ke
PSK与(EC)DHE密钥建立在这种模式下,客户端和服务器必须提供“key_share”值,如第4.2.5节所述。

4.2.7. Early Data Indication

当使用PSK时,客户端可以在其第一个消息中发送应用数据如果客户端选择这样做,它必须提供一个“early_data”扩展以及“pre_shared_key”扩展。
此扩展的“extension_data”字段包含“EarlyDataIndication”值。
   struct {       select (Handshake.msg_type) {           case new_session_ticket:              uint32 max_early_data_size;           case client_hello:           case encrypted_extensions:              // empty       };   } EarlyDataIndication;
接收“early_data”扩展的服务器可以以三种方式之一进行操作:
  • 忽略扩展并返回常规的1-RTT响应。服务器然后使用试验解密忽略早期数据,直到它能够接收客户端的第二次飞行并完成普通的1-RTT握手。
  • 请求客户端通过使用HelloRetryRequest响应来发送另一个ClientHello。客户端不得在其后续ClientHello中包含“early_data”扩展。服务器然后通过跳过具有外部内容类型“application_data”的所有记录(指示它们被加密)来忽略早期数据。
  • 在EncryptedExtensions中返回自己的扩展,表明它打算处理早期数据。服务器不可能只接受早期数据消息的一个子集。
为了接受早期数据,服务器必须接受一个PSK密码组,并选择在客户端的“pre_shared_key”扩展中提供的第一个密钥。此外,它必须验证以下值与在建立ticket的连接中协商的值一致。
  • TLS版本号和加密套件。
  • 所选的ALPN [RFC7301]协议(如果有)。
未来扩展必须定义它们与0-RTT的交互。

如果任何这些检查失败,服务器不得响应扩展,并且必须丢弃所有剩余的第一飞行数据(因此回落到1-RTT)。如果客户端尝试0-RTT握手但服务器拒绝它,则服务器将通常不具有0-RTT记录保护密钥,并且必须替代地尝试用1-RTT握手密钥解密每个记录,直到其找到正确解密的记录,然后从那一点拿起握手。
如果服务器选择接受“early_data”扩展,那么在处理早期数据记录时,它必须符合为所有记录指定的相同错误处理要求。具体来说,如果服务器未能在接受的“early_data”扩展之后解密任何0-RTT记录,它必须按照第5.2节终止与“bad_record_mac”警报的连接。
如果服务器拒绝“early_data”扩展,则一旦握手已完成,客户端应用可以选择重传早期数据。 TLS实现不应该自动重新发送早期数据;应用程序处于更好的位置来决定何时重传是适当的。自动重传早期数据可能导致关于连接状态不正确的假设。特别地,TLS实现不能自动重新发送早期数据,除非协商的连接选择相同的ALPN协议。如果选择了不同的协议,应用程序可能需要构造不同的消息。类似地,如果早期数据假定关于连接状态的任何事情,则它可能在握手完成之后错误地发送。

4.2.8. Pre-Shared Key Extension

“pre_shared_key”扩展用于指示与PSK密钥建立相关联的给定握手使用的预共享密钥的身份
此扩展的“extension_data”字段包含“PreSharedKeyExtension”值:
   struct {       opaque identity<1..2^16-1>;       uint32 obfuscated_ticket_age;   } PskIdentity;   opaque PskBinderEntry<32..255>;   struct {       select (Handshake.msg_type) {           case client_hello:               PskIdentity identities<7..2^16-1>;               PskBinderEntry binders<33..2^16-1>;           case server_hello:               uint16 selected_identity;       };   } PreSharedKeyExtension;
【identity】
键的标签。例如,附录B.3.4中定义的ticket,或外部建立的预共享密钥的标签。
obfuscated_ticket_age
对于每个故障单,自客户端了解其正在使用的服务器配置以来的时间(以毫秒为单位)。此值以模2 ^ 32添加到ticket中包括的“ticket_age_add”值,请参见第4.6.1节。此添加可防止被动观察器关联会话,除非ticket被重用。注意:因为ticket生存期限制为一周,32位足以表示任何合理的年龄,即使以毫秒为单位。对于外部建立的标识,应该使用obfuscated_ticket_age为0,服务器必须忽略该值。
【identities】
客户端愿意与服务器协商的身份列表。如果与“early_data”扩展一起发送(参见第4.2.7节),第一个标识是用于0-RTT数据的标识。
【binders】
一系列HMAC值,一个用于在“pre_shared_keys”扩展中提供的并且以相同顺序提供的每个PSK,如下所述计算。
selected_identity
服务器选择的身份表示为基于(从0开始)索引到客户端列表中的身份。

每个PSK与单个哈希算法相关联。对于通过ticket机制建立的PSK(第4.6.1节),这是用于KDF的哈希。对于外部建立的PSK,当PSK建立时,必须设置哈希算法。服务器必须确保它选择兼容的PSK(如果有的话)和密码套件
实现者的注意:实现PSK /密码套件匹配要求的最直接的方法是先协商密码套件,然后排除任何不兼容的PSK
在接受PSK密钥建立之前,服务器务必验证相应的binder值(见下面的4.2.8.1节)。如果此值不存在或未验证,则服务器必须中止握手。服务器不应该尝试验证多个binder;而是他们应该选择单个PSK并且仅验证对应于该PSK的绑定器为了接受PSK密钥建立,服务器发送指示所选择的标识的“pre_shared_key”扩展
客户端必须验证服务器的selected_identity是否在客户端提供的范围内,服务器选择了包含与PSK关联的哈希的加密套件,并且如果ClientHello“psk_key_exchange_modes”需要,还存在服务器“key_share”扩展。如果这些值不一致,客户端必须使用“illegal_parameter”警报中止握手。
如果服务器提供了“early_data”扩展客户端必须验证服务器的selected_identity是否为0.如果返回任何其他值,客户端必须使用“illegal_parameter”警报中止握手。
该扩展必须是ClientHello中的最后一个扩展(这有助于如下所述的实现)。服务器必须检查它是最后一个扩展,否则失败握手与“illegal_parameter”警报。

4.2.8.1. PSK Binder

PSK绑定器值在PSK和当前握手之间以及在建立PSK的会话(如果通过NewSessionTicket消息)和使用它的会话之间形成绑定。绑定者列表中的每个条目被计算为直到并包括PreSharedKeyExtension.identities字段的ClientHello的部分(包括握手报头)上的HMAC。也就是说,它包括所有ClientHello,但不包括绑定者列表本身。消息的长度字段(包括总长度,扩展块的长度和“pre_shared_key”扩展的长度)都被设置为如果存在正确长度的绑定器。
binding_value以与完成消息(第4.4.3节)相同的方式计算,但是BaseKey是通过来自提供的相应PSK的密钥计划派生的binder_key(见第7.1节)。
如果握手包括HelloRetryRequest,则初始ClientHello和HelloRetryRequest与新的ClientHello一起被包括在副本中。例如,如果客户端发送ClientHello1,则其绑定器将通过以下计算:
   ClientHello1[truncated]
如果服务器响应HelloRetryRequest,然后客户端然后发送ClientHello2,其绑定器将通过计算:
   ClientHello1 + HelloRetryRequest + ClientHello2[truncated]
完整的ClientHello包括在所有其他握手哈希计算中。

4.2.8.2. Processing Order

客户端被允许“流”0-RTT数据,直到它们接收服务器的 Finished,然后发送EndOfEarlyData消息为了避免死锁,当接受“early_data”时,服务器必须处理客户端的ClientHello,然后立即发送ServerHello,而不是等待客户端的EndOfEarlyData消息。

4.2.8.3. Replay Properties

如第2.3节所述,TLS为客户端在第一个飞行中发送的数据提供了重放保护的有限机制。
服务器应该使用客户端“pre_shared_key”扩展中的“obfuscated_ticket_age”参数来限制第一个flight可能被重放的时间。服务器可以存储向客户端发送会话ticket的时间,或者对ticket中的时间进行编码。然后,每次它收到一个“pre_shared_key”扩展,它可以减去基本值,并检查客户端使用的值是否匹配其期望。

由客户端提供的ticket期限(减去“ticket_age_add”的值)将比服务器上经过一个往返时间的实际时间短。这个差异包括向客户端发送NewSessionTicket消息的延迟,以及将ClientHello发送到服务器所花费的时间。因此,服务器应该在发送NewSessionTicket消息之前测量往返时间,并在它保存的值中记录它。

要正确验证ticket期限,服务器需要保存至少两个项目:
  • 服务器生成会话ticket的时间和估计的往返时间可以一起添加以形成基线时间
  • 需要NewSessionTicket的“ticket_age_add”参数来从“obfuscated_ticket_age”参数恢复ticket期限

有几个潜在的误差源使得精确的时间测量困难。客户端和服务器时钟速率的变化很可能是最小的,尽管可能具有总时间校正。网络传播延迟很可能是由于经过时间的合法值不匹配引起的。 NewSessionTicket和ClientHello消息都可能被重新传输并因此被延迟,这可能被TCP隐藏。
建议在时钟误差和测量误差方面留有小量余量。However, any allowance also increases the opportunity for replay. 在这种情况下,最好是拒绝早期数据并回退到完全的1-RTT握手,而不是承担更大的重放攻击的风险。


4.3. Server Parameters

来自服务器的接下来两条消息EncryptedExtensionsCertificateRequest包含来自确定其余握手的服务器的信息。 这些消息使用从server_handshake_traffic_secret派生的密钥加密。

4.3.1. Encrypted Extensions

在所有握手中,服务器必须在ServerHello消息之后立即发送EncryptedExtensions消息这是在从server_handshake_traffic_secret派生的密钥下加密的第一条消息。
EncryptedExtensions消息包含应该被保护的扩展,即,不需要建立加密上下文但不与各个证书相关联的扩展。客户端必须检查EncryptedExtensions是否存在任何禁止的扩展,如果发现任何扩展,必须用“illegal_parameter”警报中止握手
此消息的结构:
   struct {       Extension extensions<0..2^16-1>;   } EncryptedExtensions;
【extensions】
扩展列表。 有关详细信息,请参阅第10节中的表。

4.3.2. Certificate Request

使用证书进行身份验证的服务器可以选择向客户端请求证书。 此邮件(如果已发送)将遵循EncryptedExtensions。
此消息的结构:
   struct {       opaque certificate_request_context<0..2^8-1>;       Extension extensions<2..2^16-1>;   } CertificateRequest;
certificate_request_context
一个不透明的字符串,用于标识证书请求,并在客户端的证书消息中回显。 certificate_request_context在此连接的范围内必须是唯一的(从而防止客户端CertificateVerify消息的重放)。该字段应为零长度,除非用于第4.6.2节中描述的握手后身份验证交换。
【extensions】
描述正在请求的证书的参数的可选扩展集必须指定“signature_algorithms”扩展名
在TLS的先前版本中,服务器将接受携带签名算法和证书授权的列表CertificateRequest消息。在TLS 1.3中,前者通过发送“signature_algorithms”扩展来表示。后者通过发送“certificate_authorities”扩展名来表示(见第4.2.3.1节)。
使用PSK进行认证的服务器不得发送CertificateRequest消息


4.3.2.1. OID Filters

“oid_filters”扩展允许服务器提供一组OID /值对它希望客户端的证书匹配 此扩展必须只在CertificateRequest消息中发送
  struct {      opaque certificate_extension_oid<1..2^8-1>;      opaque certificate_extension_values<0..2^16-1>;  } OIDFilter;  struct {      OIDFilter filters<0..2^16-1>;  } OIDFilterExtension;
【filters】
具有允许值的证书扩展OID [RFC5280]的列表,以DER编码[X690]格式表示。一些证书扩展OID允许多个值(例如,扩展密钥用法)。如果服务器包含非空的certificate_extensions列表,则响应中包含的客户端证书必须包含客户端识别的所有指定的扩展OID。对于客户端识别的每个扩展OID,所有指定的值必须存在于客户端证书中(但是证书也可以具有其他值)。但是,客户端必须忽略并跳过任何无法识别的证书扩展OID。如果客户端忽略了一些所需的证书扩展OID并提供了不满足请求的证书,则服务器可以自行决定是否继续会话而不进行客户端身份验证,或者使用“unsupported_certificate”警报中止握手。 

PKIX RFC定义了各种证书扩展OID及其对应的值类型。根据类型,匹配的证书扩展值不一定是按位相等的。期望TLS实现将依靠它们的PKI库来使用证书扩展OID来执行证书选择。

本文档定义了[RFC5280]中定义的两个标准证书扩展的匹配规则
  • The Key Usage extension in a certificate matches the request when all key usage bits asserted in the request are also asserted in the Key Usage certificate extension.
  • The Extended Key Usage extension in a certificate matches the request when all key purpose OIDs present in the request are also found in the Extended Key Usage certificate extension. The special anyExtendedKeyUsage OID MUST NOT be used in the request.


4.4. Authentication Messages

如第2节所述,TLS通常使用一组公共消息来进行身份验证,密钥确认和握手完整性Certificate,CertificateVerify和Finished。 (PreSharedKey绑定器也以类似的方式执行密钥确认。)这三个消息总是作为它们的握手飞行中的最后消息发送。 Certificate和CertificateVerify消息仅在某些情况下发送,如下所定义。Finished的消息总是作为认证块的一部分发送。这些消息在从[sender]_handshake_traffic_secret派生的密钥下加密。

认证消息的计算统一采用以下输入:

  • 要使用的证书和签名密钥
  • 握手基于握手消息的记录的上下文
  • 用于计算MAC密钥的基本密钥
基于这些输入,消息包含:
Certificate
用于认证的证书和链中的任何支持证书。请注意,基于证书的客户端身份验证在0-RTT的情况下不可用。
CertificateVerify
值Hash(握手上下文+证书)上的签名
Finished
使用从基本密钥导出的MAC密钥的值超过值Hash(握手上下文+证书+证书验证)的MAC
因为CertificateVerify签署握手上下文+证书和完成的MACs握手上下文+证书+ CertificateVerify,这大体上等同于保持握手消息的运行的哈希(在纯1-RTT情况下正是如此)。然而,注意,随后的握手后认证不包括彼此,只是消息通过主握手的结束。
下表定义了每个场景的握手上下文和MAC基本密钥:

ModeHandshake ContextBase KeyServerClientHello … later of EncryptedExtensions/CertificateRequestserver_handshake_traffic_secretClientClientHello … ServerFinishedclient_handshake_traffic_secretPost-HandshakeClientHello … ClientFinished + CertificateRequestclient_traffic_secret_N

在所有情况下,通过连接指示的握手消息(包括握手消息类型和长度字段,但不包括记录层头部)来形成握手上下文


4.4.1. Certificate

只要约定的密钥交换方法使用证书进行认证,服务器必须发送证书消息(这包括本文档中定义的除PSK之外的所有密钥交换方法)。 此消息将端点的证书链传达给对等体。
当且仅当服务器通过CertificateRequest消息请求客户端认证时,客户端必须发送证书消息(第4.3.2节)。如果服务器请求客户端认证但没有合适的证书可用,则客户端必须发送不包含证书的证书消息(即,具有长度为0的“certificate_list”字段)
此消息的结构:

   opaque ASN1Cert<1..2^24-1>;   struct {       ASN1Cert cert_data;       Extension extensions<0..2^16-1>;   } CertificateEntry;   struct {       opaque certificate_request_context<0..2^8-1>;       CertificateEntry certificate_list<0..2^24-1>;   } Certificate;
certificate_request_context
如果此消息是响应CertificateRequest,则该消息中的certificate_request_context的值。否则(在服务器认证的情况下),该字段应为零长度。
certificate_list
这是一个CertificateEntry结构的序列(链),每个结构包含单个证书和一组扩展发送者的证书必须在列表中的第一个CertificateEntry中后面的每个证书应该直接证明前一个证书。因为证书验证要求信任锚被独立地分发,所以指定信任锚的证书可以从链中被省略,只要被支持的对等体已知具有任何省略的证书。
【extensions】
CertificateEntry的一组扩展名值。 “扩展”格式在第4.2节中定义。有效的扩展包括OCSP状态扩展([RFC6066]和[RFC6961])和SignedCertificateTimestamps([RFC6962])。如果在初始握手中呈现相应的ClientHello扩展,则扩展必须只存在于证书消息中。如果扩展应用于整个链,它应该被包括在第一个CertificateEntry中。


注意:在TLS 1.3之前,“certificate_list”排序需要每个证书来证明紧接在其前面的证书,然而,一些实现允许一些灵活性。服务器有时为了过渡目的而发送当前和已弃用的中间体,而其他的配置不正确,但这些情况仍然可以正确地验证。为了最大程度的兼容性,所有实现应该准备处理潜在的外部证书和任何TLS版本的任意排序,除了必须首先是最终实体证书。
服务器的certificate_list必须总是非空的如果客户端没有相应的证书来响应服务器的身份验证请求,则客户端将发送一个空的certificate_list。


4.4.1.1. OCSP Status and SCT Extensions

[RFC6066]和[RFC6961]提供了协商服务器向客户端发送OCSP响应的扩展。 在TLS 1.2及以下版本中,服务器用空扩展名回复以指示此扩展的协商,并且OCSP信息在CertificateStatus消息中携带。 在TLS 1.3中,服务器的OCSP信息携带在包含相关证书的CertificateEntry中的扩展中。 具体来说:来自服务器的“status_request”或“status_request_v2”扩展的主体必须是分别在[RFC6066]和[RFC6961]中定义的CertificateStatus结构。
类似地,[RFC6962]提供用于服务器发送签名证书时间戳(SCT)作为ServerHello中的扩展的机制。 在TLS 1.3中,服务器的SCT信息在CertificateEntry中的扩展中承载。



4.4.1.2. Server Certificate Selection

以下规则适用于服务器发送的证书:
  • 证书类型必须是X.509v3 [RFC5280],除非另有明确协商(例如,[RFC5081])。
  • 服务器的终端实体证书的公钥(和相关限制)必须与所选的认证算法(当前为RSA或ECDSA)兼容。
  • 证书必须允许密钥用于在客户端的“signature_algorithms”扩展中指示的签名方案的签名(即,如果密钥使用扩展存在则必须设置digitalSignature位必须被设置)。
  • “server_name”和“trusted_ca_keys”扩展名[RFC6066]用于指导证书选择。由于服务器可能需要存在“server_name”扩展,因此客户端应在适用时发送此扩展。
服务器提供的所有证书都必须由客户端提供的“signature_algorithms”扩展中出现的签名算法签名,如果它们能够提供这样的链(见第4.2.3节)。自签名的证书或预期为信任锚的证书不会作为链的一部分进行验证,因此可以使用任何算法签名。
如果服务器不能产生只通过所指示的支持的算法签名的证书链,则它应当通过向客户端发送其选择的证书链来继续握手,该证书链可以包括客户端不知道支持的算法。这个回退链可以只在客户端提供的“signature_algorithms”扩展允许的情况下使用已弃用的SHA-1哈希算法。如果客户端不能使用提供的证书构造可接受的链并且决定中止握手,则它必须用“unsupported_certificate”警报来中止握手。
如果服务器有多个证书,它会根据上述标准(除了其他标准,如传输层端点,本地配置和首选项)选择其中一个。

4.4.1.3. Client Certificate Selection

以下规则适用于客户端发送的证书:
  • 证书类型必须是X.509v3 [RFC5280],除非另有明确协商(例如,[RFC5081])。
  • 如果证书请求消息中的certificate_authorities列表不为空,则证书链中的至少一个证书应该由所列出的CA之一发布。
  • 证书必须使用可接受的签名算法签名,如第4.3.2节所述。 注意,这放松了在TLS的先前版本中发现的证书签名算法的约束。
  • 如果证书请求消息中的certificate_extensions列表不为空,那么终端实体证书必须匹配客户端识别的扩展OID,如第4.3.2节所述。
请注意,与服务器证书一样,存在使用当前无法与TLS一起使用的算法组合的证书。

4.4.1.4. Receiving a Certificate Message

一般来说,详细的证书验证过程超出了TLS的范围(参见[RFC5280])。本节提供TLS特定的要求。
如果服务器提供空的证书消息,客户端必须用“decode_error”警报中止握手。
如果客户端不发送任何证书,则服务器可以自行决定是否在没有客户端认证的情况下继续握手,或者使用“certificate_required”警报来中止握手。此外,如果证书链的某些方面是不可接受的(例如,它不是由已知的可信CA签署的),则服务器可以自行决定是继续握手(考虑到客户端未认证)还是中止握手。
任何接收使用任何使用MD5哈希的签名算法签名的证书的端点必须中止具有“bad_certificate”警报的握手。SHA-1已弃用,建议任何使用任何签名算法使用SHA-1散列签名的证书终止具有“bad_certificate”警报的握手。建议所有端点尽快转换到SHA-256或更高版本,以保持与逐步淘汰SHA-1支持过程中当前的实现的互操作性。
注意,包含用于一个签名算法的密钥的证书可以使用不同的签名算法(例如,用ECDSA密钥签名的RSA密钥)来签名。



4.4.2. Certificate Verify

该消息用于提供端点拥有与其证书相对应的私钥的明确证明,并且还为到目前为止的握手提供完整性。服务器必须在通过证书进行身份验证时发送此消息。 客户端必须在通过证书进行身份验证时(即,当证书消息非空时)发送此消息。发送时,此消息必须紧接在证书消息之后并紧接在完成消息之前。
此消息的结构:

   struct {       SignatureScheme algorithm;       opaque signature<0..2^16-1>;   } CertificateVerify;
算法字段指定所使用的签名算法(有关此字段的定义,请参见第4.2.3节)。 签名是使用覆盖第4.4节中描述的散列输出的算法的数字签名,即:
   Hash(Handshake Context + Certificate)
在TLS 1.3中,数字签名过程作为输入:
  • 签名密钥
  • 上下文字符串
  • 要签署的实际内容
然后使用签名密钥在以下相关联的内容上计算数字签名:
  • 由八位字节32(0x20)组成的字符串重复64次
  • 上下文字符串
  • 用作分隔符的单个0字节
  • 要签名的内容
此结构旨在防止对先前版本的TLS的攻击,其中ServerKeyExchange格式意味着攻击者可以获得具有选择的32字节前缀的消息的签名。 最初的64字节填充清除该前缀。
服务器签名的上下文字符串为“TLS 1.3,server CertificateVerify”,客户端签名为“TLS 1.3,client CertificateVerify”。
例如,如果Hash(握手上下文+证书)是01的32字节(这个长度对于SHA-256将是有意义的),服务器CertificateVerify的最终签名过程的输入将是:
   2020202020202020202020202020202020202020202020202020202020202020   2020202020202020202020202020202020202020202020202020202020202020   544c5320312e332c207365727665722043657274696669636174655665726966   79   00   0101010101010101010101010101010101010101010101010101010101010101
如果由服务器发送,签名算法必须是在客户端的“signature_algorithms”扩展中提供的,除非没有有效的证书链可以没有没有支持的算法(见第4.2.3节)。
如果由客户端发送,则签名中使用的签名算法必须是存在于CertificateRequest消息的supported_signature_algorithms字段中的签名算法之一。
此外,签名算法必须与发送方的端实体证书中的密钥兼容。 RSA签名必须使用RSASSA-PSS算法,而不管RSASSA-PKCS1-v1_5算法是否出现在“signature_algorithms”中。 SHA-1不得用于CertificateVerify中的任何签名。本规范中的所有SHA-1签名算法都定义为仅用于传统证书,并且对CertificateVerify签名无效。
注意:当与非基于证书的握手(例如,PSK)一起使用时,客户端的签名不直接覆盖服务器的证书。当通过NewSessionTicket建立PSK时,客户端的签名传递地通过PSK绑定器覆盖服务器的证书。 [PSK-FINISHED]描述了对不绑定到服务器证书的结构的具体攻击。当客户端可能与两个不同的端点共享相同的PSK /密钥ID对时,使用基于证书的客户端认证是不安全的,并且实现不能将外部PSK与基于证书的认证组合。

4.4.3. Finished

Finished消息是在认证块中最终的消息。它是用于提供握手和所计算的密钥的认证是必不可少的。Finished消息的收件人必须验证内容是正确的。
用于计算Finished消息的密钥是在4.4节中定义的基本密钥利用HKDF计算(参见7.1节)。具体做法是:
finished_key =    HKDF-Expand-Label(BaseKey, "finished", "", Hash.length)
此消息的结构:
   struct {       opaque verify_data[Hash.length];   } Finished;
该verify_data值的计算如下:
   verify_data =       HMAC(finished_key, Hash(Handshake Context +                               Certificate* +                               CertificateVerify*))   * Only included if present.

4.5. End of Early Data

   struct {} EndOfEarlyData;
该EndOfEarlyData消息由客户端发送来表明所有0-RTT已转交Application_Data信息(或没有人会在所有发送)和下面的记录下的交通握手密钥保护。服务器不得发送这封邮件和客户接受它必须终止连接随着“unexpected_message”警报。此消息在从client_early_traffic_secret派生密钥加密。

4.6. Post-Handshake Messages

此外TLS允许在握手后发送其他消息。这些消息用握手的内容类型并且在适当的关键应用流量下进行加密。

4.6.1. New Session Ticket Message

在服务器收到客户端完成的消息后的任何时间,就可以发送消息NewSessionTicket。此消息在ticket值和恢复主密钥之间创建一个预共享密钥(PSK)的绑定。

客户端可以在未来的握手中使用PSK,通过在ClientHello中包含“pre_shared_key”扩展,在扩展中包含ticket值(参加4.2.8节)
服务器可以在一个连接上发送多个tickets,无论是立即还是在特定事件后。例如,服务器可能为了添加客户端验证状态,在post-handshake验证后发送一个新的ticket。客户端应该尝试使用每个ticket最多一次,并且使用最近收到的ticket

任何ticket恢复必须仅使用具有相同的KDF哈希的密码套件,建立初始连接,并且只有在客户端提供相同的SNI值在原来的连接,如第3节中描述[RFC6066] 。

注:虽然恢复主密钥取决于客户端的第二次飞行,但是不要求客户端认证的服务器可能独立地计算谈话的剩余部分,然后在发送它的Finished消息时,立即发送一个NewSessionTicket,而不是等待客户端的Finished消息。在客户端打开多个TLS连接时,这将减少握手恢复的开销。

   struct {       uint32 ticket_lifetime;       uint32 ticket_age_add;       opaque ticket<1..2^16-1>;       Extension extensions<0..2^16-2>;   } NewSessionTicket;
ticket_lifetime
生存时间。以秒为单位;以网络字节顺序;32位无符号整数。服务器不得使用任何超过604800秒的值(7天)。为零时指示应立即丢弃。客户端不能缓存ticket超过7天。
ticket_age_add
一种随机生成的32位值,用来延长ticket的年龄,包括在“pre_shared_key”。客户端ticket年龄被增加到该值,模2 ^ 32以获得由客户端发送的值。
【ticket】
ticket的价值要用作PSK身份。ticket本身是不透明的标签。它可能是一个数据库查找键或自我加密和自我认证的值。
【extensions】
一组扩展的ticket值。客户端必须忽略无法识别的扩展。

目前为NewSessionTicket定义的唯一的扩展是“early_data”,表示ticket可以被用来发送0-RTT数据(第4.2.7节)。它包含以下值:
max_early_data_size
当使用这种ticket,以字节为单位,客户端被允许发送,
0-RTT数据的最大量。服务器接收数据超过max_early_data_size0-RTT字节应该终止连接使用“unexpected_message”警报。

4.6.2. Post-Handshake Authentication

通过发送CertificateRequest消息,在握手已经完成后,服务器被允许在任何时间请求客户验证。客户端应该响应与适当的身份验证信息。如果客户选择进行身份验证,它必须发送Certificate,CertificateVerify,Finished。如果拒绝,它必须发送不包含证书的Certificate消息以及Finished

注:由于客户端身份验证可能需要提示用户,服务器必须为一些延迟做好准备,待接收包括发送和接收响应之间CertificateRequest其他消息任意数量。此外,哪些客户端收到紧密相继可能响应它们以不同的顺序比他们收到了多个CertificateRequests(价值certificate_request_context允许服务器歧义的响应)。

4.6.3. Key and IV Update

   enum {       update_not_requested(0), update_requested(1), (255)   } KeyUpdateRequest;   struct {       KeyUpdateRequest request_update;   } KeyUpdate;
request_update
指示keyupdate的接收者是否应该响应它自身的KeyUpdate。如果实现接收到任何其它的值,它必须终止连接随着“illegal_parameter”警报。

keyupdate握手消息被用来表示发件人更新它发送的加密密钥。此消息可以在发送Finished消息后发送。在系统实现KeyUpdate接收成品必须终止连接随着“unexpected_message”警告消息之前收到的消息。发送KeyUpdate消息后,发送方使用下一代键,如第7.2节所述计算发送其所有流量。在接收到KeyUpdate,接收机必须更新其接收密钥。
如果request_update字段设置为“update_requested”,然后接收方必须发送自己的KeyUpdate随着request_update设置为“update_not_requested”发送其下一个应用程序的数据记录之前。这种机制一左一右强制允许更新整个连接,但是会导致接收多个KeyUpdates而这是无声的一次更新,以应对实现。还要注意的是实现接收发送给KeyUpdate随着request_update设置为update_requested和接收端的KeyUpdate,因为这些消息可能已在飞行之间的消息任意数量。然而,由于发送和接收密钥是从独立的通信秘密来源,保留这个秘密没有收到威胁的流量发送键之前发送的数据的前向安全性的变化。
如果实现独立发送KeyUpdates,用request_update设为“update_requested”,它们交叉和在飞行中,那么每个方将另外由两代发送响应,其结果是每一边的增量。

发送者和接收者必须用旧密钥加密他们的KeyUpdate消息。此外,这两端都必须强制,在接受任何一个用新密钥加密的消息之前,用旧密钥加密的KeyUpdate消息被接收。不这样做,可能遭到消息截断攻击。

5. Record Protocol




6. Alert Protocol


1 0