How do I set the 'ServerCertificateValidationCallback' property back to its default behavior?
This actually appears to work (as simple as it is) and makes the object behave in its default manner.
ServicePointManager.ServerCertificateValidationCallback = Nothing
You'll want to only return true for certain URLs, but otherwise, this does what you want, leaving the possibility of using multiple delegates. The logic for each callback could include a check via reflection so that the callback only returns true when called from certain components, thus creating a sort of tunnel between certain URLs and certain applications.
One way to use this code: 1. Define the mIgnoreBadCertificates delegate early in your object's life 2. Set a property containing the 'beSecure' code true 3. Send the Http Request. 4. Set the property false. This is very important, and should be implemented in a way that guarantees it gets called. The IDisposable pattern is one option.
private System.Net.Security.RemoteCertificateValidationCallback mIgnoreBadCertificates = new
System.Net.Security.RemoteCertificateValidationCallback(
delegate { return true; });
if (beSecure)
{ //require secure communications
System.Net.ServicePointManager.ServerCertificateValidationCallback -= mIgnoreBadCertificates;
Iwds.EventLogger.LogVeryFrequentEvent("Requiring Good Certificates from Remote Sites");
}
else
{ /// Allow connections to SSL sites that have unsafe certificates.
System.Net.ServicePointManager.ServerCertificateValidationCallback += mIgnoreBadCertificates;
Iwds.EventLogger.LogVeryFrequentEvent("Ignoring Bad Certificates from Remote Sites");
}
A key point to solving your problem is the fact that the sender
parameter to the RemoteCertificateValidationCallback
is the WebRequest
. You can check the sender against your webrequest so you only do checking for your webrequest. Here is my (relatively untested) solution:
// Main Code
request = (FtpWebRequest)FtpWebRequest.Create("ftp://example.com");
using(var validator = new WebRequestCertificateValidator(request))
{
// etc...
}
// WebRequestCertificateValidator Class
public sealed class WebRequestCertificateValidator : IDisposable
{
private bool disposed;
private WebRequest request;
private RemoteCertificateValidationCallback callback;
/// <summary>
/// Creates a certificate validator that allows all certificates for the supplied web request.
/// </summary>
/// <param name="request">The WebRequest to validate for.</param>
public WebRequestCertificateValidator(WebRequest request) : this(request, null)
{
//
}
/// <summary>
/// Creates a certificate validator that only allows certificates for the supplied web request of the callback returns true.
/// </summary>
/// <param name="request">The WebRequest to validate for.</param>
/// <param name="callback">The delegate that will be called to validate certificates for the WebRequest.</param>
public WebRequestCertificateValidator(WebRequest request, RemoteCertificateValidationCallback callback)
{
this.disposed = false;
this.request = request;
this.callback = callback;
ServicePointManager.ServerCertificateValidationCallback += this.InternalCallback;
}
private bool InternalCallback(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors)
{
WebRequest request = sender as WebRequest;
if(request != null)
{
if(request == this.request)
{
if(this.callback != null)
{
return this.callback(sender, certificate, chain, sslPolicyErrors);
}
}
}
return true;
}
public void Dispose()
{
if(!this.disposed)
{
ServicePointManager.ServerCertificateValidationCallback -= this.InternalCallback;
this.callback = null;
this.request = null;
this.disposed = true;
}
}
}