【发布时间】:2020-05-03 17:44:07
【问题描述】:
您好,这个问题的某种形式似乎已经被问了一百万种不同的方法,但很多都没有答案,或者答案不适用于我。
我们有一个微不足道的小 .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 签名。一切都使用 sha1 或 sha256 进行签名,并使用 RSA 加密。
我已启用跟踪。以下输出似乎表明找到证书或其私钥没有问题:
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 签名。我想可能是这样,我们正在联系我们的供应商。
【问题讨论】:
-
在 TLS 握手中,客户端仅在服务器发送自己的证书后,才在服务器请求时发送其证书。您确定服务器确实在要求客户端发送其证书吗?
-
当然可以。当我们说话时,我正在查看 Wireshark 中的 Server Hello 之后的证书和证书请求消息。
-
你在哪里添加代码
ServicePointManager.Expect100Continue = true; ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12; -
我们在 .Net 4.7.2 上,所以技术上没有必要。但是我玩过这些设置,它们没有任何区别。
-
你有一些你的供应商的 url 用于测试或者一些测试吗?如果您在请求中不包含证书会怎样?
标签: .net ssl tls1.2 client-certificates