Could not establish trust relationship with remote server.

When you use HTTPS for your web services, you may get a System.Net.WebException that, "The underlying connection was closed: Could not establish trust relationship with remote server." This indicates that the client is unable to negotiate a secure connection with the server.

Try visiting the URL of your web service with IE. You will likely get a Security Alert message box warning about one or more of the following:

1) The certificate is not from a trusted authority. This happens if the issuing authority is not trusted by the Certificate Manager. For testing, you can issue your own certificates and add yourself to the trusted authorities list. For production, you should probably buy a certificate.

2) The date on the certificate is invalid. The certificate's dates don't match those on the client computer. If this happens only on some computers, check that the clock on the offending computers is set to the right day.

3) The name on the certificate does not match the name of the site. Most certificates are issued with a www prefix; for example: www.yahoo.com. If your web service is hosted on a named server, (daffy.yahoo.com) you will get this warning. I understand you can buy wildcard certificates that accept any server name, but I've never used them.

Once you know the problem, you can decide to fix it, or ignore it when establishing the connection. The following class shows how to selectively ignore any CertificateProblems that you choose. Use this carefully, as establishing a secure connection to an attacker's server is worse than sending data in the clear.

using System;
using System.Net;
using System.Security.Cryptography.X509Certificates;

namespace Graham.Utilities
{
        public class AcceptServerNameMismatch : ICertificatePolicy
        {
                // HACK: This is a workaround.  The .NET Framwork should expose these, but they don't.
                public enum CertificateProblem : long
                {
                        CertEXPIRED                   = 2148204801,
                        CertVALIDITYPERIODNESTING     = 2148204802,
                        CertROLE                      = 2148204803,
                        CertPATHLENCONST              = 2148204804,
                        CertCRITICAL                  = 2148204805,
                        CertPURPOSE                   = 2148204806,
                        CertISSUERCHAINING            = 2148204807,
                        CertMALFORMED                 = 2148204808,
                        CertUNTRUSTEDROOT             = 2148204809,
                        CertCHAINING                  = 2148204810,
                        CertREVOKED                   = 2148204812,
                        CertUNTRUSTEDTESTROOT         = 2148204813,
                        CertREVOCATION_FAILURE        = 2148204814,
                        CertCN_NO_MATCH               = 2148204815,
                        CertWRONG_USAGE               = 2148204816,
                        CertUNTRUSTEDCA               = 2148204818
                }

                /// <summary>
                /// Implement CheckValidationResult to ignore problems that we are willing to accept.
                /// </summary>
                public bool CheckValidationResult(ServicePoint sp, X509Certificate cert,
                        WebRequest request, int problem)
                {       
                        int CertificateNameDoesntMatch = unchecked( (int) CertificateProblem.CertCN_NO_MATCH);
                        if ( problem == CertificateNameDoesntMatch ) // only accept server name failed match
                                return true;

                        // The 1.1 framework calls this method with a problem of 0, even if nothing is wrong
                        return (problem == 0);         
                } 
        }
}

Published 12 August 2004 08:03 AM by Ted_Graham

Comments

# Manish Jadhav said on 15 June, 2007 01:59 PM

The solution provided by Doug de la Torre can be implemented if you are hosting the web service and have control over the server's config. But if you are just utilizing a web service provided by somebody else, then the ICertificatePolicy hack provided by Ted is your only way around this issue.

# Richard Chen said on 17 August, 2007 01:28 AM

The solution provided by Doug de la Torre means modifying the machin.config of your local machine instead of the server machine. since it is the local machine's responsibility to check whether the server certificate is authticate or not.

Therefore, it has nothering to do with the web service being hosted by yourself or somebody else.

# Bob said on 14 May, 2008 11:26 AM

how do you use this class?  You have given no instruction on how to implement it.

# Robsta said on 05 September, 2008 07:23 AM

I found that the issue could also be due to not having the root certificate installed, for the relevant certificate you have.

This was found on a Windows CE device.

You can get the root certificate by taking the cert from the handheld to your windows box, then opening it.

From here, go to "Certification Path" tab, and click on the top one from the list. Then click "View Certificate", "Details", then "Copy to File...".

# Diogo C S Cordeiro said on 13 September, 2008 12:26 PM

Hello, thank you for this code.

To add two little lines to it :

To use this class, you need two lines :

"using System.Net"

and right before the webservice call :

"ServicePointManager.CertificatePolicy = new AcceptServerNameMismatch();"

My problem was win untrusted root, so i had to change that if to....

# Ananda said on 11 November, 2008 07:15 PM

You don't need to modify the machine.config.  Just add the same configuration element to your web.config / app.config file (depending on whether you are consuming the web services in a web application or another type of application).

# Maxwell B said on 17 November, 2008 04:47 PM

A more .NET 2.0 way to do this (accept any server certificate, or customize the delegate):

#if DEBUG

System.Net.ServicePointManager.ServerCertificateValidationCallback =

(System.Net.Security.RemoteCertificateValidationCallback)

delegate(

object o,

System.Security.Cryptography.X509Certificates.X509Certificate c,

System.Security.Cryptography.X509Certificates.X509Chain ch,

System.Net.Security.SslPolicyErrors s )

{

return true;

};

#endif

Then use your Web service client proxy.

# Ashish Dekate said on 10 March, 2009 12:30 AM

Hi,

I tried putting entries in both machine.config and web.config of web application. But that didn't work.

Code is of C#. Can you plz provide in Vb.net?

# someguy said on 17 April, 2009 02:57 PM

THANKS!

Step #2 solved my problem. I developed a complex mobile app for my company that had to be put on hold for financial reasons. Finally, someone got interested again, but the device had been sitting around resulting in the battery getting low resulting in the clock resetting to an early default date. I spent hours trying every fix I knew. This did it.

# CR said on 12 May, 2009 10:40 AM

System.Net.ServicePointManager.ServerCertificateValidationCallback

is not available in Windows Mobile platform