What is the recommended way to manage a strong-name key pair for an open-source project?
Asked Answered
T

3

11

I manage an open-source project and would like to sign the binaries that are released in the project's binary package. I use Visual Studio csproj and sln files to manage and build my project, and also distribute these files as part of the project's source packages.

How can I sign the produced binaries of my build and not have to distribute the snk key-pair file? If I use Visual Studio to sign the assemblies, each project file now needs a copy of the key-pair in order to build. I'm not comfortable with distributing the key-pair, even if it is password protected.

Edit:

Another caveat is that some assemblies in the project grant friend access via InternalsVisibleToAttribute, and build those friends via a project reference. Consequently, such assemblies need to use a strong name when referring to a signed assembly. However, if the key-pair is not distributed then how can end-users build the sources and maintain the project relationships? If a temporary key-pair file is used, won't the public key token of the signed assemblies change, breaking the InternalsVisibleToAttribute references?

Tiddlywinks answered 2/12, 2009 at 7:43 Comment(0)
T
2

Sharptooth's solution works well if the only assembly references in the code are those encoded in the project files. If your project refers to other assemblies via InternalsVisibleToAttribute or other means where a strong-name string is required, then it is not feasible to build the repository-sources with a temporary key. Doing so will change the public key references that are present in the strong-name strings and break the code.

This is the case in my application so I needed to adopt a different approach.

I basically created a copy of the sln and csproj files in a separate folder heirarchy and modified the csproj files as follows.

  • Transformed all file references to links, pointing to the original sources.
  • Copied and modified each AssemblyInfo.cs file to contain uses of InternalsVisibleToAttribute with a strong name.
  • Modified each csproj file so that the snk file reference is a relative path (removes the need to copy the snk file to each project)

I first did all of this manually, but then realized that this can be automated in a straightforward manner. The first and third steps may be implemented with an XSLT, where as the second step can be implemented with a regex search/replace function.

Since I need to maintain two solutions now, it makes sense to automate this task to avoid future headaches.

The sources in the repository do not build assemblies with strong-names, which is fine, since I wouldn't want to impose any build restrictions or processes on end-users.

Tiddlywinks answered 7/12, 2009 at 21:12 Comment(0)
H
10

This is an old question, but the currently highest-voted answer is not accurate, so I figured it's worth posting a new answer.

For open source projects, Microsoft recommends checking in your private key into your repository. This is safe because strong name keys are used for identity, not security.

See here for reference: https://learn.microsoft.com/en-us/dotnet/framework/app-domains/strong-named-assemblies

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

They also specifically address open source projects:

If you are an open-source developer and you want the identity benefits of a strong-named assembly, consider checking in the private key associated with an assembly into your source control system.

If you want security for your assemblies, then you should look into Authenticode signing: https://blogs.msdn.microsoft.com/shawnfa/2005/12/13/authenticode-and-assemblies/

Hegira answered 8/9, 2018 at 4:48 Comment(0)
S
6

You should not distribute the keypair. The strongname is for verifying that the new version of assembly comes from the same publisher.

If another developer wants to branch your project they will generate their own keypair and that will effectively show that their version is not from you so that other assemblies that depend on yours will not load anymore unless they are recompiled. That's not always convenient but it protects you from someone issuing a malicious version of assembly and silently distributing it.

Stour answered 2/12, 2009 at 7:52 Comment(3)
Since I need to distribute the project and solution files, and since the key-pair is required for the solution to build (when signing is enabled), should I also distribute a "dummy" key-pair so that end-users can build without having to manipulate the project files? It seems cumbersome to check-in project files that disable signing, only to have to toggle this setting every time a release is made.Tiddlywinks
You could do the following: add a build step that would check if an .snk file already exists and run sn.exe to generate a new one if necessary. Then it will build right out of the repository for other users.Stour
Ensuring publisher identity is not the intended purpose of strong-name signing. You're supposed to use Authenticode for that. Microsoft's own documentation recommends publishing the SNK file: learn.microsoft.com/en-us/dotnet/standard/assembly/…Crowning
T
2

Sharptooth's solution works well if the only assembly references in the code are those encoded in the project files. If your project refers to other assemblies via InternalsVisibleToAttribute or other means where a strong-name string is required, then it is not feasible to build the repository-sources with a temporary key. Doing so will change the public key references that are present in the strong-name strings and break the code.

This is the case in my application so I needed to adopt a different approach.

I basically created a copy of the sln and csproj files in a separate folder heirarchy and modified the csproj files as follows.

  • Transformed all file references to links, pointing to the original sources.
  • Copied and modified each AssemblyInfo.cs file to contain uses of InternalsVisibleToAttribute with a strong name.
  • Modified each csproj file so that the snk file reference is a relative path (removes the need to copy the snk file to each project)

I first did all of this manually, but then realized that this can be automated in a straightforward manner. The first and third steps may be implemented with an XSLT, where as the second step can be implemented with a regex search/replace function.

Since I need to maintain two solutions now, it makes sense to automate this task to avoid future headaches.

The sources in the repository do not build assemblies with strong-names, which is fine, since I wouldn't want to impose any build restrictions or processes on end-users.

Tiddlywinks answered 7/12, 2009 at 21:12 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.