仅在 .Net 中证书身份验证失败并出现 SSL 错误

Certificate Authentication fails with SSL error in .Net only

我正在尝试使用相互证书身份验证与外部网站通信,但收到 "Could not establish secure channel for SSL/TLS with authority" 异常。我已将其缩小为以下片段(删除了敏感内容):

void Example() 
{
                string KeyIdentifier = "<MyKeyId>";

                X509Store store = new X509Store("My", StoreLocation.LocalMachine);
                store.Open(OpenFlags.ReadOnly);

                X509Certificate2Collection certificates = store.Certificates.Find(X509FindType.FindByThumbprint, KeyIdentifier, true);
                X509Certificate2 certificate = certificates[0];

                HttpWebRequest r = (HttpWebRequest)HttpWebRequest.Create("https://www.example.org");
                r.ClientCertificates.Add( certificate);

                r.Accept = "text/xml";
                r.Method = WebRequestMethods.Http.Post;

                string result = null;
                using (HttpWebResponse resp = (HttpWebResponse)r.GetResponse())
                {
                    StreamReader reader = new StreamReader(resp.GetResponseStream());
                    result = reader.ReadToEnd();
                }
}

我已经正确设置了证书等,此代码成功找到它们,certificate.HasPrivateKey=true,但失败了。 SoapUI 愉快地与 TLS 连接。 Chrome访问该网站时报告没有证书错误。但是,上面的代码总是抛出异常。我已经尝试了所有 3 个 TLS 版本,但都没有成功。使用 ServicePointManager 跳过服务器证书验证没有任何区别。

奇怪的是,如果我指定 SSL3

ServicePointManager.SecurityProtocol = SecurityProtocolType.Ssl3;

然后该过程成功完成,但自然我不想使用 SSL3。该应用程序是 Server 2012 上的 .Net 4.6 运行。

经过几个月和更多的断断续续的挖掘,我最终尝试使用 SSLStream 建立连接,得到了一个不同的异常,并找到了这个答案:

建议您添加以下注册表项: [HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\KeyExchangeAlgorithms\Diffie-Hellman] "ClientMinKeyBitLength"=dword:00000200

这会将 Diffie-Hellman 的最小密钥长度切换为 512 位。这个最小值是在 Windows 更新到 1024 位时提高的,以尝试减轻 logjam 攻击,所以在设置这个值时要小心,因为它是系统范围的,可能会打开针对你的系统的攻击向量。