Code signatures: 2 How to check them

The simplest and most direct way to check if an app or other software has a significant signature problem is to run it. If the signature fails those checks made by macOS at the time, you’ll know the outcome immediately: the software will either run normally, or macOS will refuse it with no other option.

signing1

There are times, though, when it’s helpful to get more and better information. A recent example with the 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 suffer 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, or 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 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. For the rest of us, of course, we’ve already got the information we wanted from What’s Your Sign? or Taccy. Have fun.

Coming up next

Until now, by far the most common signing certificates found on Mac executable code have been those issued by Apple to developers, and Apple’s own. This is set to change with the release of the first Apple Silicon Macs, which require all ARM executable code to be signed, even if only with an ad-hoc signature. This is compounded by the fact that Universal binaries contain separate signatures for each architecture which they support. It’s therefore perfectly feasible to create a Universal binary which contains an unsigned Intel executable, and an ad-hoc signed ARM executable.

Checking code signatures is just about to become both more complex and more important. I’m looking at how best to support that in both ArchiChect and Signet, and in the ARM checking feature in Mints.

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 which are 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 apps may still nest an Autoupdate.app inside them to support Sparkle, which the developer hasn’t signed. 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