C#和dotnet 4.7.1没有为TLS 1.2调用添加自定义证书

时间:2017-12-20 11:16:58

标签: c# tls1.2 x509certificate2

我有以下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:远程主机强行关闭现有连接

.Net版本:4.7.1

操作系统:Windows 10版本1703(支持的密码列表: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 dump - Csharp tls 1.1

然而,在wireshark中,我可以看到,使用C#/ Tls 1.2,没有证书从客户端发送到服务器。这是C#tls 1.2调用的wireshark转储:

enter image description here

谁能看到我在这里缺少的东西?

更新

证书似乎有一个md5签名,Windows中的Schannel不支持tls 1.2。我们的供应商已经为我们创建了另一个证书作为解决方案。

我遇到了这个讨论问题的随机主题:https://community.qualys.com/thread/15498

3 个答案:

答案 0 :(得分:2)

您正确解决此问题的根本原因:默认情况下,基于schannel的客户端提供SHA1,SHA256,SHA384和SHA512(在Win10 / Server 2016上)。因此,TLS 1.2服务器不应将其MD5证书发送给这些客户端。

客户端(HttpClient)未在signature_algorithms扩展中列出MD5,因此TLS 1.2握手失败。修复方法是使用安全服务器证书。

答案 1 :(得分:0)

我相信这段代码总是盲目地返回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;};

答案 2 :(得分:0)

您是否应该指定处理程序的SslProtocols属性?

尝试在hander定义后添加此行:

handler.SslProtocols = SslProtocols.Tls12;