galets
galets

Reputation: 18502

Custom X509CertificateValidator with BasicHttpSecurityMode.Transport?

Is there an easy way to tie custom X509 cert validation to BasicHttpBinding (or CustomHttpBinding for the same matter, which will implement transport-only security)?

EDIT1: I added a ServerCertificateValidationCallback to the code for the sake of showing that it doesn't fire up either

Here's what I'm trying to do:

1) wrote custom X509CertificateValidator:

public class MyX509Validator : X509CertificateValidator
{
    public override void Validate(X509Certificate2 certificate)
    {
        Console.WriteLine("Incoming validation: subj={0}, thumb={1}",
                certificate.Subject, certificate.Thumbprint);
    }
}

2) created host:

var soapBinding = new BasicHttpBinding() { Namespace = "http://test.com" };
soapBinding.Security.Mode = BasicHttpSecurityMode.Transport;
soapBinding.Security.Transport.ClientCredentialType =
            HttpClientCredentialType.Certificate;

var sh = new ServiceHost(typeof(Service1), uri);
sh.AddServiceEndpoint(typeof(IService1), soapBinding, "");
sh.Credentials.ServiceCertificate.SetCertificate(StoreLocation.LocalMachine,
           StoreName.My, X509FindType.FindBySubjectName, "localhost");
sh.Credentials.ClientCertificate.Authentication.CertificateValidationMode =
           System.ServiceModel.Security.X509CertificateValidationMode.Custom;
sh.Credentials.ClientCertificate.Authentication.CustomCertificateValidator = 
           new MyX509Validator();
System.Net.ServicePointManager.ServerCertificateValidationCallback += 
           delegate(object sender, X509Certificate certificate, 
                    X509Chain chain, SslPolicyErrors sslPolicyErrors)
           {
                Console.WriteLine("Incoming validation: subj={0}, thumb={1}",
                    certificate.Subject, certificate.GetIssuerName());
                return true;
           };
sh.Open();

3) Created WCF Client:

var binding = new BasicHttpBinding();
binding.Security.Mode = BasicHttpSecurityMode.Transport;
binding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Certificate;
var cli = new ServiceReference2.Service1Client(binding, 
           new EndpointAddress("https://localhost:801/Service1"));
cli.ClientCredentials.ClientCertificate.SetCertificate(StoreLocation.LocalMachine, 
           StoreName.My, X509FindType.FindBySubjectName, "localhost");
cli.HelloWorld();

Authentication works fine, but MyX509Validator.Validate() never gets called. I have suspicion that X509CertificateValidator only works on message security, not on transport. Is that right? Is there something I could do to override transport-level cert validation?

Upvotes: 1

Views: 4454

Answers (2)

Fenton
Fenton

Reputation: 251152

I am doing this using the following settings and my custom validator definitely gets hit:

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

serviceHost.Credentials.ClientCertificate.Authentication.CustomCertificateValidator =
    new CertificateValidator(ConfigurationManager.AppSettings["Cerficate"]);

My behaviour is:

    <behavior name="CustomCertificateBehavior">
      <serviceCredentials>
        <clientCertificate>
          <authentication certificateValidationMode="Custom" />
        </clientCertificate>
      </serviceCredentials>
    </behavior>
  </serviceBehaviors>

And my binding:

  <basicHttpBinding>
    <binding name="SecureBinding" maxReceivedMessageSize="5242880">
      <security mode="Transport">
        <transport clientCredentialType="Certificate"></transport>
      </security>
    </binding>
  </basicHttpBinding>

Upvotes: 0

Mitch Baker
Mitch Baker

Reputation: 624

I'm assuming that you are talking about the certificate that is tied to HTTPS...

If so, here is the answer: The X509CertificateValidationMode is used within the header of the document that you are exchanging to provide authentication. It does nothing for the underlying transport itself, which in this case is HTTPS with its' associated x.509 cert. So, you are spot on with your assumption.

If you want to provide custom certificate validation of the transport, use System.Net.ServicePointManager.ServerCertificateValidationCallback instead. Be careful though, this is an app wide setting. If you are cycling through multiple endpoints and don't set this to null, it will remain active.

Upvotes: 1

Related Questions