Using TLS 1.3 from .NET 4.0 Application

Due to ubiquitous support for .NET 4.0 on all Windows platforms (including Windows 10) out-of-box, I still keep most of my freeware apps on it. Yes, I lose some new fancy features but not dealing with .NET Framework download makes it really convenient. But there is one thing that proved to be a problem - TLS 1.3.

When I changed my web server to use only TLS 1.2 and above, built-in upgrade suddenly stopped working. Digging a bit showed reason was that .NET 4.0 supported only TLS 1.0 by default and my web server where upgrades were located required TLS 1.2 at the minimum.

For the latest .NET versions, updating to a higher TLS is easy enough:

Code
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls13
| SecurityProtocolType.Tls12
| SecurityProtocolType.Tls11;
| SecurityProtocolType.Tls;

But Tls11, Tls12, and Tls13 enums are not part of .NET 4.0. However, because .NET is so closely integrated with Windows, sometime it's worth asking it directly - by specifying enum's numerical value:

Code
ServicePointManager.SecurityProtocol = (SecurityProtocolType)12288
| (SecurityProtocolType)3072
| (SecurityProtocolType)768;
| SecurityProtocolType.Tls;

If you run this code before making the first HTTP request, suddenly you are not limited to the SSL and the ancient TLS anymore.

As this code still requires a bit of error checking, I finally ended up with the function below:

TryProtocolUpgrade()
try { //try TLS 1.3
ServicePointManager.SecurityProtocol = (SecurityProtocolType)12288
| (SecurityProtocolType)3072
| (SecurityProtocolType)768
| SecurityProtocolType.Tls;
} catch (NotSupportedException) {
try { //try TLS 1.2
ServicePointManager.SecurityProtocol = (SecurityProtocolType)3072
| (SecurityProtocolType)768
| SecurityProtocolType.Tls;
} catch (NotSupportedException) {
try { //try TLS 1.1
ServicePointManager.SecurityProtocol = (SecurityProtocolType)768
| SecurityProtocolType.Tls;
} catch (NotSupportedException) { //TLS 1.0
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls;
}
}
}

This code ensures the highest TLS is supported even from the poor old .NET 4.0.

4 thoughts to “Using TLS 1.3 from .NET 4.0 Application”

  1. Medo, you are an absolute god – you have just saved my bacon with this solution. I am supporting an ancient solution written in the .Net 4 days which has just been enhanced to call a new web API but the API uses TLS 1.3. I have spent more than 3 days trying to upgrade the solution to .Net 4.8 and it was killing me because there were so many packages that had to be upgraded to support 4.8 that had incurred breaking changes, and one of them in particular (AutoMapper) had its claws in everywhere and I clearly failed to figure out how to replace the broken code sequences (it built but fell on its ear when it ran). Your solution has allowed me to just keep building against .Net 4 and all is sweet. Thank you thank you thank you.

  2. I am using HtmlAgilityPac for reading data from site using .net 4.5.2 sol. How to use the above method ?

    string trURL = “https://www”;
    HtmlWeb trweb = new HtmlWeb();
    HtmlDocument doc = trweb.Load(trURL); // This throws error
    System.Net.WebException: The request was aborted: Could not create SSL/TLS secure channel. at System.Net.HttpWebRequest.GetResponse() at HtmlAgilityPack.HtmlWeb.Get(Uri uri, String method, String path, HtmlDocument doc, IWebProxy proxy, ICredentials creds) at HtmlAgilityPack.HtmlWeb.LoadUrl(Uri uri, String method, WebProxy proxy, NetworkCredential creds) at HtmlAgilityPack.HtmlWeb.Load(String url, String method) at HtmlAgilityPack.HtmlWeb.Load(String url)

    1. Where exactly do i need to keep the below code. It throws error

      string trURL = “https://www”;
      HtmlWeb trweb = new HtmlWeb();
      HtmlDocument doc = trweb.Load(trURL); // This throws error

Leave a Reply

Your email address will not be published. Required fields are marked *