如何强制WCF客户端发送客户端证书?

13

我正在尝试通过https访问一个公共托管的SOAP Web服务(不是WCF),但我遇到了一个以前从未见过的错误。以下是事实:

  • 此服务需要客户端证书。我有一个由与服务器证书签名相同的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协议方面的专家,可能会错过一些提示。然而,以下是我看到的:

  1. C -> S 客户端Hello
    • 包含随机数、日期/时间、支持的加密套件等内容
  2. S -> C 服务器Hello、证书、证书请求、服务器Hello Done
    • 包含服务器的证书和对客户端证书的请求
  3. C -> S 证书、客户端密钥交换、更改密码规范、加密握手消息
    • 这里是有趣的部分-- 这个数据包的第一部分是证书握手,我假设客户端证书应该在其中,但没有证书出现(证书长度:0)。
  4. 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 连接时,拒绝发送证书?

3个回答

10

我已经解决了这个问题,但我不明白为什么这个配置更改可以修复它。 我更改了这行代码:

<httpsTransport useDefaultWebProxy="false" />

到这个:

<httpsTransport useDefaultWebProxy="false" requireClientCertificate="true" />

神奇的是它开始工作了。我原本以为 requireClientCertificate 这个 "旋钮" 是用在服务器端的,所以我在处理过程中没有尝试过它。显然,我错了。


2
我非常讨厌WCF。这个解决方案对我很有用,非常感谢 - 但是所有这些都很琐碎。现在就杀了我吧。 - robnick

2

服务器应该发送一个证书请求,命名可接受的证书类型和CA。如果您的证书不符合这些要求,则不会被发送。


如果所有这些都是真的,那么在服务器发送证书请求后,客户端应该会收到一个证书消息。不可避免的结论是其中一些不是真的。您需要仔细检查所有内容:特别是证书是否(a)对应用程序可用,并且(b)符合证书请求中表达的所有约束条件。 - user207421
可以明确的是,您收到了CertificateRequest消息,并且没有发送证书。这就是上面显示的转储内容。如果有客户端证书消息,它将会作为响应出现。 - user207421
是的,这就是我说的。整个问题归结为,“服务器请求客户端证书,为什么WCF没有发送证书?” - Mark
@Mark 答案已经在我回答的最后一句话和我的第一个评论中给出。 - user207421
答案是我六年半前写下并接受的那个。 - Mark
显示剩余2条评论

0

可能存在一个协商使用哪个安全协议的问题。具体而言,我认为服务器可能不喜欢WCF尝试使用TLS 1.0。

要查看是否是这种情况,请在调用服务之前尝试添加以下内容

System.Net.ServicePointManager.SecurityProtocol = System.Net.SecurityProtocolType.Ssl3

这可以通过在客户端代码中添加或将其放置在IEndpointBehavior中来实现


我尝试过这个,但结果并没有改变。我确实知道服务器支持TLS 1.0(实际上只支持一种特定的密码),但该密码在握手时发送到服务器的列表中。 - Mark
您IP地址为143.198.54.68,由于运营成本限制,当前对于免费用户的使用频率限制为每个IP每72小时10次对话,如需解除限制,请点击左下角设置图标按钮(手机用户先点击左上角菜单按钮)。 - user207421

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接