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);         
                } 
        }
}

10 Comments

  • 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.

  • 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.

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

  • 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...".

  • 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....

  • 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).

  • 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.

  • 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?

  • 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.

  • System.Net.ServicePointManager.ServerCertificateValidationCallback

    is not available in Windows Mobile platform

Comments have been disabled for this content.