使用WCF进行相互SSL身份验证:握手阶段没有CertificateRequest和CertificateVerify

Mar*_* N. 23 ssl wcf wcf-binding wcf-security

我正在开发一个WCF服务,该服务将由我不开发的客户端使用,而且它不是.NET(可能是Java).

在任何情况下,该服务都应支持相互SSL身份验证,其中服务和客户端都在传输层使用证书X.509证书进行身份验证.证书已在之前的各方之间进行了交换.

我的问题是我似乎无法获得正确的WCF配置,以便客户端证书身份验证正常工作.我期望的是,作为TLS握手的一部分,服务器还包括一个Certificate Request,如下所示:

在此输入图像描述

在此之后,客户应该回答"证书验证"等问题:

在此输入图像描述

(最新)服务配置就是这个.我正在使用自定义绑定,身份验证模式设置为MutualSslNegotiated.

<bindings>
  <customBinding>
    <binding name="CarShareSecureHttpBindingCustom">
      <textMessageEncoding messageVersion="Soap11" />
      <security authenticationMode="MutualSslNegotiated"/>
      <httpsTransport requireClientCertificate="true" />
    </binding>
  </customBinding>
</bindings>

...

<serviceBehaviors>
  <behavior name="ServiceBehavior">
    <serviceMetadata httpGetEnabled="false" httpsGetEnabled="true" />
    <serviceDebug includeExceptionDetailInFaults="false" httpHelpPageEnabled="false" />
    <serviceCredentials>
      <serviceCertificate findValue="..." storeLocation="LocalMachine" x509FindType="FindByIssuerName" storeName="My" />
      <clientCertificate>
        <certificate findValue="..." storeName="My" storeLocation="LocalMachine" x509FindType="FindByIssuerName"/>
      </clientCertificate>
    </serviceCredentials>
  </behavior>
</serviceBehaviors>
Run Code Online (Sandbox Code Playgroud)

对于我尝试过的所有服务配置,握手的Server Hello部分都是这样的,没有CertificateRequest. 在此输入图像描述

其他我应该提到的事情:

  • 该服务是自托管的,并且在非默认端口(而不是443)上侦听.服务器SSL证书已绑定到此端口.
  • 我也尝试过将a basicHttpBinding和a wsHttpBidning安全模式设置为Transport和客户端身份验证设置为Certificate,没有结果(实际上是相同的结果).

任何想法,将不胜感激.

Mar*_* N. 13

好的,经过几次尝试后我才明白了.如果其他人遇到同样的问题,请发布此信息.

我应该继续提到这个行为确实需要在MSDN上的某个地方提及,这个位置对于任何寻找WCF安全信息并且没有埋藏在某些工具文档中的人来说是真正可见的.

我能够重现并修复此问题的平台:Windows 8.1 x64和Windows Server 2008 R2 Standard.

正如我所提到的,我的问题是我无法配置WCF安全性,因此该服务需要客户端证书.我在寻找解决方案时注意到的常见混淆是,许多人认为客户端可以发送证书(如果有的话),不会受到质疑.这是当然,情况并非如此-服务器需要先提出要求,而且,指定哪些CA被允许通过一个CertificateRequest答复.

总而言之,我的情况是:

  • 服务是自托管的.
  • 服务在HTTPS上运行,在非标准端口(不是443但是9000)上运行.

这意味着我必须使用为端口9000创建SSL证书绑定netsh.exe http add sslcert.好吧,绑定已经创建,但有一个问题.我只是在运行netsh http show sslcert检查我的绑定后才发现问题:

 IP:port                      : 0.0.0.0:9000
 Certificate Hash             : ...
 Application ID               : ...
 Certificate Store Name       : MY
 Verify Client Certificate Revocation : Enabled
 Verify Revocation Using Cached Client Certificate Only : Disabled
 Usage Check                  : Enabled
 Revocation Freshness Time    : 0
 URL Retrieval Timeout        : 0
 Ctl Identifier               : (null)
 Ctl Store Name               : (null)
 DS Mapper Usage              : Disabled
 -->Negotiate Client Certificate : Disabled
Run Code Online (Sandbox Code Playgroud)

罪魁祸首是绑定的最后一个属性,"谈判客户证书",在此记录.显然,默认情况下,此属性已禁用.您需要在创建绑定时显式启用它.

使用以下语句重新创建绑定解决了以下问题:

netsh.exe http add sslcert ipport=0.0.0.0:9000 certhash=... appid=... certstorename=MY verifyclientcertrevocation=Enable VerifyRevocationWithCachedClientCertOnly=Disable UsageCheck=Enable clientcertnegotiation=Enable
Run Code Online (Sandbox Code Playgroud)

在检查绑定之前,我尝试在IIS中托管一个简单的WCF服务,并从那里启用客户端证书身份验证.很遗憾看到虽然CertificateRequestIIS 没有发布,但仍然失败了403.7.甚至IIS也没有使用适当的参数创建绑定.

无论如何,现在它工作,这是你如何解决它.

不要忘记,服务配置也发生了变化(绑定安全性),以便允许证书协商:

<customBinding>
  <binding name="CustomHttpBindingCustom" receiveTimeout="01:00:00">
    <textMessageEncoding messageVersion="Soap11" />
    <security authenticationMode="SecureConversation" requireSecurityContextCancellation="true">
      <secureConversationBootstrap allowInsecureTransport="false" authenticationMode="MutualSslNegotiated" requireSecurityContextCancellation="true"></secureConversationBootstrap>
    </security>
    <httpsTransport requireClientCertificate="true" />
  </binding>
</customBinding>
Run Code Online (Sandbox Code Playgroud)