如何强制 WCF 客户端发送客户端证书?
Posted
技术标签:
【中文标题】如何强制 WCF 客户端发送客户端证书?【英文标题】:How to force WCF client to send client certificate? 【发布时间】:2011-05-04 16:59:40 【问题描述】:我正在尝试通过 https 访问公共托管的 SOAP Web 服务(不是 WCF),但我遇到了以前从未见过的错误。首先,这是事实:
此服务需要客户端证书。我的证书由与服务器证书相同的 CA 签名。 我知道该 URL 可用,因为我可以在 Internet Explorer 中点击它。 IE 弹出“选择证书”窗口,如果我选择它(并忽略 server-host-name-does-not-match-certificate 错误),它会继续并给我一个 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 协议方面的专家,因此我可能会丢失关于正在发生什么的线索。然而,这是我所看到的:
-
C -> S 客户端你好
包含随机数、日期/时间、支持的密码套件等内容
S -> C 服务器问候,证书,证书请求,服务器问候完成
包含服务器证书和客户端证书请求
C -> S 证书、客户端密钥交换、更改密码规范、加密握手消息
这里是有趣的部分 -- 这个数据包的第一部分是证书握手,我假设客户端证书应该是,但没有证书存在(证书长度:0)。
S -> C 警报(级别:致命,描述:错误证书)
嗯,是的,没有发送证书。
我的绑定设置如下:
<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 连接时拒绝发送证书?
【问题讨论】:
【参考方案1】:我解决了这个问题,但我不明白为什么这个配置更改修复了它。我改变了这一行:
<httpsTransport useDefaultWebProxy="false" />
到这里:
<httpsTransport useDefaultWebProxy="false" requireClientCertificate="true" />
神奇地它开始工作了。我知道requireClientCertificate
“旋钮”是用于服务器端的,所以我在争论期间没有尝试过。显然我错了。
【讨论】:
我非常讨厌 WCF。这个解决方案对我有用,非常感谢 - 但这一切都太繁琐了。现在杀了我。【参考方案2】:应该有来自服务器的 CertificateRequest,命名可接受的证书类型和 CA。如果您的证书与那些不匹配,则不会发送。
【讨论】:
有一个证书请求(参见 #2),它确实包含了 CA 和证书类型的列表。我确实有一个适当的证书,它是行为中指定的。 如果这一切都是真的,那么在服务器发出 CertificateRequest 之后就会有来自客户端的 Certificate 消息。不可避免的结论是,其中一些是不正确的。您需要仔细检查所有内容:具体而言,证书 (a) 对应用程序可用,并且 (b) 符合 CertificateRequest 中表达的所有约束。 这是可验证的真实...我这里有 WireShark 捕获。不过,我确实最终解决了这个问题,但我真的不明白为什么我所做的改变解决了它。我会在单独的答案中发布。 您确实收到了 CertificateRequest 消息并且您没有发送证书。这就是您上面的转储显示的内容。如果有客户端证书消息,它会在响应请求时出现。 是的,我就是这么说的。整个问题归结为“服务器请求了客户端证书,为什么 WCF 不发送一个?”【参考方案3】:协商使用哪种安全协议可能存在问题。特别是我认为服务器可能不喜欢 WCF 尝试使用 TLS 1.0。
要查看是否是这种情况,请尝试在调用服务之前添加以下内容
System.Net.ServicePointManager.SecurityProtocol = System.Net.SecurityProtocolType.Ssl3
这可以在客户端代码中添加,也可以通过将其放置在 IEndpointBehavior 中来添加
【讨论】:
我试过了,结果没有改变。我知道服务器支持 TLS 1.0(实际上只有一个特定的密码,但该密码在握手时发送到服务器的列表中)。 如果交换达到了 ChangeCipherSpec 消息,则不会。这意味着协议的所有内容都已达成一致。以上是关于如何强制 WCF 客户端发送客户端证书?的主要内容,如果未能解决你的问题,请参考以下文章