Friday, February 19, 2016

Executable Signing Using SHA-256 Certificates

A few weeks ago, a customer complained that when they downloaded the installer for Stonefield Query, they got a warning that the download was corrupted. I tried it myself and couldn’t reproduce it, so I assumed their anti-virus software was the culprit. Then a second customer had the same problem, and then a third. Googling the error message led me to this article describing the real problem: executables signed with SHA-1 certificates (which ours are) are blocked after January 1, 2016 (although it appears to be an issue on some operating systems and not others because, as I said, the downloads worked for me). Although my certificate provider had been sending me emails about upgrading to a SHA-256 certificate, for some reason, I thought it only applied to web servers.

Several years ago, I discussed signing executables with Inno Setup (which incidentally is my most popular blog post ever). There are a few changes necessary to using a SHA-256 certificate with Inno Setup, so I thought I’d document the entire process here, even those things that aren’t specific to the new certificates.

Once you’ve purchased a certificate from your chosen provider, you’ll likely get an email with a link to download the certificate into the certificate store on your machine. Normally, you’ll want the certificate in file form to make signing easier, so you need to get it out of the certificate store after you’ve downloaded it. To do so, do the following:

  • Start the Certificate Manager snap-in by running CertMgr.msc.
  • The downloaded certificate is in the Personal\Certificates section. Right-click the certificate and select All Tasks, Export to bring up the Certificate Export Wizard.
  • In the Export Private Key step, choose Yes, export the private key.
  • In the Export File Format step, Personal Information Exchange (.PFX) is already selected. Make sure Include all certificates in the certification path is turned on (it should be by default). Turn on Export all extended properties.
  • In the Security step, turn on Password and enter a password.
  • In the File to Export step, enter the name of the PFX file to create.

You can then use SignTool to sign EXEs using the PFX file. SignTool comes with Microsoft Visual Studio and the Microsoft Windows SDK. If you don’t have Visual Studio, you can download the SDK from Microsoft’s web site; search for “download Windows SDK” to find the appropriate download page. You can typically find SignTool.EXE in C:\Program Files (x86)\Microsoft SDKs\Windows\v7.1a\Bin (the version number may be different depending on what version of the SDK you download and it may be in C:\Program Files instead). Here’s an example of a command to sign an EXE (the section highlighted in yellow is new for SHA-256 certificates):

"C:\Program Files (x86)\Microsoft SDKs\Windows\v7.1a\Bin\signtool.exe" sign /fd SHA256 /tr timestampServer /td SHA256 /f certificatePath /p password /d "description" fileToSign

where timestampServer is the URL to your certificate provider’s timestamp server so the certificate can be timestamped (see your provider’s documentation), certificatePath is the path to the PFX file, password is the password for the PFX, description is the description for the digital signature, and fileToSign is the path to the EXE to sign. Remember to add quotes around any path containing spaces.

It’s actually even easier than that to sign the installer generated by Inno Setup. You can do it one of two ways:

  • In the Inno Setup Compiler, choose Configure Sign Tools from the Tools menu, click Add, specify a name (I use “Standard”), and enter something like the following for the command:

C:\Program Files (x86)\Microsoft SDKs\Windows\v7.1A\Bin\signtool.exe sign /fd SHA256 /tr timestampServer /td SHA256 /f certificatePath /p password $p

Note there are no quotes in the path and that $p is a placeholder for the SignTool parameters specified in the [Setup] section. Then add the following to the [Setup] section of your ISS file:

SignTool=Standard /d $q{#MyAppName}$q $f

$q is a special symbol meaning insert a quote (you can’t use actual quotes here) and $f is a placeholder for the name of the file to be signed. This assumes you have a constant defined for MyAppName. If not, use whatever you wish for the description.

  • If you compile your ISS file using the Inno command line compiler, pass the following parameter to the compiler:

"/sStandard=C:\Program Files (x86)\Microsoft SDKs\Windows\v7.1A\Bin\ signtool.exe sign /fd SHA256 /tr timestampServer /td SHA256 /f certificatePath /p password"

Be sure to put the certificate in a path with no spaces in any of the folder names or you’ll get unhelpful error messages when you build the setup.


Unknown said...

Thanks, Doug. This was a big help. I finally got the inno setup to sign thanks to your explanation. I ran into one problem though. I didn't understand what Description was supposed to be and just put a few words like My Software. Based on the error message, that was supposed to be a file name. I simply removed it, and the signing went as expected. Perhaps you could provide a description of description for dummies like me. Thanks again. I was pulling my hair out, and there isn't much of that left.

Koen said...

An other dummy question:
Compile error: Error 2 - The system cannot locate the given file

Hmm, which file do you think the system is looking for/

I have followed your instructions and have passed
"/sStandard=C:\Program Files (x86)\Microsoft SDKs\Windows\v7.1A\Bin\signtool.exe sign /fd SHA256 /tr /td SHA256 /f D:\InnoSetUp /p password"
(where password to be excanged with the actual password)
as parameter.
The command for the Configure Sign Tool was identical, without the quotes and without the first letter s.
The two sections as advised where added to ISS.
The certificate is in the given path "D:\TnnoSetUp"

Doug Hennig said...

1. The command for the Configure Sign Tool should not include "Standard=" either.

2. Do you have a C:\Program Files (x86)\Microsoft SDKs\Windows\v7.1A\Bin folder and does it contain signtool.exe?

3. The /f parameter has to have the full path for the certificate file, including the file name, such as D:\InnoSetup\mycert.pfx.


Koen said...

Indeed my bad: copied and pasted the wrong path to signtool.exe into my routine. Now it seems to work.

Unknown said...

Up till this point (pre-signing certificate) I used a PRG called "Maker.prg" to build a batch file that called "c:\Program Files (x86)\Inno Script Studio\isstudio" -COMPILE, which worked fine.

I was able to get InnoScript Studio to successfully sign the installer, so I moved to adapting the Maker procedure, which handles everything (including multiple exe functional scopes) to include command line

However, in trying to add code signing, I followed your example using this code, except I used /a (as I did above) instead of specifying the certificate and password (this works if I sign the program executable as well as when I compile the installer from the InnoScript environment):

FPUTS(lnBatchHandle, '"c:\Program Files (x86)\Inno Setup 6\iscc" ' + ;
'"/sSignTool=c:\ffezinst\distrib\signtool.exe sign /v /tr /td sha256 /fd sha256 /a $p" ' + ;
'"c:\ffezinst\distrib\Inno Setup Projects\FF&EZ\' + lcISSFile + '"')

...but the resulting installers were not signed (but also no error popped). Have I bungled the syntax here or is the certificate store not accessed by iscc.exe?

Unknown said...

I resolved the problem described in my last comment (actually the two problems). 1) I did not realize that the signing setup for Inno Script Studio was not duplicated in Inno Setup Compiler and 2) the "$p" parameter is still required in the command line syntax (which I believe I included at first, then eliminated in a desperate try-anything-to-see-if-it-works mode.