Monday 7 July 2014

Strong name signing fails on C++/CLI project on Visual Studio 2010 SP1

Introduction

On C++/CLI projects, we may specify a strong name key for the output module on AssemblyInfo.cpp, like this:

[assembly: AssemblyDelaySign(false)];  
[assembly: AssemblyKeyFile("..\\strong.snk")];  

The first line explicitly sets that we are not going to use delay-signing whilst the second line specifies the key file to sign with. This syntax is legit and should produce a strong name signed .Net module. However, sometimes it doesn't, with producing this warning: 

mt.exe : general warning 810100b3: ??????.dll is a strong-name signed assembly and embedding a manifest invalidates the signature. You will need to re-sign this file to make it a valid assembly.

You might think let's just ignore it, but probably this will make your runtime crash upon loading this module with "System.IO.FileLoadException" which complains about the missing strong name signature on the module. Again - I definitely set the syntax to put a strong name key in the module but the file is not produced so. What's going on inside? 

Under the bonnet 

Let's focus on the warning back - "embedding a manifest invalidates the signature". It sounds like the module had been successfully built with the given strong name key, but then a manifest was embedded, which broke the strong name signature. Perhaps it's possible not to embed a manifest but this is not a right thing to fix the problem. 

So what's happening? Does Visual Studio support a syntax which is not fully implemented? Maybe, yes. The syntax should automatically re-sign the assembly after embedding a manifest, but by some reason it does not do that, yet. Even worse, the Visual Studio versions lower than 2010 did not generate that warning at all so that the developers wasted much time to get to know what was going on there. 

Solution 

Having said that, all we need to fix (or workaround) the issue is to re-sign the module. 

1. Define a post-build custom action using SN.EXE

On Visual Studio 2010 command prompt or Microsoft SDK command prompt, SN.EXE (Strong Name Tool) is available for strong name signature works. Open this link http://msdn.microsoft.com/en-us/library/k5b5tt23(v=vs.100).aspx for details of this utility. Please note that the options of that tool are case-sensitive

To re-sign the module, this syntax can be used on a new custom post-build event (Project property - Configuration Properties - Build Events - Post-Build Event):

  Command Line: sn.exe -Ra "$(TargetPath)" <snk file name/path>  

"-Ra" option is to re-sign an assembly which is already signed, which means AssemblyInfo.cpp should still have the strong name key syntax as shown on "Instruction". 

2. Set "Key File" and "Delay Sign (false)" on project properties

Visual Studio introduced "Key File" and "Delay Sign" fields on C++/CLI projects, which can be used to set a key file explicitly. (Project property - Configuration Properties - Linker - Advanced) Please don't forget that you should apply this on all configurations such as "debug" and "release". 
  • Set "Key File" as what you set on [assembly: AssemblyKeyFile] field on AssemblyInfo.cpp
  • Set "Delay Sign" to false
  • Mind you, the counterparts on AssemblyInfo.cpp should be removed as they conflict.
The build process automatically re-sign the module after embedding a manifest, if these fields are set correctly. Even if you have done this before, you may need to do this again because the internal field syntaxes on the project had been changed on Visual Studio 2010 SP1. If you already set that on RTM and upgraded Visual Studio 2010 to SP1, the settings won't be recognised. If your team has a mixed environment of RTM and SP1, it'll be better to upgrade all to SP1. 

If the problem persists, please refer to the links listed on "References" as many people encountered this issue and succeeded in fixing/workarounding it in various ways. 

References 

2 comments:

Unknown said...

Thank you for this, you saved me!

Unknown said...

No worries, it's my pleasure!