How to manage the private key for signing .NET assemblies

cryptographynet

I write open source .NET class libraries as a hobby and thought about signing them. I can get Visual Studio to generate me a password protected public/private key pair and save it as a .pfx file, but I don't think I should do this for each and every project. One key pair should be enough, right?

Obviously I'm not going to put my .pfx file with the source code in my online public repository: only the assemblies I release should be signed with my key pair. Other people can use their own keys if they want.

So I'm left with some .pfx file that supposedly contains my public/private key pair.

  • How do I manage my key pair effectively?
  • Where do I store it?
  • Do I have to import it somewhere?
  • How can I use it on both my PC and my laptop?
  • How do I prevent the key pair hell when switching from PC to laptop?

Best Answer

The method of storing the key pair depends very heavily on how badly you want to protect it from undesired use. Personally I store my keys in a folder protected by the standard ACLs (so anybody who manages to get admin access to my machine can get to my key pairs). For me that's good enough given that my key pairs aren't that valuable. Microsoft recommends using a key container.

If you want to avoid having to synchronize your key pairs between machines then it is probably best if you were to build the release version of the libraries on one single machine (either your PC or the laptop) and make that machine the 'build machine'. In that case depending on where you are storing your key pair (in a file protected by ACLs or in a key container) you can use either one of these techniques:

If you keep the key pair in a file:

  1. Create public/private key pairs for both computers. You can copy the key pair but that's not required, generating individual ones for each machine is equally valid.
  2. On each machine create an environment variable that points to the location of the key pair on that specific machine. Make sure the environment variables have the same name on both machines.
  3. To allow you to share code between the machines and still use the machine specific key files add the following section to your C# project file.

    <PropertyGroup>
        <SignAssembly>true</SignAssembly>
        <DelaySign>false</DelaySign>
        <AssemblyOriginatorKeyFile>$(YOUR_ENVIRONMENT_VARIABLE_HERE)</AssemblyOriginatorKeyFile>
    </PropertyGroup>
    

If you also want the key to show up in the 'properties' section of the project then you can add the following section

<None Include="$(YOUR_ENVIRONMENT_VARIABLE_HERE)">
  <Link>Properties\App.snk</Link>
</None>

If you keep the key pair in a key container:

  1. Create public/private key pairs for both computers and store them in the key containers. Make sure you use the same name for the key container.
  2. To allow you to share code between the machines and still use the machine specific key files add the following section to your C# project file.

    <PropertyGroup>
        <SignAssembly>true</SignAssembly>
        <DelaySign>false</DelaySign>
        <KeyContainerName>YOUR_CONTAINER_NAME_HERE</KeyContainerName>
    </PropertyGroup>
    

In this case I'm not sure if you can link the key from the 'properties' section (I suspect not).

Using either one of these ways allows MsBuild to find your key and use it during the build while still giving you a (semi-)portable way of dealing with different keys on different machines. Just make sure that you always build your release version of the libraries on the same machine (which will have one set of keys), otherwise you get releases done with different keys.

As for key-pair hell, the only thing you can't do is move the bin folders from one machine to another and expect partial builds to work. If you rebuild the libraries then there shouldn't be any problems.

Related Topic