C#: How to accept an invalid SSL certificate programmatically
In the project I’m working on at the moment, we have a requirement to call some REST services using .NET#’s built-in System.Net.HttpWebRequest class. The calls will eventually be over SSL using a properly issued certificate when we go live, but for testing we’ve been using a self-signed certificate.
When you navigate to an HTTP URL with a dodgy certificate in a browser, you get a warning that gives you the option to ignore the problems. In code, this just results in an exception being thrown. The exception is a System.Security.Authentication.AuthenticationException (wrapped in a System.Net.WebException), with an error message of “The remote certificate is invalid according to the validation procedure.”
So, for testing, we needed to find a way to bypass the certificate validation. It turns out that you need to provide a RemoteCertificateValidationCallback delegate and attach it to ServicePointManager.ServerCertificateValidationCallback. What’s not clear is what happens if two threads are competing to set this property to different values, since it’s a static property. Reflector suggests that the property set method doesn’t do anything fancy, so you could easily get into a race condition.
Anyway, here’s s snippet that shows how to do this. Hopefully someone will find it useful, because it took me a while to find.
// callback used to validate the certificate in an SSL conversation
private static bool ValidateRemoteCertificate(
object sender,
X509Certificate certificate,
X509Chain chain,
SslPolicyErrors policyErrors
)
{
if (Convert.ToBoolean(ConfigurationManager.AppSettings["IgnoreSslErrors"]))
{
// allow any old dodgy certificate…
return true;
}
else
{
return policyErrors == SslPolicyErrors.None;
}
}
private static string MakeRequest(string uri, string method, WebProxy proxy)
{
HttpWebRequest webRequest = (HttpWebRequest)WebRequest.Create(uri);
webRequest.AllowAutoRedirect = true;
webRequest.Method = method;
// allows for validation of SSL conversations
ServicePointManager.ServerCertificateValidationCallback += new RemoteCertificateValidationCallback(
ValidateRemoteCertificate
);
if (proxy != null)
{
webRequest.Proxy = proxy;
}
HttpWebResponse response = null;
try
{
response = (HttpWebResponse)webRequest.GetResponse();
using (Stream s = response.GetResponseStream())
{
using (StreamReader sr = new StreamReader(s))
{
return sr.ReadToEnd();
}
}
}
finally
{
if (response != null)
response.Close();
}
}
2 Comments