从 C 核心客户端到 .NET 核心服务器的 HTTPS GRPC 连接:TLS 握手失败

HTTPS GRPC connections from C core clients to .NET core server: TLS handshake failure

这个问题与 密切相关,但我的诊断信息非常不同,我想我应该更新并重新提交:如果我应该删除其中一个,请告诉我。

我有一个用 .NET 核心编写的玩具 GRPC 服务器,我需要使用使用 grpc C 核心的客户端连接到它。

您可以找到 .net 核心服务器 here. Nothing too interesting, except a call to UseHttps. I've verified the server works by connecting to it (over https) from a .net core clientStartup.csProgram.cs

但是我现在尝试从用 C++ 和 python 编写的客户端连接到此服务器,结果是 GRPC 错误 14 和客户端的以下消息

E0304 08:36:58.510065400 4905 ssl_transport_security.cc:1455] Handshake failed with fatal error SSL_ERROR_SSL: error:10000410:SSL routines:OPENSSL_internal:SSLV3_ALERT_HANDSHAKE_FAILURE.

以及服务器端的以下消息。

dbug: Microsoft.AspNetCore.Server.Kestrel.Core.KestrelServer[2] 
  Connection id "0HM6UG4PBICBP" accepted.
dbug: Microsoft.AspNetCore.Server.Kestrel[1]
      Connection id "0HM6UG4PBICBP" started.
dbug: Microsoft.AspNetCore.Server.Kestrel.Https.Internal.HttpsConnectionMiddleware[1]
      Failed to authenticate HTTPS connection.
System.Security.Authentication.AuthenticationException: Authentication failed, see inner exception.
---> System.ComponentModel.Win32Exception (0x80090367): No common application protocol exists between the client and the server. Application protocol negotiation failed.

C++ 客户端将服务器的 public 键加载到 SslOpts.pem_root_certs 中,并使用它创建 SslCredentialsChannel 对象。 Python 客户端根本不读取证书文件,而是将其通道创建为 grpc.secure_channel("localhost:50052", grpc.ssl_channel_credentials())。不过我认为这并不重要:在交换任何证书信息之前 TLS 握手失败。

我用wireshark查看数据包中是否有任何信息。从那里我可以看到.NET 核心客户端发送 this TLS client hello, which elicits a corresponding server hello. The client hello sent by the Python client looks like this(C++ 数据包类似),服务器立即响应握手失败消息。

我对 TLS 的了解很基本,但 .NET 和 Python hello 之间的一些差异让我印象深刻。

  1. 工作的 TLS hello 数据包似乎是“完全通过”的 TLS 1.2。 TLS 序列的开头如下所示
 Transport Layer Security
    TLSv1.2 Record Layer: Handshake Protocol: Client Hello
        Content Type: Handshake (22)
        Version: TLS 1.2 (0x0303)
        Length: 160
        Handshake Protocol: Client Hello
            Handshake Type: Client Hello (1)
            Length: 156
            Version: TLS 1.2 (0x0303)

而失败的TLS数据包中对应的序列是

Transport Layer Security
    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)

出于某种原因,中间提到了 TLS 1.0

  1. 在服务器 hello 中,服务器选择 TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384 (0xc028) 密码套件,失败的 TLS hello 数据包中未提及。

当然还有其他差异,但在我未经训练的眼中,它们似乎不太相关。

除了“我如何让它工作?”之外,我还有几个具体问题

  1. 当我看到 grpc 客户端正在通过 tls 1.2 发送 hello(参考 tls 1.0)时,为什么 grpc 客户端抱怨与 ssl 3 相关的问题?

  2. 这两个客户端问候包之间的真正区别是什么?我可以看到密码套件的差异,即我之前提到的 TLS 版本,每个都有一些其他没有的扩展:但我不知道这里有什么相关的,特别是因为它与为什么 asp.net核心服务器会拒绝客户端hello

  3. 我应该设置一些 grpc C-core 环境变量来解决这个问题吗?如果可以的话怎么办?我尝试使用 GRPC_SSL_CIPHER_SUITES=ECDHE-RSA-AES256-SHA384 python client.py 启动客户端(查看了转换 here),但我只是因为以下错误而大喊大叫

E0304 08:13:28.257362600 4893 ssl_transport_security.cc:815] Invalid cipher list: ECDHE-RSA-AES256-SHA384. 

发送失败数据包的python客户端是运行通过Python3,Ubuntu18.04(在WSL上)

$ openssl version
OpenSSL 1.1.0g  2 Nov 2017 (Library: OpenSSL 1.1.1  11 Sep 2018) 

我的连接问题似乎是由我的机器上的一些错误配置引起的,因为我无法在其他设置上重现错误。这样就解决了“我如何让它工作?”

我回答了这三个具体问题。

  1. 我的 grpc issue 上的乐于助人的人得出的结论是,不,我提到的混合 TLS 版本不是问题

  2. 我仍然不确定是什么导致一个客户端问候数据包被拒绝而另一个被接受,但它似乎又是我的机器特有的东西,这在新鲜 Windows 服务器 2019 或 windows 我创建的 10 个虚拟机

  3. 对此不确定:我很确定我正确设置了该环境变量,但我不确定为什么 openssl 无法识别该值。另外,我认为 GRPC_SSL_CIPHER_SUITES 对 windows

    没有任何影响