2014-09-04 55 views
4

在我的WCF自托管WebService使用相互证书来验证客户端,我设置CertificateValidationMode = PeerTrust,但它似乎被忽略,因为我仍然可以执行某些客户端的方法,至此我已删除相应的证书TrustedPeople服务器商店。Wcf证书作为ClientCredentials

赫雷什宿主例如:

static void Main() 
    { 
     var httpsUri = new Uri("https://192.168.0.57:xxx/HelloServer"); 
     var binding = new WSHttpBinding 
     { 
      Security = 
      { 
       Mode = SecurityMode.Transport, 
       Transport = {ClientCredentialType = HttpClientCredentialType.Certificate} 
     };   

     var host = new ServiceHost(typeof(HelloWorld), httpsUri); 

     //This line is not working 
     host.Credentials.ClientCertificate.Authentication.CertificateValidationMode =X509CertificateValidationMode.PeerTrust; 

     host.AddServiceEndpoint(typeof(IHelloWorld), binding, string.Empty, httpsUri); 

     host.Credentials.ServiceCertificate.SetCertificate(
      StoreLocation.LocalMachine, 
      StoreName.My, 
      X509FindType.FindBySubjectName, 
      "server.com"); 

     // Open the service. 
     host.Open(); 
     Console.WriteLine("Listening on {0}...", httpsUri); 
     Console.ReadLine(); 

     // Close the service. 
     host.Close(); 
    } 

的客户端应用程序:

static void Main(string[] args) 
    { 
     try 
     { 
      var c = new HelloWorld.HelloWorldClient(); 
      ServicePointManager.ServerCertificateValidationCallback = (sender, cert, chain, error) => true; 
      c.ClientCredentials.ClientCertificate.SetCertificate(
       StoreLocation.LocalMachine, 
       StoreName.My, 
       X509FindType.FindBySubjectName, 
       "client.com"); 

      Console.WriteLine(c.GetIp()); 
     } 
     catch (Exception ex) 
     { 
      Console.WriteLine(ex.Message); 
     } 
     Console.ReadKey();   
    } 

我生成server.comclient.com根CA证书。此RootCA证书安装在客户端和服务器的受信任根存储中。 现在的问题是,我不应该执行GetIp()方法,如果我的client.com证书不在TrustedPeople存储的服务器,对不对?但即时执行它没有任何问题。

问题是,在这种情况下,如何验证客户端证书将其公钥置于服务器的TrustedPeople上?

ps:在this MSDN运输安全与客户端证书的文章,theres报价为The server’s certificate must be trusted by the client and the client’s certificate must be trusted by the server.但我可以从客户端执行webmethods,即使客户端证书没有在服务器TrustedPeople商店。

回答

2

我的建议是使用custom validation。通过这种方式,您可以设置一些断点并观察验证过程,并根据整个验证过程中可用的数据查看您可以提出哪些验证选项。

首先确保您的绑定需要证书消息客户端证书。如果您只使用运输证书,则我的测试中的客户端无法验证。只有这一点可以解决你的问题。

binding.Security.Mode = SecurityMode.TransportWithMessageCredential; 
binding.Security.Message.ClientCredentialType = 
     MessageCredentialType.Certificate; 

要设置自定义验证器,请遵循其余步骤。

替换:

host.Credentials.ClientCertificate.Authentication.CertificateValidationMode 
     =X509CertificateValidationMode.PeerTrust; 

有了:

host.Credentials.ClientCertificate.Authentication.CertificateValidationMode 
     =X509CertificateValidationMode.Custom; 

host.Credentials.ClientCertificate.Authentication.CustomCertificateValidator = 
     new IssuerNameCertValidator("CN=client.com"); 

然后添加它来创建自定义验证,并根据需要调整(这一个验证基于对发行人):

public class IssuerNameCertValidator : X509CertificateValidator 
{ 
    string allowedIssuerName; 

    public IssuerNameCertValidator(string allowedIssuerName) 
    { 
     if (allowedIssuerName == null) 
     { 
      throw new ArgumentNullException("allowedIssuerName"); 
     } 

     this.allowedIssuerName = allowedIssuerName; 
    } 

    public override void Validate(X509Certificate2 certificate) 
    { 
     // Check that there is a certificate. 
     if (certificate == null) 
     { 
      throw new ArgumentNullException("certificate"); 
     } 

     // Check that the certificate issuer matches the configured issuer. 
     if (allowedIssuerName != certificate.IssuerName.Name) 
     { 
      throw new SecurityTokenValidationException 
       ("Certificate was not issued by a trusted issuer"); 
     } 
    } 
}