Code Signing is for the Birds

Ok, maybe the title came across a bit too strong. I actually really like the idea of executable packages being signed so I know where/who they came from. And for device drivers I can see why they have effectively made it mandatory.

But this last week I ran into a major road block with the Windows 8 smart screen filtering. Supposedly this is to keep me safe. I can even buy that requiring an installer to be signed so you know where it comes from implies a greater degree of reliability.

I have a software package that has been shipping for years, has always been signed, and now our digital certificate has expired and been renewed. For some reason, Microsoft has decided that this must mean that our software is untrustworthy. They have conveniently provided us with the opportunity to purchase a more expensive certificate for signing (EV code signing) that will let us me immediately trustworthy.

But when we tried to go down that road, we ran into all kinds of road blocks. The EV certificate has to be on a hardware token, cannot be used on an Amazon EC2 instance (or any other cloud based machine), and it also cannot be used on a VM of any kind (they informed me that this was a “security feature”). So my only option is to purchase dedicated hardware for the relatively rare situation where I need to perform a publically released build.

It feels like so-called security companies don’t have a clue about usability. The down side of this is that the more they make security unusable, the less it will be used. There is a huge human factor to security that they just don’t want to admit exists.

It also feels like Microsoft is just trying to help generate revenue for signing certificate providers. If we have proven our identity, and created a reputation for our existing certificate, then the fact that we have to renew our certificate shouldn’t be a cause for lowering our reputation. Rather, Microsoft needs to provide a way for our reputation to migrate to the renewed certificate.

Signing Kernel-mode Drivers with SHA-2/SHA-256

I hit a pretty frustrating problem the other day when I renewed my digital certificate for code signing and my drivers stopped working. When I renewed the certificate through VeriSign (Symantec), I was given the option of choosing a SHA-1 or a SHA-2 (with 256-bit digest) hashing algorithm for the certificate. After reading through the background information on these options, and understanding that the new and improved SHA-2 was supported on Vista and above, I determined that SHA-2 would meet my requirements and clicked the button.

I got the new cert, put it in my cert store, and reconfigured all my projects in Visual Studio to sign with the new cert. Everything was working perfectly. It installed and run fine on my test machine, but then one of my co-workers complained that the driver wouldn’t load on his machine. After a short while I realized that I had the same problem on my machine, I just wasn’t seeing it because I had a kernel debugger attached. (Note that there are some registry options that can enable mandatory kernel mode code signing even when the debugger is attached. Read more at MSDN.)

So now that I could reproduce the problem, I started troubleshooting the signing itself. Using “signtool.exe verify /kp”, I verified that the driver was signed, all certificates were valid, and the cross-certificate from Microsoft was also in the signing chain. Signtool claimed that everything was just fine, but the darn thing still wouldn’t load. I was getting the error ERROR_INVALID_IMAGE_HASH (0x80070241): “Windows cannot verify the digital signature for this file. A recent hardware or software change might have installed a file that is signed incorrectly or damaged, or that might be malicious software from an unknown source.” After searching the event logs for a bit, I found the Microsoft-Windows-CodeIntegrity log which contained an Event 3004 with basically the same message as the error code above.

After exhausting my Google-Fu skills with no results, we started brainstorming about what was different between the build yesterday that worked and the one today. Somebody mentioned encryption algorithms, and the light bulbs went on in my head. Adding the specific case of SHA-2 to my searching yielded a couple of pages: Practical Windows Code and Driver Signing and PiXCL: Signing Windows 8 Drivers.

Some of my own testing showed that I couldn’t get a driver built with Visual Studio and a SHA-2 certificate to load on both Windows 7 and Windows 8. Theoretically you could sign it twice with each algorithm (using the /fd switch of signtool), but Visual Studio with the WDK is not really set up to do that, I didn’t want to go monkeying with MSBuild stuff too much.

After calling Symantec support and describing the problem we were basically told, “oh yeah, the support for SHA-2 is not really there for a lot of systems.” You think? Maybe you could have mentioned this when we were renewing the certificate?

The moral of the story, dear reader, is stick with the SHA-1 hash algorithm for signing your kernel mode drivers, at least for the time being.