ssl - 当服务器验证客户端证书失败时,tls 1.3 客户端不报告握手失败

标签 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 时,我注意到虽然验证错误仍在服务器上发生,但它不再报告给客户端。

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

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

最佳答案

当 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 中,客户端在发回其证书和已完成消息之前从服务器接收“已完成”消息。当客户端发送它的“Finished”消息时,它已经收到了“Finished”,因此握手已经完成,它可以立即开始发送应用程序数据。

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

I'm aware that the handshake protocol got completely re-written as part of TLS 1.3 however it seems like with all of the various callbacks available I should be able somehow on the client side to determine that authentication has failed without having to attempt to write data to the server.



重要的不是向服务器写入数据——而是读取数据。只有这样您才能知道服务器是否发送了警报或只是发送了正常的应用程序数据。在读取该数据之前,OpenSSL 中没有可用的回调可以告诉您这一点 - 因为 OpenSSL 本身由于底层协议(protocol)而无法知道。

关于ssl - 当服务器验证客户端证书失败时,tls 1.3 客户端不报告握手失败,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62459802/

相关文章:

ubuntu - 在 Ubuntu Nginx 盒子上生成通配符 SSL 并替换过期的 SSL(证书和 key )

javascript - Web Crypto API 无法导入 openssl key

python - NodeJS - SocketIO over SSL with websocket transport

node.js - 找不到 socket.io.js 的路径

c# - SSL/TLS - 查找证书时出现问题

ssl - 将 OpenSSL 与自定义 channel 结合使用

android - 如何为 Android 6.0.1 构建 OpenSSL 1.0.2?

linux - 无法将 mosquitto-clients 从 1.4.15 更新到 1.6.9

ssl - 从 .NET 5 中的 ServicePointManager.SecurityProtocol 解析密码套件

java - 如何在Java Spring boot应用程序中实现TLS 1.3?