这是我参与8月更文挑战的第4天,活动详情查看:8月更文挑战
| 8月份更文挑战主题:TLS1.3协议 |
|---|
| TLS1.3系列文章(4):TLS1.3握手之认证阶段(1) |
在认证阶段中,客户端和服务端互相交互认证消息。这个过程一般包括两组共计三类消息:证书载荷(Certificate), 证书校验载荷(CertificateVerify), Finished载荷。如果服务端不对客户端进行证书认证时,则客户端便不再需要发送自己的证书载荷和证书校验载荷,此时只需要发送Finished载荷即可。
wireshark抓包Server端报文如下:
在服务端不对客户端进行证书认证时,wireshare抓包显示如下:
TLS通常使用一组消息来进行身份验证,密钥确认和握手完整性校验:Certificate,CertificateVerify和Finished。 (PSK binder也以类似的方式执行密钥确认) 这三个消息总是在握手中的最后发送。 Certificate和CertificateVerify消息仅在某些情况下发送。Finished的消息总是作为Authentication阶段的一部分发送。这些消息使用[sender]_handshake_traffic_secret派生的密钥加密。
认证消息的计算时的输入参数包括: • 要使用的证书和签名密钥。 • 一个握手上下文,由要包含在transcript哈希中的一组消息组成。 • 用于计算MAC密钥的基本密钥。
基于这些输入,认证消息包含的载荷有如下几个: Certificate:用于认证的证书,以及证书链中的任何支持证书。请注意,基于证书的客户端身份验证在PSK握手流中不可用(包括0-RTT)。 CertificateVerify:Transcript-Hash值的签名(握手上下文+证书)。 Finished:Transcript-Hash值的MAC(握手上下文+证书+证书验证),使用Base Key派生的MAC秘钥。
不同场景下的握手上下文和对应的BaseKey:
2.3.1 Certificate消息
证书消息(Certificate)用来将本端的证书链传递给对端。 当双方协商出使用证书进行认证的密钥交换算法,服务器必须发送一个Certificate消息(RFC中规定,除了使用PSK进行密钥交换之外,其他任何形式的握手消息必须发送证书载荷)。
当且仅当服务器通过CertificateRequest消息要求对客户端进行证书认证时,客户端才必须发送Certificate消息;否则其他客户端不必发送证书消息。 如果服务器请求客户端使用证书认证时,但客户端没有合适的证书,则客户端必须发送一个不包含证书的Certificate消息(即"certificate_list "字段长度为0)。 无论证书消息是否为空,都必须发送一个Finished消息。
Certificate的结构如下:
- certificate_request_context:如果该消息是对CertificateRequest的响应,则填充为CertificateRequest中的certificate_request_context值。 在其他情况下,该字段长度为零。
- certificate_list:CertificateEntry结构的序列(链),每个结构包含一个证书和一组扩展
- extensions:CertificateEntry的扩展载荷。目前服务器证书的有效扩展包括OCSP Status扩展[RFC6066]和SignedCertificateTimestamp扩展[RFC6962];未来也可以为该消息定义扩展。 服务器的Certificate消息中的扩展必须与ClientHello消息的扩展相对应。 客户端的Certificate消息中的扩展必须与服务器的 CertificateRequest 消息中的扩展相对应。 如果一个扩展用于整个链,它应该包含在第一个CertificateEntry 中
如果对应的证书类型扩展(server_certificate_type或client_certificate_type)没有在EncryptedExtensions中协商,或者协商使用X.509类型的证书,那么每个CertificateEntry都包含一个DER编码的X.509证书(默认情况下为X509证书)。 发送者的证书必须在列表中的第一个CertificateEntry 中。 后面的每个证书都应该直接认证紧邻它前面的证书。 因为证书验证要求trust anchors是独立分发的,所以指定trust anchors的证书可以从链中省略,前提是支持的对端已知拥有任何省略的证书。
注意:在TLS 1.3之前,certificate_list的排序要求每个证书都要对紧接在它前面的证书进行认证;
但是,一些实现允许一些灵活性。 服务器有时会为了过渡目的同时发送一个当前的和过时的中间文件,还有一些只是配置不正确,但这些情况还是可以被正确验证。 为了实现最大的兼容性,所有的实现都应该准备好处理任何TLS版本中潜在的无关证书和任意的顺序,但最终实体证书必须放在第一位。
如果协商为RawPublicKey证书类型,那么certificate_list只能包含一个CertificateEntry,其中包含[RFC7250]第3节中定义的ASN1_subjectPublicKeyInfo值。 OpenPGP证书类型[RFC6091]不得用于TLS 1.3。服务器的certificate_list必须是非空的。如果客户端没有合适的证书来响应服务器的认证请求,客户端将发送一个空的证书列表。
2.3.1.1 OCSP状态和SCT(签名时间戳)
[RFC6066]和[RFC6961]提供了一些扩展载荷用来协商服务器向客户端发送OCSP响应。 在TLS 1.2及之前版本中,服务器用一个空的扩展来表示协商这个扩展,OCSP信息携带在CertificateStatus消息中。 在TLS 1.3中,服务器的OCSP信息在包含相关证书的CertificateEntry中的扩展中。 具体来说,服务器的"status_request"扩展的主体必须是[RFC6066]中定义的CertificateStatus结构,其解释在[RFC6960]中定义。
注意:status_request_v2扩展[RFC6961]已经废弃。TLS 1.3服务器在处理ClientHello消息时,不能根据status_request_v2的存在或其中的信息采取行动,尤其是不能在EncryptedExtensions、CertificateRequest 或 Certificate 消息中发送此扩展。TLS 1.3服务器必须能够处理包含status_request_v2的ClientHello消息,因为使用早期协议版本的客户端发送可能想要使用。
服务器可以通过在CertificateRequest消息中发送一个空的"status_request"扩展,要求客户机提供OCSP响应和它的证书。如果客户端选择发送OCSP响应,其"status_request"扩展的主体必须是[RFC6066]中定义的CertificateStatus结构。 同样,[RFC6962]提供了一种机制,在TLS 1.2及以下版本中,服务器可以将签名证书时间戳(SCT,Signed Certificate Timestamp)作为ServerHello中的扩展发送。 在TLS 1.3中,服务器的SCT信息在CertificateEntry的扩展中
2.3.1.2 Server端证书选择
服务器发送的证书遵循以下规则:
- 证书类型必须是X.509v3[RFC5280],除非另有显式协商(如[RFC7250]) 。
- 服务器的终端实体证书的公钥(和相关的限制)必须与客户的"signature_algorithms"扩展(目前是RSA、ECDSA或EdDSA)中选择的认证算法兼容。
- 证书必须允许使用秘钥进行签名(即如果有Key Usage扩展,digitalSignature位必须被设置),签名方案在客户端的signature_algorithms或signature_algorithms_cert扩展中指明。
- server_name[RFC6066]和certificate_authorities扩展用来指导证书的选择。由于服务器可能需要server_name扩展,客户端应该可用情况下发送此扩展。
服务器提供的所有证书必须由客户端提供的签名算法签名(如果客户端能够提供这样的链) 。 自签证书或预期为trust anchors的证书不作为链的一部分进行验证,因此可以用任何算法进行签名。
如果服务器不能产生一个只通过指定的支持算法进行签名的证书链,那么它应该向客户端发送一个自己选择的包含不知道客户端是否支持的算法证书链来继续握手。这个fallback链一般不应使用已淘汰的SHA-1散列算法,但如果客户端通告允许的话可以使用,否则不得使用。 如果客户端不能使用提供的证书构建一个可接受的链,并决定放弃握手,那么它必须用一个适当的certificate-related告警(默认情况下为unsupported_certificate)来放弃握手。如果服务器有多个证书,它就会根据上述标准(除此之外还有其他标准,如传输层端点、本地配置和偏好)选择其中一个。
2.3.1.3 Client证书选择
客户端发送的证书遵循以下规则:
- 证书类型必须是X.509v3[RFC5280],除非另有明确协商(如[RFC7250])。
- 如果CertificateRequest消息中存在certificate_authorities扩展,那么证书链中至少有一个证书应该是由所列的CA签发的。
- 证书必须使用可接受的签名算法来签署。需要注意的是,这放宽了以前版本的TLS中对证书签名算法的限制。
- 如果CertificateRequest消息包含一个非空的oid_filters扩展,那么终端实体证书必须与客户端识别的扩展名OID匹配。
2.1.3.4 收到一个证书消息
一般来说,详细的证书验证程序不在TLS协议讨论的范围内(见[RFC5280])。 本节提供了专门针对TLS的要求。
🩸 如果服务器提供了空的Certificate消息,客户端必须用decode_error警告中止握手。
🩸 如果客户端没有发送任何证书(比如发送一个空的Certificate消息),服务器可以自行决定是在没有客户端认证的情况下继续握手,还是用certificate_required 警告中止握手。 另外,如果证书链的某些方面是不能接受的(例如,不是由已知的、受信任的CA签发的),服务器可以自行决定继续握手(考虑到客户端未被认证)或中止握手。
🩸 任何端点收到任何需要使用MD5哈希签名算法来验证的证书,都必须以 bad_certificate警告来中止握手。 SHA-1已废弃,建议任何端点收到任何需要使用SHA-1散列签名算法来验证的证书时,应当以bad_certificate警告中止握手。 为明确起见,这意味着端点可以接受这些算法,用于自签或trust anchors的证书。
🩸 建议所有端点尽快过渡到SHA-256或更高版本,以保持与目前正在逐步取消SHA-1支持的实施方案的互操作性。 请注意,包含一种签名算法密钥的证书可以使用不同的签名算法进行签名(例如,用ECDSA密钥签名的RSA密钥)。