Monday 7 July 2014

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

No comments: