'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 |
