.NET 通过 TLS 1.2 删除客户端证书

.NET dropping client certificate over TLS 1.2

您好,这个问题的某种形式似乎已经被问过一百万种不同的方式,但很多人没有答案,或者答案不适用于我。

我们有一个微不足道的小 .NET 服务,可以调用现在仅支持 TLS 1.2 的第 3 方 API。

        var requestHandler = new WebRequestHandler();
        var clientCert = GetClientCert("THUMBPRINT");

        requestHandler.ClientCertificates.Add(clientCert);
        var encodedHeader = "FOO";
        var httpClient = new HttpClient(requestHandler) { BaseAddress = new Uri("https://foo.bar.com/rest/api/") };
        httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", encodedHeader);

        var httpResponse = httpClient.GetAsync("").Result;
        var responseContent = httpResponse.Content.ReadAsStringAsync().Result;

当我将安全协议明确设置为 1.2,或针对默认为 1.2 的框架时,客户端证书不是发送到服务器的数据包的一部分。我已经在 Wireshark 中对其进行了检查,并且证书从未超过 1.2。此时服务器发送致命警报握手失败 (40),这会导致以下 .Net 异常:

The request was aborted: Could not create SSL/TLS secure channel.

我可以通过 Chrome 或 Postman(本机)进行相同的调用,并且工作正常。如果我将协议设置为 1.1,它就可以正常工作。但是,如果我通过 .NET 运行 它作为 1.2,它每次都会失败。即使我故意根本不添加我的客户端证书,我也会在 Wireshark 中得到完全相同的错误和相同的流量。

我 运行 通过 https://www.ssllabs.com/ 的第 3 方端点,它的评分很好。我在两边都能看到的任何地方都没有 MD5 签名。一切都使用带有 RSA 加密的 sha1 或 sha256 签名。

我启用了追踪功能。以下输出似乎表明查找证书或其私钥没有问题:

System.Net Information: 0 : [19512] SecureChannel#41622463 - Certificate is of type X509Certificate2 and contains the private key.
System.Net Information: 0 : [19512] SecureChannel#41622463::.AcquireClientCredentials, new SecureCredential() (flags=(ValidateManual, NoDefaultCred, SendAuxRecord, UseStrongCrypto), m_ProtocolFlags=(Zero), m_EncryptionPolicy=RequireEncryption)
System.Net Information: 0 : [19512] AcquireCredentialsHandle(package = Microsoft Unified Security Protocol Provider, intent  = Outbound, scc     = System.Net.SecureCredential)
System.Net Information: 0 : [19512] InitializeSecurityContext(credential = 
System.Net.SafeFreeCredential_SECURITY, context = 1ed7465db80:1f1d854c910, targetName = foo.bar.com, inFlags = ReplayDetect, SequenceDetect, Confidentiality, AllocateMemory, InitManualCredValidation)
System.Net Information: 0 : [19512] InitializeSecurityContext(In-Buffers count=2, Out-Buffer length=133, returned code=ContinueNeeded).

我还打开了 SCHANNEL 事件记录。在那里我可以看到它使用私钥获取客户端证书。

The TLS client credential's private key has the following properties:

   CSP name: Microsoft Enhanced Cryptographic Provider v1.0
   CSP type: 1
   Key name: {some hex here}
   Key Type: key exchange
   Key Flags: 0x0

 The attached data contains the certificate.

后面是Wireshark中Alert包对应的错误:

A fatal alert was received from the remote endpoint. The TLS protocol defined fatal alert code is 40.

我完全没思路了。感觉像是 .Net 中的错误。我们想了一下,这是一个与我们的客户端证书不完整的信任链,因为我们的证书包只有客户端证书和一个中间 CA。但是我们从供应商那里得到了根 CA,现在 Windows 说证书是合法的。

我在 Wireshark 中注意到的一件有趣的事情是我们在成功调用时发送客户端证书和中间 CA。我不知道它是如何获取中间 CA 的,因为我只提取客户端证书以附加到请求。为什么它不在我们拥有根 CA 后也提交它?我的直觉告诉我问题可能仍然存在于某个地方,但我无法证明这一点。任何地方的任何日志中都没有任何内容表明信任链失败。

我什至还连接了 ProcMon 以查看我是否能看到任何不对劲但没有任何东西跳出。伙计,我本可以在 Java 中用我花在这上面的时间重写整个东西。

我尝试过的其他一些方法无效:

针对 .Net 4.8

机器存储与用户存储

改为直接从 pfx 加载

HttpWebRequest 而不是 HttpClient

带 SslStream 的 TcpClient

更新 Windows 10 版本

编辑 我刚刚读到一些内容说 SHA-1 签名也与 MD5 一起从 TLS 1.2 中删除。我们的客户证书以 SHA-1 签名。我想可能就是这样,我们正在联系我们的供应商。

我的问题和我的解决方案最终与这个相同。唯一的区别是我的客户端证书是 SHA1 而不是 MD5。 .NET 显然也在放弃 SHA1 证书。

这篇文章给了我线索,因为其他帖子表明 SHA1 仍然被接受。我的 SHA1 证书在 .NET 之外仍然有效。

https://tools.ietf.org/id/draft-ietf-tls-md5-sha1-deprecate-00.html