Calling Web Services That Use Self-Signed Certificates

When you try to call a web service that uses a self-signed certificate from a client application you get the following error:
The underlying connection was closed: Could not establish trust relationship for the SSL/TLS secure channel.

This make sense since if you access the site directly in your browser you get an invalid certificate message.  When you look at the details of the error it states that the certificate cannot be verified up to a trusted certification authority.  This is not a big issue when using the browser since you can accept the certificate, and even add install the certificate so you don’t get the error on subsequent calls to the web services. 

There are 2 ways you can fix this issue.

1) You can install the certificate on all desktops/servers the client application is running on.  For a desktop application used by tons of people this is really not a good solution, and even for web application this still could become a maintenance/support nightmare. 

2)  The other way is to add some code to your project that allows your application to ignore the certificate error.  Below are the instructions on how to do this in VS 2003 and VS2005/2008.

 

VS2003

1) Create a class files that contains the following code (I recommend calling the file Certificates.cs).

    1 using System.Net;

    2 using System.Security.Cryptography.X509Certificates;

    3 

    4 /// <summary>

    5 /// Class to handle any certificate specific code

    6 /// </summary>

    7 public class Certificates

    8 {

    9 }

   10 

   11 

   12 /// <summary>

   13 /// Class to overide policy so calling a web service with a

   14 /// self-signed cert works.

   15 /// </summary>

   16 public class SelfSignedPolicy : ICertificatePolicy

   17 {

   18     public bool CheckValidationResult(ServicePoint srvPoint,

   19                                       X509Certificate cert,

   20                                       WebRequest request,

   21                                       int certificateProblem)

   22     {

   23         if (certificateProblem == 0 ||

   24             certificateProblem == -2146762487)

   25             return true;

   26 

   27         return false;

   28     }

   29 }

 

2) Add the following line to the Application_BeginRequest event or the OnInit event of any page that needs to call a web services that uses a self-signed cert. 

    1 System.Net.ServicePointManager.CertificatePolicy = New SelfSignedPolicy

 

VS2005/2008

1) Create a class files that contains the following code (I recommend calling the file Certificates.cs).

    1 using System.Net.Security;

    2 using System.Security.Cryptography.X509Certificates;

    3 

    4 class Certificates

    5 {

    6     public static bool ValidateRemoteCertificate(object sender,

    7                                                  X509Certificate certificate,

    8                                                  X509Chain chain,

    9                                                  SslPolicyErrors policyErrors)

   10     {

   11         //Return True to force the certificate to be accepted.     

   12         //Needed so that calling web services with self-signed certs will work.

   13         return true;

   14     }

   15 }

2) Add the following lines to the Application_BeginRequest event in the global.asx file or the OnInit event of any page that needs to call a web services that uses a self-signed cert. 

    1 using System;

    2 using System.Net;

    3 using System.Net.Security;

    4 

    5 

    6 protected void Application_BeginRequest(Object sender, EventArgs e)

    7 {

    8     ServicePointManager.ServerCertificateValidationCallback =

    9     new RemoteCertificateValidationCallback

   10     (Certificates.ValidateRemoteCertificate);

   11 }

 

Summary

Of course, ignoring the certificate errors within the code could open up a security risk depending on what it is being used for.  Therefore, you need to look at each situation this could be used and decide if this is the right approach to take based on the risks.  As a developer it is up to you to look at the risks, what problem is being solved and the priority of the issue to determine whether to implement a particular solution.

Also, in most situations I would wrap the code in the Application_BeginRequest or OnInit functions so that they only run when in a Dev/QA environment.  There should not be any reason you would need a production site to access web services running under a self-signed cert (or an invalid certificate).  Since this can be done in many different ways, the code to do that is not shown in the examples above. 

[AddThis]

2 Comments

  • So that explains it. I anm new to all this and was hitting my head because I was Implementing the ICertificatePolicy and trying to pass the older CheckValidationResult method into the RemoteCertificateValidationCallback instead of a custom method with the right signature (handler) such as your example ValidateRemoteCertificate

    The first example is the OLD way to do this with the ICertificatePolicy? It's funny because PayPal insists on giving their clients that old code example instead of the new which really, you shouldn't implement ICertificatePolicy if you're using .NET 2.0+ because it creates an entirely different validation method

  • Great information, it save a lot of time.

Comments have been disabled for this content.