TLS v1.2 Cipher Suites in .NET 6 / GET Request Timeout
Asked Answered
M

2

7

I am currently trying to connect to an AWS REST API which requires at least TLS v1.2. The documentation stats that clients must also support cipher suites with perfect forward secrecy (PFS) such as Ephemeral Diffie-Hellman (DHE) or Elliptic Curve Ephemeral Diffie-Hellman (ECDHE).

When sending a GET request using the HttpClient, the connection simply times out. I have set the TLS version explicitly to TLSv1.2 like this:

httpClientHandler.SslProtocols = SslProtocols.Tls12;

This works, I can see in the Wireshark trace that the correct TLS version is used. I have also confirmed that there is no firewall issue or similar.

Working Example (CURL)

When using cURL, I can see that the cipher suite in the Sever Hello response is TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (0xc030), which is also what the server requires.

enter image description here

Broken Example (.NET 6 with HttpClient)

When using the HttpClient in .NET 6, the above mentioned cipher suite is offered in the Client Hello, but the server response uses all of a sudden TLS_RSA_WITH_AES_256_GCM_SHA384:

enter image description here

I can see that there are additional extensions in the cURL request, for example Extension: psk_key_exchange_modes. Are there any explanations for why the server does not accept the first cipher suite? From my understanding, the first offered cipher suite should be the preferred one, is that correct?

Is there a way to force a certain cipher suite in .NET 6?

This is the example I use to reproduce the issue:

public async void PollUrl(string url)
{
    HttpResponseMessage msg = new HttpResponseMessage();

    ServicePointManager.Expect100Continue = true;
    ServicePointManager.SecurityProtocol |= SecurityProtocolType.Tls12 | SecurityProtocolType.Tls13;

    using HttpClientHandler httpClientHandler = new();

    httpClientHandler.ServerCertificateCustomValidationCallback = (message, cert, chain, sslPolicyErrors) => true;
    httpClientHandler.SslProtocols = SslProtocols.Tls12;

    using HttpClient client = new(httpClientHandler);

    // This content type is required for the API call
    client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/xml"));

    try
    {
        client.Timeout = TimeSpan.FromSeconds(5);
        msg = await client.GetAsync(url);
    }
    catch (Exception e)
    {
        Console.WriteLine(e);
    }

    string stringValue = await msg.Content.ReadAsStringAsync();
    Console.WriteLine(stringValue);
}

The application is running on Server 2016.

Mating answered 13/12, 2021 at 17:56 Comment(0)
M
3

We finally found the reason for this. Windows did not have the required cypher suites enabled. We have used IISCrypto to enable the corresponding cypher suites and all is ok now.

It looks like it's possible to force .NET to TLS 1.2, even though it was not enabled on the server itself.

Mating answered 30/3, 2022 at 12:52 Comment(0)
K
0

Is there a way to force a certain cipher suite in .NET 6?

YES

I have tried this in our production environment which runs on Ubuntu.

// Windows OS throws PlatformNotSupportedException for explicit list of TlsCipherSuite
if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
{
    httpClientBuilder.ConfigurePrimaryHttpMessageHandler(() =>
    {
        var allowedCipherSuites = Enum.GetValues<TlsCipherSuite>();

        return new SocketsHttpHandler()
        {
            SslOptions = new()
            {
                CipherSuitesPolicy = new CipherSuitesPolicy(allowedCipherSuites)
            }
        };
    });
}
Krouse answered 11/11, 2022 at 15:38 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.