服务器失败客户端证书验证时,TLS 1.3客户端不会报告握手失败

时间:2020-06-18 21:37:34

标签: ssl openssl tls1.3

我有一个使用OpenSSL的C客户端,该客户端使用在服务器端进行SSL_do_handshake()调用期间在服务器端未通过验证的证书时测试失败。当应用程序使用TLS 1.2时,当服务器调用SSL_do_handshake()作为失败返回值时,服务器上的SSL_do_handshake()失败将被报告回客户端。

将我的应用程序升级到OpenSSL 1.1.1和TLS 1.3时,我注意到虽然服务器上仍然发生验证错误,但不再将其报告给客户端。

我知道握手协议已完全重写为TLS 1.3的一部分,但是似乎有了所有可用的各种回调,我应该能够以某种方式在客户端确定身份验证失败而不必尝试将数据写入服务器。

其他人遇到过这种情况吗,他们可以推荐前进的路吗?

1 个答案:

答案 0 :(得分:1)

当TLSv1.2和TLSv1.3中的服务器和客户端都已写完“已完成”消息并从对等方收到消息时,它们认为握手已完成。这是TLSv1.2(来自RFC5246)中的握手形式:

      Client                                               Server

      ClientHello                  -------->
                                                      ServerHello
                                                     Certificate*
                                               ServerKeyExchange*
                                              CertificateRequest*
                                   <--------      ServerHelloDone
      Certificate*
      ClientKeyExchange
      CertificateVerify*
      [ChangeCipherSpec]
      Finished                     -------->
                                               [ChangeCipherSpec]
                                   <--------             Finished
      Application Data             <------->     Application Data

因此,在这里您可以看到客户端在与服务器的第二次通信中发送了其证书和完成消息。然后,它在认为握手“完成”之前可以等待从服务器接收到ChangeCipherSpec和Finished消息,并可以开始发送应用程序数据。

这是从RFC8446提取的TLSv1.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]

TLSv1.3的优点之一是它可以加快完成握手所需的时间。在TLSv1.3中,客户端从服务器之前接收到“已完成”消息,它将其证书和已完成消息发回。到客户端发送其“完成”消息时,它已经收到“完成”消息,因此握手已完成,它可以立即开始发送应用程序数据。

这当然意味着客户端将不知道服务器是否已接受证书,直到它下次从服务器读取数据为止。如果已被拒绝,则客户端将读取的下一件事将是失败警报(否则将是正常的应用程序数据)。

我知道握手协议已完全重写为TLS 1.3的一部分,但是似乎有了所有可用的各种回调,我应该能够以某种方式在客户端确定身份验证失败而不必尝试将数据写入服务器。

这不是重要的数据写入服务器-是读取数据。只有这样,您才能知道服务器是发送警报还是仅发送正常的应用程序数据。在读取该数据之前,OpenSSL中没有可用的回调告诉您这一信息-因为OpenSSL本身由于底层协议而无法识别。