How to strong name partially signed assemblies

When developing software based on .NET it is quite common to strong name your assemblies especially if you’re a library vendor providing your libraries to other people. One rule of strong named assemblies is that every other assembly they depend upon must also be strong named. If you are a managed library vendor and you don’t provide strong named assemblies, you prevent your users from strong naming their assemblies. Or much more likely, your users will find another library that is strong named.

.NET assemblies are strong named using an asymmetric cryptographic keyfile usually generated by the .NET Framework SDK utility sn.exe. Development shops typically try to protect the public-private key pair in the keyfile by limiting access to the file, putting it only on dedicated build machines. For developers, a public key file is created that can be used to partially sign an assembly which is also sometimes referred to as “delay signing” e.g.:

C:\PS> sn –p .\keyfile.snk public.snk

Delay signed assemblies are consider strong named for assembly referencing purposes but the CLR loader will not load them directly. Developers usually run sn.exe to bypass the strong name verification check for these partially signed assemblies e.g.:

PS> sn –t .\public.snk # display public key token
PS> sn –Vr *,<copy-pasted-public-key-token>

Now if you tried the commands above in your PowerShell console there’s a good chance you’ll get an error indicating PowerShell doesn’t recognize sn.exe as a valid command. Normally, you would run this tool from a Visual Studio Command Prompt which will have the PATH environment variable configured to include the .NET Framework SDK. But this is PowerShell column and we want to use PowerShell. Fortunately the PowerShell Community Extensions (2.1 and 3.0) provides an easy to get the PowerShell environment configured in the same way. Just execute the following command:

PS> Import-VisualStudioVars 2012

Of course, you can also supply arguments of “2008” and “2010”. Once you’ve executed this command, PowerShell will be able to find all the standard Windows and .NET Framework SDK tools. Note also that Import-VisualStudioVars will configure the environment for either x86 or x64 tools based on the bitness of the PowerShell session.

Now that we’ve got all that configured, developers can happily run and debug their partially signed assemblies. Yay! However, someone on the team gets the job making sure the final build re-signs the assemblies with the full (public/private) keyfile.

One popular way to do this is to walk all binaries in the Binaries directory and run the sn.exe tool against. However, it is quite common that even managed software has some native binaries in the output and sn.exe will error on a native binary. Fortunately, the PowerShell Community Extensions provides a handy command called Test-Assembly to help you determine if a file is a managed assembly or not. The loop to accomplish looks something like this:

Get-ChildItem . –Recurse –Include *.dll,*.exe |
Where-Object {Test-Assembly $_} |
Foreach-Object {sn.exe $_.Fullname keyfile.snk}

With that, your developers are able to get their job done without requiring access to the private key file and your build machine is able to easily re-sign only the managed binaries. Don’t forget that if you’re also Authenticode signing your assemblies, you will need to do that step after re-signing the partially signed assemblies.

Share on: