'How to scan and verify the version of TLS for a website?

How to scan and verify the version of TLS for a website?

I was hunting for solutions which can automatically scan all the endpoint website domain in our company. SSL Labs had a manual online solution

https://www.ssllabs.com/ssltest/index.html

How can this feature be achieved programmatically?



Solution 1:[1]

I had same issue. Created free and open-source project on GitHub https://github.com/JocysCom/SslScanner, which contains:

  • Portable standalone SSL, TLS, STARTTLS Scanner Tool.
  • /Tool/Common/Test_SSL_Support.cs - C# code which will check SSL/TLS version
  • /Tool/Common/Test_SSL_Support.bat - simple batch script which runs C# like a script on Windows Command Line. Note: I use PowerShell and Batch on Windows to run C# like a scripting language in order to automate tons of stuff.

Test_SSL_Support.cs have 'TestTCP' method which returns 'true' if connection supports specified protocol version:

static bool TestTCP(string host, int port, SslProtocols protocol, out bool connected)
{
    var success = false;
    var client = new TcpClient();
    var asyncResult = client.BeginConnect(host, port, null, null);
    // 5 seconds timeout.
    connected = asyncResult.AsyncWaitHandle.WaitOne(TimeSpan.FromSeconds(5));
    // Connected.
    if (connected)
    {
        var stream = client.GetStream();
        // Don't dispose underlying stream.
        using (var sslStream = new SslStream(stream, true, ValidateServerCertificate))
        {
            sslStream.ReadTimeout = 15000;
            sslStream.WriteTimeout = 15000;
            sslStream.AuthenticateAsClient(host, null, protocol, false);
            result.UpdateFromSslStream(sslStream);
            success = true;
        }
        client.EndConnect(asyncResult);
    }
    return success;
}

Test_SSL_Support.cs supports StartTLS protocol too. Look for method:

static bool TestStarTLS(string host, int port, SslProtocols protocol, out bool connected)

You can add multiple hosts and ports to Test_SSL_Support.bat for scan:

:: Test SSL/TLS.
CALL:PS www.google.com 443
:: Test StartTLS.
CALL:PS mail.jocys.com 110

Command line results are represented as:

172.217.169.4 www.google.com:443

  Ssl2  = False | The client and server cannot communicate, because they do not possess a common algorithm
  Ssl3  = False | The client and server cannot communicate, because they do not possess a common algorithm
  Tls   = True  | Exchange = ECC-256 | Cipher = AES128 | Hash = SHA1
  Tls11 = True  | Exchange = ECC-256 | Cipher = AES128 | Hash = SHA1
  Tls12 = True  | Exchange = ECC-256 | Cipher = AES128 | Hash = SHA256
  Tls13 = True  | Exchange = ECC-256 | Cipher = AES256 | Hash = SHA384

62.30.149.144 mail.jocys.com:110

  Ssl2  = False | The client and server cannot communicate, because they do not possess a common algorithm
  Ssl3  = False | The client and server cannot communicate, because they do not possess a common algorithm
  Tls   = False | Authentication failed because the remote party has closed the transport stream.
  Tls11 = False | Authentication failed because the remote party has closed the transport stream.
  Tls12 = True  | Exchange = ECC-384 | Cipher = AES256 | Hash = SHA384
  Tls13 = False | Authentication failed because the remote party has closed the transport stream.

Solution 2:[2]

SSLLabsAPI seems to work

using SslLabsLib.Enums;
using SslLabsLib;

public static void TLSChecker(string urlString)
{

    SslLabsClient client = new SslLabsClient();                                 
    // Get ipaddress and host
    var analysis = client.GetAnalysis(urlString, 24, AnalyzeOptions.Publish);
    Console.WriteLine(analysis.Host);            

    foreach (var item in analysis.Endpoints)
    {
        Console.WriteLine(item.IpAddress);

       var endpointanalysis = client.GetCachedEndpointAnalysis(analysis.Host, IPAddress.Parse(item.IpAddress));

        // get protocol list
        foreach (var protocol in endpointanalysis.Details.Protocols)
        {
            Console.WriteLine(protocol.Id);
            Console.WriteLine(protocol.Name);
            Console.WriteLine(protocol.Version);                    
        }                

    }

Solution 3:[3]

Use HttpClient... force it to use TLS 1.2... see if it fails... profit.

public async Task<bool> SupportsTls12(string url)
{
    ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
    var client = new HttpClient();
    try
    {
        var response = await client.GetAsync(url);
        return true;
    }
    catch(HttpRequestException)
    {
        return false;
    }
}

If you find this gives you false positive/negatives, you may have to modify the exception handler to inspect the specific error that is returned. But this is the general idea.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Evaldas Jocys
Solution 2 Heretic Monkey
Solution 3 John Wu