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 

What is "delay-signing" and how to use / test / prohibit it for testing

Introduction 

In .Net, we have some new concepts of "strong name key" and "strong name signing" to ensure that the modules we supplied to users are from our side. Although it's basically optional, the most of commercial projects use this for security. Microsoft calls the strong name signed assemblies as "Strong-named assemblies". (If you're interested more details, please refer to http://msdn.microsoft.com/en-us/library/wd40t7ad(v=vs.110).aspx ) Please note that this concept is different from "digital signature" which appears on the file properties on Windows Explorer. Strong name key-related information does not appear on Windows Explorer. 

With this information, we understand that there are two sort of modules in terms of strong name signature; "strong-named modules" and "non-signed modules". But what is "delay-signed" ones? 

Why "Delay-Signing" is needed 

To give a strong name to a module, we need a key file which has ".snk" as extension. For security reasons, some company don't open this for all of their developers. Instead, they apply the signatures via a batch process or open/close the file periodically. This means, most of test builds are not allowed to use the snk file whilst they should be built correctly and able to be tested without changing the Visual Studio project properties every time. This is why we have the third option of "delay-signing". 

"Delay signing" does not actually sign binaries but just leave blanks on the binaries in order to really sign them later. These "delay-signed" binaries won't throw an error of "Referenced assembly does not have a strong name" so the build will pass. However, it is still true that the modules don't have valid strong name signatures so that the runtime will crash with "System.IO.FileLoadException" but there is a second chance to re-sign them with a valid strong name key file with SN.EXE (Strong Name Tool). This is a console application which can be run via Visual Studio Command Prompt or Microsoft SDK Command Prompt. Please refer to http://msdn.microsoft.com/en-us/library/k5b5tt23(v=vs.100).aspx for details of this tool. 

How to set "delay sign"

(C#) 
  1. Go to "project properties - Signing". 
  2. Tick "Sign the assembly" and then "Delay sign only"
  3. Set a strong name key file as what you are expected to use for 'real' signing later. 
(C++)
  1. Go to "project properties - Linker - Advanced"
  2. Set "Key File" field
  3. Set "Delay Sign" to "Yes". 
Or, the same thing is achievable on AssemblyInfo.cs or AssemblyInfo.cpp. 

(C#)
[assembly: AssemblyDelaySign(true)]
[assembly: AssemblyKeyFile("myKey.snk")]  

(C++)
[assembly:AssemblyDelaySignAttribute(true)];  
[assembly:AssemblyKeyFileAttribute("myKey.snk")];  

We can set delay-signing on modules to pass the build. Do we still need a valid strong name key to run the binary? 

I said that the build would pass but the runtime would throw an exception due to security checking. Does this mean that this is only for build pass? Of course not. There is another step to "ignore" the signature verification for internal testing. Using SN.EXE, it is possible to register assemblies for verification skipping by specifying -Vr <assembly> option. (Be careful - the option is case-sensitive.) For example, 

  sn.exe -Vr myassembly.dll   

This will add an entry on verification skipping list and the loader procedure won't throw the exception. It makes sense that the list is stored locally on a machine and cannot turn off the verification permanently as this procedure is only for internal testing. 

Not to mention, the "real" signature should be put on the modules before shipping. The procedure will be like this. 

  sn -R myAssembly.dll sgKey.snk  

This is useful if the actual signing should be done by someone else or the key file is not open for every developer. 

Isn't it a security hole as we can run the binary anyway, without a valid strong name signature? 

That's absolutely correct, but at least we can print out the verification skipping list to check if any exception is defined on the machine, by doing this: 

  sn.exe -Vl   

If no entry is defined, it will say "No verification entries registered". As the list exists on registry, it is also possible to visually see the table on regedit. Check these keys when/if your runtime seems to work incorrectly by malicious modules and you're not ready to install Visual Studio or SDK on the target machine.
  • HKLM\Software\Microsoft\StrongName\Verification
  • HKLM\Software\Wow6432Node\Microsoft\StrongName\Verification   (only for x64)
It is also important to ensure that there is no entry here on test machine to perform final test before product release. To do the same thing, there is another useful thing to ensure that there is no exception entry; Create a DWORD entry set to 0 named "AllowStrongNameBypass", under: 
  • HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\.NETFramework
  • HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\.NETFramework  (only for x64)
References

Setup web browser (Google Chrome) search engine for TFS2013

Introduction 

On TFS 2013 Web Interface, it is possible to search any item with new custom queries. However, sometimes it takes too long time if we just need to search items with a short keyword. e.g. "Crash", "Password", ... It's really ineffective to define a new custom query every time for this purpose, indeed. 

Luckily, TFS supports WIQL syntax directly on URL so we can easily setup browser search engine by pre-setting WIQL syntax with keyword replacements. I'm illustrating how-to for Google Chrome, but the same idea can be used in other browsers. 

Keyword Search
  1. ​​Go to settings
  2. Click "Manage search engines" on "Search" tab
  3. Put a new search engine with the following:
    • ​name: TFS title and contents 
    • keyword: tfs 
    • url: http://<TFS web interface base URL>/_workitems#_a=query&wiql=SELECT [System.Title], [System.State], [System.AssignedTo], [Microsoft.VSTS.Scheduling.RemainingWork] FROM WorkItemLinks WHERE (Source.[System.Title] contains '%s' or Source.[System.Description] contains words '%s' or Source.[System.History] contains words '%s') and ([System.Links.LinkType] = 'System.LinkTypes.Hierarchy-Forward') ORDER BY [Microsoft.VSTS.Common.BacklogPriority], [System.Id] mode(Recursive)
      • The base URL is usually the home address of your project. e.g. http://my-tfs-01/tfs/org/TheProject
  4. ​Click "done" 
This is an example result with search keyword 'Evolution':



Item ID search 

Similarly, it is also possible to setup another search engine with TFS ID number. For this case, the configuration will be like this:
  • ​​name: TFS ID
  • keyword: tfsid
  • url: http://<base URL>/_workitems#_a=query&wiql=SELECT [System.Title], [System.State], [System.AssignedTo], [Microsoft.VSTS.Scheduling.RemainingWork] FROM WorkItemLinks WHERE (Source.[System.Id] = %s) and ([System.Links.LinkType] = 'System.LinkTypes.Hierarchy-Forward') ORDER BY [Microsoft.VSTS.Common.BacklogPriority], [System.Id] mode(Recursive)​