Secure Tauri/Windows Code Signing with Certum HSM
One of our products — Defguard & WireGuard Desktop Client has multiple platform releases (Linux, MacOS, and Windows). We're building it with our beloved Rust and a great multi-platform desktop framework Tauri.
![](/images/blog/defguard-main-screen.png)
Defguard & WireGuard desktop client
While doing releases with Tauri is pretty straightforward and well-documented, the Code Signing for MacOS is spot-on, but the Windows Code Signing is not that straightforward. Tauri documentation assumes you have a certificate file (pfx - with certificate & key) - but most (if not all) Code Signing Certificates are sold on dedicated HSMs (Hardware Security Modules) that must be FIPS 140-2 compliant.
Thus to handle signing:
- One has to have a self-hosted GitLab/Github Runner - which just physically can have the HSM connected to the USB (and of course the runner needs to be in a secure network location and well as the system needs to be secured).
- There needs to be a solution & tools to handle this process automatically during the build & release.
Most certificate authorities have a dedicated solution for that (DigiCert, Sectigo) or solutions, examples, and a great documentation (SSL.com) but we have chosen Certum Code Signing certificate for two reasons, they operate as us in Szczecin Poland and they have a great Open Source Code Signing product - and defguard is an open-source project. The downside is that they do not have any CI/CD documentation or solutions, and weirdly (everything should be on the internet, right?) there are no docs, solutions, snippets, projects, or blogs (you name it), that could help us set up this process.
So after weeks of going back and forward with the Certum support and going nowhere (greeting for our colleagues), we took this project on our shoulders - and here are the recipes for building a Debian GNU/Linux CI/CD runner.
We assume you have:
- a configured GitHub/GitLab self-hosted runner based on Debian GNU/Linux (but Ubuntu should work as well)
- Bought an Open Source Code Signing Certificate set from Certum
- Have the certificate issued and the key is on the HSM shipped by Certum and it’s connected to the runner.
- You also have downloaded the certificate file in PEM format (from certum website), and placed it in /srv/codesign/certum/certificate.pem
Now we need to prepare the runner system to support the HSM. First let’s install all necessary system software:
apt install opensc opensc-pkcs11 libpcsclite-dev pcscd libacsccid1 \ libengine-pkcs11-openssl osslsigncode
Now, we need to install the Linux version of proCertumCardManager provided by Certum:
mkdir /srv/codesign/cd /srv/codesign/
# We download proCertumCardManagerwget https://www.files.certum.eu/software/proCertumCardManager/Linux-Ubuntu/2.2.11/proCertumCardManager-2.2.11-x86_64-ubuntu.bin
# We do not install the software, just extract it/srv/codesign/proCertumCardManager-2.2.11-x86_64-ubuntu.bin --keepmv dist certum
# create links, if you would like to actually use the# Certum Card Manager software
ln -s /srv/codesign/certum/cryptoCertum3PKCS-3.0.6.69-MS.so /usr/lib/libcrypto3PKCS.soln -s /srv/codesign/certum/cryptoCertum3PKCS-3.0.6.69-MS.so /usr/lib/libcryptoCertum3PKCS.so
Now, we can check if the system sees the HSM and can show us the certificate & key details:
$ pkcs11-tool --module /srv/codesign/certum/sc30pkcs11-3.0.6.68-MS.so --login --list-objects
Using slot 0 with a present token (0x1)Logging in to "profil standardowy".
# here you need to provide the PIN to access the card/HSM
Please enter User PIN:
# After providing the PIN, you should see the contents of the card
Private Key Object; RSA label: Open Source Developer, Robert Olejnik ID: 352c322687efb09df068a792c49cbac631d40cf0 Usage: decrypt, sign, unwrapwarning: PKCS11 function C_GetAttributeValue(ALWAYS_AUTHENTICATE) failed: rv = CKR_ATTRIBUTE_TYPE_INVALID (0x12)
Access: sensitive, always sensitive, never extractable, localPublic Key Object; RSA 4096 bits label: Open Source Developer, Robert Olejnik ID: 352c322687efb09df068a792c49cbac631d40cf0 Usage: encrypt, verify, wrap Access: localCertificate Object; type = X.509 cert label: Open Source Developer, Robert Olejnik subject: DN: C=PL, ST=zachodniopomorskie, L=Szczecin, O=Open Source Developer, CN=Open Source Developer, Robert Olejnik serial: 29EE7778CA5217107841BBBF6B3062E1 ID: 352c322687efb09df068a792c49cbac631d40cf0
! As you can see, the key ID (this is important) is: 352c322687efb09df068a792c49cbac631d40cf0
Now the final, let’s check if the code signing works - for that we have a defguard.exe unsigned binary, which we will sign and check if it works:
$ osslsigncode sign \ -pkcs11module /srv/codesign/certum/sc30pkcs11-3.0.6.68-MS.so \ -certs /srv/codesign/certificate.pem \ -key 352c322687efb09df068a792c49cbac631d40cf0 \ -pass <PIN> \ -h sha256 \ -t http://time.certum.pl/ \ -in defguard.exe \ -out defguard-signed.exe
# You should see the following message and result:
Engine "pkcs11" set.Succeeded
And checking the signature:
$ osslsigncode verify defguard-signed.exe
Current PE checksum : 0134E4A0Calculated PE checksum: 0134E4A0
Signature Index: 0 (Primary Signature)Message digest algorithm : SHA256Current message digest : 13A86CCDF9DE5177ACC15A3AC895A1F39A652D85F6E9C3533C151D64547F930ACalculated message digest : 13A86CCDF9DE5177ACC15A3AC895A1F39A652D85F6E9C3533C151D64547F930A
Signer's certificate: Signer #0: Subject: /C=PL/ST=zachodniopomorskie/L=Szczecin/O=Open Source Developer/CN=Open Source Developer, Robert Olejnik Issuer : /C=PL/O=Asseco Data Systems S.A./CN=Certum Code Signing 2021 CA Serial : 29EE7778CA5217107841BBBF6B3062E1 Certificate expiration date: notBefore : Mar 21 06:12:37 2024 GMT notAfter : Mar 21 06:12:36 2025 GMT
Number of certificates: 4 Signer #0: Subject: /C=PL/ST=zachodniopomorskie/L=Szczecin/O=Open Source Developer/CN=Open Source Developer, Robert Olejnik Issuer : /C=PL/O=Asseco Data Systems S.A./CN=Certum Code Signing 2021 CA Serial : 29EE7778CA5217107841BBBF6B3062E1 Certificate expiration date: notBefore : Mar 21 06:12:37 2024 GMT notAfter : Mar 21 06:12:36 2025 GMT# And so on...# And so on...# And so on...
Now what is left for you to do, is add the osslsigncode sign to your pipeline, and don’t forget to make the PIN a secret.
Robert Olejnik - Founder, Security and Open Source Advocate