A primer on code signing errors

Whether you’re checking in Terminal or using my free Signet, code signature errors can get thoroughly confusing. Telling the important errors from the run of the mill isn’t always easy, and often needs some knowledge of the app or command tool which you’re checking.

If you run a scan in Signet with the Show 100021 checkbox ticked, a lot are likely to return errors of type 100021, kPOSIXErrorEISDIR, an ‘illegal operation on a directory’. These generally appear benign and irrelevant, and unless you have a particular fascination for them, I recommend leaving that option unchecked.

The other error code which stands out when you encounter it is -2147409652 CSSMERR_TP_CERT_REVOKED, which indicates that particular certificate has been revoked. Revocations aren’t necessarily sinister, and the great majority of these have been requested by the developer when a particular product is discontinued. If you’re suspicious that the revocation has been because of abuse of that certificate, inspect it more closely using Objective-See’s Whats Your Sign? or the excellent Max Inspect from the App Store.

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

Notarization should fail in these cases, so they should now be rare. However, if you have older apps which use Sparkle, you may still encounter these.

Unsigned apps and components such as frameworks and plugins remain common in older releases, although you shouldn’t see them in code which has been signed from 1 June 2019 onwards. These are the bane of signature checking, and security in general, because with no signature to check, it’s impossible to know whether they’ve been tampered with or to obtain an audit trail of developer and certificate authority.

Until notarization was introduced, it was not uncommon for otherwise correctly-signed apps to include unsigned components. Examples from major vendors include nested and supporting apps in Adobe Acrobat 2015, Microsoft Silverlight (which is completely unsigned), Java Virtual Machines and the JDK itself, and proofing tools in Microsoft Office. Some of those which have been signed are now reported as having had those certificates revoked, which might arouse even greater suspicion.

So what should you do with a bundle for which errors are reported?

That depends on what the bundle is for and what the error is. Some reputable software developers consider that checking signatures of apps once they have successfully completed their first run is inappropriate. They argue that signatures are only there for Gatekeeper, and as Gatekeeper is only there to check apps when they are first run, it doesn’t matter once the app has passed that check. Others consider that checking signatures is “security theatre”, as unless those checks are accompanied by databases containing ‘true’ signature references, they are worthless.

Changes in signature checking in Mojave 10.14.5 and in Catalina are set to alter this. macOS is increasingly expecting apps and other executable code to pass signature checks whenever they’re run, and the hardened runtime required in notarized apps also expect this. That said, macOS continues to run unsigned code, and Apple hasn’t indicated that policy will change in the future. But apps and other executable code which return errors when their signatures are checked should be cause for more concern now than in the past.