C# 和 dotnet 4.7.1 没有为 TLS 1.2 调用添加自定义证书
Posted
技术标签:
【中文标题】C# 和 dotnet 4.7.1 没有为 TLS 1.2 调用添加自定义证书【英文标题】:C# and dotnet 4.7.1 not adding custom certificate for TLS 1.2 calls 【发布时间】:2018-06-02 22:32:51 【问题描述】:我有以下 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 中,我可以看到使用C#/Tls 1.2 没有证书从客户端发送到服务器。这是 C# tls 1.2 调用的 wireshark 转储:
谁能看到我在这里遗漏了什么?
更新
证书似乎有一个 md5 签名,Windows 中的 Schannel 不支持与 tls 1.2 结合使用。我们的供应商为我们创建了另一个证书作为解决方案。
我偶然发现了一个讨论这个问题的线程:https://community.qualys.com/thread/15498
【问题讨论】:
我在 .Net Core 2.0 客户端/服务器应用程序中遇到了类似的问题。我通过在服务器上强制使用 TLS 1.2 来解决。这样,客户端就可以正确协商协议和证书。您可能会尝试连接到仅强制使用 TLS 1.2 的服务器,看看您是否与 .NET Framework 有相同的行为。 在服务器上更改它并不是一个真正的选择,因为服务器属于供应商。如果我添加 tls 1.1 也没关系。只要 tls 1.2 只是在允许的协议中,就会发生此问题。我需要知道为什么当 curl 工作正常时 .net 会以这种方式运行。我需要启用 tls 1.2,因为这是一个静态设置,其他连接依赖于同一应用程序中的 tls 1.2。如果我可以为这个单一的电话打开 tls 1.3,那就可以了。但是在处理程序对象上设置协议会抛出一个异常,告诉这在当前环境中是不可能的。 看起来很像这个问题的重复***.com/questions/44751179/… 嗯,我不认为它是重复的。首先,您的链接显示了一个线程,描述了一个问题,即除非明确设置,否则 tls 1.2 不起作用 - 我的问题恰恰相反:启用 tls 1.2 时 https 不起作用。其次,使用 app.config 描述的修复没有任何帮助。 检查您是否在协议级别对密码套件有任何限制,例如:technet.microsoft.com/en-us/library/… 【参考方案1】:您对这个问题的根本原因是正确的:默认情况下,基于 schannel 的客户端提供 SHA1、SHA256、SHA384 和 SHA512(在 Win10/Server 2016 上)。因此 TLS 1.2 服务器不应该将其 MD5 证书发送给这些客户端。
客户端(HttpClient)没有在signature_algorithms扩展中列出MD5,所以TLS 1.2握手失败。解决方法是使用安全的服务器证书。
【讨论】:
【参考方案2】:您不应该指定处理程序的SslProtocols
属性吗?
尝试在hander
定义之后添加这一行:
handler.SslProtocols = SslProtocols.Tls12;
【讨论】:
【参考方案3】:我相信这段代码总是盲目地返回 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;;
【讨论】:
首先感谢您的评论!但是,永远不会调用回调函数。我只是在函数中添加了一个带有断点和控制台写入调用的主体,但这些都没有被命中。 Ctznkane 实际上,即使在使用 tls 1.2 时没有调用它,但实际上在使用 tls 1.1 时会调用它并指定错误类型“System.Net.Security.SslPolicyErrors.RemoteCertificateChainErrors”。该方法返回 true,允许在 tls 1.1 中调用,但由于更高的安全标准,tls 1.2 可能根本不允许这样做?我最好的选择是找出为什么现在 tls 1.1 会出现链错误,然后修复错误并再次尝试使用 tls 1.2。我会带着结果回来的。 在为回调方法提供的对象中挖掘了一些之后,我在深处发现了这条消息:“证书链已处理,但在信任提供者不信任的根证书中终止。” - 我会专门去谷歌搜索这个错误。 您是从有效的公司购买证书还是自己制作证书...制作一个仅用于内部文件是可以的 这可能有助于解决第二个错误***.com/questions/11230091/…以上是关于C# 和 dotnet 4.7.1 没有为 TLS 1.2 调用添加自定义证书的主要内容,如果未能解决你的问题,请参考以下文章
DotNet Core:如何跨平台客户端证书 TLS 身份验证?
dotnet C# 字典 Dictionary 和 Hashtable 的性能对比