Code Signing with the YubiKey on Windows


You can use the YubiKey to securely store your code signing certificate, safe from attackers. This article assumes you already have obtained a signing certificate from a valid certificate authority and that it is in the .pfx format.

1 Obtaining the signtool.exe Utility

We will use the signtool.exe utility to sign code on Windows. This utility is distributed as a part of the Windows SDK. Download and install the SDK from the following link: https://go.microsoft.com/fwlink/p/?linkid=870807.

2 Importing the Certificate to the YubiKey

The steps to import the certificate depend on whether you have the YubiKey Smart Card Minidriver installed. If you are unsure, check the Smart Cards section in Device Manager. If the smart card is listed as “Yubico Yubikey …” the minidriver is installed, if it is listed as a “NIST …” device, it is not.

2.1 With the YubiKey Smart Card Minidriver

Optional: Enabling Support for ECDSA and ECDHE Certificates

Windows Smart Card KSP by default does not support certificates associated with ECDSA and ECDHE algorithm keys, and the permissions to use them must be enabled in the registry. If you are code signing with just certificates associated with RSA keys, this section may be skipped.

The registry keys for the smart card KSP are in HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Control\Cryptography\Providers\Microsoft Smart Card Key Storage Provider.

Two entries need to be changed to have a value of "1":

Registry Key Description
AllowPrivateECDHEKeyImport This value allows Ephemeral Elliptic Curve Diffie-Hellman (ECDHE) private keys to be imported for use in key archival scenarios.
AllowPrivateECDSAKeyImport This value allows Elliptic Curve Digital Signature Algorithm (ECDSA) private keys to be imported for use in key archival scenarios.

 

Enabling the Minidriver for importing Certificates for Code Signing:

  1. Open PowerShell as Administrator.

  2. Run: reg add “HKLM\SOFTWARE\Microsoft\Cryptography\Defaults\Provider\Microsoft Base Smart Card Crypto Provider” /v AllowPrivateExchangeKeyImport /t REG_DWORD /d 1

  3. Run: reg add “HKLM\SOFTWARE\Microsoft\Cryptography\Defaults\Provider\Microsoft Base Smart Card Crypto Provider” /v AllowPrivateSignatureKeyImport /t REG_DWORD /d 1

  4. Run: certutil –csp "Microsoft Base Smart Card Crypto Provider" –importpfx C:\Path\to\your.pfx

  5. When prompted, enter the PIN. If you have not set a PIN, the default value is 123456.

2.2 Without the Minidriver

  1. Download and install YubiKey Manager.

  2. Open PowerShell.

  3. Run: cd “%PROGRAMFILES%\Yubico\YubiKey Manager”

  4. Run: .\ykman piv import-key --pin-policy=once 9c C:\path\to\your.pfx

  5. When prompted, enter the PIN, management key, and password for the PFX.

  6. Run: .\ykman piv import-certificate 9c C:\path\to\your.pfx

  7. When prompted, enter the PIN, management key, and password for the PFX.

3 Signing Code

Now that your code signing certificate is stored on the YubiKey, you can sign code with it.

3.1 Obtaining the Certificate’s Thumbprint

The most reliable way to ensure the correct certificate is used for signing is to specify the SHA1 thumbprint. To obtain the thumbprint, follow the steps below.

  1. Press Win+R to open the Run menu and run “certmgr.msc”.

  2. In the tree view on the left side, navigate to Personal > Certificates.

  3. Locate your certificate and double-click it, it should have Code Signing under the Intended Purposes column.

  4. Click on the Details tab.

  5. Scroll to the bottom of the list and select Thumbprint.

  6. Highlight the value below and press Ctrl+C to copy it to your clipboard.

  7. Save this somewhere so you do not have to go through these steps each time you want to sign code.

3.2 Signing an Executable

  1. Open PowerShell.

  2. Run: cd “%PROGRAMFILES(X86)%\Windows Kits\10\bin\x64”

    • Note: If your Windows installation is 32bit remove “(X86)” from the command and change the “x64” at the end to “x86”

  3. Run: .\signtool sign /sha1 <THUMBPRINT> /fd SHA256 /t http://tsa.safecreative.org C:\path\to\your_application.exe

    • Replace <THUMBPRINT> with the thumbprint you looked up in the previous section.

    • Note: The /t parameter is optional and specifies a timestamp server. This is used to securely stamp your digital signature with a time and a date.

  4. When prompted, enter your PIN. 

Success! You have signed an executable with a certificate stored on the YubiKey. You can verify the signature in the Digital Signature tab on the executable’s properties. 

4 Troubleshooting

4.1 Windows Does Not Prompting for a PIN When Signing

If you are not prompted for a PIN, this can mean two things: 

  1. The PIN was entered recently and is cached.

  2. The certificate and private key are in the Windows certificate store.

To test if it is the first possible cause, simply remove and reinsert the YubiKey and see if you are prompted for the PIN when you run signtool again. If you are not, continue with the following steps to remove the certificate and private key from the Windows store.

  1. Press Win+R to open the Run menu and run “certmgr.msc”.

  2. In the tree view on the left side, navigate to Personal > Certificates.

  3. Locate your certificate, it should have Code Signing under the Intended Purposes column.

  4. Right-click on the certificate, and select Delete. Press Yes to confirm the deletion.

    • Note: This does not delete the certificate from the YubiKey.

  5. Repeat steps 3-4 for any other instances of the certificate in the list.

Remove and reinsert your YubiKey, then click Action > Refresh and verify that your certificate appears again. This means Windows correctly read the certificate from the YubiKey, and that it is the only certificate with that SHA1 hash in the certificate store. The next time you use signtool you will be prompted for the PIN.

4.2 Code Signing Fails With Error 0x8010006A

If you experience error code 0x8010006A when attempting to use the signtool utility, this indicates the pin-policy option was set to always which does not work with the YubiKey Smart Card Minidriver and signtool due to a restriction in the Microsoft Base Smart Card CSP. Unless otherwise specified, slot 9c (Digital Signature, used for code signing) will have the pin-policy option set to always unless otherwise specified to adhere to the PIV specification. To resolve this, import the certificate to the YubiKey using one of the options in section 2 of this guide.