I need to upgrade a .NET application to support a call to an API on a website that only supports TLS 1.2. From what I read, if the application is targeting 4.6 or higher then it will use TLS 1.2 by default.
To test I created a Windows Forms app that targets 4.7. Unfortunately it errors when I don't explicitly set ServicePointManager.SecurityProtocol. Here is the code:
HttpClient _client = new HttpClient();
var msg = new StringBuilder();
// If I uncomment the next line it works, but fails even with 4.7
// ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
var httpWebRequest = (HttpWebRequest)WebRequest.Create("https://sandbox.authorize.net");
httpWebRequest.KeepAlive = false;
try
{
var httpWebResponse = (HttpWebResponse) httpWebRequest.GetResponse();
msg.AppendLine("The HTTP request Headers for the first request are: ");
foreach (var header in httpWebRequest.Headers)
{
msg.AppendLine(header.ToString());
}
ResponseTextBox.Text = msg.ToString();
}
catch (Exception exception)
{
ResponseTextBox.Text = exception.Message;
if (exception.InnerException != null)
{
ResponseTextBox.Text += Environment.NewLine + @" ->" + exception.InnerException.Message;
if (exception.InnerException.InnerException != null)
{
ResponseTextBox.Text += Environment.NewLine + @" ->" + exception.InnerException.InnerException.Message;
}
}
}
If you uncomment out the following line:
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
it works. This isn't a good solution since it hard codes what TLS version to use, so it wouldn't use TLS 1.3 in future.
What else do I need to do to get it work without having this line. I'm testing from a Window 10 machine with 4.7 installed.
Update
I tried a test with HttpClient and had the same results, I had to explicitly set SecurityProtocol.
Code:
var msg = new StringBuilder();
// Need to uncomment code below for TLS 1.2 to be used
// ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
try
{
var response = await _client.GetAsync(@"https://sandbox.authorize.net");
msg.AppendLine("response.IsSuccessStatusCode : " + response.IsSuccessStatusCode);
msg.AppendLine(await response.Content.ReadAsStringAsync());
textBox.Text = msg.ToString();
}
catch (Exception exception)
{
textBox.Text = exception.Message;
if (exception.InnerException != null)
{
textBox.Text += Environment.NewLine + @" ->" + exception.InnerException.Message;
}
}
I've found one solution. It doesn't answer the question about why TLS 1.2 isn't being used by default on Win10 with .NET 4.7, but it does allow me not to have to set ServicePointManager.SecurityProtocol.
The solution that worked from both my 4.5.2 and 4.7 test apps is to add the following to app.config:
<AppContextSwitchOverrides value="Switch.System.Net.DontEnableSchUseStrongCrypto=false"/>
Here the whole app.config:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.7"/>
</startup>
<runtime>
<AppContextSwitchOverrides value="Switch.System.Net.DontEnableSchUseStrongCrypto=false"/>
</runtime>
</configuration>