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:

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:

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:

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.