TLS 致命:握手失败
Posted
技术标签:
【中文标题】TLS 致命:握手失败【英文标题】:TLS Fatal: Handshake Failure 【发布时间】:2019-12-16 04:44:58 【问题描述】:我需要连接外部服务,但客户端身份验证有问题。该服务在请求时需要证书、用户名和密码。
我使用的是 Windows Server 2008 R2。
我已收到带有证书的 PKCS#7 包并已导入:
本地计算机/个人的 SSL 证书(只有公钥) LocalComputer/TrustedRootCertificationAuthorities 的中间 CA 和根 CA我已在 Windows Register 中启用了 TLS 1.0、1.1、1.2 客户端: Windows Register
我正在尝试使用 WCF 客户端和 Web 浏览器(IE 和 Chrome)连接到服务器。
WCF 客户端 (.NET 4.6.1):
App.config:
<bindings>
<wsHttpBinding>
<binding name="WSHttpBinding_ICalculator" >
<security mode="Transport">
<transport clientCredentialType="Certificate" />
</security>
</binding>
</wsHttpBinding>
</bindings>
<behaviors>
<endpointBehaviors>
<behavior name="endpointCredentialBehavior">
<clientCredentials>
<clientCertificate findValue="<thumbprint>"
storeLocation="LocalMachine"
storeName="My"
x509FindType="FindByThumbprint" />
</clientCredentials>
</behavior>
</endpointBehaviors>
</behaviors>
Program.cs:
ServicePointManager.Expect100Continue = true;
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls
| SecurityProtocolType.Tls11
| SecurityProtocolType.Tls12;
using (var client = new ServiceClient())
client.ClientCredentials.UserName.UserName = "username";
client.ClientCredentials.UserName.Password = "pwd";
client.Open();
var response = client.DoSth();
我得到一个错误:
“无法为具有权限的 SSL/TLS 建立安全通道......”。
Internet Explorer 显示: IE error
Chrome 显示: Chrome error
我也尝试通过 Wireshark 对其进行调试。对我来说,怀疑来自客户端的“证书”消息不包含任何证书(既不使用 WCF 客户端也不使用 Web 浏览器)。是否应该在此处添加证书,如果是,可能会导致什么问题?
Wireshark packages
我知道在 *** 和 Google 上有很多关于 TLS 和身份验证的文章,但是我浏览了很多,但没有找到任何关于我做错了什么的信息。
【问题讨论】:
您确定ServiceClient
使用的是配置文件中的设置吗?从 .Net 4.5 开始,WCF 非常擅长假装一切正常,但很高兴地忽略了您的配置设置。启用 WCF 跟踪和日志记录以查看是否加载了任何配置。请使用详细日志记录。
@rene 我能够检查客户端的对象,我看到它包含从配置文件加载的信息,因此绑定和 clientCredentials。我想知道为什么网络浏览器无法访问服务或 ?wsdl 信息。
【参考方案1】:
我们最好不要指定 TLS 版本,配置你的代码让操作系统决定。通信中使用的具体 TLS 版本将由服务器和客户端环境共同决定。https://docs.microsoft.com/en-us/dotnet/framework/network-programming/tls 传输安全模式要求服务器和客户端在通信前建立信任关系。 在我看来,这个错误通常表明客户端没有正确安装服务器证书。https://docs.microsoft.com/en-us/dotnet/framework/wcf/feature-details/transport-security-with-certificate-authentication 只有服务端添加Servicemetadata行为,我们才能访问服务定义(WSDL)。 通常客户端提供的证书足以表明其身份,无需再次提供用户名/密码。就像生成的客户端配置一样,我们只需要提供一个证书。服务具体是怎么调用的,我们要知道服务器的配置或者WSDL文件。 如果有什么可以帮助的,请随时告诉我。
【讨论】:
你能扩展一下关于那个客户端没有正确安装服务器证书的话题吗?如何正确安装它们或验证它们?正如我在问题中提到的: > 我已经收到带有证书的 PKCS#7 包并导入: > SSL 证书(只有公钥)到 LocalComputer/Personal > 中间 CA 和根 CA 到 LocalComputer/TrustedRootCertificationAuthorities。我应该额外做某事吗?我还检查了第二个链接,我的代码看起来非常相似。唯一的区别是我使用带有证书的“FindByThumbprint”。 对于存储在客户端Local Machine中的客户端证书,请将Everyone帐户添加到可以管理私有证书的用户组中。对于我们只有公钥的服务器证书,我们最好将它安装在本地机器/RootCA中。必须注意的另一件事是客户端证书应该受到服务器的信任。所以当我们提供客户端证书时,我们应该确保证书已经安装在服务器RootCA中。以上是关于TLS 致命:握手失败的主要内容,如果未能解决你的问题,请参考以下文章
尝试使用此代码在 TLS 上运行 TLS 时,为啥会出现握手失败?
TLS 握手失败,CurrentUser 工作,而 LocalMachine 不工作