Security Embedded is 15+ years of experience in building secure systems. Learn more about how we can help you by exploring Phil's blog or contacting us.

Application Trust is Hard, but Apple does it Well

Application Trust is Hard, but Apple does it Well

image.jpg

On November 12, 2020 Apple released macOS Big Sur. In the hours after the release went live, somewhere in Apple's infrastructure an Online Certificate Status Protocol (OCSP) responder cried out in pain, dropping to its knees, begging for mercy as load increased beyond what it could handle. The OCSP responder slowing down, being a critical aspect of a modern public key infrastructure (PKI), makes it hard for clients of the PKI to verify the validity of identity documents. These documents, called X.509 Certificates, are attached to every verified application the user is launching on their Mac. Mayhem ensued, and after the issues were cleaned up, many questions remained about the implications of this failure. But first, let's take a look at the mechanisms involved in authenticating an application package, at the most fundamental level.

What is X.509?

The X.509 is a ratified ITU specification that defines (among other things) a standard representation for documents that convey trust relationships between entities, known as Certificates. Certificates can be thought of as policy documents. Any X.509 certificate consists of

  • a public key,
  • an indication who the certificate was issued for,
  • what actions the authority allows the certificate holder to perform,
  • the date the certificate is first valid on,
  • the date the certificate expires on,
  • metadata about how to check if the certificate has been revoked (optional, but highly recommended),
  • the authority who issued the certificate, and
  • a signature across all this metadata, from the authority.

By retrieving the authority certificate, one can verify the integrity of the issued certificate. In fact, most authority certificates were issued by an even higher authority. By verifying all the way up to the root entity certificate (the "self-signed" highest level authority), it is possible to get a high degree of confidence of the provenance of the end entity certificate. Oftentimes a certain set of policy requirements must be met for an authority to issue a certificate to an end entity, or any intermediate entity. A certificate can be viewed as an embodiment of the proof that the authorities involved performed the appropriate checks to make sure all these conditions were met. If you fail these checks, an authority should not issue you a certificate!

The ceremony of creating these documents, how to interpret the document, how to represent the hierarchy of business trust decisions are all encoded in a certificate chain. Certificate chains are powerful concepts: they can be used to verify an authority who generated a public key, and who verified it was done to a certain standard. By reducing the scope of public keys to only keys you trust by specifying only certain root authorities you will accept certificate chains originating from, you can make a policy to reject any public keys (and thus any certificates) that were issued by a different authority.

The Hard Part: Revocation

But what if, after the date the certificate is issued and before the date the certificate expires, something goes wrong? Maybe the authority decides that the entity the certificate was issued to has committed some malfeasance, and revokes their certificate. Sometimes the private key for a certificate is stolen, and so the assertions about who the party is that the certificate represents are no longer true, since an entity with the stolen key could impersonate the legitimate original party. There are numerous reasons why a certificate could be revoked.

One of the fantastic design attributes of X.509 is the fact that you should be able to perform X.509 certificate chain validation offline. So long as you have an accurate idea of what the current date is and what root entities you trust, it's (relatively) easy for a party to verify a certificate chain. The offline verification confers a great deal of resilience upon the system. But this revocation problem remains a challenge - for some systems you need to be able to check back with the authority who issued the certificate and ask "hey, is this assertion you made still valid?"

To solve this problem, there are three common mechanisms in use today. First, most authorities publish certificate revocation lists (CRLs). This list, signed by the issuing authority, can be periodically downloaded from a location specified in the certificate's metadata (say on a daily basis). When performing certificate validation, the locally downloaded copy of the CRL will provide a indication if a certificate has been revoked. These CRLs can get quite large though, and having to wait for the CRL to be refreshed for a revocation to take effect could be risky for certain applications. CRLs work for certain use cases, but the storage and update frequency trade-offs are significant.

Enter OCSP. When an authority offers an OCSP responder, the URL for the responder is also encoded in the certificate. A certificate verifier can make a call to the OCSP responder, with the serial number of the certificate to be verified. The OCSP responder checks against its database of revoked certificates. The OCSP responder will then respond with a simple "valid" or "revoked" to the query, and the calling party can then decide what to do with that information. Of course, this means that the OCSP responder can log each and every one of these queries, and build a very useful paper trail to help monitor user behaviour. This risk, along with the systemic resiliency challenges, led to a search for a middle ground.

The final mode is a variant on calling the OCSP responder. An OCSP responder can issue a short-lived, cryptographically signed document to a certificate holder. This document is "stapled" together with the certificate, and is sent to to the verifying party. So long as the time stamps match up, the recipient can assume (within some bounded risk) that the certificate is still valid, per the issuing authority. Of course, this approach only works for certain use cases (usually connectivity-oriented usage), but it does anonymize the certificate verifying parties.

Apple chose the second revocation model for app certificate verification. This mode has its benefits - revocation can be performed in real-time. So, if Apple finds that an app they issued a certificate to is actually malware, they can rapidly revoke this certificate and prevent the malware from running, even on machines it has already installed itself on. This does put a lot of policy control in Apple's hands. This is where you have to make a business decision as to whether or not you trust Apple to be benevolent or not.

X.509 and Authenticating Signed Applications

A signed application is an interesting corner case in certificate validation. Certificates are valid for a certain range of dates. Additionally, applications don't involve (at least at launch time) any sort of exchange between a server and a client that can perform an OCSP lookup on your behalf. This limits the options we have.

The first problem is more nuanced than one might think. Should an application, signed at a specific point in time, be only launchable between the validity start/end dates of the certificate issued to sign the application? Probably not - this puts an artificial horizon on the application being valid, and if this is an app you paid a lot of money for, this might be frustrating. Implementation details might vary, but there is a concept of a trusted timestamp server, where a timestamp with a nonce is signed by a trusted authority. By integrating a trusted timestamp into the bundle of attributes cryptographically verified by the application launcher, we can reduce this problem to only needing to verify the app signing certificate was valid at the time the bundle was signed. So the current calendar date is irrelevant for determining this validity, but rather the date that has been bundled into the signed app is to be used.

The second problem limits your options for handling revocation. A CRL might be useful in a subset of cases - for example if large swaths of certificates are to be revoked. However, there are some concerns with this approach, beyond scalability and size of these revocation lists. One operational concern is that you could be leaking information about which certificates have been revoked, or providing insight into the revocation process. This could be exploited by malfeasant actors to game the certificate issuing process, or at least make it more obvious which certificates have been revoked and when, so malware developers could get more insight into the process, giving them an edge in "gaming the system."

Apple opted to solve this problem with an OCSP responder. So at every launch of an app (perhaps outside of some window where the OCSP response could be cached - I have not looked into this detail), macOS would dutifully check if the certificate used by the signer is still valid, per the OCSP responder. Of course, if macOS couldn't reach the OCSP responder, it would go about its merry way launching an app. After all, a computer needs to work offline, too.

Privacy Implications vs. Usability

An OCSP responder certainly would generate logs, as we discussed before. Those logs could contain the serial numbers of certificates that users had requested be checked, as well as the IP address of the requestor. Apple certainly has a database that maps a serial number back to the actual X.509 certificate, which then can likely be used to identify what app(s) this certificate was used to sign. The metadata about the request could likely be mapped back to who you are (through the power of AppleID, perhaps), the and the attributes of the certificate could be tied to your app store purchases (or lack thereof). Theoretically, this could be used to clamp down on piracy, private software distribution and other free use of a device.

But here is where we have to consider the user. I'm knee-deep in systems security problems, day-in and day-out. All these systems we interact with have become more complex than what most people (myself included) can maintain a mental model of. Malware is hiding in more places than I have creative brain cells to think of, and every executable package I run makes me wonder who I might be handing the keys to the kingdom over to, especially if there's no way to tie the package back to the original developer who built it. App signing is actually a very good thing, in my opinion. If anything, it gives me the confidence that the package wasn't tampered with between when the developer built it and when I installed it.

I always advocate against opt-outs for security features as fundamental as app signing. Even if there is an opt-out, developers must make opting out as unpleasant as possible for the user. Why? Most users are not capable of evaluating the impact of opting out of a security process like app signing. A blanket switch that says "Disable All Code Signing Checks," even if temporary, is hard for many users to understand the implications of. And once that switch is set, how does a user (who has a hard enough time with remembering a password) remember that this setting has been changed? How do you measure the impact this has had on system integrity? How does a user know the difference between a system that has controls enabled, versus one that has no controls enabled? How does a user even reason around how this has impacted their computer?

Update: a few folks have pointed out that Apple provides the capability to temporarily disable app signature verification on a per-app launch basis. I'm not a fan of these features: this makes it easier to trick users into making unsafe changes to their computer. As well, this makes it difficult to benefit from app blacklisting and other features that Gatekeeper enables.

Google took an interesting approach to this with the boot process for the Pixelbook. When you enabled booting signed images from sources other than Google, a very annoying pop-up at boot time (complete with sound effects, if memory serves) would remind you that you were booting untrusted code. This works for developers, but most users would be confused about what the implications of this message are. Searching the web for answers this message nets you hits where people opine that you should ignore the message altogether. Not good.

One might argue Apple has catered to the lowest common denominator in this case. There's some truth to this - you don't want to start a war against your users and assume they're stupid. But if people who are "information security professionals" can't even tell you what the implications of various controls truly are (due to the vast complexity of these systems), how could your average user make these decisions?

Finally, there's the open source argument - if I have the code, build the code, nothing can hide in the code. This is a fallacy that people buy in to thanks to effective marketing by the open source community. Software systems are so complex today that subtle issues lurk in even the most carefully curated code bases. Would a Chrome build that you built yourself and are running be inherently more secure or less likely to be compromised than one you downloaded from Google that was co-signed by Apple? Definitely not (I'd argue the other direction, in fact, but that is not germane to this conversation), but the Chrome build co-signed by Apple could be revoked if there turns out to be some malware embedded in the package. This is an interesting control that benefits users massively.

Dogwhistles

The privacy squad mobilised on this one - in fact, one blog post recieved a lot of attention for decrying such systems with the dogwhistle "you no longer own your computer!" Some took a look at the Epic Megagames situation, where Fortnite has been pulled from the App Store on iOS (and Android) as evidence of the abuse potential that these systems enable. And honestly, their points are valid - in a narrow universe of discourse.

It comes down to an argument of trust - do you trust Apple, acting in their best interests, is sufficiently aligned with your best interests too? Or do you believe they're a malevolent entity? It's not feasible for an individual to maintain the list of trustworthy or untrustworthy parties that Apple does. No matter who you are, you will end up outsourcing this to someone - most users capable of running a security program that monitors for malicious apps (the same applies to most corporations, for that matter). This harkens back to the classic antivirus value proposition - the only reason legacy antivirus was of any value was because someone, somewhere, had to experience a virus first, and then report it to the antivirus vendor, who then would produce a signature. But replicating that on your own is infeasible: you need the crowdsourcing and the broad network to get these reports in early to respond. Or you simply buy this service from someone.

Perhaps more transparency would help ease peoples' concerns around misuse of their data. Having an auditable third-party run the OCSP responders for app certificate checks would assuage peoples' concerns that Apple is misusing this data. There are probably a few tweaks Apple could make to improve transparency without easing up on the platform security model they offer. Any takers for auditing this hypothetical OCSP responder?

In the Harsh Light of the Morning

In the aftermath of the OCSP responder outage, and the dust settling on the macOS Big Sur release, there are a lot of folks reasonably asking if they can trust Apple to be in the loop of deciding what apps should or should not run on their Macs. My argument is - who better than Apple?

Ditto for Microsoft - Windows has made amazing strides, bounding past controls afforded by other OSes, providing a great deal of simplicity for users while focusing on verifying who compiled code that is running on a user's PC. Trust in this process is critical (hence why the Stuxnet driver signing certificate private key theft was such a huge blow), and ultimately opting in to this trust model is a business (or at least personal) decision.

While I'm going to sound like an Apple apologist, I think the privacy arguments are far-fetched. Even if we took them to their extreme conclusion and Apple allowed users to disable all the controls they provide, we would cause more harm than good. There is certainly an opportunity for Apple to abuse the data they have access to (and oh boy do they have a lot of data on their users), but then again I think about the data that companies like Reddit, Facebook, Google and PornHub have on the average user and ask myself who has the most power to compromise a person's life?

Reddit knows what you're searching for, what subreddit forums you visit, even in that incognito window. I'm also sure that PornHub has every single query made on their search indexed by IP address and date... and if you think it's hard to map back to a particular human being, I've got bad news for you, Steve from Long Island.

We are not at the Precipice of a GPS Disaster

We are not at the Precipice of a GPS Disaster

A Treatise on Voting Machines

A Treatise on Voting Machines