WCF per connection server certificate validation
Seems like in .NET 4.5 you can do the following:
var request = (HttpWebRequest)WebRequest.Create(url);
request.ServerCertificateValidationCallback +=
(sender, certificate, chain, sslPolicyErrors) => true
I did not realize it initially, as you actually have to cast result of Create
method to HttpWebRequest
, as abstract WebRequest
does not contain this delegate.
Something like this:
ServicePointManager.ServerCertificateValidationCallback = new System.Net.Security.RemoteCertificateValidationCallback(ValidateCert);
public static bool ValidateCert(Object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors)
{
string requestHost;
if(sender is string)
{
requestHost = sender.ToString();
}
else
{
HttpWebRequest request = sender as HttpWebRequest;
if(request != null)
{
requestHost = request.Host;
}
}
if(!string.IsNullOrEmpty(requestHost) && requestHost == "my_test_machine")
return true;
return sslPolicyErrors == SslPolicyErrors.None;
}
Note the documentation on the sender
parameter:
sender parameter passed to the RemoteCertificateValidationCallback can be a host string name or an object derived from WebRequest (HttpWebRequest, for example) depending on the CertificatePolicy property
Disclaimer - I didn't test this, I wrote it based on the documentation. YMMV.
I was finally able to found a real solution when using .net 4.5.
This code allows you to use a custom validator only for a specific WCF client.
It has been tested against BasicHttpBinding with BasicHttpSecurityMode.Transport
.
There is a new property named SslCertificateAuthentication
in ClientBase.ClientCredentials.ServiceCertificate
.
You can initialize this property with a X509ServiceCertificateAuthentication
where you can provide a custom X509CertificateValidator
.
For example:
// initialize the ssl certificate authentication
client.ClientCredentials.ServiceCertificate.SslCertificateAuthentication = new X509ServiceCertificateAuthentication()
{
CertificateValidationMode = X509CertificateValidationMode.Custom,
CustomCertificateValidator = new CustomValidator(serverCert)
};
// simple custom validator, only valid against a specific thumbprint
class CustomValidator : X509CertificateValidator
{
private readonly X509Certificate2 knownCertificate;
public CustomValidator(X509Certificate2 knownCertificate)
{
this.knownCertificate = knownCertificate;
}
public override void Validate(X509Certificate2 certificate)
{
if (this.knownCertificate.Thumbprint != certificate.Thumbprint)
{
throw new SecurityTokenValidationException("Unknown certificate");
}
}
}