Testing Services with HTTPS
How do I setup a test environment for a service that is using HTTPS? Certificate validation fails because the test machine doesn’t have the right machine name.
Included in the definition of a certificate is the fully qualified domain name that you gave to the certificate authority when the certificate was created. This definition is incorporated into the signature of the certificate so there’s no way to change the certificate without being issued a new one.
The certificate can then only be used with a machine of that particularly signed name or else a name mismatch error occurs. There is some additional flexibility if the certificate you’re using is a wildcard certificate, but you still won’t be able to use in a test setup as the address of the service the IP address, localhost, or other domain names besides the one that the certificate was created for.
Instead, to test the HTTPS service you need to make the certificate appear acceptable. There’s two ways to do that.
The first way to make the certificate acceptable is to tell the machine to trust you. In a test environment you control both of the machines communicating. This means you can create your self-signed certificate and install a new trusted root certificate authority telling the machine to trust the certificates that you’ve signed.
The second way to make the certificate acceptable is to override how the application checks the certificate. The System.Net.ServicePointManager class has a property called ServerCertificateValidationCallback, to which you can install your own validation routine. The validation routine is an implementation of the RemoteCertificateValidationCallback delegate.
public delegate bool RemoteCertificateValidationCallback
(
Object sender,
X509Certificate certificate,
X509Chain chain,
SslPolicyErrors sslPolicyErrors
)
If you write a validation callback that returns true, then you can install that callback on the test machine to use certificates even if they don’t pass the normal validation logic.
Comments
- Anonymous
July 14, 2009
The comment has been removed - Anonymous
July 20, 2009
In case anyone is looking for a quick implementation :) : You can ignore the tracing comments. I always look for a CA one level up for a thumbprint check. public class AuthenticationProvider : ClientFormsAuthenticationMembershipProvider { public AuthenticationProvider() { var tracer = new Tracer(); var errInfo = new Dictionary<string, object>(); ServicePointManager.ServerCertificateValidationCallback += ((sender, certificate, chain, sslPolicyErrors) => { if (SslPolicyErrors.None == sslPolicyErrors) { return true; } try { if (chain.ChainElements != null && chain.ChainElements.Count > 1 && sslPolicyErrors.Equals(SslPolicyErrors.RemoteCertificateNameMismatch)) { var parent = chain.ChainElements[1].Certificate; if (parent.Thumbprint != null && parent.Thumbprint.ToLower().Equals("2c3d2126e58ab5804528b32278b1290c195416bc")) { return true; } } } catch (Exception e) { tracer.Write("Certificate verification failed", TraceSeverity.Error,new[] { TraceCategory.Framework }, errInfo); return false; } tracer.Write("Certificate verification failed", TraceSeverity.Error,new[] { TraceCategory.Framework }, errInfo); return false; }); } }