6

I am trying to consume Client's Web Service from Web API, Below is the code we are currently using to bypass SSL certificate

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

It was working fine, until they disabled TLS 1.0 and TLS 1.1 from their end. Now we have added follwing code to use TLS 1.2 for client server connection

ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12; ServicePointManager.ServerCertificateValidationCallback += (sender, cert, chain, sslPolicyErrors) => true;

Now i am getting "The request was aborted: Could not create SSL/TLS secure channel." Error only when i am hitting the API for first time, and then getting results if i am continuously hitting the API, If i wait for some time like a minute or so, Again getting same error for first time only.

Soniya
  • 221
  • 2
  • 6
  • 13
  • What framework are you using and where in the application do you set the ServicePointManager.SecurityProtocol? – martennis Apr 19 '19 at 12:41
  • Can you disable _ServicePointManager.ServerCertificateValidationCallback += (sender, cert, chain, sslPolicyErrors) => true;_ and debug the callback to review the **sslPolicyErrors**? This may give you some insight into the issue. – Stinky Towel Apr 19 '19 at 12:47
  • Hi Martennis, i am using framework 4.5.2, we are using proxy class generated from wsdl and setting ServicePointManager.SecurityProtocol just before calling their method. – Soniya Apr 19 '19 at 12:55
  • Hi Stinky, Debugging is not an option from us , Only one IP is whitelisted for Service, we do not have dev environment there, though i tried accessing the Service from SOAPUI 5.4.0 , getting below error for first request only there as well ERROR:javax.net.ssl.SSLHandshakeException: Received fatal alert: handshake_failure – Soniya Apr 19 '19 at 12:59
  • @Soniya - if can't debug, how are you able to update the _ServicePointManager_? – Stinky Towel Apr 19 '19 at 13:01
  • @Stinky, we change the code in dev env then deploy it and then test it. service is accessible from deployement server only. – Soniya Apr 19 '19 at 13:11
  • @Soniya - see my answer post below with some code that may help you troubleshoot. It assumes you can write an app log of some sort. – Stinky Towel Apr 19 '19 at 14:17
  • Do you perhaps go to the HTTP url instead of the HTTPS url? In that case, what might happen is the fact that the first time you hit the service, you get a 301/302 redirect, which causes next requests to automatically go to the HTTPS url (if your customers WebAPI uses something like RequireSSL). Then, after some time, when you're http/webclient has released it's socket, the same thing happens again. There are some assumptions in here, but you might want to check the url. – martennis Apr 19 '19 at 14:50

3 Answers3

15

Setting the security protocol type needs to be done before the issuing request is created. So this:

ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;

Should appear before this:

HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);

So if you're seeing it work on subsequent requests, it might be that you're setting the protocol too late.

Dharman
  • 30,962
  • 25
  • 85
  • 135
chill_cat
  • 151
  • 1
  • 3
4

The following code can be used to help troubleshoot the issue.

ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12 | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls;
ServicePointManager.ServerCertificateValidationCallback += ValidateServerCertificate;

...

private static bool ValidateServerCertificate(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors)
{
    // If the certificate is a valid, signed certificate, return true to short circuit any add'l processing.
    if (sslPolicyErrors == SslPolicyErrors.None)
    {
        return true;
    }
    else
    {
        // cast cert as v2 in order to expose thumbprint prop - if needed
        var requestCertificate = (X509Certificate2)certificate;

        // init string builder for creating a long log entry
        var logEntry = new StringBuilder();

        // capture initial info for the log entry
        logEntry.AppendFormat("SSL Policy Error(s): {0} - Cert Issuer: {1} - SubjectName: {2}",
           sslPolicyErrors.ToString(),
           requestCertificate.Issuer,
           requestCertificate.SubjectName.Name);

        // check for other error types as needed
        if (sslPolicyErrors == SslPolicyErrors.RemoteCertificateChainErrors) //Root CA problem
        {
            // check chain status and log
            if (chain != null && chain.ChainStatus != null)
            {
                // check errors in chain and add to log entry
                foreach (var chainStatus in chain.ChainStatus)
                {
                    logEntry.AppendFormat("|Chain Status: {0} - {1}", chainStatus.Status.ToString(), chainStatus.StatusInformation.Trim());
                }
            }
        }

        // replace with your logger
        MyLogger.Info(logEntry.ToString().Trim());
    }

    return false;
}
Stinky Towel
  • 768
  • 6
  • 26
  • The result of returning false when use in conjunction with `HttpWebRequest` is a `WebException` with an associated `Status` of [`WebExceptionStatus.TrustFailure`](https://learn.microsoft.com/en-us/dotnet/api/system.net.webexceptionstatus?f1url=https%3A%2F%2Fmsdn.microsoft.com%2Fquery%2Fdev16.query%3FappId%3DDev16IDEF1%26l%3DEN-US%26k%3Dk(System.Net.WebExceptionStatus.TrustFailure);k(TargetFrameworkMoniker-.NETFramework,Version%3Dv4.0);k(DevLang-csharp)%26rd%3Dtrue%26f%3D255%26MSPPError%3D-2147217396&view=netframework-4.8). – Suncat2000 Nov 25 '19 at 17:17
1

For those running .NET version 4, they can use below

ServicePointManager.SecurityProtocol = CType(768, SecurityProtocolType) Or CType(3072,SecurityProtocolType)
ServicePointManager.Expect100Continue = True
Peter Csala
  • 17,736
  • 16
  • 35
  • 75
Vikky
  • 752
  • 3
  • 15
  • 35