Frequently Asked Questions
Looking for something specific? The User Guide and FAQ are indexed within the app — open Apparency, click on the Help menu (Command-?), and type in the Search field. Results listed under Help Topics link directly to the appropriate User Guide section or FAQ entry here.
What versions of macOS does Apparency support?
- macOS 13 (Ventura)
- macOS 12 (Monterey)
- macOS 11 (Big Sur)
We've done some initial testing of Apparency on the first macOS 14 (Sonoma) beta release, and aren't aware of any major problems. However, we have more work to do, and expect that macOS will continue to be in flux. If you run into any new issues on Sonoma, please do let us know.
If you're using an older version of macOS, you can download an old version of Apparency as follows:
We make these older versions available for those who need them, but we have not tested them since they were current, and can't make any claims about how well they might work.
Ensuring that Apparency works properly on even a single version of macOS takes a great deal of work, especially for our one-person company. Since we are not willing to claim support for a macOS version that we have not tested, and since Apple releases a new macOS version every year, we must periodically drop support for older versions.
Does Apparency automatically check for updates?
Yes, once every 2 weeks — or less, if you use it less often — Apparency will download a small file from our website to get the current version number. If a newer version is available, you'll see an Update Available button on the right side of the app's title bar:
Click on Update Available to open the Apparency download page, where you can get the latest version.
If you want to change the frequency with which Apparency checks for updates, or turn off automatic checking entirely, use Apparency > Preferences > Update:
Apparency never automatically downloads or installs the actual updated app. You make the decision about when or if to download it, and where and how to install it.
Why should I care about these details of an app?
You shouldn't need to care about these details. And maybe you don't need to care about them — that is clearly Apple's position on the matter.
But if you do care about them, shouldn't it be easier to get the information?
Apparency is primarily for people who already know that they wanted something like this. If it doesn't sound like something you want, we won't try to convince you. After all, we make the same $0 whether you use it or not.
“But isn't [security feature X] just more Apple security theater?”
Maybe. Maybe not. But what is theater without an audience? ¯\_(ツ)_/¯
Seriously, we don't claim to be authorities on this. There is no shortage of other people who have opinions on the matter. Apparency simply provides visibility into the mechanisms that exist. You can decide for yourself how much trust to put in them.
“Won't [some command in Terminal] give me the same information?”
Yes, absolutely. There's nothing that Apparency shows that isn't available through some Terminal command or another.
For example, the information about the code signature, entitlements and such can
be discovered using the
codesign(1) command. But you have to wrangle codesign's arcane command line
options, and run it multiple times different ways to get all of the relevant information. If you want Gatekeeper information,
you also need to use the
spctl(1) command. And if you want to actually examine the signing certificate, you
need to grok codesign's
--extract-certificates option, hunt down the (buried) Certificate Assistant app, click through
its certificate evaluation flow, and drag the extracted certificates into it.
Apparency is simply aiming to make this all easier and more convenient.
Is Apparency “sandboxed”? What entitlements does it have?
Yes, Apparency is sandboxed. In fact, you can easily see this using Apparency itself.
To quickly open Apparency using Apparency, use Cmd-Option-O. You can see that App Sandbox is enabled.
If you use Component > Show Entitlements, you'll see that the top-level Apparency app has the following entitlements:
|com.apple.security.files.user-selected.read-only||YES||This allows Apparency to see the app that you tell it to open — even if it's in a place that is not otherwise accessible to sandboxed apps, such as inside your home folder.|
|com.apple.security.temporary-exception.mach-lookup.global-name||com.apple.security.syspolicy||This allows Apparency to talk to the /usr/libexec/syspolicyd daemon, which is required to successfully check an app's notarization status. (Apparency uses the macOS Security.framework APIs to check for notarization, but that framework's sandbox configuration isn't complete.)|
Within Apparency, there are two other components that are also sandboxed, and thus have explicit entitlements.
The ApparencyPreviewExtension.appex component provides the Quick Look Preview to the Finder, and has the following entitlements:
|com.apple.security.files.user-selected.read-only||YES||As above, this allows the Quick Look extension to see the app to preview.|
|com.apple.security.temporary-exception.mach-lookup.global-name||com.apple.security.syspolicy||As above, this allows the Quick Look extension to check an app's notarization status.|
|com.apple.security.temporary-exception.sbpl||(allow lsopen)||On macOS 11 (Big Sur) or later, this allows the Open With Apparency button to work. That button does the equivalent of opening a custom URL, which is handled by the Apparency app. The sandboxing of Quick Look Preview extensions on Big Sur is such that, by default, this operation — opening a URL via LaunchServices — is not allowed.|
Finally, under the MRSFoundation.framework component, you'll find a com.mothersruin.MRSFoundation.UpdateCheckingService.xpc XPC service. This is the component that performs the periodic check for updates, and is entitled as follows:
|com.apple.security.network.client||YES||This allows the XPC service to make an outgoing network connection, in order to fetch this file, which contains the information about the current version of Apparency available for download.|
Why don't I get a Quick Look preview? What if I prefer the standard preview instead?
Once you've opened Apparency for the first time, macOS ought to enable its Quick Look Preview extension, so that previewing an app from the Finder will show the enhanced version.
However, if you don't get the expected preview, open System Settings and go to Privacy & Security > Others > Extensions > Quick Look and make sure Apparency is checked. (On macOS 12 or earlier, open System Preferences and go to Extensions > Quick Look.)
If you'd rather not use the Apparency preview — but want to keep the Apparency app — you can disable the previews here as well.
Why the name “Apparency” anyway?
It's a portmanteau of “app” and “transparency.”
Yeah, we know, but naming things is hard. At least we didn't give it a name that makes people think it's malware, like last time.
What do the different Notarization statuses mean?
In the info pane, the Notarization status is described with one of the following:
|Granted||The app or component was submitted to Apple's notarization service and approved for distribution.|
|Granted — Stapled Ticket||The app or component was submitted to Apple's notarization service and approved for distribution, and a
notarization ticket was “stapled” to the app. A notarization ticket is cryptographically signed by Apple,
and stapling it to the app allows Gatekeeper to verify the notarization, even when your computer isn't
connected to the internet. (However, stapling the ticket to the app is not strictly required. Sometimes,
the ticket is stapled to the disk image that contains the app: this serves the same purpose but doesn't
leave behind a stapled ticket that Apparency will find. If neither is stapled, macOS will
query Apple's servers as needed to check for notarization.)
If a ticket is stapled to the app, you can use Component > Show Notarization Ticket to see details, including the notarization time and the Apple certificate that signed the ticket.
|None detected||The app or component does not appear to be notarized. This might be caused by an inability to connect to Apple's servers. However, a network connection is required only the first time that macOS checks for notarization of a given app, and then only if the notarization is not “stapled” to the downloaded copy. So even in the absence of Internet connectivity, it is likely the app is not actually notarized.|
|Not applicable||The app or component is signed by Apple directly, and therefore is not required nor expected to be notarized. This typically applies to apps installed with macOS, downloaded from the Apple web site, or installed from the Mac App Store.|
|Conflicting signatures||The app or component supports multiple processor architectures, which have different notarization statuses. See more below.|
|Verifying signature||Apparency is still verifying the signature on the app or component, and can't evaluate the notarization status until this is complete.|
|Multiple values||Multiple apps or components are selected in the browser, and these have different notarization statuses. Select a single component to see its notarization status.|
What do the different Gatekeeper statuses mean?
In the info pane, the Gatekeeper status is described with one of the following:
|Apple System||The app or component was signed by Apple, and is always allowed to run. This applies to apps pre-installed with macOS and to some software downloaded from the Apple website — including most developer tools.|
|Mac App Store||The app or component was signed by Apple for distribution via the Mac App Store, and is always allowed to run.|
|Notarized Developer ID||The app or component was signed with an Apple-issued Developer ID certificate, and subsequently
approved for distribution by Apple's notarization service. The code will be allowed to
run by default, unless disabled via System Settings, under
Privacy & Security > Security > Allow apps downloaded from
(or on macOS 12 or earlier, in System Preferences under
Security & Privacy > General).
Note that “identified developers” here refers to Developer ID certificates.
The system policy might also be changed through the |
|Developer ID||The app or component was signed with an Apple-issued Developer ID certificate, but does not appear to be notarized. However, macOS will allow this code to run, because (a) the developer began distributing apps under this Developer ID prior to the release of macOS 10.14.5 (April 8, 2019), and (b) the app or component has a verified signing time no later than June 1, 2019. [macOS 10.15 (Catalina) and later enforce both of these requirements on unnotarized code, while macOS 10.14 (Mojave) enforces only the first.]|
|Can't evaluate||Apparency can't evaluate the Gatekeeper status because the signature itself is not valid, as shown by the Signed By identity (and documented below). Since the identity of the signing certificate can't be relied upon, it doesn't make sense to evaluate that identity against any Gatekeeper policy.|
|Not evaluated||Apparency isn't able to evaluate the app or component against the Gatekeeper policies. Currently, this should only be the case for kernel extensions, which have special requirements that go beyond those for normal apps. (In particular, the Apple-issued Developer ID certificate must be explicitly approved for signing of kernel extensions, so an additional level of Apple review is involved.)|
|Rejected||The app or component was signed with a certificate that is not trusted by Gatekeeper (or perhaps not even by macOS; see below). This might be case the if the component was signed with a third-party certificate (which would be uncommon) or perhaps with an Apple-issued certificate that is not of the Developer ID variety (such as an App Store distribution certificate, which is only supposed to be used for submission to Apple, but is sometimes mistakenly used elsewhere).|
|Unnotarized Developer ID||The app or component was signed with an Apple-issued Developer ID certificate, but does not appear to be notarized. Since the exceptions described above for the Developer ID status are not met, macOS will not allow this code to run (unless it is found to be notarized when Gatekeeper runs).|
|Conflicting signatures||The app or component supports multiple processor architectures, which have different Gatekeeper statuses. See more below.|
|Verifying signature||Apparency is still verifying the signature on the app or component, and can't evaluate the Gatekeeper status until this is complete.|
|Multiple values||Multiple apps or components are selected in the browser, and these have different Gatekeeper statuses. Select a single component to see its Gatekeeper status.|
What do the different Signed By identities mean?
In the info pane, the Signed By identity will resemble one of the following:
|Software Signing||The app or component was signed by Apple. This Apple certificate is used to sign the components of macOS itself (including those delivered through Software Update), as well as some software distributed through the Apple website, including most developer tools.|
|Apple Mac OS Application Signing||The app or component was signed by Apple, prior to making it available on the Mac App Store. This applies to all apps from the store, whether made by Apple or by other developers. (All apps submitted to the Mac App Store are re-signed with this certificate before being made available for sale.)|
|Johnny Appleseed (123DE678IJ)||The app or component was signed with the named certificate. The exact format varies with the type of certificate and the issuer. If it's an Apple-issued Developer ID certificate, there will usually be a parenthesized string of numbers and letters at the end, as in this example: this is the team identifier that Apple assigned to that developer's account. Click Show Code Signature to see details about the signing certificate.|
|No signature||The app or component was not signed at all. This is often the case with older apps, or with developers who aren't particularly excited about paying Apple US$99 per year for the privilege of shipping software for macOS.|
|Ad-hoc signature||The app or component was signed without using a certificate. This now-uncommon scheme allows certain code-signing features (such as entitlements) to be used with effectively unsigned code. But ad-hoc signatures don't tell you anything about the developer's identity.|
|Expired certificate||The app or component was signed with a certificate that is now expired, and the signature doesn't have a verified signing time that predates the expiration. See more on macOS handling of expired certificates below.|
|Untrusted certificate||The app or component was signed with a certificate that is not trusted by macOS. That is, the certificate was issued by a certificate authority that is not included in the macOS “system anchors.” This is unusual, especially since most modern apps are signed with certificates that were issued by Apple's own certificate authority (which is obviously trusted by macOS). See more on untrusted certificates and code-signing below.|
|Can't verify signature||The app or component appears to have been corrupted or tampered with since being signed. As such, the identity implied by the signing certificate is not reliable. This could be a result of the app being compromised at the point of download. Or it could simply be the result of errors occurring during signing, or in a software update process — the latter is depressingly common, even and especially for built-in macOS apps. (For iOS apps installed on Apple Silicon Macs, read more below.)|
|Missing or inaccessible bundle||The component is the main executable of a bundle (e.g. X.app/Contents/MacOS/X), but
the enclosing bundle is either missing, or Apparency can't access it. Apparency can read only
the file or folder you select in the File > Open dialog, not the
folders above it: this is how the App Sandbox works (unless the app is in the shared Applications folder,
which all apps can read). If Apparency can't read the bundle resources (such as the Info.plist file),
it can't verify the code signature. You will likely get more useful information by opening the enclosing bundle instead.
Another reason you might see this error is if you're using Suspicious Package to Quick Look an executable within a macOS Installer package. If you preview the executable directly, Suspicious Package will export only that file. Using Quick Look on the enclosing bundle will probably yield more complete information.
|Skipped verification due to size||The app or component is so large that Apparency suspects it would take an unusually long time to verify, and so did not try to do so automatically: see more on this below.|
|Conflicting signatures||The app or component supports multiple processor architectures, which were signed with different certificates. See more below.|
|Failed to read signature||A low-level error occurred in the macOS security subsystem while attempting to read the signature. If this occurs, it probably indicates corruption of the app that fundamentally damaged the signature, and is unlikely to be recoverable.|
|Removed to DYLD shared cache||The component is part of macOS itself, and the signature was removed when the Mach-O binary was moved into the DYLD shared cache — an optimization used in macOS 11 (Big Sur) and later.|
|Verifying signature||Apparency is still verifying the signature on the app or component, and can't report the signing identity until this is complete.|
|Multiple values||Multiple apps or components are selected in the browser, and these have different signing identities. Select a single component to see its signing identity.|
What is a de facto “code place” and how does Apparency handle it?
When you open an app (or other component), Apparency tries to find all of the meaningful components within the app — such as plug-ins that add to system functionality, frameworks that the app uses, or standalone executables that it runs (or provides for you to run from the Terminal). As a general rule, these components either have their own code signatures — and possibly, entitlements — or are types that at least could be signed.
By default, Apparency looks for components only in well-defined places, rather than examining every file and folder inside the app (which could become quite slow for large apps). Apple historically published some guidelines about where such components (or nested code) should be placed. However, these guidelines have not been updated in many years, and were never followed very closely, even by Apple itself.
As such, Apparency looks in both the “standard” code places — such as Contents/PlugIns or Contents/XPCServices — as well as other places that usually contain code — such as Contents/Library/QuickLook or Contents/Library/SystemExtensions. It doesn't look in places that mostly contain non-code items, such as Contents/Resources, because it would likely spend a lot of time examining unrelated files, like nib, image and strings files.
However, for some apps, this approach might omit some components. The Contents/Resources folder, especially, is pretty much a de facto code place, in that developers (including Apple) have put code there for years, without much consequence. (The only known consequence is that it slows down verification of the code signature, because the nested code gets “sealed” twice — once through its own code signature, and once as a resource of the parent component's code signature. This redundancy is generally noticeable only on huge apps, though.)
For this reason, you can ask Apparency to try harder to find components, which means searching in the Contents/Resources folder as well. To do this, when you select the app in the File > Open dialog, check Look for components in de facto “code places” before clicking Open.
Alternatively, if the app is already open in Apparency, use File > Re-open with Options (Cmd-Shift-O) to quickly re-open it. Apparency will remember this setting on a per-app basis, so if you open the same app again — say, using Finder > Services > Open With Apparency or File > Open Recent — it will find components the same way.
How does Apparency determine the required macOS version?
macOS has a few different mechanisms for an app to declare the oldest version of macOS that it supports:
- For an app bundle, the
LSMinimumSystemVersionkey in Info.plist gives a single requirement that applies to all processor architectures.
- Less common, the
LSMinimumSystemVersionByArchitecturekey gives a (potentially) different requirement for each processor architecture.
- For a Mach-O executable, the deployment target (e.g. the
MACOSX_DEPLOYMENT_TARGETXcode build setting) is stored in the Mach-O
LC_BUILD_VERSIONload command (or the older
LC_VERSION_MIN_MACOSXload command). For a Universal executable, there will be a distinct version for each processor architecture, and these are sometimes adjusted by Xcode (e.g. bumped to a minimum of 11.0 for Apple Silicon, since nothing earlier supports that architecture).
For quick reference, Apparency tries to reconcile all of these sources into a single macOS version, and shows this as the Requires version on the info pane. It does this by choosing the oldest of all the Info.plist specifications, or if there are none (such as for a standalone Mach-O executable), it chooses the oldest of the deployment targets for all architectures. Whether this makes sense depends on how you intend to use this information.
If you need more detail, all of the individual bits of information are still available via Apparency:
- To see the Info.plist properties, use Component > Show Info Property List (Shift-Cmd-I),
and look for the
- To see the deployment targets, use Component > Show Executable Information (Shift-Cmd-X), and look at the Deployment Version. Use the Processor Architecture pop-up to see how this differs between architectures.
For iOS apps installed on Apple Silicon Macs, there is instead a minimum iOS version requirement, which is (presumably) checked against the version of the iOS frameworks bundled with that version of macOS. Apparency uses the
MinimumOSVersionkey from the Info.plist, as well as the Mach-O
LC_BUILD_VERSIONload commands, to determine what to show for the Requires version.
Why would Apparency tell me an app was “downloaded” when it clearly wasn't?
When you download a file in your web browser, macOS records how and where it was downloaded. If the file is an app, this tells macOS to activate Gatekeeper when the app is first opened. (If the file contains an app, as in the case of a disk image or zip file, the download information gets copied along with the app. So even after you've dragged the app to your Applications folder, macOS still knows that the app was downloaded.) Usually, the result of Gatekeeper is an alert, saying that the app was “downloaded from the Internet,” and asking you if you still want to open it.
In between when you download a file, and when you click OK in that Gatekeeper alert, macOS considers the file to be in quarantine (this terminology was more whimsical before 2020). Once you've allowed Gatekeeper to open the app, it is no longer considered quarantined, but there may still be enough information left behind for Apparency to detect when it was downloaded and by what app (i.e. your web browser). Apparency shows this information in the info pane; you can click on the download date once to see the downloading app name, and a second time to see the kind of download (e.g. from the Internet).
This is all probably what you'd expect “downloaded” to mean. But macOS also applies the quarantine mechanism elsewhere. Most significantly, when an app uses the App Sandbox, all files saved by that app are considered quarantined. For example, say that you receive an email with a zip file attached, and that zip file contains an app. When you ask the Apple Mail app to save that attachment, the zip file gets quarantined: as a result, opening the zip file and then the app inside will activate Gatekeeper. This happens because Apple Mail uses the App Sandbox, and not because of any special knowledge about the source of the files being saved. (Contrast this with Safari or Chrome, which explicitly tell macOS to quarantine a downloaded file, because it came from the Internet.)
Of course, for an app like Apple Mail, almost every file it saves was essentially downloaded from the Internet. Other sandboxed apps might not be downloading anything, but the files they save will still be quarantined — for example, simply save an image in the Preview app and it will be quarantined. This is because macOS does not rely on the (sandboxed) app to decide if content is potentially unsafe, but instead quarantines pretty much everything, and leaves it to Gatekeeper to decide what should be checked and how. (Obviously, Gatekeeper is going to check a quarantined app, but even some kinds of documents can be unsafe and will be subject to Gatekeeper checks.)
So, if an app that you open with Apparency was quarantined — even if it wasn't strictly “downloaded” in the traditional sense — you might still see a Downloaded date in the info pane. Apparency can detect that the quarantine came from a sandboxed app, but it doesn't know whether there was any actual download involved. If you click on the date, Apparency will show the app that saved it, and if you click again, from App Sandbox (save or open).
Sometimes, simply opening a file, without ever changing or saving it, will cause a quarantine to be added.
When you use the standard File > Open dialog from a sandboxed app, macOS gives the app permission to open and/or save that file, depending on the app's entitlements. But, when the Resume feature of macOS saves the open windows of the app, it saves the app's permissions in a way that does not preclude changing the file, and this triggers a quarantine on the file. [More precisely, in a document-based app, AppKit creates a security-scoped bookmark for each open document URL, and if the URL is user-writable, it omits the
NSURLBookmarkCreationSecurityScopeAllowOnlyReadAccessoption — even if the app has declared its read-only intent via both the
com.apple.security.files.user-selected.read-only=YESentitlement and the
CFBundleTypeRole=Viewerdocument type declaration. This creation of a read-write bookmark triggers a quarantine on the file, at least in the absence of the
This surprising behavior applies to Apparency itself: if you open a standalone executable with Apparency, you might find that Apparency claims that it was downloaded by Apparency itself! This is simply because Apparency opened it, even though it never changes or saves anything. This can be baffling, but it only happens when you open a standalone executable (not an app or other bundle); we don't try to fudge or hide it, because you should be able to trust that Apparency is showing you the actual quarantine information.
What are “code signing options” and how can I view them?
The macOS code signing mechanism has a number of additional options that can be applied to a component. These flags change the way that macOS handles certain aspects of the code signature when the app is used.
For example, there's a Library Validation option that restricts the app to using only those dynamic libraries or frameworks provided by macOS, or those signed by the same developer. And there is a Kill option that tells macOS that it should terminate the app if the code signature should become invalid while open.
To our knowledge, the only Apple documentation of these options are in the
codesign(1)man page (see the Option Flags section), and in the
Security/CSCommon.hheader (see the
SecCodeSignatureFlagsenumeration). The latter contains some options not mentioned in the former.
Apparency doesn't show these options by default, because they are not terribly common, and (quite frankly) because we don't understand the nuances of them ourselves, and can't really provide any guidance on interpreting them! However, if you want to see them in Apparency, you can enable them using Apparency > Preferences > General > Show code signature options for selected component. With this enabled, Apparency will show the options at the bottom of the info pane. (Note that Apparency won't show the Runtime or Adhoc options here, though, since these are already represented elsewhere in the info pane — the first under Hardening and the second under Signed By.)
Examining Code Signatures
What does it mean when a code signature has a “verified signing time”?
All certificates — including Apple-issued Developer ID certificates — expire after some amount of time. (This is a security precaution, since the underlying technology and the attacks against it are always moving forward.) In the ideal case, developers replace certificates before they expire, and an app you download today will be signed with a still-valid certificate. But in the real world, developers don't always get ahead of expiring certificates — or you might just have an older version of an app and still want to use it after the certificate has expired.
However, an expired certificate does not necessarily make the code signature invalid.
When an app is signed on macOS, the current date and time can be incorporated into the signature in a way that is
independently verified by Apple. That is, instead of the app just claiming to have been signed at a specific date
and time, the actual signing time is securely supplied by Apple, and bound to the code signature cryptographically.
(This is known as a
timestamp,” with an Apple server as the “Time Stamping Authority.”)
This typically happens automatically when the developer signs the app, but it might have been disabled (see the
man page, and the
This becomes relevant when Apparency evaluates the trustworthiness of the code signature. If there is a verified signing time, macOS will evaluate the signing certificate as of that date and time. If the certificate is expired now, but was not expired (and was otherwise valid) at the time the app was signed, macOS might decide that the signature is still trusted. (There are exceptions; for example, a certificate might have been explicitly revoked, and might not be considered valid for any signature on any date.)
Even in the absence of a verified signing time, Gatekeeper is quite lax about expired certificates in code signatures. See more on this below.
Unfortunately, the way that this scenario is presented in the standard macOS certificate trust sheet is less than clear: if you examine the certificate details, you'll see that the certificate has expired, but macOS still says “this certificate is valid.” Of course, the certificate itself is no longer valid, but since it was valid at the verified signing time, the signature is nevertheless valid. However, macOS doesn't show the verified signing time anywhere, nor even note its existence.
Apparency attempts to improve matters by explicitly noting when a verified signing time is found in the code signature. When you use Component > Show Code Signature, if the code signature includes a verified signing time, it will be shown in the sheet:
If you click Show Certificate, you may still see the certificate-is-expired-but-valid confusion described above — since Apparency uses the standard macOS certificate trust sheet, and can't change this bit — but at least this gives some context to the confusion.
Why does Apparency complain that a certificate is expired when Gatekeeper doesn't seem to mind it?
If an app was signed with a certificate that has since expired — and the signature lacks a verified signing time — Apparency will show the Signed By identity as Expired certificate. However, macOS generally does not consider an expired certificate to invalidate a code signature, such as when evaluating Gatekeeper policies.
We can only speculate why this is the case. Presumably, too much would break if expired certificates invalidated a code signature, especially if it prevented otherwise-valid apps from being used. The existence of verified signing times ought to solve this problem, but in fact, these are not used consistently enough. Most third-party apps have them, but most Apple apps — and apps distributed via the App Store — do not.
In any case, Apparency shows expired certificates as such, so you can decide whether or not you care.
Why does Apparency say that a certificate is untrusted when codesign(1) doesn't complain?
If an app was signed with a certificate that is not trusted by macOS, Apparency will show the Signed By identity as
Untrusted certificate. However, if you run
codesign(1) with the
option, it might not report any error. That's because the macOS code-signing mechanism does not, by default, impose any
trust requirements on the certificate used to sign an app. Features built on top of code-signing, such as Gatekeeper, can and do impose
such trust requirements, but when you use
codesign(1), you are interacting with the bare code-signing mechanism only.
To understand why this is the case, we have to go back in time. The macOS code-signing mechanism dates to Mac OS X 10.5 (Leopard), way back in 2007. In those early days, signed third-party apps were rare. Apple was code-signing components of macOS itself, but even those signatures were frequently broken by the Software Update process, with little ill effect. Indeed, before the introduction of Gatekeeper in Mac OS X 10.7 (Lion), Apple wasn't issuing code-signing certificates to third-party macOS developers. (Certificates issued to App Store developers, even with the advent of the Mac App Store, were never intended to be used for signing apps to be installed on macOS, but only for signing apps being submitted to App Review. App Store apps are always re-signed by Apple prior to being offered on the store.)
In those ancient times, a third-party developer could have gotten a signing certificate from some non-Apple certificate authority — any of the ones generally trusted via the macOS “system anchors” — but that would've been a lot of trouble and expense for no real benefit. In fact, the only benefit was that a code-signed app could be updated without losing access to any keychain items it created: as long as each new version of the app was signed with the same certificate as the original version of the app, it would maintain access. But even this could be achieved with a self-signed certificate, which can be created freely by a developer, and doesn't involve any third-party validation. It didn't matter that the self-signed certificate wasn't trusted by macOS; all that mattered is that the same self-signed certificate was used to sign subsequent app versions, indicating that they came from the same developer as the original.
Anyway, given that code signing was optional and uncommon for so many years after introduction, it is not so surprising that the
basic code-signing mechanism doesn't enforce much actual policy — that's what features such as Gatekeeper added. As such,
when you run
codesign ‑‑verify, you are asking it to verify only two things:
- The app has not been modified since being signed, denoted by
valid on disk. This means that the executable, the Info.plist and all of the other resources (images, nib files and so on) are identical to the versions that were present when the app was signed. (The signature is formed by calculating a digest of these files — called the cdhash, or code directory hash — and cryptographically signing that.)
- The code signing identity is matched, denoted by
satisfies its Designated Requirement. The designated requirement is a set of rules that identifies the app in some way. By default, the designated requirement specifies a trusted certificate, issued by Apple to a specific developer, along with a specific bundle identifier. However, the designated requirement can be overridden at signing time, so what it actually requires is not guaranteed.
Unless you've examined the designated requirement — such as by using
codesign with the
‑‑requirements options — you can't be certain that
satisfies its Designated Requirement implies
a trusted certificate. You can, however, ask
codesign to check an additional, explicit requirement that includes trustworthiness. For example:
$ /usr/bin/codesign --verify --verbose=4 --test-requirement="=anchor trusted" /Applications/Some.app /Applications/Some.app: valid on disk /Applications/Some.app: satisfies its Designated Requirement /Applications/Some.app: explicit requirement satisfied
Here, the explicit requirement says that the signing certificate must ultimately
be issued by a certificate authority that is trusted by macOS. Often, this will be Apple's own certificate authority, but this requirement
is more general than that. (Use
anchor apple generic instead to require an Apple-issued certificate.)
Again, this is only interesting to understand what the
codesign tool is actually checking — and what it isn't.
It doesn't mean that macOS isn't checking the trust of code signing certificates in specific circumstances. For example,
Gatekeeper rules are themselves code-signing requirements, just like the above. You can see these rules via something like:
In fact, these are the same requirements that Apparency uses to determine the Gatekeeper status.
Why does Apparency say that a signature is valid when codesign(1) reports the “resource envelope is obsolete (custom omit rules)”?
As described above, part of verifying a code signature is verifying that the resources inside the app (such as strings or nib files) haven't been changed since the app was signed. For a standard macOS app, there are a handful of files that are allowed to change without being flagged as an error (for example, .DS_Store or PkgInfo files). In olden times, apps could add files to this list (i.e. “custom omit rules”), but since OS X 10.9 (Mavericks), such custom exclusions from the code signature have been prohibited. This is because macOS apps are not supposed to modify themselves — they should store customizations in standard places, usually inside a Library folder.
However, Apple grants itself some exceptions to this prohibition on custom exclusions, in at least 3 cases that we're aware of:
- The “Install macOS” app — delivered in a macOS Full Installer package — has an unique install process that adds the Contents/SharedSupport/SharedSupport.dmg file to the app bundle, which isn't part of the code signature. Apple adds custom omit rules here to exclude the dmg (and, indeed, all other resources) from the code signature. The disk image is verified independently of the code signature when the “Install macOS” app runs.
- On an Apple Silicon Mac, iOS apps delivered from the App Store are modified by the addition of SC_Info folders. These contain files related to the FairPlay DRM scheme, and are specific to the purchasing user. When Apple re-signs apps for delivery on the iOS App Store, it adds custom omit rules that exclude these SC_Info files. The App Store install process presumably has an exception for these custom omit rules when verifying these App Store-signed apps.
- On macOS 11 (Big Sur) or later, everything on the signed system volume has custom omit rules which exclude
all resources, presumably because it is redundant to the protections of the system volume itself. Normally,
codesign(1)won't complain about these, because it knows not to verify resources on the signed system volume — unless you run codesign to verify a component found on a secondary (non-booted) signed system volume, that is.
In each of these cases, if you run
codesign(1), you'll get something like:
$ /usr/bin/codesign --verify /Applications/Overcast.app /Applications/Overcast.app: resource envelope is obsolete (custom omit rules)
Prior to version 1.4, Apparency would show Can't verify signature for these components, for the same reason. This was accurate, but obscured the more useful information about the signature. It also preempted any verification of the non-omitted resources, because the code signing machinery balks at the custom omit rules before attempting to verify what is not omitted.
To present more useful information, Apparency now disables the “custom omit rule” error on components that are signed by Apple or by the App Store (but not those signed by any other certificate, not even one issued by Apple). This avoids presenting not-very-interesting signature errors, and allows any non-omitted resources to be verified. (Admittedly, the latter probably only applies to iOS apps, since the other two cases omit all resources.)
What is a “code signing identity” and what is it used for?
A code signing identity allows macOS to recognize a specific app from an Apple-registered developer, without regard to a particular version of that app. This is used by macOS to grant access to sensitive resources — such as keychain items or App Sandbox “containers” — in a way that won't break every time the app is updated.
In its typical form, a code signing identity consists of two pieces:
- a bundle identifier, which is not trustworthy on its own, since any app can claim to be, say,
- an Apple-assigned developer identity, which can be claimed only by someone holding the private key of a matching Apple-issued Developer ID certificate.
Any app that matches both of these attributes is assumed to be the “same” app, and is allowed to access the same resources. The developer can update the app with abandon, as long as the code signing identity doesn't change.
Usually, this all happens behind the scenes and isn't very interesting, but there are a few places where you do need
to work with the code signing identity, such when creating a
Policy Control (PPPC) configuration profile. You can grab the code signing identity from Apparency
by selecting the app and choosing Edit > Copy Code Signing Identity (Cmd-Ctrl-C). The
code signing identity can them be pasted into the profile's
CodeRequirement key, for example.
A code signing identity — also known as a designated requirement — is defined using Apple's Code Signing Requirement Language. These requirements can get arbitrarily complex, and an app might not use the typical form. But for the curious, here's an annotated version of a typical code signing identity (the one for Apparency itself):anchor apple generic /* signing certificate was issued by Apple, trusted by Apple Root CA */ and identifier "com.mothersruin.Apparency" /* and app has this bundle identifier */ and ( certificate leaf[field.1.2.840.1136184.108.40.206.9] /* and signing certificate is the Mac App Store one */ or ( certificate 1[field.1.2.840.1136220.127.116.11.6] /* ... OR was issued by the Developer ID intermediate CA */ and certificate leaf[field.1.2.840.113618.104.22.168.13] /* ... for Developer ID Application use */ and certificate leaf[subject.OU] = "936EB786NH" ) ) /* ... for the developer with this team ID */
The team ID is an identifier that Apple assigns to each registered developer; every Developer ID certificate that Apple issues to that developer will have the same team ID, and so will meet the latter part of this requirement. (You'll see the same team ID in parentheses in the Signed By identity in Apparency's info pane.) This scheme avoids problems when the Developer ID certificate gets renewed between app updates.
The alternative check for the Mac App Store certificate allows the same resources to be shared between a Mac App Store version of the app, and the same app distributed outside the store; this is part of the default code signing identity, and doesn't necessarily mean that both versions actually exist.
Why does Apparency sometimes say that it skipped verification of the signature?
In order to verify the signature of an app or component, every file that makes up that component has to be read in its entirety, creating a cryptographic digest (or hash) of the complete component. This digest is then compared against the one that was produced when the component was signed by the developer. Any changes that are made to any file of the component are thus detected, because it will result in a different digest and invalidate the signature. (This is a bit of an oversimplification, but conceptually accurate anyway.)
In most cases, creating the digest takes a few seconds at most, and the signature is verified quickly. However, for extremely large apps, verification can start to take real time. For example, Xcode — weighing in at over 10 GB in size — can take several minutes to verify. (Anyone who has ever installed Xcode has surely noticed the long delay upon first launch!) You might want Apparency to do the verification anyway, if the signature is the information that you're interested in inspecting, but otherwise, it is just an annoying use of your CPU.
Apparency tries to guess when an app or component is so large that the verification will take an unusually long time. Where it believes this to be the case, Apparency will not automatically verify that component. Instead, it shows the Signed By identity as Skipped verification due to size. When this occurs:
- If you don't care about the signature of the component, you can ignore this entirely.
- If you would like to proceed with verification of the signature for just this single component, select it, click the Signature toolbar button (or use Cmd-Shift-S), and then choose Verify Signature.
- If you would to proceed with verification of the signatures for all components in this app, choose File > Verify All Signatures.
- If you would like Apparency to always verify all signatures, even where it believes that this make take a long time, go to Apparency > Preferences > General and uncheck Skip automatic signature verification for large code.
What does “Conflicting signatures” mean? Why does Apparency show a processor architecture pop-up?
The macOS code signing mechanism stores most of the information about the signature inside the executable of the app or component. This information includes the entitlements and the code signing identity — along with a web of cryptographic digests (or hashes) that uniquely identifies the compiled code, the Info.plist and the other bundle resources (such as images or strings files).
If an app supports multiple processor architectures (e.g. Intel — 64-bit and Apple Silicon — 64-bit), there will actually be a separate code signature for each architecture. This is simply how the code signing mechanism is designed. (The app can even be “thinned” to remove architectures, without invalidating the signatures on the remaining architectures.) Typically, each of these distinct signatures is functionally identical: that is, signed by the same certificate, with the same entitlements, code signing identity, and so on. (They can't be exactly identical, however, because the compiled code is always going to differ.)
To ensure that a multiple-architecture component has functionally identical code signatures, Apparency will evaluate the signature for every architecture. If everything is indeed consistent, Apparency won't show anything special: the Signed By, Gatekeeper, Entitlements and other attributes will simply show the common values extracted from every architecture.
However, in the (unlikely!) event that Apparency does find a difference between signatures, it will instead show Conflicting signatures in the applicable field of the info pane. When you use Component > Show Code Signature or Component > Show Entitlements to get more details, you will be given a choice of architecture to examine. This allows you to see how the architectures differ. Obviously, the architecture that your Mac will use is the most interesting, but a difference in signatures is unusual enough that you may want to examine everything more closely.
What do the different Provisioned Entitlement statuses mean?
When viewing the entitlements with Component > Show Entitlements, you may see an additional column. This appears only if the selected app has a provisioning profile, and shows the provisioned status of each entitlement. The meaning of each status icon is as follows:
|Provisioned Entitlement Status||Description|
|The entitlement is one that requires provisioning, and is allowed by the provisioning profile. Such entitlements are usually for an Apple service — such as iCloud or push notifications — or for a macOS feature to which Apple has decided to restrict access, such as system extensions.|
|The entitlement is one that requires provisioning, but it is not allowed by the provisioning profile. As a result, macOS will likely prevent the app from opening. (The macOS kernel will intentionally crash the app when it finds that it is using entitlements that are not permitted by the provisioning.)|
|The entitlement is not allowed by the provisioning profile, but is one of a subset of entitlements that are only
quasi-restricted by Apple. These include |
|The entitlement does not require provisioning at all. Generally, the entitlements related to App Sandbox and runtime hardening fall into this category.|
What are “merged entitlements” and what do they have to do with PPPC Profiles?
Apparency allows you to select an app or other executable and show the entitlements that it requests. However, since an app might contain a large number of executable components, each which might have its own entitlements, Apparency also provides a way to see a high-level view of all entitlements requested by all components. For example, this can be useful when you are creating a Privacy Preferences Policy Control (PPPC) Profile, because it tells you (indirectly) what capabilities the app will request, and how you want macOS to prompt (or not) the end users.
If this sounds a bit hand-wavy, that's because we are not Mac admins, and have never built a PPPC Profile ourselves. We hope that this feature is useful, but if you have any feedback or suggestions in this area, please do contact us.
To get this merged view of entitlements, choose File > Show Entitlements for All Executables (Cmd-Control-A).
In this view, Apparency shows every entitlement key that is requested by at least one executable component. In some cases, the keys might be all that you need, in order to see what the software wants to do. But if you need more information, Apparency also merges together all of the distinct values for a given key. If all executables use the same value (such as a Boolean YES), that will also be the merged value. But if different executables use different values (such as string identifiers), Apparency will combine these into an array (or if it's already an array, it will combine the distinct values).
The icon in the rightmost column tells you how Apparency created the merged value: either the same value was found for all executables, or multiple values were merged together. If you move the pointer over the icon, a tooltip will show how many executables requested this particular entitlement.
If you're creating a PPPC Profile, you may want to allow a specific “service” for all of the
executables that request a related entitlement. For example, perhaps you want to allow the
AddressBook service for executables that request
If you select that entitlement, and choose Copy App Identities for PPPC Profile,
Apparency will construct the array-of-dictionaries structure that a PPPC Profile uses to establish
and put this on the clipboard. Then you can go to your property list editor and paste directly under the
Apparency doesn't understand the mapping between entitlements and PPPC services, so you will still need to infer that part. The intent here is only to reduce the tedium of gathering identifiers and code signing identities (requirements) from multiple components.