TLS 致命:握手失败

Posted

技术标签:

【中文标题】TLS 致命:握手失败【英文标题】:TLS Fatal: Handshake Failure 【发布时间】:2019-12-16 04:44:58 【问题描述】:

我需要连接外部服务,但客户端身份验证有问题。该服务在请求时需要证书、用户名和密码。

我使用的是 Windows Server 2008 R2。

我已收到带有证书的 PKCS#7 包并已导入:

本地计算机/个人的 SSL 证书(只有公钥) Lo​​calComputer/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 时,为啥会出现握手失败?

PHP握手失败TLS1.0

TLS 握手失败,CurrentUser 工作,而 LocalMachine 不工作

收到致命警报:与 Tomcat 的握手失败

最近的 Java 升级导致椭圆曲线服务器证书的 TLS 握手失败?

与 SSL 的 mysql jdbc 连接在 tls 握手级别失败