Have you ever noticed that old apps seem to retain valid signatures forever, but Installer packages fall out of date, and can’t be used because their certificates are no longer valid? This article explains how that happens, and what’s going to happen with notarization.
Code signing
For executable code which is distributed outside Apple’s App Store, it’s now expected that it will be signed using an Apple developer certificate and notarized too. This isn’t an absolute requirement, but part of a system which Apple ensures gives the user the minimum amount of work in exchange for improved security. All executable code running native on M1 Macs must be signed, or it won’t run, but there the requirement isn’t a signature with an Apple developer certificate; home-made ad hoc signatures are fine too.
To be able to sign their apps and other code including command tools, developers use Developer ID Application certificates issued only by Apple, which is a certificate authority (CA) in its own right. The rule which applies when determining whether one of these certificates is still valid, or has expired, is whether the certificate was valid at the time that the app was signed by its developer, as recorded in a secure timestamp. So if I build a new version of SilentKnight today, and sign it with a certificate which expires in a couple of days, that signature remains valid forever, unless Apple as CA revokes that certificate.
That’s essential for executable code, as otherwise we’d all have to keep replacing our apps and command tools every few years, when their certificates expire.
Package signing
When a developer builds an Installer package, that too is expected to be signed, although it’s not yet compulsory by any means. A long time ago, though, Apple decided that such packages couldn’t be signed with a Developer ID Application certificate, but required something different, a Developer ID Installer certificate, issued separately by Apple. This provides the security necessary to ensure that installing a command tool or other executable code which doesn’t come in a bundle has a reasonable degree of security.
Command tools are different from apps in that they don’t consist of a bundle, like a folder, which can contain signing certificate details. Almost all command tools are single binary executable files, and traditionally didn’t get signed at all. It’s possible to sign a Mach-O executable file, in which case the signature details are merged into the single file, but until notarization came along that was quite unusual. Installer packages are simpler to sign, and it’s those which copy the command tool into a sensitive folder on your Mac. So if a developer wants to sign that package, as they should, they’ll need to obtain from Apple a Developer ID Installer certificate for that purpose.
Unlike app signatures, the signature on an Installer package should be valid at the time the package is run to install the software. So if I put SilentKnight into a package for you to install, that package would be signed using a Developer ID Installer certificate, in addition to the app’s own Developer ID Application certificate. If I built that package today, you could only use it normally until its certificate expired, which could be in just a couple of days.
Apple states: “If your certificate expires, users can no longer launch installer packages for your Mac applications that were signed with this certificate. Previously installed apps will continue to run however new installations won’t be possible until you have re-signed your installer package with a valid Developer ID Installer certificate.”
At the moment, that’s a gloomier picture than you’ll experience in Monterey. For quite a few years, packages have also been incorporating secure timestamps, and macOS should give you the benefit of the doubt when the certificate has now expired but was valid at the time the package was signed, just like apps.
Look further back in a collection of old installer packages, and you’ll find many older ones with expired certificates and no timestamp. Although they can be a bit more fiddly, most will still open under minor protest, and may well install correctly. The major exception to those, ironically, are older OS X installers whose Intermediate Certificate expired on 24 October 2019. Because they’re system installers, rules are rightly applied more rigorously, and there’s no way those old packages can be used now.
Notarization
Unlike code and package signatures, Apple doesn’t put any time limit on the validity of notarization, which requires in-depth code signing but doesn’t itself involve signatures or certificates. This is because checking notarization depends on matching cdhashes, cryptographic hashes for the code. Once a notarization ticket has been issued against a given cdhash, that should remain without time limit.
This becomes more confusing when notarizing signed Mach-O files such as command tools within an Installer package. Intuitively you might think that, so long as the executable code and its signature haven’t changed, the package signature isn’t important. However, when a package is submitted for notarization, Apple matches the notarization ticket against the package rather than the enclosed Mach-O file.
I’ve stumbled into this recently, as my Developer ID Installer certificate expires in early March. To ensure that my command tools install as seamlessly as possible, I’m now in the process of generating new Installer packages for each of them. I prefer using Stéphane Sudre’s marvellous Packages to make that easier. This also makes it simple to update the signature on the package. However, once that’s done it’s necessary to staple the notarization ticker to the package.
Try using the old ticket with a newly signed package using stapler
and you’ll find that Apple’s notary service no longer recognises the re-signed package. If you need to do this, you’ll have to get the updated package notarized again, then use stapler
. At least you don’t have to go back and rebuild the command tool from scratch. So my workflow has been to open the Packages project, remove the old Developer ID Installer certificate, sign with the new one in a fresh build of the package, then submit that package for notarization in the normal way, which for me remains altool
and stapler
.
This is another example of where notarization favours the regular app, and becomes unnecessarily clumsy with command tools. I think I recall Apple once suggesting that the process would get better for command tools and other Mach-O files, but that seems to have been long since forgotten.