macOS has checked app signatures online for over 2 years

A week ago, largely as the result of a server problem on 12 November, there was a storm of concern over the use by macOS of Apple’s OCSP service to check certificates, and resulting leakage of private data. Apple responded rapidly to mounting concerns and made commitments to address these issues over the coming year. What has been puzzling me ever since is that these OCSP checks have been well-known for a couple of years, and only now have attracted attention. With the immediate aftermath of the release of Big Sur now subsiding, this article traces their history, and explains how they came about.

Although the origin of code signing in macOS has become lost in the mists of time, as far as I can see, it appeared in 2007, but wasn’t really taken seriously until Gatekeeper was introduced in 2012, and became even more important with notarization, which was new with Mojave in 2018.

Various vulnerabilities have been discovered in the processes involved in signing and their use in macOS over that period. Among the most important, and most relevant to this story, are those detailed by Josh Pitts in June 2018. These affected a lot of well-known security products including LittleSnitch, and more generally software from Facebook. What is particularly significant, with the wisdom of hindsight, is that these vulnerabilities exploited Universal binaries, which Apple internally knew would soon become widespread again, and of potentially great importance.

At the end of that year, I reported here that macOS Mojave 10.14.2 was happy to run apps whose developer certificates appeared to have been revoked. This provoked long discussions, in which a very experienced developer asserted:
“I disagree with the whole notion that there are ‘signature problems’. Code signatures are designed for Gatekeeper. Gatekeeper is designed for first launch. Gatekeeper has changed over the years. Old signatures on installed apps are irrelevant, not a problem.”

A security researcher expressed opposite opinions about the value of signature checks:
“Since macOS doesn’t check code signatures after the first run, malware could infect many of the apps on your system, without root, and you’d never know. All it would take is running the wrong app once. Plus, of course, when malware gets revoked, it’ll still run on infected Macs.”

I delved a bit deeper, and a couple of days later I described how macOS 10.14.2 was starting to check signatures more thoroughly after first launch. Among the log excerpts that I published in that article were the telling entries:
30.343884 SecTrustEvaluateIfNecessary
30.345255 com.apple.securityd asynchronously fetching CRL (http://crl.apple.com/root.crl) for client (lsd[355]/0#-1 LF=0)
30.345305 com.apple.securityd cert[2]: AnchorTrusted =(leaf)[force]> 0
30.346576 com.apple.securityd MacOS error: -67030
30.346629 com.apple.securityd MacOS error: -67030
30.361455 SecTrustEvaluateIfNecessary
30.362900 com.apple.securityd asynchronously fetching CRL (http://crl.apple.com/root.crl) for client (amfid[124]/0#-1 LF=0)
30.362964 com.apple.securityd cert[2]: AnchorTrusted =(leaf)[force]> 0
30.364183 com.apple.securityd MacOS error: -67030
30.378125 com.apple.securityd MacOS error: -67030
30.378189 com.apple.securityd MacOS error: -67030
30.378271 com.apple.securityd MacOS error: -67030
30.378316 com.apple.securityd MacOS error: -67030
30.378356 com.apple.MobileFileIntegrity Basic requirement validation failed, error: (null)
30.378463 /Applications/SignetTest.app/Contents/MacOS/Signet signature not valid: -67030
30.378478 AMFI: code signature validation failed.
30.380499 SecTrustEvaluateIfNecessary
30.381862 com.apple.securityd asynchronously fetching CRL (http://crl.apple.com/root.crl) for client (amfid[124]/0#-1 LF=0)
30.381904 com.apple.securityd cert[2]: AnchorTrusted =(leaf)[force]> 0
30.383124 com.apple.securityd MacOS error: -67030
30.383692 com.apple.MobileFileIntegrity <private>: Broken signature with Team ID fatal.
30.383781 mac_vnode_check_signature: /Applications/SignetTest.app/Contents/MacOS/Signet: code signature validation failed fatally: When validating /Applications/SignetTest.app/Contents/MacOS/Signet:
The code contains a Team ID, but validating its signature failed.
Please check your system log.
30.383800 proc 17245: load code signature error 4 for file "Signet"
30.403372 com.apple.launchservices RETURNING: { "ApplicationType"="Foreground", "CFBundleExecutablePath"="/Applications/SignetTest.app/Contents/MacOS/Signet", "CFBundleIdentifier"="co.eclecticlight.Signet", "DeathTime"=now-ish 2018/12/21 09:18:30, "LSBundlePath"="/Applications/SignetTest.app", "LSDisplayName"="SignetTest", "LSExitStatus"=9, "pid"=17245 }
30.648151 Saved crash report for Signet[17245] version ??? to Signet_2018-12-21-091830_Howards-iMac-Pro.crash

That was for a notarized app which didn’t have a quarantine flag set, and had never even passed through my local network, let alone been downloaded from the internet. Those entries show clearly three separate connections being made by com.apple.securityd to Apple’s Certificate Revocation List (CRL) service using OCSP and a plain HTTP connection (in bold). In this case, the validation failed on each occasion, and as a result the app was crashed and not allowed to open. At the time, no one raised any concerns about these connections or their use of plain HTTP.

In July 2019, I explained here how different types of signature checks worked, and how developers could add their own code integrity checks which include a CRL check with Apple’s OCSP service. This included log extracts which again showed clearly what happened.

Until 2018-19, it appears that macOS stored information about certificate revocations locally, in the ‘Gatekeeper’ database at /private/var/db/gkopaque.bundle, which at one time Apple updated every couple of weeks. But those Macs which have kept pace with the latest release of macOS stopped accessing that database in September 2019, with the release of macOS 10.15 Catalina. Apple hasn’t released an update to it since 26 August 2019, and anyone with a fresh installation of Big Sur will have a truly ancient version installed. As I pointed out here, that ‘Gatekeeper’ database is now disused.

Instead, Catalina and Big Sur now check all executable code on loading, and, when that code is signed with a developer certificate, perform an online check with Apple’s OCSP service, which has suddenly become so controversial.

Since the introduction of Gatekeeper in 2012, Apple has apparently revoked many compromised developer certificates. We see the tip of the iceberg of malicious software which is signed, detected by Apple, and quickly has its certificate revoked. That has already occurred with several malware products which were also notarized, including Shlayer and MacOffers. Without a rapid and effective means of checking the validity of a signing certificate with Apple’s OCSP server, there is little point in using signatures as a means of distinguishing benign from malicious code.

Those who consider that Apple’s current online certificate checks are unnecessary, invasive or controlling should familiarise themselves with how they have come about, and their importance to macOS security. They should also explain how, having enjoyed their benefits for a couple of years, they’ve suddenly decided they were such a bad idea after all, and what should replace them.

Postscript

This article has generated a lot of discussion, and I’m very grateful to Jeff Johnson in particular who has run more tests on older versions of macOS. I think there’s reasonable consensus that, when code signatures were first introduced, by “Perry the Cynic”, signing certificates passed unchecked, and if Apple did revoke certificates it seems to have had little if any effect until the introduction of Gatekeeper and the quarantine system from 2012.

As that system developed, well before High Sierra and probably before El Capitan too, Gatekeeper started to perform OCSP queries to check code signing certificate validity, but only for quarantined apps undergoing their first run. That would probably place the start of such limited checks to around 2014, but not that much earlier, as others have pointed out that in 2009 many apps still had broken signatures.

With the release of High Sierra in 2017, code signing certificate checks remained confined to Gatekeeper and quarantine, and that appears to have been the case with the first release of Mojave in 2018. However, recent certificate revocation incidents appear to have struck both Mojave and Catalina users as quickly, which suggests that by 10.14.6 in July 2019, code signing certificate checks had been extended to apps which had already cleared quarantine. Whether that was taking place around the time that I ran my tests late in 2018 (on 10.14.2) we’ll probably never know. One phenomenon which certainly confused me at that time was that moving an unquarantined app and launching it from a previously unknown path triggered more thorough signature checks, although I don’t know whether those might have included certificate checks using OCSP.

By the release of Catalina in October 2019, code signing certificates were being checked on loading all executable code when no quarantine flag was set. As far as we can tell those included the systematic checks of both signature and cdhashes which Jeff has described and I’ve summarised here.

So Apple only seems to have been performing such extensive checks over the last 16, and no more than 23, months, although they have been applied to quarantined apps for around six years. Perry the Cynic must be over the moon.