首页 > 解决方案 > 从 C 核心客户端到 .NET 核心服务器的 HTTPS GRPC 连接:TLS 握手失败

问题描述

这个问题与我昨天问的一个问题密切相关,但我的诊断信息有很大的不同,以至于我认为我会更新并重新提交:让我知道是否应该删除其中一个。

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

您可以在此处找到.net 核心服务器的Startup.csand 。没有什么太有趣的了,除了调用. 我已经通过从.net 核心客户端(通过 https)连接到服务器来验证服务器是否正常工作。Program.csUseHttps

但是,我现在尝试从用 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++ 客户端将服务器的公钥加载到 an中,然后SslOpts.pem_root_certs使用它来创建对象。Python 客户端根本不读取证书文件,并将其通道创建为. 不过我认为这并不重要:TLS 握手在交换任何证书信息之前失败。SslCredentialsChannelgrpc.secure_channel("localhost:50052", grpc.ssl_channel_credentials())

我使用wireshark查看数据包中是否有任何信息。从那里我可以看到 .NET 核心客户端发送此 TLS 客户端 hello,这会引发相应的服务器 hello。Python客户端发送的客户端hello是这样的(C++包类似),服务器立即响应握手失败消息。

我对 TLS 的了解是初级的,但是 .NET 和 Python hellos 之间的一些差异对我来说很突出。

  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(引用 tls 1.0)发送它的 hello 时,它会抱怨与 ssl 3 相关的内容?

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

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

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

发送该失败数据包的 python 客户端通过 Python 3、Ubuntu 18.04(在 WSL 上)运行

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

标签: asp.net-coresslopensslgrpctls1.2

解决方案


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

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

  1. 对我的grpc 问题有帮助的人得出的结论是,不,我提到的 TLS 版本的混合不是问题

  2. 我仍然不确定是什么导致一个客户端 hello 数据包被拒绝而另一个被接受,但这似乎是我的机器特有的东西,这在我创建的新 Windows Server 2019 或 Windows 10 VM 上不是问题

  3. 不确定这个:我很确定我正确设置了该环境变量,但我不确定为什么 openssl 无法识别该值。另外,我认为GRPC_SSL_CIPHER_SUITES对windows没有任何影响


推荐阅读