Notes on signing code with your own hardware (Yubikey)

I missed the opportunity to get a new non-hardware-based code signing certificate last May. Here are some notes of the process to get a new one.

  • First option is to get it through Lindersoft. Cost is US$681 for the 3 years certificate, plus $50 for the USB token and $40 for standard shipping ($90 for expedited shipping). Average cost is $257 per year.

  • Googling I found the site SignMyCode which is a certificates reseller, but has a lot for resources and tutorials. SignMyCode lets you buy certificate without a USB key, if you have your own hardware to store the keys.

  • Hardware Security Modules (HSM) are usually expensive, but you can also use a cheaper Yubikey

  • Since I always use a laptop to work, I liked a lot the idea to use a tiny Yubikey Nano and keep it plugged in the USB port, instead of having to find a regular sized USB token every time I need to sign code.

  • Ordering the lowest priced certificate from SygnMyCode costs US$599.97 for 3 years, no shipping needed. A FIPS Certified Yubikey 5C Nano costs $95 plus tax and shipping, total $107.51. Average per year is $235.82, a little less than Lindersoft’s option. Since you don’t need to buy another USB token every three years, the average per year for 9 years is $211.93. But the decisive reason for me was the convenience of the size of the Yubikey Nano.

  • To be fair, the certificates sold through Lindersoft are EV (Extended Validation). The one I bought is only OV (Organization Validated). Upgrading to EV in SignMyCode costs $70 more per year. I think the validation process for EV may be more complicated than OV so I preferred the OV option.

  • Important: if you order a Yubikey, double check that you are buying the FIPS certified version. I didn’t know there were two version and ordered the first one I found in Amazon, but it was rejected when I tried to get the certificate. The FIPS capable versions cost around US$60, the FIPS certified versions are closer to $100. It may be better to order directly from Yubico.

  • When you receive your Yubikey, you should change the default PIN and Management keys, then follow this tutorial to create a CSR (certificate request) and to export the key attestation and intermediate files. The video talks about merging the files, but the order page in SignMyCode now lets you paste each file in a different field.

  • With your CSR and key attestation files, you are ready to order the certificate. The process will ask information about your company. A DUNS number is requested but I think it’s optional (I had one I got when registering in the Apple Developer Program).

  • The next day you’ll received a link to upload the documentation. They ask for a picture of a government issued ID and a selfie of you holding the ID. You also should upload any documentation that proves that your company exists. I lost a few days at this part because I only had uploaded the ID pictures, and I realized I needed to upload more documents until they replied to my support ticket.

  • After the documentation is validated, you receive another link to start the order validation phone call. The link shows the phone number they are going to call. They must validate this number somewhere else, fortunately I used my personal cel phone when registering with the Apple Develpers Program, so that part was easy. The process is automated, you press a Call me now button, your phone rings and a recording tells you to dial 1 to confirm the order (it took me a few tries until the 1 registered) and then reads you a number. You enter that number on the page where you pressed the call me now button and the order is validated.

  • The next day you receive a notice that your certificate was issued (I confirmed my order in a Friday and received the certificate until next Monday). You can then log into the SignMyCode site and download a zip file that includes your certificate .crt file and an additional CA bundle .crt file.

  • SignMyCode gives you support through a chat window in their site, they are very responsive. Support with the certificate issuer is through support tickets. Maybe they are in a diferente time zone because all interactions took 24 to 48 hours to complete.

  • Now that you have the crt file, the next step is to import it into your Yubikey using this tutorial. This video also explains the command you use to sign your files, more details bellow.

  • After if you import the certificate, if you run certmgr.msc you should see your new certificate under Personal / Certificates. In my case, when I first tried to sign code, I received errors saying the certificate wasn’t found. When I ran certmgr.msc the certificate wasn’t there. The solution was to install the YubiKey Smart Card Minidriver. After installing the drivers and unplugging and plugin again the Yubikey, the certificate was displayed.

  • You need a signtool.exe to sign your code. I’m not sure if older versions (I had one from 2016) are compatible with hardware-based certificates, but if you want to download the latest version (May 2023) you need to install the Windows SDK, or download the Windows SDK .iso file and extract the code signing tools installer.

  • This is the command I’m using to sign exes and dlls:

    signtool sign /sha1 CERTIFICATE_THUMBPRINT /ac Certera_CABundle.crt /as /fd sha256 /d "DESCRIPTION" /du "URL" /td sha256 /tr FILENAME

    • signtool sign: sign command for signtool
    • /sha1 CERTIFICATE_THUMBPRINT: Instead of passing the name of the pfx file as usual, you pass the sha1 thumbprint of your certificate. You can view it using certmgr.msc, it’s a 40 digits hex number.
    • /ac Certera_CABundle.crt: The additional file you receive in the zip file where you get the certificate. If not included, the certificate may show as not validated in the signature.
    • /as: Add a new signature in case the file has already been signed.
    • /fd sha256: Use the sha256 signing algorithm
    • /d "DESCRIPTION" /du "URL" Information about you program
    • /td sha256 /tr Timestamp the signature
    • FILENAME: name of the exe or dll to sign (may be more than one)
  • For completeness, this is the command to sign using sha1, but I don’t think it’s needed anymore, unless you need compatibility with computers running an os older than Windows XP SP2

    signtool sign /sha1 CERTIFICATE_THUMBPRINT /ac Certera_CABundle.crt /as /fd sha1 /d "DESCRIPTION" /du "URL" /t FILENAME

  • In the version of Setupbuilder I’m using (2019.7 with current maintenance plan) I didn’t find a way to configure a certificate using its thumbprint. I ended disabling code signing and the option Enable Installer Integrity Check, and now I sign the installer after SB finishes, using the same command shown above. There’s a Setupbuilder 2023 version currently in beta, but I haven’t tested it yet.

  • Since the certificate is now protected by the Yubikey, it’s necessary to enter the PIN code every time a file is signed, in my case it’s a few dozen files for every release, very annoying. There seem to exist options to cache the PIN for a few minutes, but they must be specified when the key is crated, maybe I’ll look into this in 3 years. Another option is to pass all the exes and dlls to sign to a single signtool command, so it only asks for the PIN once. A simpler solution is to use this alternate signing tool that lets you pass the PIN as a parameter. With it the command can be changed to:

    scsigntool -pin PINNUMBER sign /sha1 ...

  • If you have an automated cloud-based build server, it’s possible to use Azure Keyvault HSM to store your certificate. I think you pay Azure around US$5 per key per month, but it only works with more expensive certificates.

  • NEW: I had visited the Lindersoft order page a few months ago and only found options to order the certificate with physical token. Now they also have an option to order by pasting a key attestation file from a Yubikey. If you want an EV certificate, this may be a better deal.

I hope this helps anyone getting a new certificate. If you need help in a particular part, just let me know and I’ll try to share more details or screenshots.




Thanks Carlos for the detailed information.

1 Like


We’re in the tail end of this process as well, but we’re going the HSM route.

RE: the pin issue, have you tried using wildcards to sign instead of signing each file individually?

I’d be very curious to hear about your experiences.

RE: the pin issue, have you tried using wildcards to sign instead of signing each file individually?

Yes, it works, with both signtool.exe and scsigntool.exe. You can pass wildcards or a list of filenames.

I don’t use wildcards because I like to first check if the file already has a valid signature, since the installer may include signed binaries from other projects or third parties. I use a bat file to check all files in a folder.

signfolder c:\project\release "Description" "http://url"


@echo off
rem %1 folder
rem %2 description
rem %3 url

echo Signing folder %1\*.dll,*.exe

for %%F in (%1\*.dll %1\*.exe) do (
  call sign.cmd %%F %2 %3


@echo off
rem %1 exe/dll
rem %2 description
rem %3 url

signtool.exe verify /q /pa %1 > nul
if not errorlevel 1 (
echo %~nx1 Already signed
goto :eof

scsigntool.exe -pin PIN sign /sha1 HASH /ac BUNDLE /as /fd sha256 /d %2 /du %3 /td sha256 /tr  %1 > nul
if errorlevel 1 goto error  
echo %~nx1 ok
goto :eof

echo Error signing!
echo Errorlevel: %Errorlevel%
echo 1:%1 2:%2 3:%3

Hi Carlos - With your batch file, does a password dialog come up multiple times, or does it accept a passed password? I wonder if the EV is different. For some reason, I thought you couldn’t pass a password. Maybe I’m mistaken.

With your batch file, does a password dialog come up multiple times

With signtool.exe, yes, the PIN dialog is shown for each file.

With scsigntool.exe, no, because you can pass the PIN as a parameter:

scsigntool.exe -pin PIN sign /sha ......
1 Like

Carlos, how long is the PIN good for? IOW, if I generate and pass it into a build system that takes 30 minutes, would the PIN still be valid for signing the program and Installer at the end of the build?

Hi Rick

For Yubikey, the PIN is setup once to protect the device, so it remains the same as long as you don’t change it.

Probably more advanced HSMs may use some kind of temporary PIN/OTP, but I don’t have experience with that.

1 Like

Interesting. Thanks. Malwarebytes won’t let me go to that site, but VirusTotal says it’s fine.

Once we finish our HSM experience, I’ll ask our devops guy to write up his experience. It’s been interesting. Note: He might use different words:)

1 Like

BTW, he told me today after a successful test that he is not prompted for a pin because the HSM takes care of confirming the use of the cert.

1 Like

Hi Carlos,

Thank you very much for the information!

All I know is that after my experience this spring with Sectigo (former Comodo) I will never do business with that company again! I had to do most of the “verification” for them myself because they couldn’t open official government websites in their browsers! As a safety measure for users, it was an absolute joke and completely pointless.