C# 和 dotnet 4.7.1 不为 TLS 1.2 调用添加自定义证书
C# and dotnet 4.7.1 not adding custom certificate for TLS 1.2 calls
我有以下 C# 代码,使用自定义证书构建 https 调用。使用 Tls 1.1 时,调用工作正常。使用 Tls 1.2 时,呼叫中断。我使用 curl,使用 tls 1.2 也能正常工作。
C#代码:
X509Certificate2Collection collection = new X509Certificate2Collection();
collection.Import("C:\SomePath\MyCertificate.pfx", "MyPassword", X509KeyStorageFlags.PersistKeySet);
var cert = collection[0];
ServicePointManager.SecurityProtocol = ...;
ServicePointManager.ServerCertificateValidationCallback += (sender, certificate, chain, errors) => true;
HttpClientHandler handler = new HttpClientHandler();
handler.ServerCertificateCustomValidationCallback = (message, certificate2, arg3, arg4) => true;
handler.ClientCertificates.Add(cert);
var content = new ByteArrayContent(Encoding.GetEncoding("latin1").GetBytes("Hello world"));
HttpClient client = new HttpClient(handler);
var resp = client.PostAsync(requestUri: url, content: content).Result.Content.ReadAsStringAsync().Result;
适用于:
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls11;
错误:
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
.Net 错误消息:SocketException:现有连接被远程主机强行关闭
.网络版本:4.7.1
OS: Windows 10 version 1703 (supported cipher list: https://msdn.microsoft.com/en-us/library/windows/desktop/mt808163(v=vs.85).aspx) - 服务器指定要使用的 TLS_RSA_WITH_AES_256_GCM_SHA384,这是受支持的密码之一.
在 wireshark 中,我可以看到通过工作调用(C#/Tls 1.1 和 Curl Tls 1.2),证书正在发送到服务器。这是 C# tls 1.1 调用的 wireshark 转储:
但是,同样在 wireshark 中,我可以看到使用 C#/Tls 1.2 时没有证书从客户端发送到服务器。这是 C# tls 1.2 调用的 wireshark 转储:
谁能看到我在这里遗漏了什么?
更新
似乎证书有一个 md5 签名,Schannel 在 windows 中不支持结合 tls 1.2。我们的供应商已经为我们创建了另一个证书作为解决方案。
我遇到了这个讨论这个问题的随机线程:https://community.qualys.com/thread/15498
我相信这段代码通过总是盲目地返回 true 来掩盖某种类型的证书错误:
handler.ServerCertificateCustomValidationCallback = (message, certificate2, arg3, arg4) => true;
我建议你有一个函数来真正分析 arg4 的结果。那是你的 SSL 策略错误。记录他们,你会得到你的答案。在我的示例中,我写入控制台,但您可以写入跟踪或文件。您将获得一个数字,该数字将与 SslPolicyErrors 枚举的值相关联。根据结果,您可能需要检查您的 arg3,这是您的链。
ServicePointManager.ServerCertificateValidationCallback += (sender, cert, chain, sslPolicyErrors) => {
SslPolicyErrors errs = sslPolicyErrors;
Console.WriteLine("Policy Errors " + sslPolicyErrors.ToString());
return true;};
你不应该指定处理程序的 SslProtocols
属性 吗?
尝试在 hander
定义后添加此行:
handler.SslProtocols = SslProtocols.Tls12;
您说对了这个问题的根本原因:默认情况下,基于 schannel 的客户端提供 SHA1、SHA256、SHA384 和 SHA512(在 Win10/Server 2016 年)。所以 TLS 1.2 服务器不应该将它们的 MD5 证书发送给这些客户端。
客户端 (HttpClient) 未在 signature_algorithms 扩展名中列出 MD5,因此 TLS 1.2 握手失败。解决方法是使用安全服务器证书。
我有以下 C# 代码,使用自定义证书构建 https 调用。使用 Tls 1.1 时,调用工作正常。使用 Tls 1.2 时,呼叫中断。我使用 curl,使用 tls 1.2 也能正常工作。
C#代码:
X509Certificate2Collection collection = new X509Certificate2Collection();
collection.Import("C:\SomePath\MyCertificate.pfx", "MyPassword", X509KeyStorageFlags.PersistKeySet);
var cert = collection[0];
ServicePointManager.SecurityProtocol = ...;
ServicePointManager.ServerCertificateValidationCallback += (sender, certificate, chain, errors) => true;
HttpClientHandler handler = new HttpClientHandler();
handler.ServerCertificateCustomValidationCallback = (message, certificate2, arg3, arg4) => true;
handler.ClientCertificates.Add(cert);
var content = new ByteArrayContent(Encoding.GetEncoding("latin1").GetBytes("Hello world"));
HttpClient client = new HttpClient(handler);
var resp = client.PostAsync(requestUri: url, content: content).Result.Content.ReadAsStringAsync().Result;
适用于:
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls11;
错误:
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
.Net 错误消息:SocketException:现有连接被远程主机强行关闭
.网络版本:4.7.1
OS: Windows 10 version 1703 (supported cipher list: https://msdn.microsoft.com/en-us/library/windows/desktop/mt808163(v=vs.85).aspx) - 服务器指定要使用的 TLS_RSA_WITH_AES_256_GCM_SHA384,这是受支持的密码之一.
在 wireshark 中,我可以看到通过工作调用(C#/Tls 1.1 和 Curl Tls 1.2),证书正在发送到服务器。这是 C# tls 1.1 调用的 wireshark 转储:
但是,同样在 wireshark 中,我可以看到使用 C#/Tls 1.2 时没有证书从客户端发送到服务器。这是 C# tls 1.2 调用的 wireshark 转储:
谁能看到我在这里遗漏了什么?
更新
似乎证书有一个 md5 签名,Schannel 在 windows 中不支持结合 tls 1.2。我们的供应商已经为我们创建了另一个证书作为解决方案。
我遇到了这个讨论这个问题的随机线程:https://community.qualys.com/thread/15498
我相信这段代码通过总是盲目地返回 true 来掩盖某种类型的证书错误:
handler.ServerCertificateCustomValidationCallback = (message, certificate2, arg3, arg4) => true;
我建议你有一个函数来真正分析 arg4 的结果。那是你的 SSL 策略错误。记录他们,你会得到你的答案。在我的示例中,我写入控制台,但您可以写入跟踪或文件。您将获得一个数字,该数字将与 SslPolicyErrors 枚举的值相关联。根据结果,您可能需要检查您的 arg3,这是您的链。
ServicePointManager.ServerCertificateValidationCallback += (sender, cert, chain, sslPolicyErrors) => {
SslPolicyErrors errs = sslPolicyErrors;
Console.WriteLine("Policy Errors " + sslPolicyErrors.ToString());
return true;};
你不应该指定处理程序的 SslProtocols
属性 吗?
尝试在 hander
定义后添加此行:
handler.SslProtocols = SslProtocols.Tls12;
您说对了这个问题的根本原因:默认情况下,基于 schannel 的客户端提供 SHA1、SHA256、SHA384 和 SHA512(在 Win10/Server 2016 年)。所以 TLS 1.2 服务器不应该将它们的 MD5 证书发送给这些客户端。
客户端 (HttpClient) 未在 signature_algorithms 扩展名中列出 MD5,因此 TLS 1.2 握手失败。解决方法是使用安全服务器证书。