Home > Blockchain >  How should I specify the path to the strong name key in projects published on GitHub and NuGet?
How should I specify the path to the strong name key in projects published on GitHub and NuGet?

Time:12-07

I'm not asking where the path to the strong name key goes. It should be obvious. I'm asking how the path expression should look like, knowing pretty much everything about operating system path specifications.

The GitHub project is a Visual Studio 2022 solution consisting of over 20 .NET 6.0 C# projects. Most of the projects are intended to be published as separate NuGet packages.

With those things out of the way, the details.

The path to the key should be placed in the project file. And here's my concern: I can specify 2 kind of paths: absolute and relative. The relative will break when I move my project. The absolute will break when I move the key.

Absolute path like "D:\Source\Keys\MyKey.snk" will also break when I change the drive letter, the Windows assigns a different drive letter to a removable drive etc.

Unless I pass the path like "\Source\Keys\MyKey.snk". It seems like the most elegant and best solution, if only Visual Studio allowed that to work. But it doesn't. I guess it resolves it as "C:\Source\Keys\MyKey.snk" because why not, if it's installed in "C:\...".

So, either the ugly path with the drive letter, or the ugly relative path. My exact question is is there a third option? Maybe IDK, using an environment variable, a Visual Studio configured internal variable or something like that?

For now I stick to the relative path. Then there's another issue. If someone pulls the GitHub project, it won't compile complaining on the missing keys. Of course they can remove assembly signing and then it would work.

Is there another way?

So the current state of my GitHub project is "strong names by default / relative key paths", it allows me to focus on the coding without unnecessary distraction when pushing or publishing the code changes. But if there was a better solution for the keys, I'm just curious.

CodePudding user response:

Recommended: Check in the strong name key

The .NET team have the following documentation with guidance for library authors, with a page specifically about strong naming: https://docs.microsoft.com/dotnet/standard/library-guidance/strong-naming

This part is relevant:

CONSIDER adding the strong naming key to your source control system.

A publicly available key lets developers modify and recompile your library source code with the same key.

You shouldn't make the strong naming key public if it has been used in the past to give special permissions in partial-trust scenarios. Otherwise, you might compromise existing environments.

Important

When the identity of the publisher of the code is desired, Authenticode and NuGet Package Signing are recommended. Code Access Security (CAS) should not be used as a security mitigation.

Also relevant is this page on strong names: https://docs.microsoft.com/dotnet/standard/assembly/strong-named

Warning

Do not rely on strong names for security. They provide a unique identity only.

So, strong names keys are not about security, so there shouldn't be any real risk if you just commit it to source control. If you want security, that's what Authenticode is for, which uses a different key.

Alternative: PublicSign

There's another feature, PublicSign, which gets around trust issues on the .NET Framework with delay signed assemblies. But honestly, it's really not much different to just checking in the whole strong name key, since it requires you to commit the public key.

First, use sn.exe to extract just the public key (from a very quick look, I think it's the -p option). Notice how this docs page also has the warning saying a strong name is not security. Anyway, this way anyone can build your code on their local machine, and it produces an assembly with the same identity, allowing them to drop in their locally built copy as a replacement in their own app, and everything should Just Work.

Not recommended: CI and local builds work differently

If for some reason you won't check in the strong name key, then you should configure your build to work differently when run locally, compared to when run in CI. Like most things in software development, there's an almost unlimited number of ways you can achieve this, your own creativity is the limiting factor.

One way is to configure your project files not to sign the assembly, and then have a separate step in your CI scripts that runs sn.exe to sign the assembly. However, this will add complexity if you have even a single ProjectReference.

Another way is to exploit the fact that MSBuild is a programming language, despite the fact that it looks like a declarative XML file. Something like <SignAssembly Condition=" '$(StrongNameKey)' != '' ">true</SignAssembly>, and do not commit the <StrongNameKey> attribute in your project file. Change your CI build to use dotnet build -p:StrongNameKey=c:\full\path\to\sn.snk

However, this means that any developer who builds your library locally, will not be capable of producing a binary that is a drop-in replacement that is binary compatible with the binary that you distribute. If someone finds and fixes a bug, and wants to use their own copy while waiting for you to accept the bugfix upstream, they'll have to re-compile all their assemblies that use your package, to ensure they all use the same different identity than your binaries. If they use 3rd party assemblies that use your package, then they're in a really hard spot, because they'll have to also recompile all of those assemblies to use their locally built version of your assembly, only because you didn't provide the strong name key.

  • Related