6

I encounter the folowing exception when connecting to the website of Western digital:

website of Western digital

22:02:34,803 |      HttpGrabber | DEBUG | Grabbing: GET https://shop.westerndigital.com/de-de/products/internal-drives/wd-red-sata-2-5-ssd#WDS200T1R0A
22:02:34,858 |      HttpGrabber | DEBUG | System.Net.Http.SocketsHttpHandler.Http2Support: True
22:02:34,865 |      HttpGrabber | DEBUG | System.Net.Http.UseSocketsHttpHandler: True
22:02:35,067 |      HttpGrabber | ERROR | System.AggregateException: One or more errors occurred. (The SSL connection could not be established, see inner exception.)
 ---> System.Net.Http.HttpRequestException: The SSL connection could not be established, see inner exception.
 ---> System.Security.Authentication.AuthenticationException: Authentication failed, see inner exception.
 ---> System.ComponentModel.Win32Exception (0x80090326): Le message reçu était inattendu ou formaté de façon incorrecte.
   --- End of inner exception stack trace ---

I think that the C# code is correct as I have 3/4 Unit test Passing:

        [TestCase("https://allianz-fonds.webfg.net/sheet/fund/FR0013192572/730?date_entree=2018-04-04")]
        [TestCase("https://www.galaxus.de/de/s1/product/zotac-zbox-magnus-en72070v-intel-core-i7-9750h-0gb-pc-13590721")]
        [TestCase("https://www.hystou.com/Gaming-Mini-PC-F7-with-Nvidia-GeForce-GTX-1650-p177717.html")]
        [TestCase("https://shop.westerndigital.com/de-de/products/internal-drives/wd-red-sata-2-5-ssd#WDS200T1R0A")]

Unit test pass

The SSL diagnostic done by ssllabs gives a list of supported cipher suites handled by the website of Western digital: diagnostic

Firefox connects succesfully to the website, and Wireshark spots that firefox has 1 cipher in the list: cipher list of firefox

However my dotnet core application has a fatal in the ssl handshake because it has not a single cipher common with WD :

dot net cipher suite

I took a lot of time to understand that the error comes from here.... if it really comes from here.

Hence 2 questions comes from this analysis:

  • Is it possible to add a cipher suite in my dot net core 3.1 application , written in C# to be compliant with this website ? I have seen discussion on internet stipulating that maybe the Us company which is Microsoft is not allowed to export strong cryptographic algorithms... if this is true, what about firefox (Usa too) using the same suite as Western digital (Usa too).

  • Is there a possibility to use in C# another library ( I think about open SSl) but the other library does provide all layers of https (ie propose equivalent of httpClient) / what about crossplatform to avoid loosing the cross platform feature of dotnetcore ....

Remark: Even Fiddler has this problem ! Which is understandable as it is also relying on the dot net framework technology: Fiddler handshake

  • To answer comment of @Steffen Ullrich I run this stuff on Win7: Windows version
Thierry Brémard
  • 625
  • 1
  • 5
  • 14
  • What Windows version you are running the client on? .NET Core uses the systems TLS stack (i.e. SChannel) and can only support what is in there. Firefox instead uses its own TLS stack and does not depend on the OS for it. – Steffen Ullrich Apr 07 '21 at 05:06
  • Hello @Steffen Ullrich, I edited my answer with screenshot of my windows version. I am on Win7 – Thierry Brémard Apr 07 '21 at 10:34

3 Answers3

17

I had the same issue, my autotests (dotnetcore3.1) are run on the WS 2012 R2 machines and I have to call third-party API which accepts only TWO cipher suites: TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 (0xc02f) TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (0xc030).

C# HttpClient relies on cipher suites in the host system, in contrast to Chrome, Firefox, and Curl which have their own Security and Cryptography systems. WS 2012 R2 doesn't have those two ciphers and I know no way how to add them to the machines, there are no windows updates with those ciphers.

I've chosen using a pretty cool NuGet packet CurlThin as the solution. Using it we can set up our own cipher suites for requests, so we need to do nothing with the server side.

I've installed two packets: CurlThin itself and CurlThin.Native.
The resulting code for a GET request with a header, to an HTTPS endpoint, looks like this:

using CurlThin;
using CurlThin.Enums;
using CurlThin.Helpers;
using CurlThin.Native;
using CurlThin.SafeHandles;
using System.Text;

private static string GetToken()
{
    //This string is for extracting libcurl and ssl libs to the bin directory.
    CurlResources.Init();
    var global = CurlNative.Init();
    var easy = CurlNative.Easy.Init();
    string content;

    try
    {
        var dataCopier = new DataCallbackCopier();

        CurlNative.Easy.SetOpt(easy, CURLoption.URL, "https://someendpoints.net/thatendpoint?fake=true");
        CurlNative.Easy.SetOpt(easy, CURLoption.WRITEFUNCTION, dataCopier.DataHandler);
        //This string is needed when you call a https endpoint.
        CurlNative.Easy.SetOpt(easy, CURLoption.CAINFO, CurlResources.CaBundlePath);

        var headers = CurlNative.Slist.Append(SafeSlistHandle.Null, "Authorization: Bearer blablabla");
        CurlNative.Easy.SetOpt(easy, CURLoption.HTTPHEADER, headers.DangerousGetHandle());
        //Your set of ciphers, full list is here https://curl.se/docs/ssl-ciphers.html
        CurlNative.Easy.SetOpt(easy, CURLoption.SSL_CIPHER_LIST, "ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256");

        CurlNative.Easy.Perform(easy);

        content = Encoding.UTF8.GetString(dataCopier.Stream.ToArray());
    }
    finally
    {
        easy.Dispose();

        if (global == CURLcode.OK)
            CurlNative.Cleanup();
    }

    return content;
}
Wai Ha Lee
  • 8,598
  • 83
  • 57
  • 92
Dmitrij Abashin
  • 351
  • 3
  • 7
  • Thanks so much for posting this, saved me having to rebuild a server just to support a specific cipher suite that Windows Server 2012 R2 does not support :) – Ben May 07 '22 at 10:59
  • My pleasure Ben :) – Dmitrij Abashin May 08 '22 at 11:29
  • 1
    I was getting an odd SSL error using .NET 6 HttpClient on my Windows 10 dev machine when trying to make a simple GET request to a server. No error when making the request using Postman, cURL, browser, or running the code on a Windows Server 2022 box. The above solution worked for me, posting here in case it helps anyone else. The error I kept receiving was: "The SSL connection could not be established, see inner exception" -> "Authentication failed, see inner exception." -> "The message or signature supplied for verification has been altered" – styl0r Apr 27 '23 at 22:50
8

.NET Core uses the ciphers supported by the native TLS stack, i.e. SChannel. Which ciphers are supported depend on the version of Windows. Which ciphers are supported by your OS (is documented in TLS Cipher Suites in Windows 7. As you can see, none of the ciphers offered by the server are supported by your OS.

With Firefox or Chrome browser the situation is different. These come with their own stack and are thus not limited on what the OS offers. That's why they work.

Steffen Ullrich
  • 114,247
  • 10
  • 131
  • 172
  • Thank you Steffen. I see on the bottom of the page: "To add cipher suites, use the group policy setting SSL Cipher Suite Order under Computer Configuration" ==> Is it possible to add cipher suite matching one of the cipher suite of the server ? – Thierry Brémard Apr 07 '21 at 16:30
  • @ThierryBrémard: this statement refers to the table above, which is about *"The following cipher suites are supported by the Microsoft Schannel Provider, but not enabled by default"*. None of the ciphers you need is in this table either. – Steffen Ullrich Apr 07 '21 at 16:40
  • holly shit this means I am locked by win7 and unable to use https with .netcore on some websites.... – Thierry Brémard Apr 07 '21 at 16:49
0

Indeed the same code PASS succefully when executed on Windows 10: win 10 exec

Thierry Brémard
  • 625
  • 1
  • 5
  • 14