如何强制WCF客户端发送客户端证书?
我试图通过https访问一个公共托管的SOAP web服务(不是WCF),但我遇到了一个我以前从未见过的错误。首先,事实如下:如何强制WCF客户端发送客户端证书?,wcf,https,certificate,ssl,Wcf,Https,Certificate,Ssl,我试图通过https访问一个公共托管的SOAP web服务(不是WCF),但我遇到了一个我以前从未见过的错误。首先,事实如下: 此服务需要客户端证书。我有一个证书,该证书由与服务器证书相同的CA签署 我知道URL是可用的,因为我可以在Internet Explorer中点击它。IE打开“选择证书”窗口,如果我选中它(忽略服务器主机名与证书不匹配的错误),它将继续并给我一个HTTP 500错误 如果我在Chrome中打开站点,在选择证书并忽略错误后,我会收到一条关于WSA Action=null
- 此服务需要客户端证书。我有一个证书,该证书由与服务器证书相同的CA签署
- 我知道URL是可用的,因为我可以在Internet Explorer中点击它。IE打开“选择证书”窗口,如果我选中它(忽略服务器主机名与证书不匹配的错误),它将继续并给我一个HTTP 500错误
- 如果我在Chrome中打开站点,在选择证书并忽略错误后,我会收到一条关于WSA Action=null的正常错误消息
- 如果我在FireFox中打开站点,在忽略错误后,我会得到一个页面,说明服务器如何无法验证我的证书。它从来没有让我选一个,所以这很有道理
Error occurred while executing test 12302: System.ServiceModel.Security.SecurityNegotiationException: Could not establish secure channel for SSL/TLS with authority 'ihexds.nist.gov:9085'. ---> System.Net.WebException: The request was aborted: Could not create SSL/TLS secure channel.
at System.Net.HttpWebRequest.GetResponse()
at System.ServiceModel.Channels.HttpChannelFactory.HttpRequestChannel.HttpChannelRequest.WaitForReply(TimeSpan timeout)
我已经追踪了与WireShark的互动,但因为我不是TLS协议的专家,我可能会错过一些线索。然而,我看到的是:
- 包含诸如随机数、日期/时间、支持的密码套件等内容
- 包含服务器的证书和对客户端证书的请求
- 这里是有趣的部分——这个数据包的第一部分是证书握手,我假设客户端证书是,但是没有证书(证书长度:0)
- 嗯,是的,没有发送证书
<binding name="https_binding">
<textMessageEncoding />
<httpsTransport useDefaultWebProxy="false" />
</binding>
<behavior name="clientcred">
<clientCredentials>
<clientCertificate findValue="69b6fbbc615a20dc272a79caa201fe3f505664c3" storeLocation="CurrentUser" storeName="My" x509FindType="FindByThumbprint" />
<serviceCertificate>
<authentication certificateValidationMode="None" revocationMode="NoCheck" />
</serviceCertificate>
</clientCredentials>
<messageInspector />
</behavior>
我的行为设置如下:
<binding name="https_binding">
<textMessageEncoding />
<httpsTransport useDefaultWebProxy="false" />
</binding>
<behavior name="clientcred">
<clientCredentials>
<clientCertificate findValue="69b6fbbc615a20dc272a79caa201fe3f505664c3" storeLocation="CurrentUser" storeName="My" x509FindType="FindByThumbprint" />
<serviceCertificate>
<authentication certificateValidationMode="None" revocationMode="NoCheck" />
</serviceCertificate>
</clientCredentials>
<messageInspector />
</behavior>
我的端点设置为同时使用绑定和行为。为什么WCF在创建https连接时拒绝发送证书?在协商使用哪个安全协议时可能会出现问题。具体来说,我认为服务器可能不喜欢WCF尝试使用TLS1.0 要查看是否是这种情况,请在调用服务之前尝试添加以下内容
System.Net.ServicePointManager.SecurityProtocol = System.Net.SecurityProtocolType.Ssl3
这可以添加到客户端代码中,也可以将其放置在IEndpointBehavior中。应该有来自服务器的CertificateRequest,命名可接受的证书类型和CA。如果您的证书与这些证书不匹配,它将不会被发送。我解决了这个问题,但我不明白为什么此配置更改会修复它。我改变了这一行:
<httpsTransport useDefaultWebProxy="false" />
为此:
<httpsTransport useDefaultWebProxy="false" requireClientCertificate="true" />
神奇的是,它开始工作了。我知道,
requireClientCertificate
“旋钮”是服务器端的,所以在争吵期间我没有试过。显然我错了。有一个证书请求(请参见#2),它确实包含CA和证书类型的列表。我确实有一个合适的证书,它是行为中指定的证书。如果所有这些都是真的,那么在服务器发出CertificateRequest之后,客户端就会发出一条证书消息。不可避免的结论是,其中一些是不真实的。您需要仔细检查所有内容:具体来说,证书(a)对应用程序可用,并且(b)符合CertificateRequest中表示的所有约束。这是可验证的事实。。。我在这里抓到了线鲨。虽然我最终解决了这个问题,但我真的不明白为什么我改变了它。我会在一个单独的答案中发布它。你确实收到了CertificateRequest消息,并且没有发送证书。这就是你上面的垃圾堆所显示的。如果有一个客户端证书消息,它就会出现在对请求的响应中。是的,我就是这么说的。整个问题归结为,“服务器请求了一个客户端证书,为什么WCF不发送一个?”我尝试了这个,结果没有改变。我知道服务器支持TLS 1.0(事实上,只有一个特定的密码,但该密码在握手时发送给服务器的列表中)。如果exchange收到ChangeCipherSpec消息,则不支持。这意味着协议的所有内容都已达成一致。我非常讨厌WCF。这个解决方案对我来说很有效,谢谢你——但它太复杂了。现在杀了我。