Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Detecting TLS Version used for HttpClient POST or GET calls

Tags:

c#

ssl

I am trying to retrieve the TLS Version information. The code I have below makes a successful HTTP GET call using HttpClient. What am I missing? Where do I get the TLS Version information from HttpClient?

I am kind of doing the same thing as was suggested in Which TLS version was negotiated? but that is specific to WebRequest which is not the same as HttpClient.

static async Task MainAsync()
{
    Uri baseURI = new Uri("https://jsonplaceholder.typicode.com/posts/1");
    string apiPath = "";
    using (var client = new HttpClient())
    {
        client.BaseAddress = baseURI;
        HttpResponseMessage response = await client.GetAsync(apiPath);
        Console.WriteLine("HTTP status code: " + response.StatusCode.ToString());
        GetSSLConnectionInfo(response, client.BaseAddress.ToString(), apiPath);
    }
    Console.ReadKey();
}

static async Task GetSSLConnectionInfo(HttpResponseMessage response, string baseURI, string apiPath)
{
    using (Stream stream = await response.RequestMessage.Content.ReadAsStreamAsync())
    {
        BindingFlags bindingFlags = BindingFlags.Instance | BindingFlags.NonPublic;
        Stream CompressedStream = null;
        if (stream.GetType().BaseType == typeof(GZipStream))
        {
            CompressedStream = (GZipStream)stream;
        }
        else if (stream.GetType().BaseType == typeof(DeflateStream))
        {
            CompressedStream = (DeflateStream)stream;
        }

        var objbaseStream = CompressedStream?.GetType().GetProperty("BaseStream").GetValue(stream);
        if (objbaseStream == null)
        {
            objbaseStream = stream;
        }

        var objConnection = objbaseStream.GetType().GetField("m_Connection", bindingFlags).GetValue(objbaseStream);
        var objTlsStream = objConnection.GetType().GetProperty("NetworkStream", bindingFlags).GetValue(objConnection);
        var objSslState = objTlsStream.GetType().GetField("m_Worker", bindingFlags).GetValue(objTlsStream);
        SslProtocols b = (SslProtocols)objSslState.GetType().GetProperty("SslProtocol", bindingFlags).GetValue(objSslState);
        Console.WriteLine("SSL Protocol Used for " + baseURI + apiPath + System.Environment.NewLine + "The TLS version used is " + b);
    }
}

I am expecting TLS connection Info but I get an exception.

like image 219
bdawg Avatar asked Jan 07 '19 19:01

bdawg


People also ask

How do you know which TLS version is used?

Right-click the page or select the Page drop-down menu, and select Properties. In the new window, look for the Connection section. This will describe the version of TLS or SSL used.

Does HttpClient use TLS?

You need TLS 1.2+ support for HttpClient . You don't need TLS 1.2+ support for WebClient .


1 Answers

Under the hood HttpClient uses internal TlsStream class (as in your example for WebRequest). We just need to find it in another location. Here is an example:

static void Main(string[] args)
{
    using (var client = new HttpClient())
    {
        using (var response = client.GetAsync("https://example.com/").Result)
        {
            if (response.Content is StreamContent)
            {
                var webExceptionWrapperStream = GetPrivateField(response.Content, "content");
                var connectStream = GetBasePrivateField(webExceptionWrapperStream, "innerStream");
                var connection = GetPrivateProperty(connectStream, "Connection");
                var tlsStream = GetPrivateProperty(connection, "NetworkStream");
                var state = GetPrivateField(tlsStream, "m_Worker");
                var protocol = (SslProtocols)GetPrivateProperty(state, "SslProtocol");
                Console.WriteLine(protocol);
            }
            else
            {
                // not sure if this is possible
            }
        }
    }
}

private static object GetPrivateProperty(object obj, string property)
{
    return obj.GetType().GetProperty(property, BindingFlags.Instance | BindingFlags.NonPublic).GetValue(obj);
}

private static object GetPrivateField(object obj, string field)
{
    return obj.GetType().GetField(field, BindingFlags.Instance | BindingFlags.NonPublic).GetValue(obj);
}

private static object GetBasePrivateField(object obj, string field)
{
    return obj.GetType().BaseType.GetField(field, BindingFlags.Instance | BindingFlags.NonPublic).GetValue(obj);
}
like image 173
Zergatul Avatar answered Oct 01 '22 14:10

Zergatul