As of June 1, 2023, the private keys required to perform Windows code signing must be stored on a FIPS-compliant device. In most cases, a Yubikey is the tool of choice. This solves some problems and creates others.
In the past, when I ordered my certificates from K Software, as so many Xojo developers do, actually getting my private key was a huge challenge. K Software required the use of old browsers, and thanks to browser auto-updating, extracting the private key was problematic to say the least. So using my own private key is an absolute blessing. But the new frustration is that the private key now has to be locked on a Yubikey.
Buying a certificate
For my most recent renewal, I decided to go through ssl.com instead of K Software to get a much better price. At the time of this writing, a 1-year OV certificate from K Software is $313, and only $129 from ssl.com. At K Software's price, you might as well buy the EV certificate for $405 and get that sweet instant SmartScreen reputation. But ssl.com also allows you to buy up to 10 years, which drops the price to just $64.50 per year. This is the option I took, although it should be noted that they are only allowed to issue you one 3-year certificate at a time. When that expires, they will issue you a new one.
K Software will sell you the Yubikey for $90. That's a very fair price, considering that one directly from Yubico costs $80-$90, depending on the model. On the other hand, ssl.com's price for a Yubikey is absolutely insane at $279. There's some value in getting the key from them if you want to avoid the attestation steps. But if you can follow instructions and use a command line, save yourself the $200 and buy directly from Yubico.
Setting up the Yubikey
Ok, so the certificate is purchased, the validation is done, the Yubikey is delivered, and now it's time to actually sign something. You need to perform steps called "attestation", and ssl.com's documentation for this is actually pretty good, so I won't repeat it here. Instead, I'll link to their article on the subject.
HOWEVER there are two pieces of information they left out.
Setup PIV
First, you'll need to set up your private key on your Yubikey before following the other instructions. In Yubikey Manager, go to the PIV section under Applications and press "Configure PINs" to begin the setup. If you've already done this for your Yubikey, skip to the next section. The PIN is something like a six-character code that you will use as a password for signing. It's generally something you'll want to remember. The PUK is an eight character code that can be used to unlock the device if the PIN has been entered incorrectly too many times. It doesn't have to be memorable, but it should be stored somewhere safe. The Management Key is a longer string that you'll need to generate. My advice is to use a quick Xojo app:
Var Board As New Clipboard
Board.Text = EncodeHex(Crypto.GenerateRandomBytes(32))
Both the PUK and Management Key should be stored in a secure location, such as a reputable password manager.
Request a Code Signing Certificate
Second, in step 10 of their guide, they instruct you to go to the "End Entity Certificates" section to download the DER certificate to install on your Yubikey. They skipped a step. When you buy a certificate, they issue you an eSigner certificate so you have the privilege of paying for the overpriced eSigner service. This service would cost me about $175 per month. No one should use it.
Instead, you will need to open a ticket or use their live chat to have them create an actual code signing certificate. In the End Entity Certificates, you should see both an "eSigner Code Signing Certificate" and a "Code Signing Certificate". Use the table in the section for the regular "Code Signing Certificate" section. Also, don't use the look-alike table at the top of your dashboard labeled "Certificate Downloads".
Once you've completed the attestation steps, you're ready to try signing something. Code signing on Windows is most commonly done with signtool
, and Yubico has instructions on how to use your Yubikey to sign a file with signtool.
These instructions work fine, and if you already have signtool installed, I recommend following them to get familiar. When you run the command, you'll get a prompt asking for your PIN, and once you enter it, your file will be signed. It's really not much different from how we used to sign before the Yubikey requirement.
Signing without the PIN
This section was updated in December 2024. The original instructions used osslsigncode but the signatures produced were not trusted by Windows. These updated instructions are easier and produce trusted signatures.
The problem is that your PIN is needed for every single file that needs to be signed. For an Inno Setup installer, the absolute minimum number of signatures required is 3: your application, the installer, and the uninstaller. But realistically it will be more. And if you have multiple installers like I do - 32-bit, 64-bit, ARM, and combo - the number of times your PIN is needed can be very annoying.
This is where scsigntool
comes in handy. This is kind of like a wrapper around the official signtool
process. You still need an official signtool
executable. scsigntool
will take your pin on the command line and inject it into signtool's shared memory so you don't need to enter it for every file. To get scsigntool
ready, follow these steps:
- Download the Windows SDK though you only need to install the "Windows SDK Signing Tools for Desktop Apps" component.
- Download SmartCard Tools. Copy the zip archive's contents (3 files at the time of this writing) into the same directory as
signtool
. The default path isC:\Program Files (x86)\Windows Kits\10\bin\10.0.26100.0\x64
but could change if a newer version is released by Microsoft. - Download and install the YubiKey Smart Card Minidriver.
- Obtain your certificate's thumbprint. The instructions can be found on Yubico's website but the high-level overview is to use
certmgr.msc
to find your certificate under Certificates - Current User -> Personal -> Certificates. Double click your certificate and you'll find the thumbprint in the Details tab.
Now you're ready to configure Inno Setup to do the signing. Launch Inno Setup and open your installer script. In the Tools menu choose "Configure Sign Tools" to list available signing tools. If you've done signing with Inno Setup before, this list will have at least one entry that you could update. This tutorial will pretend there are no in the list.
Press the "Add" button and the first dialog will ask for a name. You'll use this in the installer script to tell Inno Setup which tool to use. I named mine The ZAZ
but you can name yours however you like. The same executable can be used more than once, so if you sign with multiple certificates, naming the tool like the certificate will help stay organized.
The next window asks for the signing command. This is where you enter the command that would be executed on the command, with a few placeholders instead. My command looks like this:
"C:\Program Files (x86)\Windows Kits\10\bin\10.0.26100.0\x64\scsigntool.exe" /pin <pin> sign /sha1 <thumbprint> /tr http://timestamp.sectigo.com /td sha384 /fd sha384 $p
Replace <pin>
and <thumbprint>
with your Yubikey PIN and certificate thumbprint, respectively. The /pin
argument must come first. The other arguments tell signtool
to include a timestamp and use more secure SHA-384 hashes instead of the default SHA-256. $p
will be replaced by parameters from your install script. This command is not stored in your install script, so it is ok to include the PIN here even if your install script is checked into version control. Officially, the recommendation is not to store the PIN anywhere, but Microsoft hasn't given us better options to automated signing.
In your install script, add to [Setup]
a SignTool
line:
SignTool=The ZAZ /d $qApp Name$q /du $qhttps://website.app$q $f
Everything after the tool name will be used instead of $p
in the tool's command. These two arguments set the app name and website. $q
will be replaced by quotation marks. By setting these two arguments in the install script, the same tool can be used for multiple products that should be signed by the same certificate. $f
will be replaced by the full file path.
Finally in your [Files]
section add a signonce
flag to any file (or group of files) that should be signed. This tells Inno Setup to execute your command with the necessary replacements so that it can sign the specified files.
And that's pretty much it. You can use all the features of signtool without having to enter your PIN all the time.