Apple would really, really, really prefer you downloaded all your applications from the App Store, where they can assess and block less-than-wholesome code before it gets onto your Mac.
But until – if ever – everything you need is available in the store, Apple employs a handful of techniques to defend you against malicious code on the wild Internet.
Two of these techniques are developer signatures and notarisation.
If you want to build macOS applications, you’ll likely join the Apple Developer Program.
As well as giving you access to all the support and resources you’ll need, the program also gives you a unique Developer ID and unique keys for signing your builds.
These signatures allow macOS to discover:
- Who wrote an application, and:
- If the application was modified after the developer released it.
Why does macOS care? Well:
- macOS won’t run an application without a signature, and:
- macOS won’t run an application that was modified after it was signed.
Who signed an application?
Generally, you don’t need to go and manually check who signed an application before you run it. macOS takes the default position of “signed good, unsigned bad” and refuses to run any application if it can’t identify the developer.
But if you’re paranoid – and that tends to be a good thing in SecOps – then fill your boots!
spctl command can assess an application to discover who signed it:
spctl -vv --assess <filename>
For example, I can find out who signed the Firefox build on my machine by running:
spctl -vv --assess /Applications/Firefox.app
In the “origin” response, we can see that the Mozilla Corporation signed the build, which shouldn’t be a huge surprise:
/Applications/Firefox.app: accepted source=Notarized Developer ID origin=Developer ID Application: Mozilla Corporation (43AQ936H96)
By default, macOS won’t run applications that haven’t been signed by their developer.
If you try, macOS tells you that the application “cannot be opened because it is from an unidentified developer.”
s3headersetter is one of my open-source applications, and I don’t sign the builds. If I download and run the latest release, well…
Well, let’s be accurate here. macOS won’t allow Finder to run unsigned applications. I got that warning above by double-clicking the application. macOS does allow terminals to run unsigned applications.
s3headersetter was built for scripts to run from the command line, I haven’t bothered to include a signing stage during the build. Maybe one day I’ll need to, but why do today what you can put off until tomorrow?
If I was a bit evil, I might want to take someone else’s signed application and modify it to do cheeky things.
What if, for example, I took a signed build of Firefox and patched it to upload the user’s passwords to my secret server. Could I trick my enemies into running it?
The short answer is no.
Since the developer’s signature is a cryptographic hash of the entire application bundle, modifying the bundle would invalidate the signature and macOS wouldn’t run it.
To try that out, I delved into my installed Firefox bundle and made an innocuous change to a property list:
If we assess Firefox with
spctl, we can confirm that there’s a mismatch between the bundle and the signature:
2019-12-28 21:03:21.745 spctl[1048:25051] There was an error parsing the Info.plist for the bundle at URL <0x7f9d26503a70>: NSCocoaErrorDomain - 3840 /Applications/Firefox.app: invalid Info.plist (plist or signature have been modified)
What about compromised developers?
One thing this doesn’t prevent, mind, is a developer actually signing malware.
It doesn’t even need to be intentional.
- What if a trusted developer’s laptop gets infected with malware that injects itself into Xcode?
- What if a villain gets access to our hero’s build process and sneaks an evil executable into the pre-signed bundle?
- What if the Tal Shiar holds the developer’s family hostage until she drops their spy bot into her bundle?
Just because a developer has signed an application doesn’t mean it contains wholesome code. The next step, then, is notarisation.
A notary is a witness to the authenticity of a document. Notarisation, then – in this context, at least – is the act of Apple being witness to the authenticity of your application.
“Authenticity” in this case means your application bundle contains no more or less than what it claims.
To be a bit more specific: notarisation checks if an application bundle contains any known malware.
Apple hosts an automated notarisation service, to which developers can submit their applications for a scan. If the application is clean, the notarisation service writes another signature – or ticket – to the bundle to verify that Apple has borne witness to its authenticity.
Notarisation is not the same as seeking App Store approval. Notarisation is entirely automated – without manual approval by Apple employees – and doesn’t check against any store or ethical policies. Also, notarisation can only check for known malware.
It’s not foolproof, but it’s far better than nothing.
Checking if Apple has notarised an application
spctl command we used earlier can tell us if Apple has notarised an application.
Let’s use it to assess Firefox and Visual Studio Code:
spctl -vv --assess /Applications/Firefox.app spctl -vv --assess "/Applications/Visual Studio Code.app"
/Applications/Firefox.app: accepted source=Notarized Developer ID origin=Developer ID Application: Mozilla Corporation (43AQ936H96) /Applications/Visual Studio Code.app: accepted source=Developer ID origin=Developer ID Application: Microsoft Corporation (UBF8T346G9)
Check out the differences in the two “source” responses. Firefox has a “Notarized Developer ID”, while Visual Studio Code has just a “Developer ID”.
Nope, Apple hasn’t notarised this build of Visual Studio Code. It doesn’t contain that additional signature. That’s not to say it failed notarisation. We can’t make that assumption. All we know is, Apple hasn’t notarised it.
But… can we run it anyway?
Running an unnotarised application
If you try to run an unnotarised application, you’ll get a warning message and no option to carry on regardless:
Since notarisation is a relatively new concept, Apple does let you bypass this check if you really, truly trust the developer and are willing to jump through a hoop to prove you accept responsibility for the risk:
- Context-click on the application.
- Click Open.
- In the warning pop-up, click Open again.
macOS remembers when you bypass a check for an application, so you won’t need to go through those steps again – for that application. Running a different unnotarised application would trigger a new warning.
TL;DR - what good do these do?
In a nutshell:
- Developer signatures verify that the developer you trust genuinely built the application you want to run.
- Developer signatures verify that an application wasn’t modified after the developer signed it.
- Notarisation verifies that Apple is a witness to an application being clear of known malware.