Monday, December 11, 2006

Code Signing with SIGNTOOL

Part of our automated build system is to digitally sign our applications with our company's Verisign code signing certificate. Predictably, the signcode command failed under Vista.

First, a little history. Originally we signed our application like this:

signcode /spc C:mycredencials.spc /v a:myprivatekey.pvk /t http://timestamp.verisign.com/scripts/timstamp.dll c:\Project1.exe

The problem is that it required us to enter a password in a dialog box every time this command was run. Since we built several applications at a time, our "automated" build process required a lot of manual intervention.

The solution to that problem was to embed the key in the registry using PVKIMPRT. This was always painful because PVKIMPRT had some issues on Windows XP, so you had to use Windows 2000 or Windows 98 to import and export the certificate into a usable format. [Update 7/25/2008 - The problem was originally caused because the key was generated on Windows 2000. This is no longer true, so you can now safely use PVKIMPRT on Windows XP.]

The command line for signcode that directly accessed the certificate store was:

signcode -cn "Cool Corp" -n "My Application" -i http://www.example.com/MyApp.html -t http://timestamp.verisign.com/scripts/timstamp.dll c:\Project1.exe

This worked well on Windows XP, but failed on Vista with the error "failed to build the certificate chain." [Update 7/25/2008 - This problem was probably caused because the intermediate key was not installed. See my later post.]

Recent discussions about codesigning seem to advocate using signtool instead of signcode, although there's no discussion about the difference. I found that signtool has one big advantage over signcode: it can read PFX files, which is what Internet Explorer exports (Control Panel / Internet Options / Content / Certificates / Export). However, if you export your certificate to a PFX file in Windows Vista, you are required to provide a password, which didn't play well with one of our automated build tools.

The first solution was to use Windows XP to create the PFX file instead of Vista. WinXP will allow you to export your certificate and private key to a PFX file without a password. However, I found a better solution with a little research.

Signtool can automatically select a code signing certificate from the registry with the /a option. That's very handy. Eventually I ended up with this command in the Post Build Event:

$(SolutionDir)Tools\SignTool sign /a /d "My Application" /du "http://www.example.com/MyApp.html" /t http://timestamp.verisign.com/scripts/timstamp.dll $(TargetPath)

11 comments:

  1. How do you verify the file integrity of file?

    Windows doesn't verify the digital signature of the file other than if it is an ActiveX object (there are few other)?

    Do you know Windows API using them one could read the digital file signature from the signed file?

    ReplyDelete
  2. In answer to sumit's question, you can check the signature of a file with the function WinVerifyTrust. Sample code can be found at http://msdn.microsoft.com/en-us/library/aa382384(VS.85).aspx.

    ReplyDelete
  3. Thanks for the tip on using /a in the post-build task, it made things much simpler.

    I'm using VS2008, and for whatever reason timestamping (using /t ) is failing in the post-build event, even though the same full signtool command works fine if I manually run it afterward. The error is

    EXEC : SignTool error : ISignedCode::Timestamp returned error: 0x80070020
    The process cannot access the file because it is being used by another process.

    Did you have that hurdle? Any suggestions?

    ReplyDelete
  4. My first guess is that the SignTool error is caused by the indexing system. Try disabling the indexer and see what happens. (Could be Windows Search, Google Search, etc.)

    ReplyDelete
  5. Regarding the error I mentioned above: Turns out it was Norton Antivirus's "real time" protection. Aside from disabling that, I was able to overcome this issue by putting the signtool command *after* another unrelated line in my post-build. The unrelated line makes two calls to updateversion and takes < 1 sec, but this gives enough time to free the file lock.

    ReplyDelete
  6. Thanks for the great post, I got several valuable ideas from it. I recently ran into the signtool 'cannot access the file' problem on Windows 7. I found that adding a command like "ping 127.0.0.1 >NUL" before the signtool command makes the problem go away, or at least makes it much less frequent.

    And just to mention another weird problem I had to resolve with signtool: Using a forward slash ('/') in the sign /d description string causes the resulting digital signature to be considered invalid by Windows. Prefixing with a backslash (like \/) gives a valid signature again, but - both characters end up in the description! I gave up and used a dash instead of the slash...

    ReplyDelete
  7. Spike,

    To sleep for one second, use something like this:

    ping 127.0.0.1 -n 2 -w 1000 > nul

    Or use a "sleep" command from CygWin or the Windows Resource Tools.

    ReplyDelete
  8. Jim, In my certificate (.cer) that I have installed in "Trusted Root Certifi....." store, I don't have any sort of description in it. This is what I use to sign :
    sign /v /n "Subject PArt of " /t http://timestamp.veris
    ign.com/scripts/timestamp.dll Application.exe

    but it doesn't work. Can you help me with this. In many sites I found they ae using storename, but you aren't using any store name also. So, is your certificate installed/imported or where it is. Kindly help me. From many days I am after this, but couldn't achieve the goal yet.

    ReplyDelete
  9. Sorry, I have no experience with Trusted Root Certificates. A Trusted Root should either be a registrar or a corporate certificate created by someone who knows what they are doing. A self-signed certificate would almost never be a trusted root.

    ReplyDelete