Today I want to explain how to get the StartSSL code-signing certificates into a state that is usable for
signtool. It is an affordable solution for individuals that would rather sign the code they publish. I bought one this week and will probably rebuild some of my code and then sign it and leave other really old code completely alone, though.
The current price is 59 USD, but it is being charged for the validation of your identity, not the certificate itself as far as I understand. There are plenty of explanations on how to do everything within the StartSSL control panel, but I’d like to explain how to do it “correctly”.
Because even though you trust them – otherwise you wouldn’t have them sign your certificate – you shouldn’t ever give them the means to decrypt your private key. But this is exactly what’s being asked of you if you choose the “easy” route.
It’s assumed that you did a class 2 or 3 validation with them before following these steps. Note that these steps are generally also valid for other issuers, not just StartSSL. For other issuers you would just use a different time stamp service in the
signtool command line (or rather you might want to use a different one, it’s not mandatory).
- Create a certificate signing request (CSR) and a key with OpenSSL. You can also use an existing key, such as your PGP key, as long as you convert it into the proper format.
openssl req -new -newkey rsa:4096 -keyout key.pem -out csr.pem
It is absolutely fine if you accept the defaults OpenSSL gives you. The reason for this is that StartSSL will only use the public key from your CSR along with the identity information from the validation step. They include: E (email), CN (common name, would be your name), L (location), S (state) und C (country).
- Under “Object Code Signing” in the second tab on the StartSSL control panel you paste the CSR and then submit it.
- At the end of the previous step you receive the certificate in a text field, which you save into a text file under some name. We will assume the file name
cert.crtfor subsequent steps.
- Now use the tool
cert2spc.exefrom the Windows SDK to convert the certificate to SPC format:
cert2spc.exe cert.crt cert.spc
- Now one uses pvktool to convert the private key generated in step one (or pre-existing) into PVK format. Newer versions of OpenSSL supposedly include the functionality to achieve exactly the same, but I was too lazy to sift through the complete docs. To build pvktool I had to append
gcccommand line in the make file. Otherwise I got a linker error with OpenSSL 1.0.0d.
pvk -in key.pem -topvk -strong -out key.pvk
- It’s now time to merge the private key and the certificate into a PFX file. This file contains thus both, the key and the certificate. It’s what can be used to sign your binaries. We use
pvk2pfx.exefrom the Windows SDK to do the conversion step:
pvk2pfx.exe -spc cert.spc -pvk key.pvk -pfx cert.pfx
NB: many consider this sufficient, but it is way more convenient and arguably more secure to store the certificate in the machine’s or the user’s certificate store. Follow the next step.
- To import the certificate in PFX format into the certificate store of either the user account or the machine, use either of these methods:
- User’s certificate store:
certutil -user -importPFX cert.pfx
- Machine’s certificate store:
certutil -importPFX cert.pfx
- User’s certificate store:
From this point on you can conveniently use the certificate. Note that the last step is mandatory for the case where you have to sign kernel mode code for Vista or newer (i.e. according to the kernel mode signing policy).
If it was installed in the machine’s certificate store one uses the
signtool.exe sign /v /a /sm /ph /d "..." /du "http://..." /tr http://... my.exe
If it was installed in the user’s certificate store simply leave the
/sm switch off:
signtool.exe sign /v /a /ph /d "..." /du "http://..." /tr http://... my.exe
Now the short explanation for the used command line switches:
/vmeans verbose and is not strictly needed. It’s useful for the first invocation when you want to see which certificate was ultimately chosen (see next bullet point).
/aautomatically selects the certificate that is valid the longest and that can be used for code signing. In most cases only one certificate will be installed on the machine anyway.
/phcomputes hashes over each section of the binary file (more secure but not strictly necessary).
/dadds a description.
/duadds a URL.
/tris the URL of a time stamp service. This part is very very important. The reason being that without this the signature of a file will expire unless the signature is time stamped. Once time stamped, the signature will remain valid even beyond the expiry date of the certificate.
(turns out this is no longer the case, see in the comment section below)
/achas to be used for kernel mode drivers to include issuer intermediate and root certificates in the signature.
The choice of
/trdepends on the timestamp service running at the URL you are using (were given)
/rcan be used to select the right certificate in case more than one is installed.
Timestamp URLs which can be used:
- http://timestamp.verisign.com/scripts/timstamp.dll works with
/t(Note: no ‘e’ in
- http://timestamp.globalsign.com/scripts/timestamp.dll works with
- http://www.startssl.com/timestamp works with
Hope it’s helpful for someone else.
- StartCom claims their extended validation certificates don’t have that issue, though. [↩]
Useful article, but i prefer to not import certificate in local store. Just using *.pfx files (important if need to sign different binaries with different certificates).
Regarding kernel mode signing:
1. Certificate issuer must have cross-certificate from Microsoft.
2. To verify kernel-mode embedded signature:
signtool.exe verify /kp /v DriverPath
Yep, point 1 I mentioned (see the
/acswitch), but point 2 is a very good point. I haven’t bought a certificate suitable for signing kernel mode code for myself, but I am using this, including the verification, in the build process at work. Tell me, how did you even get it to work with PFX files for signing kernel mode code? This worked fine for XP, I know. But with
/acI never was able to use a PFX file, only a locally stored cert. Besides, I consider it slightly more secure than having the PFX file sitting somewhere in the file system.
I’m using “/f” switch. Here you can find example:
Had tried that, but it didn’t work for me even with that switch. I’ll try again on Monday, though. Just to see.
no need in other than OpenSSL tools. You can convert CRT into PFX using this command line:
openssl pkcs12 -export -out “cert.pfx” -inkey cert.key -in cert.crt
I found it in this topic: https://forum.startcom.org/viewtopic.php?p=7091&sid=7b97b298c28a1f4353e8f9e78cc182ae
Alexey, I know you are right. However, to my knowledge this was only introduced fairly recently into OpenSSL. So for people who don’t want to (or can’t) compile OpenSSL from source themselves, this is a rather bumpy road to take.
Nevertheless, you’re of course right.
Thanks for your comment 🙂
Beware buyer: StartSSL code signing certs cannot be timestamped as they are marked with “lifetime signing”, i.e. the signature will expire eventually, even if properly time-stamped!!!
Thanks, turns out you’re right. I am adding a note to my article.
I just bought a Class 2 code signing certificate from StartSSL for US$ 59. There are two good news here:
1) The code signing certificate is valid for 2 years (at least form me)
2) The time stamp issue (mentioned above) seems to be removed.
The “Enhanced Key Usage” property “Lifetime Signing (188.8.131.52.4.1.3184.108.40.206)” is not set anymore! If you google it you’ll find that it was in their policy PDF from 2009 but it has been removed in the most recent version.
Cool, thanks for commenting!
If you have to have a class 3 – organization validated – you get 3 years from StartSSL. Without Lifetime Signing as well.