Description
This article explains how the YubiKey can be used to sign code in a Windows environment using common tools, such as SignTool or JarSigner. It is assumed that the YubiKey has already been provisioned with a code signing private key and the corresponding code signing certificate in one of its PIV slots (most commonly 9a or 9c).
Note:
YubiKeys with firmware 5.7 are able to handle RSA1024-RSA4096 which can be used for code signing. YubiKeys with firmware lower than 5.7 would have to use Elliptic Curve keys (ECCP256 or ECCP384) instead, due to the updated minimum requirements for RSA keys used for code signing by the CA/B Forum in June 2023.
SignTool
Prerequisites
- Download and install the YubiKey Smart Card Minidriver
Warning: The YubiKey Smart Card Minidriver will block the PUK if the PUK is set to the default value (12345678). It is therefore important that the PUK is changed before using the YubiKey on a machine where the YubiKey Smart Card Minidriver is installed.
-
- If the code signing is executed on a remote server, make sure to install the YubiKey Smart Card Minidriver with INSTALL_LEGACY_NODE=1, according to our article Deploying the YubiKey smart card minidriver to workstations and servers
- Generate a private key on the YubiKey and obtain a signed code signing certificate from a CA
- Download and install SignTool. SignTool can be acquired as a part of the Windows SDK.
- Make sure that the Windows smart card service (SCardSvr) is started and is running as a Local Service
- (Optional) Import the complete certificate chain to the YubiKey
Procedure
-
-
Plug in the YubiKey and locate the code signing certificate in the user's personal certificates store.
⊞ Win + r certmgr.msc → Certificates - Current User → Personal → Certificates -
Obtain the signing certificate’s sha1 thumbprint
- Double-click on the code signing certificate in the user's personal certificates store →Details →Thumbprint
- Mark the entire string and use ctrl + c to copy
-
Open Command Prompt, navigate to the folder containing signtool.exe, and perform the signature:
cd C:\Program Files (x86)\Microsoft SDKs\ClickOnce\SignTool
Example:
Signtool sign /sha1 <sha1_thumbprint> /fd SHA256 /t <url_to_TimeStamp_Server> <file_to_sign>
signtool sign /sha1 83fe6c0f1f0d1db0a09ba2cd97015df7a852b4d3 /fd SHA256 /t http://timestamp.sectigo.com "C:\Users\YubicoTest\projects\file.exe"
-
Plug in the YubiKey and locate the code signing certificate in the user's personal certificates store.
Tips: SignTool.exe requires that the PIN is entered once per signature when the private key is stored on a smart card. For large amounts of signatures, the YubiHSM2 should be used instead, which is a HSM and does not require a PIN to code sign with SignTool.
JarSigner
Prerequisites
- Java JDK or OpenJDK
- Download and install Yubico PIV Tool
- Add the C:\Program Files\Yubico\Yubico PIV Tool\bin directory to the system path
- Generate a pkcs11.config file in the same directory that the libykcs11.dll library is located.
- Refer to section ykcs11.conf below for detailed instructions
- (Optional) Import the complete certificate chain to the YubiKey
ykcs11.conf
The pkcs11.config is a configuration file used by JarSigner to locate the PKCS#11 module that is used to interact with the token storing the private key (in this case, the YubiKey). This configuration file needs to be located in the same directory as the pkcs#11 library that is being used.
In this case, libykcs11.dll is being used (package in the Yubico PIV Tool). The default installation path in 64-bit Windows is:
C:\Program Files\Yubico\Yubico PIV Tool\bin
The contents of the file should look something like this:
name = ykcs11
library = "C:\\Program Files\\Yubico\\Yubico PIV Tool\\bin\\libykcs11.dll"
Procedure
- Open Command Prompt
- Navigate to the location of the libykcs11.dll file
cd "C:\Program Files\Yubico\Yubico PIV Tool\bin"
- Check if the configuration is working and retrieve the signing certificate object label
keytool -list -keystore NONE -storepass <PIV_PIN> -storetype PKCS11 -providerclass sun.security.pkcs11.SunPKCS11 -providerarg ykcs11.conf
Example:
C:\Program Files\Yubico\Yubico PIV Tool\bin>keytool -list -keystore NONE -storepass 123456 -storetype PKCS11 -providerclass sun.security.pkcs11.SunPKCS11 -providerarg ykcs11.conf
Keystore type: PKCS11
Keystore provider: SunPKCS11-ykcs11
Your keystore contains 2 entries
X.509 Certificate for PIV Attestation, PrivateKeyEntry,
Certificate fingerprint (SHA-256): FB:FC:AB:E1:63:28:8A:B0:7E:8E:03:97:6C:1A:93:D6:E7:D6:D4:6C:D0:B8:34:A0:8F:AE:94:49:CC:10:AE:1E
X.509 Certificate for PIV Authentication, PrivateKeyEntry,
Certificate fingerprint (SHA-256): 0D:BF:B1:A3:CA:E3:1C:45:1B:D6:E4:84:D3:0A:BD:C6:5E:DF:DD:01:40:81:3B:0A:ED:68:98:70:D3:0D:C4:B1 - Sign with the following command. Ensure that you use the same PKCS#11 label that was returned by the keytool -list command, as this can vary slightly depending on which PKCS#11 module is being used. In this example, X.509 Certificate for PIV Authentication is used.
jarsigner -keystore NONE -storepass <PIV_PIN> -storetype PKCS11 -providerClass sun.security.pkcs11.SunPKCS11 -providerArg <path_to_ykcs11.conf> -signedjar <path_to_signed_file_output> <unsigned_file_path> <signing_ykcs11_object_label> -tsa <TimeStamp_server_URL>
Example:C:\Program Files\Yubico\Yubico PIV Tool\bin>jarsigner -keystore NONE -storepass 123456 -storetype PKCS11 -providerClass sun.security.pkcs11.SunPKCS11 -providerArg ykcs11.conf -signedjar C:\Users\Administrator\Documents\jarFiles\SignedFile.jar C:\Users\Administrator\Documents\jarFiles\unsigned.jar "X.509 Certificate for PIV Authentication" -tsa http://timestamp.digicert.com
jar signed.
The signer certificate will expire on 2024-07-08.
The timestamp will expire on 2031-11-09.
Import the complete certificate chain to the YubiKey
In the case that your code signing certificate is issued by a public CA, ensure that the complete certificate chain is loaded onto the YubiKey.
This can be done using YubiKey Manager (CLI) (ykman) software, which allows you to import the CA root and intermediate certificates to the PIV slots for retired keys and certificates (82 and 83, for instance). In the case that your CA has multiple intermediate CA certificates, repeat the steps for slots 84 - 95.
Importing the certificate chain to the YubiKey:
-
ykman piv certificates import 82 "<PATH\TO\ROOT\CERTIFICATE.pem>"
-
ykman piv certificates import 83 "<PATH\TO\INTERMEDIATE\CERTIFICATE.pem>"
Verify that the CA and intermediate certificates were correctly imported:
ykman piv info
Note: In order to see the full certificate chain with CA root and intermediate certificates imported into slots 82 - 95, ensure that libykcs11.dll/.dylib/.so is used instead of other PKCS#11 modules, such as the OpenSC PKCS#11 module.
Troubleshooting
Refer to Troubleshooting Code Signing on Windows for troubleshooting steps.