【问题标题】:WCF SecurityTokenValidationException using self-created certificate使用自创证书的 WCF SecurityTokenValidationException
【发布时间】:2019-11-27 06:36:06
【问题描述】:

我在使用自行创建的证书进行 WCF 客户端连接时遇到问题。

证书创建如下:

Makecert -r -pe -n "CN=MySslSocketCertificate" -b 01/01/2015 -e 01/01/2025 -sk exchange -ss my

服务器代码:

Public Sub StartWcfServer()
    Dim binding As New NetTcpBinding()

    binding.Security.Mode = SecurityMode.Transport
    binding.Security.Transport.ProtectionLevel = Net.Security.ProtectionLevel.EncryptAndSign
    binding.Security.Transport.ClientCredentialType = TcpClientCredentialType.Certificate
    binding.TransferMode = TransferMode.Streamed
    Dim baseAddress As New Uri($"net.tcp://192.168.1.1:1234/WcfServer")

    _serviceHost = New ServiceHost(GetType(WcfServer), baseAddress)
    _serviceHost.Credentials.ServiceCertificate.SetCertificate(StoreLocation.CurrentUser, StoreName.My, X509FindType.FindByIssuerName, "MySslSocketCertificate")
    _serviceHost.Credentials.ClientCertificate.Authentication.RevocationMode = X509RevocationMode.NoCheck
    _serviceHost.Credentials.ClientCertificate.Authentication.CertificateValidationMode = ServiceModel.Security.X509CertificateValidationMode.None
    _serviceHost.Credentials.ClientCertificate.Authentication.TrustedStoreLocation = StoreLocation.CurrentUser

    ServicePointManager.ServerCertificateValidationCallback = New RemoteCertificateValidationCallback(AddressOf ValidateServerCertificate)
    ServicePointManager.SecurityProtocol = SecurityProtocolType.Ssl3 Or SecurityProtocolType.Tls12

    _serviceHost.AddServiceEndpoint(GetType(IWcfServer), binding, baseAddress)
    _serviceHost.Open()
End Sub

Private Function ValidateServerCertificate(sender As Object, certificate As X509Certificate, chain As X509Chain, sslPolicyErrors As SslPolicyErrors) As Boolean
    Return True
End Function

客户端代码:

private void InitialiseWcfClient()
{
    var binding = new NetTcpBinding();
    binding.Security.Mode = SecurityMode.Transport;
    binding.Security.Transport.ProtectionLevel = System.Net.Security.ProtectionLevel.EncryptAndSign;
    binding.Security.Transport.ClientCredentialType = TcpClientCredentialType.None;
    binding.TransferMode = TransferMode.Streamed;

    var url = $"net.tcp://192.168.1.1:1234/WcfServer";
    var address = new EndpointAddress(url);
    var channelFactory = new ChannelFactory<IWcfServer>(binding, address);

    WcfServer = channelFactory.CreateChannel();
}

// call to server which causes the error
WcfServer.CallMethod();

客户端错误:

System.IdentityModel.Tokens.SecurityTokenValidationException: 'The X.509 certificate CN=MySslSocketCertificate chain building failed. The certificate that was used has a trust chain that cannot be verified. Replace the certificate or change the certificateValidationMode. A certificate chain processed, but terminated in a root certificate which is not trusted by the trust provider.

服务器端错误:

System.Security.Authentication.AuthenticationException: 'The remote certificate is invalid according to the validation procedure.'

【问题讨论】:

  • ....应该在某处有设置
  • @Stefan 这是一个非常笼统的评论 :-)
  • 是的,我不知道它在我的头顶......并且没有将它与 WCF 一起使用,但实际上所有其他库都允许您定义 TSL 上的安全级别,或者排除一些例外......这就是我所知道的,但我认为WCF中会有类似的东西。 :-/
  • 你可以通过制作一个看起来更合适的客户端证书来解决你的问题(在你的 makecert 命令中添加-eku 1.3.6.1.5.5.7.3.2)。不过,这可能还不够。

标签: c# vb.net wcf certificate


【解决方案1】:

兄弟,不管我们是否在服务器端指定了Authencation模式,在用证书对客户端进行认证时,我们都应该建立服务器和客户端之间的信任关系。
即我们应该在客户端安装服务器证书,在服务器端安装客户端证书。根据认证模式值不同,证书的安装位置也不同,一般我们应该安装在Local CA中。此外,考虑到一些访问权限问题,我们最好将证书安装在当前用户以外的本地机器存储位置。
另外,当我们明确指定传输的安全模式时,我们应该在服务器端提供一个证书。

sh.Credentials.ServiceCertificate.SetCertificate(StoreLocation.LocalMachine, StoreName.My, X509FindType.FindByThumbprint, "cbc81f77ed01a9784a12483030ccd497f01be71c");

同时,客户端应该提供一个证书来代表身份。

factory.Credentials.ClientCertificate.SetCertificate(StoreLocation.LocalMachine, StoreName.My, X509FindType.FindByThumbprint, "9ee8be61d875bd6e1108c98b590386d0a489a9ca");

我做了一个演示,希望对你有帮助。
服务器。

 class Program
{
    static void Main(string[] args)
    {
        using (ServiceHost sh = new ServiceHost(typeof(MyService)))
        {
            sh.Credentials.ServiceCertificate.SetCertificate(StoreLocation.LocalMachine, StoreName.My, X509FindType.FindByThumbprint, "cbc81f77ed01a9784a12483030ccd497f01be71c");
            sh.Open();
            Console.WriteLine("serivce is ready....");
            Console.ReadLine();
            sh.Close();
        }
    }
}
[ServiceContract]
public interface IService
{
    [OperationContract]
    string Test();

}
public class MyService : IService
{

    public string Test()
    {
        return DateTime.Now.ToString();
    }
}

App.config(服务器端)

<system.serviceModel>
  <services>
    <service name="VM1.MyService">
      <endpoint address="" binding="netTcpBinding" contract="VM1.IService" bindingConfiguration="mybinding">
      </endpoint>
      <endpoint address="mex" binding="mexTcpBinding" contract="IMetadataExchange" ></endpoint>
      <host>
        <baseAddresses>
          <add baseAddress="net.tcp://localhost:5566"/>
        </baseAddresses>
      </host>
    </service>
  </services>
  <bindings>
    <netTcpBinding>
      <binding name="mybinding">
        <security mode="Transport">
          <transport clientCredentialType="Certificate"></transport>
        </security>
      </binding>
    </netTcpBinding>
  </bindings>
  <behaviors>
    <serviceBehaviors>
      <behavior>
        <serviceMetadata />
      </behavior>
    </serviceBehaviors>
  </behaviors>
</system.serviceModel>

客户。

class Program
{
    static void Main(string[] args)
    {

        Uri uri = new Uri("net.tcp://vabqia969vm:5566");
        NetTcpBinding binding = new NetTcpBinding();
        binding.Security.Mode = SecurityMode.Transport;
        binding.Security.Transport.ClientCredentialType = TcpClientCredentialType.Certificate;
        ChannelFactory<IService> factory = new ChannelFactory<IService>(binding, new EndpointAddress(uri));
        factory.Credentials.ClientCertificate.SetCertificate(StoreLocation.LocalMachine, StoreName.My, X509FindType.FindByThumbprint, "9ee8be61d875bd6e1108c98b590386d0a489a9ca");
        IService service = factory.CreateChannel();
        try
        {
            var result = service.Test();
            Console.WriteLine(result);
        }
        catch (Exception)
        {

            throw;
        }


    }

}
[ServiceContract]
public interface IService
{
    [OperationContract]
    string Test();

}

结果。

还有一点需要注意,我们应该确保客户端证书有客户端认证的目的。

如果有什么我可以帮忙的,请随时告诉我。

【讨论】:

    猜你喜欢
    • 2014-02-15
    • 2013-01-14
    • 1970-01-01
    • 1970-01-01
    • 2011-11-10
    • 2019-12-07
    • 1970-01-01
    • 2011-01-18
    • 2015-05-27
    相关资源
    最近更新 更多