Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I force an application compiled to target .NET Framework 4 to run under .NET framework 4.6.1?

Tags:

.net

clr

I have done considerable research and not found any suitable answer. Here is the scenario.

I have an application which was compiled to target .NET Framework 4. At runtime I want that application to actually execute within the .NET Framework 4.6.1. I found two options so far.

  1. Recompile the application under .NET Framework 4.6.1
  2. Add the configuration/startup/supportedRuntime element to app.config with version="v4.0" sku=".NETFramework,Version=v4.6.1"

Option 1 is not desirable as it would require a re-release of software.

Option 2 doesn't do what I would expect. It seems to check if CLR 4.0 (not framework 4.0) is installed and if not prompts to download the appropriate SKU to install it. After being installed, the application still executes under .NET Framework 4.0

As a test, and the reason this question is posted, I created a small console app which simply does this

Console.WriteLine(System.Net.ServicePointManager.SecurityProtocol);

If that is compiled against .NET Framework 4 then the output is

Ssl3, Tls

If that is compiled against .NET Framework 4.6.1 then the output is

Tls, Tls11, Tls12

like image 964
Greg Bogumil Avatar asked Jun 17 '16 12:06

Greg Bogumil


2 Answers

The specific ServicePointManager.SecurityProtocol determination is quite unrelated to the general question of 4 vs 4.6.1 framework for which I'm afraid there's not definitive answer, because it's not relevant in the general case (all cases are probably specific, if you will).

For the specific answer, this is described here: Mitigation: TLS Protocols

Starting with the .NET Framework 4.6, the System.Net.ServicePointManager and System.Net.Security.SslStream classes are allowed to use one of the following three protocols: Tls1.0, Tls1.1, or Tls 1.2. The SSL3.0 protocol and RC4 cipher are not supported.

If the 4.6+ is installed, then you can indeed change the behavior of your program w/o recompiling it, as detailed in the article, just add this line to your .config files:

<configuration>
  ...
  <runtime>
    ...
    <AppContextSwitchOverrides value="Switch.System.Net.DontEnableSchUseStrongCrypto=false" />
  </runtime>
  ...
</configuration>
like image 190
Simon Mourier Avatar answered Nov 08 '22 23:11

Simon Mourier


I am ... asking about the general case of forcing an application compiled against framework 4.0 to run using framework 4.6.1

Well, you already did with app.config file entry. It empowers this feature, the user can't get the program running without installing 4.6.1 first. All he has to do is click the Yes button. Not that this gets exercised very often, 4.6.1 should always be present on the machine when the user is responsible about keeping his machine updated with Windows Update. If he intentionally doesn't then "forcing" isn't very likely to be received well.

But that is not actually what your question is about. You want your program to behave like it is installed on 4.6.1. That's a very different kettle of fish. Do note that 2) did not work, you can't fool the runtime that easily. The compiler embedded a TargetFrameworkAttribute attribute in your executable file, that's the one the runtime uses to determine how it should behave. Have a look-see with ildasm.exe, double-click the manifest to see it. Your app.config entry does not override it.

Biggest issue is that .NET 4.5 is rather fundamentally different with heavily breaking changes in the both the runtime and the framework assemblies. Heavy enough to would have warranted bumping the version up to 5.0. But that always causes lots of pain and suffering on the customers, Microsoft pulled out every trick in the book to make 4.5 (and up) behave like 4.0 if it runs a program that targeted 4.0.

Not just one trick. One core approach were the reference assemblies stored in c:\Program Files (x86)\Reference Assemblies directory. They store the targeting pack files. You used the ones stored in C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework.NETFramework\v4.0 when you originally built your program. If you retarget your project then you'd use the ones stored in v4.6.1. They are very different. And notably the SecurityProtocolType enum you are talking about is different, it acquired two new values. This is a breaking change, a .NET 4.0 program is liable to suffer a heart-attack when it sees SecurityProtocolType.Tls12, it has no idea whatsoever what it could mean. Building a program with the wrong targeting pack files can cause deeply mystifying exceptions.

And other tricks. Bug fixes made in post .NET 4.0 releases are selectively turned on depending on the [TargetFrameworkAttribute], backwards compatibility for bugs is important to ensure that a program doesn't observe changed runtime behavior. And the CLR is filled to the brim with appcompat switches. I could point to the source code file in CoreCLR but it is entirely too scary to look at :)

So no, making a program compiled to target .NET 4.0 behave like it runs on a higher version is not possible. The registry key and the appcontext switch you learned about is highly specific to just the ServicePointManager.SecurityProtocol property. They are there simply because you are not the only customer that wants to do this, TLS versions are rather important. Just make sure that the new enum values don't trip up your program.

like image 11
Hans Passant Avatar answered Nov 08 '22 23:11

Hans Passant