I recently ran into an interesting issue when developing a connector for a third-party API. When trying to connect to the API endpoint, I received the following error message:
“An error occurred while making the HTTP request to https://<API endpoint>. This could be due to the fact that the server certificate is not configured properly with HTTP.SYS in the HTTPS case. This could also be caused by a mismatch of the security binding between the client and the server.” Inner exception was “Unable to read data from the transport connection: An existing connection was forcibly closed by the remote host.”
Not very informative at first glance, right?
However, after some digging around I realized that the error message was correct, at least in the following part: “This could also be caused by a mismatch of the security binding between the client and the server.” I checked my SOAP bindings, and everything seemed to be correct: server required SSL connection, and I had TransportLevelSecurity specified in my binding:
var binding = new BasicHttpBinding(BasicHttpSecurityMode.Transport);
After I read more about SSL and Transport Level Security (TLS), I understood that “not all HTTPSs are created equal.” HTTPS relies on a family of lower level security protocol implementations called transport level security (TLS), each using different cryptographic algorithms. TLS standards keep developing and improving. At the moment TLS 1.2 is a latest encryption standard powering SSL and TLS 1.3 is in works. In general, anything that is using TLS standard below TLS 1.2 is considered to be non secure because these older encryption algorithms are known to be cracked.
Apparently, the provider of the API I was trying to call disabled all other security protocols except for TLS 1.2. That was reason I was getting the error.
So, why didn’t .NET framework support TLS 1.2 in my case? Well, that was because my application was using .NET 4.0. In .NET 4.0 default transport level security standard is TLS 1.1. The solution for my problem was to upgrade my application to the latest .NET framework: 4.6.1. In this framework version TLS 1.2 is a default cryptographic standard.
But what if you can’t upgrade your application to latest .NET framework and still want to use TLS 1.2? Solutions exist, but they vary depending on the framework version:
- .NET 4.6 and above. You don’t need to do any additional work to support TLS 1.2, it’s supported by default.
- .NET 4.5. TLS 1.2 is supported, but it’s not a default protocol. You need to opt-in to use it. The following code will make TLS 1.2 default, make sure to execute it before making a connection to secured resource:
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12
- .NET 4.0. TLS 1.2 is not supported, but if you have .NET 4.5 (or above) installed on the system then you still can opt in for TLS 1.2 even if your application framework doesn’t support it. The only problem is that SecurityProtocolType in .NET 4.0 doesn’t have an entry for TLS1.2, so we’d have to use a numerical representation of this enum value:
ServicePointManager.SecurityProtocol = (SecurityProtocolType)3072;
- .NET 3.5 or below. TLS 1.2 is not supported (*) and there is no workaround. Upgrade your application to more recent version of the framework.
P.S. For scenario #3 there is also a registry hack which forces 4.5 to use TLS 1.2 by default without enforcing it programmatically.
P.P.S. As Christian Pop from Microsoft mentioned below, there is a recent patch available for .NET 3.5 which is enabling TLS1.2 support.
See:
KB3154518 – Reliability Rollup HR-1605 – NDP 2.0 SP2 – Win7 SP1/Win 2008 R2 SP1
KB3154519 – Reliability Rollup HR-1605 – NDP 2.0 SP2 – Win8 RTM/Win 2012 RTM
KB3154520 – Reliability Rollup HR-1605 – NDP 2.0 SP2 – Win8.1RTM/Win 2012 R2 RTM
KB3156421 -1605 HotFix Rollup through Windows Update for Windows 10.
Nicely written. Very help. Thanks !
~Nicely written. Very helpful. Thanks !
Thank you, Vijay!
Useful. Would have been more useful had you actually explained the registry hack or at least provided a link.
Thanks a lot! It’s very helpful for us since we need to upgrade to TLS 1.2.
http://stackoverflow.com/a/32892997
This is very helpful information!
Is it possible to get the TLS 1.2 connections to work on older environments?
I’m trying to run a .net app which makes client calls on a Windows Server 2008 SP2 machine. The machine has .net 4.5 and I’m following the above instructions but couldn’t get connection to an api.
Support for TLS v1.2 included in the .NET Framework version 2.0 SP2
https://support.microsoft.com/en-us/kb/3154517
Thank you! Vendor ended support for 1.0 today and all my calls started failing. I’m using .NET 4.5 and I can’t upgrade just yet. This saved me today. Thanks again.
You saved my bacon today… upgraded the component that was making web service calls to a vendors web service who turned off TLS 1.1 (and didn’t bother to communicate it) to version 4.6 and fixed it. Thanks!
Thanks, this helped a great deal.
First of all thank you so much for this suggestion. I have did the same but my server service is throwing an error called, Service cannot be started. System.NotSupportedException: The requested security protocol is not supported. What am i suppose to do for clearing this error.
Thank you!
Samuvel, what .NET Framework version your application is running on?
Hello,
Thank you for the article!
Regarding “.NET 3.5 or below. TLS 1.2 is not supported and there is no workaround. Upgrade your application to more recent version of the framework.”:
We have recently added a feature for .Net 3.5 allowing applications to optionally use system-default SSL and TLS versions, including the deprecated TLS 1.2, rather than the versions of TLS now used by default in .Net 3.5.
To use this feature, you must first install a patch that is specific to each version of Windows, as described in the KB articles below, and then modify the registry as described in each KB article.
KB3154518 – Reliability Rollup HR-1605 – NDP 2.0 SP2 – Win7 SP1/Win 2008 R2 SP1
KB3154519 – Reliability Rollup HR-1605 – NDP 2.0 SP2 – Win8 RTM/Win 2012 RTM
KB3154520 – Reliability Rollup HR-1605 – NDP 2.0 SP2 – Win8.1RTM/Win 2012 R2 RTM
KB3156421 -1605 HotFix Rollup through Windows Update for Windows 10.
Cristian Pop, Microsoft (MSFT)
Correction:
“We have recently added a feature for .Net 3.5 allowing applications to optionally use system-default SSL and TLS versions, including TLS 1.2, rather than the versions of TLS now used by default in .Net 3.5.”
TLS 1.2 is obviously not deprecated.
Thank you, Christian!
I’ll update my post to include your notes.
> I’ll update my post to include your notes.
Thank you Stan!
Thanks for sharing this! It tremendously helped me in my research.
Thank you for the article!
I have a .NET app written against framework 3.5 and then the same app written against .NET 4.5.2. In Win 7, I can get the 4.5.2 one to connect to a TLS 1.2 only server, but I cannot get the 3.5 one to work despite the suggested patches above. On Win 10 both versions of the app work as expected.
Is there some other thing I’m missing that might provide some guidance?
I find if your server has TLSv1.0 disabled you have to designate this even with .NET 4.6.1 or you will get connection errors.
I solved this error by setting SchUseStrongCrypto in windows registry. ref https://success.outsystems.com/Support/Enterprise_Customers/Maintenance_and_Operations/(.NET)_Enable_SSL_Protocols_for_your_Integrations_-_TLS_1.1_and_TLS_1.2
Thank you very much – perfect written post and content – really helpful
Great article! I do have a question:
– we have an app running in .NET 4.5, using Tls 1.2, everything works ok
– we have a similar app running in .NET 2.0 that needed to use Tls 1.2. And we got it working using this line of code: ServicePointManager.SecurityProtocol = (SecurityProtocolType)3072;
So my question is, how can this work in the .NET 2.0 version of the application?
Hi,
I have my application in .net 4.5 , I want to enable TLS 1.2 in this application. I have upgrade application version from v4.5 to v4.6 after I checked my connection with the salesforce its giving error “UNSUPPORTED_CLIENT: TLS 1.0 has been disabled in this organization.Please use TLS 1.1 or higher when connecting to Salesforce using https.”.
If I stay on the v4.5 and used the line “ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;” then it work fine.
My client want to enable tls1.2 with upgrade v4.5 to v4.6 and we know .net v4.6 support tls 1.2 by default meand no need to extra work.
but in my case its tls1.2 not working even I change my framework version with v4.6.
I am using visual studio 2015 updated 2 version.
I have a VB project (part of a Visual Studio 2013 solution) which targets .NET 4. The remote server to which the app sends a web request has stopped supporting TLS 1.0 (which is the default in .NET 4) so the app stopped working, with exactly the same error message expressed at the top of this article. Rather than change the .NET target, I added the line of code as follows:-
System.Net.ServicePointManager.SecurityProtocol = DirectCast(3072, System.Net.SecurityProtocolType)
This appears to have done the trick.
Huge thanks!
Great article. This shed some decent light on a current situation. Obviously, I’m a little late to the game here, but, if I upgrade to 4.6+ will the framework automatically switch to the lowest common denominator (maybe they currently only support 1.1, etc…) or am I back to square one with now having to explicitly state Tls1.1?
James Collet entry above (#2 in this list), did the trick for us. Thank you!
Has 4.7 changed the way it defaults which TLS to pick
Support for TLS System Default Versions included in the .NET Framework 3.5 on Windows Server 2012
https://support.microsoft.com/en-us/help/3154519/support-for-tls-system-default-versions-included-in-the–net-framework
Helped. Thanks
I have .net 4.6.2. As per this artical – .NET 4.6 and above. You don’t need to do any additional work to support TLS 1.2, it’s supported by default. but this is not working in our case, we found this is working only on .NET 4.7 and above.
So we set following code
ServicePointManager.SecurityProtocol = (SecurityProtocolType.Tls | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls12);
and its working. But we need to add this code in different assemblies, and our architect don’t want this. This should be global and if future TLS 1.3 come we don’t need to change code , we just need to change settings or something.
Please suggest.
Thanks in advance.
Fantastic. Thanks.
As per the Microsoft site https://docs.microsoft.com/en-us/dotnet/api/system.net.servicepointmanager.securityprotocol?view=netframework-4.7#System_Net_ServicePointManager_SecurityProtocol:
Starting with the .NET Framework 4.7, the default value of this property is SecurityProtocolType.SystemDefault. This allows .NET Framework networking APIs based on SslStream (such as FTP, HTTP, and SMTP) to inherit the default security protocols from the operating system or from any custom configurations performed by a system administrator. For information about which SSL/TLS protocols are enabled by default on each version of the Windows operating system, see Protocols in TLS/SSL (Schannel SSP).
For versions of the .NET Framework through the .NET Framework 4.6.2, no default value is listed for this property. This suggests that for .Net 4.6.2 and earlier, you would need to set the TLs version in code using ServicePointManager, etc.
Thank you!
I have a CLR Assembly in SQL Server 2008R2, that connects to an external web service and which has just switched off TLS1.0, and in doing so, broke my CLR Assembly. SQL Server 2008 only supports .Net2.0 for CLR.
Tip #4, for .Net3.5 (and also .Net2.0) didn’t make an easy solution look hopeful, but there is a way!
First, make sure your SQL Server is up-to-date – patch list here:
https://support.microsoft.com/en-gb/help/3135244/tls-1-2-support-for-microsoft-sql-server
and
https://support.microsoft.com/en-gb/help/321185/how-to-determine-the-version-edition-and-update-level-of-sql-server-an
Once all this was done, then adding the line in tip #3 to the CLR made it all work again.
Disaster averted!
.NET 4.7 will use the system default for TLS, but there is a gotcha: If you are running Win7 SP1 or Server 2008 SP1, the system default for TLS 1.2 is: disabled.
To get around this you can update the registry on the machine or use the same codefix required for pre-4.5 .NET versions (see Sandesh’s comment below).
So even if my app, which is .NET 3.5, and is running under the 4.0 CLR on Windows Server 2016, I still need to re-target my application?
Very Informative. Thanks a lot 🙂
Absolute lifesaver having the tip for .NET 3.5 of using 3072. Thanks so much.
Very informative, I need exactly this.
Currently we are using VS2010 and .NET 4.5 but application framework is restricted to .NET 4.0 as VS2010 doesn’t support .NET 4.5. So we used the numerical representation of enum values for TLS1.1 and TLS1.2
Thank you sir !!!
Really helpful Thanks you 🙂
great article. you are my hero. thanks.
Thank you! It was great help for providing this resolution.
Thanks for the very helpful article. I have Client & Server WCF applications developed in Visual Studio 2017 C# with DotNet 4.5 Framework. Adding this line immediately before WebRequest.Create() fixed the problem with forced TLS 1.2, i.e.,
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
var myRequest = (HttpWebRequest)WebRequest.Create(serverURL);
Incidentally, Immediately after I put debug output of these two values:
myRequest.ProtocolVersion and myRequest.ServicePoint.ProtocolVersion
They both show 1.1. I would expect them to show 1.2, or are these unrelated to the the Security Protocol?
Thanks for this article. I realized that the error message was correct, at least in the following part: “This could also be caused by a mismatch of the security binding between the client and the server.
Hi,
I have got .net core client and want to connect to TLS enabled Sql server. I am using System.Data.SqlClient (4.4.3) package and getting below error:
Error: The connection is broken and recovery is not possible. The client driver attempted to recover the connection one or more times and all attempts failed. Increase the value of ConnectRetryCount to increase the number of recovery attempts.
at System.Data.SqlClient.SqlCommand.EndExecuteNonQuery(IAsyncResult asyncResult)
at System.Threading.Tasks.TaskFactory`1.FromAsyncCoreLogic(IAsyncResult iar, Func`2 endFunction, Action`1 endAction, Task`1 promise, Boolean requiresSynchronization)
— End of stack trace from previous location where exception was thrown —
Any idea?
Thanks,
Muhammad
Thank you for this article. 3 years after you wrote it, it just helped me track down a TLS 1.2 connection issue with an older version of svcutil.exe.