使用自创建证书的WCF SecurityTokenValidationException

时间:2019-07-18 10:35:43

标签: c# vb.net wcf certificate

我使用自行创建的证书遇到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.'

1 个答案:

答案 0 :(得分:0)

无论如何,无论我们是否在服务器端指定身份验证模式,在使用证书对客户端进行身份验证时都应在服务器与客户端之间建立信任关系。
即,我们应该在客户端安装服务器证书,并在服务器端安装客户端证书。根据身份验证模式的值,证书的安装位置有所不同,通常应将其安装在本地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();

}

结果。
enter image description here
必须注意的另一件事是,我们应确保客户端证书具有预期的客户端身份验证。
enter image description here

请随时告诉我是否有什么可以帮忙的。