= Windows Code Signing This is how we do automated code signing of Windows binaries using a !YubiKey. We started with: * Enterprise Contract with [https://www.sectigo.com Secitgo] * !YubiKey 5 FIPS * [https://www.yubico.com/support/download/smart-card-drivers-tools/ YubiKey Smart Card Minidriver (Windows)] (x64 installer) * [https://developers.yubico.com/yubico-piv-tool/ yubio-piv-tool] (win64.msi version) * !YubiKey Authenticator application from Windows Store * signtool from Microsoft Visual Studio * MGTEK's [https://www.mgtek.com/smartcard scsigntool] Protocol: * Use !YubiKey Authenticator application to set PIN, PUK, and Management Key (could use yubio-piv-tool instead) * Install !YubiKey Smart Card Minidriver * [https://support.yubico.com/hc/en-us/articles/360015654560-Deploying-the-YubiKey-Smart-Card-Minidriver-to-workstations-and-servers installation notes] * Install yubio-piv-tool * Get email invitation to submit code signing CSR to Sectigo initiated by corporate IT * Submit CSR and !YubiKey attestation * Get email from Sectigo with link to certificate * Install certificate on !YubiKey * Sign code == Submit CSR The code signing slot is the Authentication slot `9A`. === Create key in slot `yubico-piv-tool --slot=$SLOT --action=generate --touch-policy=never --algorithm=$ALGORITHM --key --output=public.key` === Use public key to create CSR `yubico-piv-tool --slot=$SLOT --action=verify-pin --action=request-certificate --subject='/CN=Sectigo/' --input=public.key --output=csr.txt` Upload `csr.txt` for the CSR === !YubiKey attestation ==== Get attestation `yubico-piv-tool --slot=$SLOT --action=attest --output=attest.crt` ==== Get !YubiKey's intermediate certificates `yubico-piv-tool --action=read-certificate --slot=f9 --output=intermediateCA.crt` ==== Combine and encode in base64 {{{ cat attest.crt intermediateCA.crt > attestation.pem base64 < attestation.pem > attestation.pem.b64 }}} Attestation is in `attestation.pem.b64`. Copy the contents and paste in the Key Attestation field. Make sure `YubiKey` is the HSM type. == Install Certificate Use "Certificate only, PEM encoded" certificate. Downloads as `$CERT_BASE_cert.cer`. === Install in Windows User Certificate manager Open `$CERT_BASE_cert.cer` in file explorer, then click on `Install Certificate...`. Choose `Current User`. Place in `Personal` Certificate Store. === Install on !YubiKey `yubico-piv-tool --action=import-certificate --slot=$SLOT --key --pin-policy=once --touch-policy=never --input=$CERT_BASE_cert.cer` === Install intermediate certificates onto !YubiKey Use "Root/Intermediate(s) only, PEM encoded" certificates. Downloads as `CERT_BASE_interm.cer`. {{{ interm=$CERT_BASE_interm.cer let slot=$((0x82)) let max_slot=$((0x95)) while openssl x509 -out cert.pem do if [ $slot -ge $max_slot ] then echo "too many intermediate certificates" exit 1 fi hex_slot=$(printf "%x" $slot) echo "Import slot $hex_slot: $(openssl x509 -in cert.pem -noout -subject | sed 's/.*CN = //')" yubico-piv-tool --action=import-certificate --slot=$hex_slot --key --input=cert.pem slot=$((slot + 1)) done < $interm }}} == Sign Code Microsoft's `signtool` doesn't have a way to provide the PIN needed utilize the private key. So use MGTEK's `scsigntool` to wrap signtool. `ScSignTool.exe` and `ScSignTool.dll` are placed in the directory where `signtool` is used. For example: {{{ scsigntool.exe -pin CODESIGN sign /v /a /sha1 CERT_SHA /fd sha256 /t http://timestamp.sectigo.com/authenticode /d "Application Name" app-installer.exe }}}