Could not establish trust relationship for SSL/TLS secure channel -- SOAP
Asked Answered
C

18

385

I have a simple web service call, generated by a .NET (C#) 2.0 Windows app, via the web service proxy generated by Visual Studio, for a web service also written in C# (2.0). This has worked for several years, and continues to do so at the dozen or so places where it is running.

A new installation at a new site is running into a problem. When attempting to invoke the web service, it fails with the message saying:

Could not establish a trust relationship for the SSL/TLS secure channel

The URL of the web service uses SSL (https://) -- but this has been working for a long time (and continues to do so) from many other locations.

Where do I look? Could this be a security issue between Windows and .NET that is unique to this install? If so, where do I set up trust relationships? I'm lost!

Catechetical answered 31/3, 2009 at 22:7 Comment(1)
In my case this error was caused by IP address forwarding.Mast
P
191

Thoughts (based on pain in the past):

  • do you have DNS and line-of-sight to the server?
  • are you using the correct name from the certificate?
  • is the certificate still valid?
  • is a badly configured load balancer messing things up?
  • does the new server machine have the clock set correctly (i.e. so that the UTC time is correct [ignore local time, it is largely irrelevent]) - this certainly matters for WCF, so may impact regular SOAP?
  • is there a certificate trust chain issue? if you browse from the server to the soap service, can you get SSL?
  • related to the above - has the certificate been installed to the correct location? (you may need a copy in Trusted Root Certification Authorities)
  • is the server's machine-level proxy set correctly? (which different to the user's proxy); see proxycfg for XP / 2003 (not sure about Vista etc)
Psychoanalysis answered 31/3, 2009 at 22:11 Comment(10)
1) The web service is on the web. We can browse to it via a browser. 2) New machine is not a server -- it is a desktop running my app, which gathers order info and uploads via the SOAP service 3) Yes, we can browse to it. 4) This is new to me: machine level proxy?Catechetical
Yes; code doesn't use the IE proxy settings; it uses a separate store... it is important that this is configured (if you are using a proxy). On XP, the easiest option is (IIRC) "proxycfg -i" to import the IE settings.Psychoanalysis
Thanks Marc. This helped me, and the problem was that the server had a cert signed by a 3rd party CA that I hadn't trusted yet. The solution was to add that CA to the Trusted Root CA list.Helper
The computer that was having this exception was unable to sync the system time using the time servers. I had to go in and manually sync the time before it worked.Tayler
You may get this if you have been using Fiddler to debug service calls and have used it's certificate interception mode. Just remove the interception in fiddler's options and you should be goodRosio
Another situation may be that an anti-virus is blocking some communications. So you could test if you get the error by temporarily disabling the anti-virus services.Phonics
I would add anti-virus such as Kaspersky can cause that as they replace certificates to traps new connection and approved them manually or not.Rancher
Make sure the request "Host" header is correct. It should be the requests' destination Authority.Annular
You also need permission to read the key: stackoverflow.com/a/27302270Thyroxine
Verify that the account running the code can use the certificate. In my scenario, the endpoint changed their SSL cert. They switched to a new provider. The code runs fine for me because my trusted cert store is up to date, however the service account that's running the code isn't.Thrombus
E
412

The following snippets will fix the case where there is something wrong with the SSL certificate on the server you are calling. For example, it may be self-signed or the host name between the certificate and the server may not match.

This is dangerous if you are calling a server outside of your direct control, since you can no longer be as sure that you are talking to the server you think you're connected to. However, if you are dealing with internal servers and getting a "correct" certificate is not practical, use the following to tell the web service to ignore the certificate problems and bravely soldier on.

The first two use lambda expressions, the third uses regular code. The first accepts any certificate. The last two at least check that the host name in the certificate is the one you expect.
... hope you find it helpful

//Trust all certificates
System.Net.ServicePointManager.ServerCertificateValidationCallback =
    ((sender, certificate, chain, sslPolicyErrors) => true);

// trust sender
System.Net.ServicePointManager.ServerCertificateValidationCallback
                = ((sender, cert, chain, errors) => cert.Subject.Contains("YourServerName"));

// validate cert by calling a function
ServicePointManager.ServerCertificateValidationCallback += new RemoteCertificateValidationCallback(ValidateRemoteCertificate);

// callback used to validate the certificate in an SSL conversation
private static bool ValidateRemoteCertificate(object sender, X509Certificate cert, X509Chain chain, SslPolicyErrors policyErrors)
{
    bool result = cert.Subject.Contains("YourServerName");
    return result;
}
Endosteum answered 7/7, 2011 at 15:52 Comment(11)
My experience with ServicePointManager. Any change to it would affect entire app domain. Though the answer is very clearly explained how this can be applied, I like to throw this point.Finnie
Setting the callback works in .NET 4.5 for me, but not .NET 4.6Sumbawa
@Finnie Any suggestions on how to reset this after a particular request is complete? A person might need to make one request to an uncertified server, then put things back the way they were.Latecomer
@Isaac Lyman: ServicePointManager.ServerCertificateValidationCallback = null; should revert to default behaviour.Expensive
@MikeChamberlain The only problem with your suggestion is that concurrent requests might be rendered insecure since you're dealing with a global app setting.Latecomer
Wouldn't it be better if you just trust the server's certificate on the client machine? That's what I did and I didn't have to do any of the above : superuser.com/a/830520/386957Middlebuster
None of your solution is secure. If you override default behavior, you should validate the certificate (which is valid over a time period) and the trust chain.Isisiskenderun
Old post but the first "Trust all certificates" option did exactly what I needed for my dev environment. Thanks.Aeroembolism
your code to be added in website or client side? my wpf tool calls web service with poor https: which is causing this error. i want to skip this error. so ..Calk
That solutions not working for me.. still error. Are these ServicePointManager settings globaly or i have to set it in specify place? @FinnieShirline
The server is in our control, is it still safe to use @Sebastian Castaldi's code on production? Using TLS, can attack like man-in-the-middle be stopped?Honna
A
213

The very simple "catch all" solution is this:

System.Net.ServicePointManager.ServerCertificateValidationCallback = delegate { return true; };

The solution from sebastian-castaldi is a bit more detailed.

Amenable answered 18/3, 2013 at 18:0 Comment(7)
I just put this in an #If CONFIG = "Debug" statement so it only is activated when in debug mode. It works great!Dukas
Detail can be good, but there is something to be said for a quick, short, and easy line of code as well. This code is short and does the trick.Fumble
will this act only on current Action (e.g. ASP MVC is used)? or it will set as the default behavior for the ASP.NET application?Stenosis
Never really confirmed this 100%, but I think it's on a per request basis.Amenable
This should be used only for testing purpose, this solution trust any certificate, even invalid / expired onesIsisiskenderun
What is the security risk of using this in production?Mcglynn
As explained in the comments above, this does not verify if the SSL connection are valid anymore. So the connection between your system and other systems might be compromised. It's always a question of what you need this for.Amenable
P
191

Thoughts (based on pain in the past):

  • do you have DNS and line-of-sight to the server?
  • are you using the correct name from the certificate?
  • is the certificate still valid?
  • is a badly configured load balancer messing things up?
  • does the new server machine have the clock set correctly (i.e. so that the UTC time is correct [ignore local time, it is largely irrelevent]) - this certainly matters for WCF, so may impact regular SOAP?
  • is there a certificate trust chain issue? if you browse from the server to the soap service, can you get SSL?
  • related to the above - has the certificate been installed to the correct location? (you may need a copy in Trusted Root Certification Authorities)
  • is the server's machine-level proxy set correctly? (which different to the user's proxy); see proxycfg for XP / 2003 (not sure about Vista etc)
Psychoanalysis answered 31/3, 2009 at 22:11 Comment(10)
1) The web service is on the web. We can browse to it via a browser. 2) New machine is not a server -- it is a desktop running my app, which gathers order info and uploads via the SOAP service 3) Yes, we can browse to it. 4) This is new to me: machine level proxy?Catechetical
Yes; code doesn't use the IE proxy settings; it uses a separate store... it is important that this is configured (if you are using a proxy). On XP, the easiest option is (IIRC) "proxycfg -i" to import the IE settings.Psychoanalysis
Thanks Marc. This helped me, and the problem was that the server had a cert signed by a 3rd party CA that I hadn't trusted yet. The solution was to add that CA to the Trusted Root CA list.Helper
The computer that was having this exception was unable to sync the system time using the time servers. I had to go in and manually sync the time before it worked.Tayler
You may get this if you have been using Fiddler to debug service calls and have used it's certificate interception mode. Just remove the interception in fiddler's options and you should be goodRosio
Another situation may be that an anti-virus is blocking some communications. So you could test if you get the error by temporarily disabling the anti-virus services.Phonics
I would add anti-virus such as Kaspersky can cause that as they replace certificates to traps new connection and approved them manually or not.Rancher
Make sure the request "Host" header is correct. It should be the requests' destination Authority.Annular
You also need permission to read the key: stackoverflow.com/a/27302270Thyroxine
Verify that the account running the code can use the certificate. In my scenario, the endpoint changed their SSL cert. They switched to a new provider. The code runs fine for me because my trusted cert store is up to date, however the service account that's running the code isn't.Thrombus
B
39

I personally like the following solution the most:

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

... then before you do request getting the error, do the following

System.Net.ServicePointManager.ServerCertificateValidationCallback = delegate(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors) { return true; };

Found this after consulting Luke's Solution

Barbital answered 26/2, 2013 at 22:59 Comment(4)
See the Sebastian Castaldi answer for security caveats to this approach.Esquire
What is the security risk of using this in production?Mcglynn
@Mcglynn the security risk is that it completely sidesteps any benefits of using SSL/TLS. The server can present any certificate it likes, and this code will ignore the errorGurley
VB.NET: System.Net.ServicePointManager.ServerCertificateValidationCallback = Function(s As Object, certificate As X509Certificate, chain As X509Chain, SslPolicyErrors As SslPolicyErrors) TrueBlaze
M
24

If you do not wan't to blindly trust everybody and make a trust exception only for certain hosts the following solution is more appropriate.

public static class Ssl
{
    private static readonly string[] TrustedHosts = new[] {
      "host1.domain.com", 
      "host2.domain.com"
    };

    public static void EnableTrustedHosts()
    {
      ServicePointManager.ServerCertificateValidationCallback = 
      (sender, certificate, chain, errors) =>
      {
        if (errors == SslPolicyErrors.None)
        {
          return true;
        }

        var request = sender as HttpWebRequest;
        if (request != null)
        {
          return TrustedHosts.Contains(request.RequestUri.Host);
        }

        return false;
      };
    }
}

Then just call Ssl.EnableTrustedHosts when your app starts.

Macrobiotic answered 8/10, 2014 at 7:58 Comment(4)
@thelem Yes re-reading I think I must have misread the first timeHaugh
What is the security risk of trusting all certificates in production?Mcglynn
@Mcglynn the security risk is that anyone between the client and the server can insert themselves in the middle of the communications, use their own SSL certificate and read all traffic between the client and server. Doing this effectively invalidates SSL.Adjutant
Should it work when iam using WCF addon to generate classes from wsdl?Shirline
D
18

If you are using Windows 2003, you can try this:

Open Microsoft Management Console (Start --> Run --> mmc.exe);

Choose File --> Add/Remove Snap-in;

In the Standalone tab, choose Add;

Choose the Certificates snap-in, and click Add;

In the wizard, choose the Computer Account, and then choose Local Computer. Press Finish to end the wizard;

Close the Add/Remove Snap-in dialog;

Navigate to Certificates (Local Computer) and choose a store to import:

If you have the Root CA certificate for the company that issued the certificate, choose Trusted Root Certification Authorities;

If you have the certificate for the server itself, choose Other People

Right-click the store and choose All Tasks --> Import

Follow the wizard and provide the certificate file you have;

After that, simply restart IIS and try calling the web service again.

Reference: http://www.outsystems.com/NetworkForums/ViewTopic.aspx?Topic=Web-Services:-Could-not-establish-trust-relationship-for-the-SSL/TLS-...

Disadvantageous answered 25/3, 2011 at 0:10 Comment(1)
This got me part of the way, but I needed to have the certificate in the Trusted Root Certification Authorities section in order to make it work. As per blogs.msdn.com/b/jpsanders/archive/2009/09/16/…Overuse
C
8

Microsoft's SSL Diagnostics Tool may be able to help identify the issue.

UPDATE the link has been fixed now.

Catalog answered 31/3, 2009 at 22:36 Comment(3)
As of today (August 2012), that link is now broken.Polyethylene
Searched the download directory and no SSL Diagnostics Tool is available any longer. :(Celloidin
Let us fix the link. Correct me If I am wrong iis.net/downloads/community/2009/09/…Finnie
S
8

Luke wrote a pretty good article about this .. pretty straight forward .. give this a try

Luke's Solution

Reason (quote from his article (minus cursing)) ".. The problem with the code above is that it doesn’t work if your certificate is not valid. Why would I be posting to a web page with and invalid SSL certificate? Because I’m cheap and I didn’t feel like paying Verisign or one of the other **-*s for a cert to my test box so I self signed it. When I sent the request I got a lovely exception thrown at me:

System.Net.WebException The underlying connection was closed. Could not establish trust relationship with remote server.

I don’t know about you, but to me that exception looked like something that would be caused by a silly mistake in my code that was causing the POST to fail. So I kept searching, and tweaking and doing all kinds of weird things. Only after I googled the ***n thing I found out that the default behavior after encountering an invalid SSL cert is to throw this very exception. .."

Sihun answered 25/10, 2012 at 19:36 Comment(1)
This solution is a deprecated for .Net 4.5. If you just wanna accept all certificates, see Sebastian Castaldi or my answer further below.Amenable
A
6

add this:

 ServicePointManager.ServerCertificateValidationCallback += (sender, cert, chain, sslPolicyErrors) => true;}

right before the line that you're calling the service

Appalachia answered 23/6, 2020 at 12:17 Comment(1)
This worked for me, thank you! I was trying to POST and GET to a localhost API from a .NET client app and could not get it to work even though I could hit the API through my browser using the YARC plugin (Yet Another REST Client). This line allowed my .NET app to hit the API.Celia
T
3

I just encountered this issue. My resolution was to update the system time by manually syncing to the time servers. To do this you can:

  • Right-click the clock in the task bar
  • Select Adjust Date/Time
  • Select the Internet Time tab
  • Click Change Settings
  • Select Update Now

In my case this was syncing incorrectly so I had to click it several times before it updated correctly. If it continues to update incorrectly you can even try using a different time server from the server drop-down.

Tayler answered 22/2, 2013 at 16:9 Comment(0)
H
3

I had a similar problem in .NET app in Internet Explorer.

I solved the problem adding the certificate (VeriSign Class 3 certificate in my case) to trusted editors certificates.

Go to Internet Options-> Content -> Publishers and import it

You can get the certificate if you export it from:

Internet Options-> Content -> Certificates -> Intermediate Certification Authorities -> VeriSign Class 3 Public Primary Certification Authority - G5

thanks

Hyla answered 25/5, 2015 at 14:7 Comment(0)
M
3

Try this:

System.Net.ServicePointManager.SecurityProtocol = System.Net.SecurityProtocolType.Tls12;

Notice that you have to work at least with 4.5 .NET framework

Murage answered 15/5, 2018 at 12:23 Comment(0)
C
1

I had this error running against a webserver with url like:

a.b.domain.com

but there was no certificate for it, so I got a DNS called

a_b.domain.com

Just putting hint to this solution here since this came up top in google.

Calutron answered 22/1, 2014 at 13:28 Comment(1)
In my case, website was configured under a wildcard ssl certificate (*.abcd.com). When configured the website binding was like xyz-abcd.com which was causing the issue.Hello
K
1

For those who are having this issue through a VS client side once successfully added a service reference and trying to execute the first call got this exception: “The underlying connection was closed: Could not establish trust relationship for the SSL/TLS secure channel” If you are using (like my case) an endpoint URL with the IP address and got this exception, then you should probably need to re-add the service reference doing this steps:

  • Open the endpoint URL on Internet Explorer.
  • Click on the certificate error (red icon in address bar)
  • Click on View certificates.
  • Grab the issued to: "name" and replace the IP address or whatever name we were using and getting the error for this "name".

Try again :). Thanks

Kef answered 12/6, 2017 at 20:28 Comment(0)
S
0

In my case I was trying to test SSL in my Visual Studio environment using IIS 7.

This is what I ended up doing to get it to work:

  • Under my site in the 'Bindings...' section on the right in IIS, I had to add the 'https' binding to port 443 and select "IIS Express Developement Certificate".

  • Under my site in the 'Advanced Settings...' section on the right I had to change the 'Enabled Protocols' from "http" to "https".

  • Under the 'SSL Settings' icon I selected 'Accept' for client certificates.

  • Then I had to recycle the app pool.

  • I also had to import the local host certificate into my personal store using mmc.exe.

My web.config file was already configured correctly, so after I got all the above sorted out, I was able to continue my testing.

Sofiasofie answered 17/2, 2014 at 17:55 Comment(2)
how was your web.config configured?Petard
@Petard I couldn't tell you, that was a while back, but it would have been a basic http binding set up, I typically use svcutil to generate config info for web service client info.Sofiasofie
O
0

My solution (VB.Net, the "staging" (UAT) version of this application needs to work with the "staging" certificate but not affect requests once they are on the live site):

    ...
        Dim url As String = ConfigurationManager.AppSettings("APIURL") & "token"
        If url.ToLower().Contains("staging") Then
           System.Net.ServicePointManager.ServerCertificateValidationCallback = AddressOf AcceptAllCertifications
        End If
    ...

    Private  Function AcceptAllCertifications(ByVal sender As Object, ByVal certification As System.Security.Cryptography.X509Certificates.X509Certificate, ByVal chain As System.Security.Cryptography.X509Certificates.X509Chain, ByVal sslPolicyErrors As System.Net.Security.SslPolicyErrors) As Boolean
        Return True
    End Function
Oblivious answered 15/7, 2019 at 2:5 Comment(0)
L
0

A variation I've been using for a while it if helps anyone.

The caller has to explicitly request that untrusted certifications are required and places the callback back into it's default state upon completion.

    /// <summary>
    /// Helper method for returning the content of an external webpage
    /// </summary>
    /// <param name="url">URL to get</param>
    /// <param name="allowUntrustedCertificates">Flags whether to trust untrusted or self-signed certificates</param>
    /// <returns>HTML of the webpage</returns>
    public static string HttpGet(string url, bool allowUntrustedCertificates = false) {
        var oldCallback = ServicePointManager.ServerCertificateValidationCallback;
        string webPage = "";
        try {
            WebRequest req = WebRequest.Create(url);

            if (allowUntrustedCertificates) {
                // so we can query self-signed certificates
                ServicePointManager.ServerCertificateValidationCallback = 
                    ((sender, certification, chain, sslPolicyErrors) => true);
            }

            WebResponse resp = req.GetResponse();
        
            using (StreamReader sr = new StreamReader(resp.GetResponseStream())) {
                webPage = sr.ReadToEnd().Trim();
                sr.Close();
            }
            return webPage;
        }
        catch {
            // if the remote site fails to response (or we have no connection)
            return null;
        }
        finally {
            ServicePointManager.ServerCertificateValidationCallback = oldCallback;
        }
    }
Lymphosarcoma answered 20/10, 2020 at 7:25 Comment(0)
G
-3

If not work bad sertificate, when ServerCertificateValidationCallback return true; My ServerCertificateValidationCallback code:

ServicePointManager.ServerCertificateValidationCallback += delegate
{
    LogWriter.LogInfo("Проверка сертификата отключена, на уровне ServerCertificateValidationCallback");
    return true;
};

My code which the prevented execute ServerCertificateValidationCallback:

     if (!(ServicePointManager.CertificatePolicy is CertificateValidation))
    {
        CertificateValidation certValidate = new CertificateValidation();
        certValidate.ValidatingError += new CertificateValidation.ValidateCertificateEventHandler(this.OnValidateCertificateError);
        ServicePointManager.CertificatePolicy = certValidate;
    }

OnValidateCertificateError function:

private void OnValidateCertificateError(object sender, CertificateValidationEventArgs e)
{
    string msg = string.Format(Strings.OnValidateCertificateError, e.Request.RequestUri, e.Certificate.GetName(), e.Problem, new Win32Exception(e.Problem).Message);
    LogWriter.LogError(msg);
    //Message.ShowError(msg);
}

I disabled CertificateValidation code and ServerCertificateValidationCallback running very well

Ginzburg answered 10/1, 2017 at 11:17 Comment(2)
You should never disable any certificate validation. Instead, fix the issue causing the failing validation.Ethelda
What is the security risk of using this in production?Mcglynn

© 2022 - 2024 — McMap. All rights reserved.