Recently, my Windows code signing certificate expired after about 2.5 years of unproblematic operation, after a traumatic changeover from the previous code signing certificate.
Previously, the drama had to do with the fact that reputation was lost on transferring to the new certificate. Reputation, in this case, is that Windows has seen your compiled executables downloaded by many people without any complaints or detections of malware.
This time I thought – let’s use the exact same company I bought the previous certificate through – surely they can just renew the certificate and transfer the reputation with it. Not so, as it turned out. Let’s also purchase the renewal a good month out from the old certificate expiring. The whole certificate expiry thing happened at the worst possible time – right when we’re about to launch a new product.
So I’m writing this blog – partly to vent my frustrations at the whole process – and partly so I have some breadcrumbs to be able to go through the process in 3 years time in hopefully a less traumatic fashion than the last two times.
A protection racket
Firstly – let me just say, the whole code signing thing is a protection racket. “Nice application you have there, it would be shame for anything to happen to it!”. Only things do happen to it, even if you do pay up!
Sure, in this day and age of malicious actors, a consumer of software will want to know who created a piece of software, and a creator of said software will want to ensure that the bits delivered to the consumer are the bits created on eir development machine. It is the reason why commits to Github should be signed, and why Linux packages are signed by public key infrastructure (PKI). In the case of Github, you can use your ssh key, which makes it easy and free, and consumers (ie other developers) can check who ultimately made each commit. Linux packages generated by the OpenSUSE build service are signed by the repository key, but this is linked to the user account on OpenSUSE, which is also credentialled by a form of PKI.
I first came across code signing for “mainstream” operating systems in the context of Apple’s Macintosh. It appeared in the Mountain Lion release that introduced a feature called GateKeeper that flagged you software as suspicious if it were not signed by a certificate issued by Apple under its developer programme. I grumbled a bit at the time about the annual fee for the developer programme, but given their compilers were given away for free, it didn’t seem to too bad. I also had to upgrade my development environment from Snow Leopard, which I did to Yosemite, and set the MAC_OSX_MIN_VERSION to Lion. Gradually, though, the requirements became more strict. Apple introduced “notarization”, which implied I had to bump up the minimum MacOSX version to High Sierra. The last bump occurred late last year, when I had to rebuild my developer environment on Big Sur. With notarization, Apple scans the binary blob for known malware signatures, and so this forms part of one’s developer reputation.
In the Windows world, the whole code signing system is completely insane. As an individual, your code is treated as suspicious until enough people download the software, thus generating your reputation. And by suspicious, Windows does a number of dark patterns to cajole the user into abandoning your software.
- Assuming you download the software using a web browser like Bing, it downloads, then you are prompted with
xxx isn't commonly downloaded. Make sure you trust
xxx before you open it.
When you move the mouse cursor over the download, you are presented with a garbage bin icon, and three little dots. The correct answer is to select the three little dots.
- Click on the 3 dots, then you are presented with a menu “Delete”, “Keep”, “Report this file as safe” and “Learn more”. The correct answer is “Keep”.
- Pressing “Keep” gives the message:
Make sure you trust xxx before you open it.
Microsoft Defender SmartScreen couldn't verify if this file is safe because it isn't commonly downloaded. Make sure you trust the file you downloaded or its source before you open it
and two large buttons “Delete” and “Cancel”, as well as “Show more” in small text. The correct answer is to press the small wedge next to “Show more”.
- Pressing the wedge gives more options “Keep anyway”, “Report this app as safe” and “Learn more”. The correct answer is “Keep anyway”.
- Finally, you can now run the program to install it.
Alright – so I can understand the idea of reputation – so that consumers can be reminded to be careful if installing software that hasn’t been tried by many others. But Windows is really over the top – you have to click through 4 different warnings (outlined above), ie
- Do you really want to install this software?
- Do you really, really want to install this software?
- OK, bozo, I told you once before this software might be dangerous, do you really still want to install it?
- I told you twice before. Do you really, really, really want to install it?
- OK, OK – your call!
Are Windows really that click happy they have to be prompted 4 times about whether they know what they’re doing?
Follow the money
OK, so code signing is a a source of revenue for Apple, albeit a probably rather minuscule part compared with the 30% tax they slug App Store developers. And you could argue that providing infrastructure at scale to scan executables (notarization) is also a cost, for which some sort of cost recovery is reasonable.
You could argue that Microsoft could also justify a tax to cover to cost of running their Windows Defender SmartScreen infrastructure. Only they don’t. Instead it is handled by a handful of certificate authority companies, such as Comodo, DigiCert and Sectigo. As an individual developer, in the past, you could purchase a certificate from one of them, or a reseller, it was delivered as a download, you might need to convert the file, install it on your developer machine and set up the development pipeline. Over time, as you manage to cajole your users to download the software, your reputation builds to the point where SmartScreen allows the software download without comment. As a company, there is also a much more expensive alternative called an EV certificate. This involves extensive checks that the company is properly registered, that a publicly listed phone number and email is responded to, and that a physical device (dongle) is posted to the publicly listed mailing address. The dongle contains the certificate, so that only a single “release manager” can sign the software. The upside to this is instant reputation – SmartScreen waves through software signed by EV certificates without a murmur. I can understand that company validation requires a substantial fee, but for individual certificates where the only purpose is to identify who you are and reputation has to be earned, it should really be free, or close to. After all, Let’s Encrypt manages to issue free website certificates.
Renew the certificate?
So when offered a 10% discount on renewing my certificate with the same company I bought the previous certificate, and having already suffered from loss of reputation the last time my code signing certificate was renewed, and thinking that getting the renewed certificate though the same company would prevent loss of reputation, I jumped.
To my surprise, the cost was suddenly a lot more expensive than three years previously, by about a factor of four. I paid up, but then wondered what exactly it was that I had bought. In the receipt was an amount for shipping a token – what token, I thought – that is supposed to only be for the EV “extended validation” version. Perhaps that is what I bought. I double checked the price list, and what I paid was a little less than the rack price for an EV certificate, but a little more for the base individual developer certificate. So, obviously, that was the 10% discount ordered, and I had mistakenly clicked on the more expensive option. Oh, well, at least I won’t need to worry about loss of reputation. Nup! I had bought the individual certificate, but since late 2023, all code signing certificates require a hardware token. I also had to go through validation checks – presumably they checked my company’s entry in ASIC, our national registry for corporations, and I received a phone call and email to check contact details, as well as a zoom call so that I could show my driver’s license. So the company was verified, but I don’t get the advantage of instant reputation. Reputation is not even transferred, as I found out later once the token finally arrived (another story, the token was lost in-transit in the wilds of Kentucky for a whole month), and I got it to work (outlined in the next section).
So I started reading. There are, of course, many complaints about this whole system, and how to deal with the sudden loss of reputation every three years. The best idea I came across was to order the new certificate a bit in advance of the old one expiring (OK – so maybe a month before is cutting it a bit fine, as it turns out), and then to sign executables with both the old and the new certificate to allow reputation to gradually transfer to the new certificate. I wish I’d known that sooner. But I thought, let’s try signing my last release with the new certificate as well. The old signature should be valid forever, so long as the signing was done prior to certificate expiry. Alas, that was no good, as it turned out I was signing the executable incorrectly, ever since version 3.0 of my software came out. I had omitted specifying a timestamp server, and jsign quite happily signs the software anyway without any notification of anything wrong. Then when the code signing certificate expires, so does the signature – boom! Seriously, why can’t jsign have at least emitted an error message to say no timestamp server had been supplied, or better still supply a default server.
So once the token finally arrived…
So having escalated the case of the lost token, it finally turns up in a Kentucky warehouse, and its on it way, a fortnight or so after my previous certificate had expired. But that was not the end of the story. I now have to figure out how to integrate the token into my development pipeline. The package arrives, there’s the physical token in the package with the name “SafeNet” on it, but nothing else, no instructions or anything. In the email I got from my reseller, after I’d requested more information, was a password, and a recommendation that I download “SafeNet Authentication Client”, although potentially other software might work. That was it. I did a quick internet search to see if jsign would support SafeNet eTokens, and being assured that it was supported, set about trying to get this thing to work. Suffice it to say, it was a long story, taking nearly a month of investigation and trial and error to get this thing to work. In the interest of having a neat list of things I found out so that next time (in three years) I can consult this list to hopefully narrow down what needs to be done, I’m going to list these as dot points.
- Firstly, I needed to upgrade jsign. I downloaded the latest version 6.0
- The –storetype parameter is ETOKEN, and the –keystore parameter is the name of a special configuration file that contains:
name = SafeNet eToken 5100
library = /usr/lib64/libeToken.so
slotIndex = 0
- You need to install SafeNet Authentication Client, which does exist as an RPM file for CentOS Linux, but does work with OpenSUSE.
- The documentation provided does not even tell you how to run the software – but using
rpm -qlp SafenetAuthenticationClient-10.8.28-1.e18.x86_64.rpm
tells you the names of three executables (SACTools being the most relevant), and the name and location of the library (listed above in the configuration file).
- Running SACTools, the token is not visible at all. Everything is greyed out. It turns out two things are required:
- Install the packages pcsc-tools and pcsc-ccid.
- pscs_scan will now see the token, but only when run as root! The name parameter in the configuration file was cribbed from pscs_scan output.
- SACTools will now see the token when run as root. I could not figure out how to run these commands as a normal user – for example, there is no group I need to be part of (the usual way of extending privileges). So instead, I set these up using sudo to elevate privileges when needed.
- Care must taken not to lock the token. If the wrong password is used 3 times in a row, then the token locks. jsign will not report a meaningful error due to invalid password (just some random java exception is thrown, which could be for any token related error). You can monitor the number of password retries remaining in the token using the SACTools “View Token Info” menu item.
- If you do lock the token (I managed to do it twice over the course of the month), you must raise a support ticket with Sectigo (assuming that is your CA), then follow up with an international phone call to the Sectigo support number (Skype credits is a great way to do this cheaply). The good thing is that Sectigo have staff online 24 hours (unlike the usual “hopeless desk” call centres companies use these days) that can manually unlock the token using an administrator password via a zoom call.