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#中的公钥RSA加密

dotnet C# 字典 Dictionary 和 Hashtable 的性能对比

C# DotNet Core Razor 页面,从 pageModel 为 createdModel 赋值

贝宝 C# 商人-SDK-dotnet

从另一个 C# DotNet DLL 动态加载和调用 C# DotNet DLL