12

I run an application on the Azure application Standard: 1 Small plan. Framework is 4.6.1

This application is calling a SSL secured API. The SSL is published by StartCom Class 1 DV Server CA, my local browser tells me that the certificate is valid.

If I run the application on my local machine everything works. However, when deployed to azure it fails with follwing error:

System.Net.Http.HttpRequestException: An error occurred while sending the request. ---> System.Net.WebException: The request was aborted: Could not create SSL/TLS secure channel.

at System.Net.HttpWebRequest.EndGetResponse(IAsyncResult asyncResult)

at System.Net.Http.HttpClientHandler.GetResponseCallback(IAsyncResult ar)

--- End of inner exception stack trace ---

at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)

at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)

The code:

public async Task<List<QutationOverview>> GetAll(string url, DateTime lastActionDate)
    {
        var result = string.Empty;

        try
        {


            var userName = await _settingManager.GetSettingValueAsync("API.UserName");
            var password = await _settingManager.GetSettingValueAsync("API.Password");


            ServicePointManager.SecurityProtocol = SecurityProtocolType.Ssl3 | SecurityProtocolType.Tls |
                                                   SecurityProtocolType.Tls11 | SecurityProtocolType.Tls12;


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


            //Add date filter
            //Always request qutations where the last action took place >= Yesterday
            var requestUrl =
                $"GetALL/?last_action_date={lastActionDate.AddDays(-1).ToString("yyyy-MM-dd")}&format=json";


            var baseAddress = new Uri(url);
            var credentials = Convert.ToBase64String(Encoding.ASCII.GetBytes($"{userName}:{password}"));

            Logger.InfoFormat("GetAllQuotationsAsync for url {0}{1}", url, requestUrl);

            using (var httpClient = new HttpClient {BaseAddress = baseAddress})
            {
                httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", credentials);
                using (var response = await httpClient.GetAsync(requestUrl))
                {
                    result = await response.Content.ReadAsStringAsync();
                    Logger.Info(result);
                }
            }
        }

        catch (Exception ex)
        {
            Logger.ErrorFormat("GetAllQuotationsAsync {0}: {1}", url, ex);
        }
        var data = JsonConvert.DeserializeObject<List<QutationOverview>>(result);

        return data;
    }

As you can see I skip the validation of the certificate and added the security protocols.

However, the request is still failing.


Here is the caputred response http://textuploader.com/5ers0


Do you have any idea how to get this one working on Azure?

Peter Quinn
  • 123
  • 1
  • 1
  • 5

2 Answers2

7

I ran across this error when hosting a client's certificate on Azure's App Services. The fix was to set WEBSITE_LOAD_CERTIFICATES in the App Settings.

You can set it as " * " to allow all certificates, or you can define specific certificate thumbprints to allow. See more info here.

feltocraig
  • 729
  • 7
  • 7
  • 1
    I would love to understand this, but it worked for me too. I had just removed this line because I switched to MSI and didn't need to load certificates but I never would have connected the dots if I didn't see this answer. – bwmartens Jan 04 '19 at 19:23
6

Capture the TLS handshake. If your ServerHello is missing you most probably don't have a common cipher suite with the remote.

Run both through https://www.ssllabs.com/ssltest/ to check supported cipher suites at both ends. For Windows Server, cipher suites can only be enabled or disabled globally (as in no distinction between client/server component) so that's why this makes for a good test.

UPDATE: Found a glaring problem in my reasoning, App Service has a frontend layer and that's where TLS terminates, so comparing ciphers that way goes nowhere.

Instead, run

Get-TlsCipherSuite

from Kudu's PowerShell and compare ciphers against your remote API's (the ciphers of which you can check over at https://ssllabs.com/ssltest). You should have at least one match.

If none match, you'll need to switch to Cloud Services or VMs and enable at least one of the cipher suites your remote speaks. Having to go this direction usually means one thing -- your remote is using weak cryptography (SSL 3.0 or TLS 1.0 with RC4) and you should have a chat with those citizens, or find new citizens that are rocking TLS 1.2.

From your System.Net trace:

[8356] 00000000 : 15 03 03 00 02

That's byte sequence for Fatal Handshake Error, which builds on my no common cipher theory.

Note the first byte (0x15):

 Record Type Values       dec      hex
 -------------------------------------
 CHANGE_CIPHER_SPEC        20     0x14
 ALERT                     21     0x15
 HANDSHAKE                 22     0x16
 APPLICATION_DATA          23     0x17
evilSnobu
  • 24,582
  • 8
  • 41
  • 71
  • Thank you, I removed ServicePointManager .ServerCertificateValidationCallback += (sender, cert, chain, sslPolicyErrors) => true; and added ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;. However, the error is still the same – Peter Quinn Jul 16 '16 at 16:49
  • Hmm.. use a recent `curl` with `--tlsv1.x` and check if the remote really supports TLS 1.2: https://curl.haxx.se/docs/manpage.html#--tlsv10. Try to capture the TLS handshake ClientHello + ServerHello (Wireshark or System.Net tracing), post it here, that should help in finding the root cause. – evilSnobu Jul 16 '16 at 19:05
  • I attached the wireshark response in main post. Does that one help? – Peter Quinn Jul 18 '16 at 07:31
  • Your capture shows the TLS handshake being pretty much successful. Maybe something bad happens after the ServerHello, your screenshot cuts off early. – evilSnobu Jul 18 '16 at 10:05
  • okay, I added the second one. However, at my local development machine the application runs without any problem. I only receive the error when I deploy it to an azure web app where i cant use wireshark.. – Peter Quinn Jul 18 '16 at 10:13
  • Oh, that's not going to help. I thought the Wireshark traces are from the other end. Do a System.Net trace instead (you can build a tiny console app that only attempts a HttpClient to the remote host, run it in Kudu and add all that to its app.config): https://blogs.msdn.microsoft.com/waws/2014/11/04/enable-system-net-tracing-on-azure-websites-unable-to-connect-to-remote-server/ – evilSnobu Jul 18 '16 at 11:35
  • ah thank you! I caputed not the response and uploaded it to http://textuploader.com/5ers0 – Peter Quinn Jul 18 '16 at 13:07
  • `System.Net.Sockets Verbose: 0 : [6204] 00000000 : 16 03 03` - that's the ClientHello. Notice there's no ServerHello, the remote is hanging up on you. You may want to check supported cipher suites with the remote, it could be none of them are available on Azure App Service if they're exotic enough. `15 03 03 00 02` translates to Fatal Handshake Failure. Check remote with https://www.ssllabs.com/ssltest/ – evilSnobu Jul 18 '16 at 14:03
  • ok thank you. As far as I understand the guys who run the api on the other site have to use a azure supported ciper suite. Right? Is there any way to run it on a azure web app without changing the other site? – Peter Quinn Jul 18 '16 at 15:41
  • First compare the output of https://www.ssllabs.com/ssltest/ for the Web App and for the remote host. Any common cipher suites? – evilSnobu Jul 18 '16 at 16:37
  • I compared the app and the remote host. Under "Cipher Suites" I cannot find any matching cipher suite :-(. Does that mean that either I have to move to another (non web app) server or that the remote host have to implement one of azure used suites? (sorry I am not that into SSL, until today I always thought it is just installing a piece of certificate ;-)) – Peter Quinn Jul 18 '16 at 19:10
  • Correct. Your remote probably took the hipster approach to cryptography since Azure App Service supports a large suite of ciphers that are commonly used out there and some Elliptic Curve ones too. Either your remote relaxes the crypto or you need to switch to Cloud Services or VMs and match at least one remote cipher. Wish i had better news... – evilSnobu Jul 18 '16 at 19:37