2

WCF 异常 - 未提供客户端证书。在 ClientCredentials 中指定客户端证书。

在阅读了我能找到的关于这个主题的大部分内容并尝试了许多不同的选择之后,我发现我没有更多的头发可以拉,因此这篇文章。

我希望将 SSL 与自托管的 WCF 服务一起使用,安全模式为 TransportWithMessageCredential 和 HTTP 传输。我正在使用 2 台开发机器并通过 LAN 进行测试。

如上所述,我已经阅读并仔细遵循了几乎所有证明这一点的示例,但不知何故仍然存在证书问题。

就证书而言,我尝试了很多方法。

我所做的主要工作是遵循 http://msdn.microsoft.com/en-us/library/ff647171.aspx中给出的内容

我还使用http://msdn.microsoft.com/en-us/library/ff648360.aspx中的“如何:在从 Windows 窗体调用 WCF 中使用证书身份验证和消息安全” 作为基本指南。

我首先使用基于 Http 的 basicHttpBinding 测试了服务和客户端,以进行验证。

然后,我对 wsHttpBinding、SSL 和证书进行了更改。

当我在客户端开发 PC 上“添加服务引用”时,我收到如下错误:

  • 窗口标题 -

安全警报

Visual Studio 检测到站点的安全证书存在问题。

颁发者: RootCATest 颁发者: TempCert 证书有效期从---

公司颁发的安全证书不在不信任列表中。它可能是值得信赖的。

安全证书日期有效。

主机“TempCert”的安全证书与您尝试查看的页面名称不匹配。

  • 你想继续吗?-

如果我单击“是”继续并运行客户端代码,则会发生 InvalidOperationException 并显示以下消息。

“未提供客户证书。在 ClientCredentials 中指定客户端证书。”</p>

服务配置如下:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
    <system.serviceModel>
        <behaviors>
            <serviceBehaviors>
                <behavior name="ServiceBehavior">
                    <serviceMetadata httpGetEnabled="false" httpsGetEnabled="true" />
                    <serviceDebug includeExceptionDetailInFaults="true" />
                    <serviceCredentials>
                        <serviceCertificate findValue="CN=TempCert" 
                                            storeLocation="LocalMachine"
                                            storeName="My" />
                    </serviceCredentials>
                </behavior>
            </serviceBehaviors>
        </behaviors>
        <bindings>
          <wsHttpBinding>
            <binding name="wsHttpEndpointBinding">
              <security mode="TransportWithMessageCredential">
                <message clientCredentialType="Certificate" />
              </security>
            </binding>
          </wsHttpBinding>
        </bindings>      
        <services>
            <service name="SBSWCFServiceHost.Operations" 
                     behaviorConfiguration="ServiceBehavior">
                <endpoint name="wsHttpEndpoint"
                          address=""
                          binding="wsHttpBinding"
                          bindingConfiguration="wsHttpEndpointBinding"
                          contract="SBSWCFServiceHost.IOperations" >
                    <identity>
                        <dns value="localhost" />
                    </identity>
                </endpoint>                          
                <endpoint name="mexHttpEndpoint"
                          address="mex"
                          binding="mexHttpsBinding"
                          contract="IMetadataExchange" >
                </endpoint>
                <host>
                    <baseAddresses>
                        <add baseAddress="https://10.0.0.103:8003/SBSWCFServiceHost/Operations/" />
                    </baseAddresses>
                </host>
            </service>
        </services>
    </system.serviceModel>
</configuration>

客户端配置如下:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
    <system.serviceModel>
        <behaviors>
            <endpointBehaviors>
                <behavior name="EndpointBehavior">
                    <clientCredentials>
                        <clientCertificate storeLocation="LocalMachine"
                                           storeName="My"
                                           x509FindType="FindByThumbprint"
                                           findValue="e4c87a961f796be6b6cab59c3760e43ffb6e941d"/>
                    </clientCredentials>
              </behavior>
            </endpointBehaviors>
        </behaviors>      
        <bindings>
            <wsHttpBinding>
                <binding name="wsHttpEndpoint" closeTimeout="00:01:00" openTimeout="00:01:00"
                    receiveTimeout="00:10:00" sendTimeout="00:01:00" bypassProxyOnLocal="false"
                    transactionFlow="false" hostNameComparisonMode="StrongWildcard"
                    maxBufferPoolSize="524288" maxReceivedMessageSize="65536"
                    messageEncoding="Text" textEncoding="utf-8" useDefaultWebProxy="true"
                    allowCookies="false">
                    <readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384"
                        maxBytesPerRead="4096" maxNameTableCharCount="16384" />
                    <reliableSession ordered="true" inactivityTimeout="00:10:00"
                        enabled="false" />
                    <security mode="TransportWithMessageCredential">
                        <transport clientCredentialType="None" proxyCredentialType="None"
                            realm="" />
                        <message clientCredentialType="Certificate" negotiateServiceCredential="true"
                            algorithmSuite="Default" />
                    </security>
                </binding>
            </wsHttpBinding>
        </bindings>
        <client>
          <endpoint address="https://10.0.0.103:8003/SBSWCFServiceHost/Operations/"
              binding="wsHttpBinding" bindingConfiguration="wsHttpEndpoint"
              contract="SBSWCFService.IOperations" name="wsHttpEndpoint">
              <identity>
                  <dns value="localhost" />
              </identity>
          </endpoint>
        </client>
    </system.serviceModel>
</configuration>

以下是根据大量帖子和文档的内容对我执行的任务进行的总结。

  1. 在服务器上创建了一个自签名 CA 证书(名为 RootCATest),并将其放置在本地计算机的 Trusted Root Certification Authorities Certificates 文件夹中。

  2. 在服务器上创建了一个由 RootCATest 证书(名为 TempCert)签名的证书,并将其放在本地计算机的 Personal Certificates 文件夹中。

  3. 导出了 TempCert 证书和私钥。

  4. 将 TempCert .cer 和 .pvk 文件复制到客户端计算机,并将 TempCert 证书导入本地计算机的 Personal Certificates 文件夹。

  5. 在服务器机器上执行 ICalcs.exe [private key path] /grant "NT AUTHORITY\NETWORK SERVICE":R,使用 TempCert 证书的私钥路径。

  6. 在服务器机器上执行 netsh http add sslcert ipport=oooo:8003 certash=[TempCert thumbprint] appid=[{application id}]

我相信我已经接近完成这项工作。

很明显,该应用程序对 TempCert 证书不满意,但我无法解决这个问题,并且几乎被卡住了。

对于给定配置中的任何问题、我为放置正确证书而执行的步骤以及用于添加访问权限和 sslcert 条目的步骤提供任何帮助,我们将不胜感激。

非常感谢。

经过一些进一步的实验,我注意到了其他行为。

采取的步骤如下:

我删除了客户端和服务器证书,并根据 ....codeproject.com/Articles/36683/9-simple-steps-to-enable-x-509-certificates-on-wcf 重新创建了它们

我使用 netsh 添加了新的 sslcert。然后我从服务器导出客户端证书并将其导入客户端存储。

我用新的证书信息修改了服务 app.config,并启动了服务。

我修改了客户端 app.config 如下:

<endpointBehaviors>
  <behavior name="EndpointBehavior">
    <clientCredentials>
      <clientCertificate storeLocation="LocalMachine" storeName="My"  x509FindType="FindBySubjectName" findValue="WCFClient" />
      <serviceCertificate>
        <authentication certificateValidationMode="PeerTrust" />
      </serviceCertificate>
    </clientCredentials>
  </behavior>
</endpointBehaviors>

我更新了服务参考。更新程序再次像以前一样发出安全警报。

然后我执行了客户端,并收到了这个错误:

“未提供客户端证书。在 ClientCredentials 中指定客户端证书。”

然后我在“client = new WCFService.Client();”上设置了一个断点 并检查了“客户端”实例。client.ClientCredentials.ClientCertificate.Certificate 的值 = null。

然后我在“client = new WCFService.Client();”之后的代码中添加了以下内容:

X509Store store = new X509Store("My", StoreLocation.LocalMachine);
store.Open(OpenFlags.ReadOnly | OpenFlags.OpenExistingOnly);
X509Certificate2Collection collection = (X509Certificate2Collection) store.Certificates;
foreach (X509Certificate2 x509 in collection)
{
if (x509.Thumbprint == "236D7D4AD95753B8F22D3781D61AACB45518E1B5")
{
    client.ClientCredentials.ClientCertificate.SetCertificate(
        x509.SubjectName.Name, store.Location, StoreName.My);
}
}

执行此代码后,client.ClientCredentials.ClientCertificate.Certificate 包含证书。

然后执行“client.Open();”时 ,抛出异常,内容如下。

基础连接已关闭:无法为 SSL/TLS 安全通道建立信任关系。根据验证程序,远程证书无效。无法为具有权限的 SSL/TLS 安全通道建立信任关系

如果任何了解这里可能发生的事情的人都可以对此有所了解,我将不胜感激。

4

2 回答 2

1

最后一条错误信息表明您的服务器正在向客户端请求客户端证书(服务器必须要求),并且客户端正在提供证书,但服务器无法根据可用信息确定客户端证书是否有效在服务器机器上。

由于您使用的是自签名证书(不是 CA 颁发的证书),因此您需要告诉服务器如何验证客户端证书。您可能需要在服务器的 My/LocalMachine/Trusted People 证书存储中安装客户端证书,以便 WCF 的默认证书验证可以找到它们,或者在服务器上实现您自己的自定义客户端证书验证器。(见WebHttpBinding.Credentials.ClientCertificate.Authentication.CertificateValidationModeWebHttpBinding.Credentials.ClientCertificate.Authentication.CustomCertificateValidator

于 2013-09-06T21:33:52.853 回答
1

我确实注意到在你的endpoint定义中,你没有提到behavior你定义的那个。看起来好像您正在通过一些代码手动执行等效操作。在配置中连接它可能更简单。

我希望您的端点看起来(更多)像这样:

      <endpoint address="https://10.0.0.103:8003/SBSWCFServiceHost/Operations/"
          binding="wsHttpBinding" bindingConfiguration="wsHttpEndpoint"
          contract="SBSWCFService.IOperations" name="wsHttpEndpoint"
          behaviorConfiguration="EndpointBehavior">
          <identity>
              <dns value="localhost" />
          </identity>
      </endpoint>

这是解决方案,当我收到错误“未提供客户端证书。在 ClientCredentials 中指定客户端证书”时。

于 2015-10-07T14:17:48.690 回答