Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Impossible viable fork #17184

Closed
Adahel opened this issue May 20, 2024 · 14 comments
Closed

Impossible viable fork #17184

Adahel opened this issue May 20, 2024 · 14 comments

Comments

@Adahel
Copy link

Adahel commented May 20, 2024

Is your feature request related to a problem? Please describe.

I'm going to write a project that needs to use .NET Framework 4, which has to be 100% strong name and that needs the features of at least version 4.7 of F#. I was able to make a working fork of the latest FSharp.Core, but I can't use any closed third-party libraries, because Microsoft pseudo opened F#, but didn't open MSFT.snk like they opened Open.snk for other .NET projects. I also can't sign with my own SNK and redirect public key token from a third-party assembly because this function never existed and my goal is to backport. Late signature and public signature cannot be tolerated in my project.

My issue is simple, I can modify many strongly named libraries with Open.snk in .Net Core, but why can't I modify F#?

Describe the solution you'd like

The solution that Microsoft provides.

Describe alternatives you've considered

Factor out the prime number of MSFT.snk which is currently RSA SHA-1, using the cado-nfs program, to make F# truly open source. Since my goal is to backport any future changes to RSA SHA-2, this is irrelevant to me.

Additional context

Conversation on Microsoft Copilot:
https://sl.bing.net/he65gwPYzfM

@Adahel
Copy link
Author

Adahel commented May 20, 2024

Please reopen with specific question.

Now there's a question.

@vzarytovskii
Copy link
Member

vzarytovskii commented May 20, 2024

Microsoft pseudo opened F#, but didn't open MSFT.snk like they opened Open.snk for other .NET projects.
...
My issue is simple, I can modify many strongly named libraries with Open.snk in .Net Core, but why can't I modify F#?

I honestly have no idea what Open.snk is. What are the projects it's used in?

@vzarytovskii
Copy link
Member

vzarytovskii commented May 20, 2024

Describe the solution you'd like

The solution that Microsoft provides.

Solution to what? what's the exact need? To patch a shipped dll and re-sign it? Why is it needed? We usually ship FSharp.Core backwards compatible, so, if functionality is missing from older version, a new one can likely just be taken as is. Or is the issue elsewhere? Other libraries? Why can't just additional library be shipped and loaded?

Or is that you want to "rebuild" FSharp.Core for .NET4.0, which we don't ship?

@abelbraaksma
Copy link
Contributor

You can just use the older libs of F# Core, right? They're publicly available.

Why would you want to try to break encryption? What possible gain can you have for that, other than breaking security and the law? Certainly, you're not suggesting that MS release their private keys?

What do you mean with "it's not truly open source"? Everything is in this repo, literally.

@Adahel
Copy link
Author

Adahel commented May 20, 2024

Microsoft pseudo opened F#, but didn't open MSFT.snk like they opened Open.snk for other .NET projects.
...
My issue is simple, I can modify many strongly named libraries with Open.snk in .Net Core, but why can't I modify F#?

I honestly have no idea what Open.snk is. What are the projects it's used in?

Sorry, my computer crashed and I had to restart. I don't know what you call Open.snk internally, but several .Net Core projects, but not all, use this complete and open snk. Here is a bad example: https://github.com/dotnet/LLVMSharp/blob/main/Open.snk

Open.snk has PublicKeyToken=cc7b13ffcd2ddd51, if you open all .NET assembly in ILSpy, you will discover that there are many, but not all.

Describe the solution you'd like
The solution that Microsoft provides.

Solution to what? what's the exact need? To patch a shipped dll and re-sign it? Why is it needed? We usually ship FSharp.Core backwards compatible, so, if functionality is missing from older version, a new one can likely just be taken as is. Or is the issue elsewhere? Other libraries? Why can't just additional library be shipped and loaded?

Or is that you want to "rebuild" FSharp.Core for .NET4.0, which we don't ship?

FSharp.Core above 4.1.18 does not load in .Net Framework 4.0 because it has methods that were only implemented in .Net Framework 4.5 and if I add a library like Theraot.core that implements these methods, I can compile, but it does not load after being compiled, as FSharp.Core will always load first before any third-party library, meaning the fork is necessary. theraot/Theraot#121

@Adahel
Copy link
Author

Adahel commented May 20, 2024

You can just use the older libs of F# Core, right? They're publicly available.

This to me is called Tivoization and to me, it is not open source regardless of what the license says and I don't want to use old, limited versions of F#.

Why would you want to try to break encryption? What possible gain can you have for that, other than breaking security and the law? Certainly, you're not suggesting that MS release their private keys?

If you read the conversation on Microsoft Copilot, you will know that the law has loopholes for what I want to do. FSharp is not even distributed in binary with an anti-reverse engineering license like VSCode, so a path has been opened for this possibility. I presented a problem above that can be solved without releasing the private keys. I hope the problem is resolved peacefully.

What do you mean with "it's not truly open source"? Everything is in this repo, literally.

SNK=Tivoization. If I don't have freedom, it's not open source.

@vzarytovskii
Copy link
Member

I don't know what you call Open.snk internally, but several .Net Core projects, but not all, use this complete and open snk. Here is a bad example: https://github.com/dotnet/LLVMSharp/blob/main/Open.snk

We don't use it internally in F#, hence I don't really know what's that. Maybe @jaredpar or @baronfel know how do they (or anyone else) handle resigning for shipped assemblies, and whether it's generally supported or not. It sounds to me a bit dangerous to allow users to re-sign the dll after modification with the same key.

@vzarytovskii
Copy link
Member

vzarytovskii commented May 20, 2024

This to me is called Tivoization and to me, it is not open source regardless of what the license says and I don't want to use old, limited versions of F#.

Current source is freely available and buildable, you can surely make changes, build it for desired TFM, and sign it with your key, why is original key needed? Also, shouldn't source fork be better in every sense? Since you will be able to sync any changes we make to it, and have a bunch of improvements.

@Adahel
Copy link
Author

Adahel commented May 20, 2024

This to me is called Tivoization and to me, it is not open source regardless of what the license says and I don't want to use old, limited versions of F#.

Current source is freely available and buildable, you can surely make changes, build it for desired TFM, and sign it with your key, why is original key needed? Also, shouldn't source fork be better in every sense? Since you will be able to sync any changes we make to it, and have a bunch of improvements.

Sorry if I didn't make it clear. I have nothing against security, trust and integrity, but without the original snk I can't use third-party closed libraries linked to any FSharp.Core. I can modify the IL Code of these libraries and sign it with my signature, but I will be violating the copyright of the original library and I cannot contact the original author because I am working with legacy content.

@abelbraaksma
Copy link
Contributor

abelbraaksma commented May 20, 2024

In that 4yo discussion, you're mentioning you need to support Windows XP. As you're probably aware, Windows XP is no longer supported by Microsoft. Anybody still using it should upgrade. The same is true for Framework 4.5.

You can upgrade to the latest framework, which is NetStandard 2.0 compatible. Since F# Core lib is NS20/21, it's compatible with that. It can be loaded in XP if you must.

You also mention that you don't like the load order of the assemblies. There are some (rather complex) tricks you can play on the load order, but you'll need to dive deep into how Framework loads dependencies. Use FusionLogvw. The assumption in the reference thread that "the language" requires F# Core to be loaded first is wrong. It has nothing to do with that, but purely with the JITter loading whatever types it sees first.

If you want to force another lib to be loaded first or before, ensure that F# Core is not in the GAC. Then, hook to the AssemblyLoad events. Do this in your ModuleInit.

None of these are simple and I'd advice against it (been there, done that, bad idea). Just upgrade and you'll have a much easier time.

And ditch your private build of F#, you don't need it from what I read in that old thread (but of course, you can sign it any way you want if you build it yourself, no need to hack anything).

@Adahel
Copy link
Author

Adahel commented May 20, 2024

In that 4yo discussion, you're mentioning you need to support Windows XP. As you're probably aware, Windows XP is no longer supported by Microsoft. Anybody still using it should upgrade. The same is true for Framework 4.5.

You can upgrade to the latest framework, which is NetStandard 2.0 compatible. Since F# Core lib is NS20/21, it's compatible with that. It can be loaded in XP if you must.

You also mention that you don't like the load order of the assemblies. There are some (rather complex) tricks you can play on the load order, but you'll need to dive deep into how Framework loads dependencies. Use FusionLogvw. The assumption in the reference thread that "the language" requires F# Core to be loaded first is wrong. It has nothing to do with that, but purely with the JITter loading whatever types it sees first.

If you want to force another lib to be loaded first or before, ensure that F# Core is not in the GAC. Then, hook to the AssemblyLoad events. Do this in your ModuleInit.

None of these are simple and I'd advice against it (been there, done that, bad idea). Just upgrade and you'll have a much easier time.

And ditch your private build of F#, you don't need it from what I read in that old thread (but of course, you can sign it any way you want if you build it yourself, no need to hack anything).

I'm going to study what you said to me and I'm wondering how I'm going to do this in a program that runs in F#? Maybe I have to write a wrapper in C#? And it seems like there are possibilities beyond my control. If the user has FSharp.Core deployed in the GAC, will it be impossible to run the program? It seems like a not-at-all-safe workaround, but it was the most useful comment I've read so far. Thank you very much.

I'll leave it to the team to decide whether to leave this issue open or close it. I don't know if I'll have a better solution than @abelbraaksma informed me; this is what the team will decide. Not only that, but I'm happy with the renewed hope I received for my project; after all, I'm not the owner of the truth.

@jaredpar
Copy link
Member

Maybe @jaredpar or @baronfel know how do they (or anyone else) handle resigning for shipped assemblies, and whether it's generally supported or not. It sounds to me a bit dangerous to allow users to re-sign the dll after modification with the same key.

Strong name signing has really nothing to do with security. That was the intent originally but is no longer the case. For .NET Framework the strong name only serves to provide identity information for the assembly. Thee public key is part of the assembly and that factors into assembly loading, binding redirects, etc ... . For .NET Core it's essentially ignored.

Unfortunately a lot of the .NET core ecosystem was signed with a strong name key that we can't release publicly (it is one of the few that actually factors into security). At the same time we also can't use a new strong name key because that would change the identity of the assembly (which would be an enormous compat break). For those we just use public signing which works in the vast majority of .NET Framework scenarios.

@abelbraaksma
Copy link
Contributor

abelbraaksma commented May 20, 2024

I'm going to do this in a program that runs in F#?

Typically, a program does not "run in F#". It runs in .NET, or more technically correct: the .NET runtime loads your libraries and dependencies and starts just-in-time compilation, and executes whatever you have as a main entry point.

If you were to change the public key (which you can, of course, just sign it with something you want), in .NET Framework, the libs won't load the original F# anymore (as suggested by @jaredpar above), but only yours. There's nothing that stops you from doing so, but the obvious drawback is that your library cannot be loaded anymore with other F# Core libraries, as there's going to be a clear conflict.

If you want your libs to be consumed by anybody other than yourself, there's only one way forward: use the libraries as they've been made available from RTM releases.

If the user has FSharp.Core deployed in the GAC, will it be impossible to run the program?

That's up to you. If you need to stick with old technology and mix it with new technology, you will keep running into issue like these. Best you can do is write a launch-program that executes before yours and just cleans up the system properly.

It seems like a not-at-all-safe workaround, but it was the most useful comment I've read so far. Thank you very much.

Nothing of this is safe, as you are trying to use unsupported versions of libraries that are hacked to work with unsafe operating systems. My guess is, this is going to be the least of your worries. But it's possible, it just requires quite a bit of research into the whole of Framework's assembly loading stuff.

@KevinRansom
Copy link
Member

As discussed above, Windows XP is not a supported scenario. Signing with full Microsoft key is not a supported OSS scenario. We have never specified the Ecma key as a substitute for the Microsoft key in F# core. It may be that was an error we made back in the day, but Mono did fine without it for years.

I'm going to close this issue won't fix.

@abelbraaksma abelbraaksma closed this as not planned Won't fix, can't repro, duplicate, stale May 21, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
Archived in project
Development

No branches or pull requests

5 participants