How to check an app’s signature

For any Universal app or binary, code signing is no longer optional, as macOS won’t run any binary code on Apple silicon unless it’s signed. However, just because code runs on an Apple silicon Mac doesn’t mean that it has been signed using a developer certificate.

signing1

It’s often helpful to get more and better information. A recent example with an HP printer software problem is when an app with a human interface reports a puzzling error which might result from a signature failure in one of its components. Signature failures reported to the user by macOS don’t always come with any explanation; you aren’t informed what’s wrong with the signature, so don’t know whether replacing the software will do anything useful. If the failure has resulted from certificate revocation, that’s important to know, as anything else signed with the same certificate is doomed to the same fate.

GUI utilities

The most convenient way to check single signatures on apps, executable bundles and command tools is using Objective-See’s What’s Your Sign? This free app installs a Finder extension which adds a new command to the Finder’s contextual menu. Select the app or other item you want to check, and its Signing Info command gives immediate access to a signature check.

signing2

Every Mac user should have the current version of What’s Your Sign? ready for use, it’s as simple as that.

When you want more detailed information, or want to check multiple items, I have a choice of three tools for you: ArchiChect for Mojave and later, Taccy for Sierra and later, and Signet for High Sierra and later. Each offers different features.

Taccy is aimed mainly at sorting out problems with privacy protection, and works with both apps and Installer packages. It shows a great deal more than just code signature checks too.

signing3

Taccy uses both spctl and codesign to check signatures, and shows full results in its scrolling text view, as well as details on hardening, notarization and more.

If you’re mainly interested in the signature and running Mojave or later, you should find ArchiChect even more suitable. It offers the same detailed spctl and codesign checks as Taccy, but covers a much wider range of types which it can check. The only commonly-encountered form which it doesn’t check are disk images. It also informs you whether the quarantine flag is set, whether it’s notarized, and 64-bit.

signing4

Signet is designed to exhaustively scan a folder containing signed apps or other items, checking their signatures, for which it returns any error reports. Its Help book contains a detailed account of the error codes you’re likely to encounter, which I include in the Appendix to this article.

signing5

Command line

The two main command tools used to check code signatures are spctl and codesign. Both have their quirks.

To check an app fully in Terminal, use both
/usr/sbin/spctl -a -vv filePath
and
/usr/bin/codesign -dvvv filePath
which are the commands used internally by Taccy and ArchiChect.

To check an Installer package, use both
/usr/sbin/spctl -a -vv -t install filePath
and
/usr/sbin/pkgutil --check-signature filePath
instead.

codesign is a poorly designed command tool in that its -v option can mean either verbose or verify. The first -v encountered is interpreted as meaning verify, unless other actions such as display or sign are requested, in which case it means verbose instead. The simple answer seems to be to use at least -vv if you want either option, and you’ll probably then get both. Thanks to @rosyna, who writes that “you can never have enough v” and recommends using -vvvv or even more.

Although codesign returns quite a lot of information about the signing certificates, if you want further detail you’ll probably want to extract them from the signature and analyse them further. The command
codesign -dv filePath --extract-certificates
generates three certificates named codesign0 to codesign2, ready for study. Then using
openssl x509 -inform DER -in codesign0 -text > outfile.text
will dump full information into the text file outfile.text.

That includes:

  • the certificate serial number, useful for looking it up in a CRL;
  • the start and end datestamps of its validity;
  • the URL for OCSP access to its CA.

If you’re really adept with SSL and certificates, given that macOS includes LibreSSL, you can then use openssl to query the revocation status of a signing certificate using OCSL, something I’ll leave as an exercise for the reader.

There’s a catch when interpreting the validity of code-signing certificates, though. Unlike Apple’s Developer Installer certificates for signing installers, which must be valid at the time of installation, Developer Application certificates may well have expired when you run an app. Their rule for validity is that they must have been fully valid at the time the app or code was signed, according to its secure date and timestamp. They must also not have been revoked, of course. macOS command tools are aware of such distinctions, but checking the certificates on your own could lead you to misleading conclusions.

For the rest of us, we’ve already got the information we wanted from What’s Your Sign? or Taccy.

Apple has recently published a series of three in-depth Technical Notes detailing technical features and use of code signing:
Apple TN3125: Inside Code Signing: Provisioning Profiles
Apple TN3126: Inside Code Signing: Hashes
Apple TN3127: Inside Code Signing: Requirements
Unlike its older, archived documentation those are fully up to date.

Appendix: Common Signature Errors

Checking some objects may return an error of type 100021, kPOSIXErrorEISDIR, an ‘illegal operation on a directory’, which appears benign.

The most significant error code is -2147409652 CSSMERR_TP_CERT_REVOKED, which indicates that particular certificate has been revoked.

After those comes the main series of code signature errors, between -67000 and -67080. Some of the more frequently encountered include:

  • -67007, the resource envelope is obsolete as this is version 1 signature.
  • -67008, unsealed contents are present in the root directory of an embedded framework. This is an error on the part of the developer, who hasn’t put the app together and signed it correctly.
  • -67013, the resource envelope is obsolete (custom omit rules). This is likely to be an old signature, such as those on Aperture or Bento.
  • -67021, nested code is modified or invalid. This occurs when an app has a more complex structure, for example having additional helper apps, plugins and the like inside. Signing these correctly can get tricky, and errors can even occur in some apps supplied through the App Store. This is very much a developer problem.
  • -67023, invalid resource directory, as the resource directory or its signature have been modified. The resource directory shouldn’t contain executable code, only resources such as icons. Although tolerated in some signature checks, this shouldn’t happen, and will break checking of apps with the quarantine flag set. Check with the developer.
  • -67028, bundle format not recognised or invalid. This might not be an app (or whatever), or the developer has got it seriously wrong.
  • -67029, code has no main executable file. This app has become mangled, or it isn’t an app at all.
  • -67030, invalid Info.plist, because the Info.plist file or its signature have been modified. That should never occur, and merits a close look to check what has happened. Although this property list is readily readable, its contents are complex and detecting deliberate tampering may not be easy.
  • -67049, object file format invalid. Another indication of mangling.
  • -67050, code failed to satisfy one of the code requirements. This is another potentially serious error which can be hard to pin down.
  • -67051, unsupported type or version of code requirements. Possibly very old.
  • -67052, invalid code requirements. Probably from mangling or tampering.
  • -67053, invalid resource selection rule.
  • -67054, a sealed resource is missing or invalid. Most probably something has gone missing from the bundle, or something within it which should be signed isn’t, and is throwing a -67062 unsigned error. See below for discussion.
  • -67055, the sealed resource directory is invalid. Usually mangling.
  • -67056, code has no resources but signature indicates they must be present. Most probably structural damage, which should be referred to the developer.
  • -67057, resources are not sealed by the signature. The Resources folder has been omitted from the signing process. Another developer error.
  • -67058, a required Info.plist file or resource is broken. Check with the developer, as this could indicate tampering had occurred.
  • -67059, unsupported type or version of signature. Most probably very old.
  • -67060, the signature can’t be read, e.g. permissions issues. Occurs when signature checking processes are prevented from accessing the signature. Check permissions.
  • -67061, invalid signature (code or signature have been modified). A generic error which could indicate tampering and needs to be referred to the developer.
  • -67062, the code object is not signed at all, which is by far the most common error encountered. See below for further discussion.
  • -67072, code signing feature is unimplemented. An odd one, refer to the developer.

Many third-party apps distributed independently of the App Store use the Sparkle mechanism to offer and install updates. This results in a complex app bundle which developers haven’t always signed fully in the past. Older and unnotarized apps may still nest an unsigned Autoupdate.app inside them to support Sparkle. This is normally found in the path within the app’s bundle of /Frameworks/Sparkle.framework/Versions/A/Resources/Autoupdate.app, and may lead to a cascade of errors such as
Demo.prefPane/Contents/MacOS/DemoHelper.app/Contents/Frameworks/Sparkle.framework error -67054 a sealed resource is missing or invalid
Demo.prefPane/Contents/MacOS/DemoHelper.app/Contents/Frameworks/Sparkle.framework/Versions/A error -67054 a sealed resource is missing or invalid
Demo.prefPane/Contents/MacOS/DemoHelper.app/Contents/Frameworks/Sparkle.framework/Versions/A/Resources/finish_installation.app error -67062 code object is not signed at all

Another problem coming with Ventura is that Gatekeeper will check the signature of executable code whenever it’s run, not just when it’s first run with a quarantine flag set. If an updater has modified an app but hasn’t ensured that the updated app passes that signature check, it’s going to fail Gatekeeper long after the app was first installed. The best solution is then to download the latest version of the app, and install that to replace the updated version on disk.