Code Signing with Apple Tools Outside The Keychain

We have been working on a project that solves the problem of code signing with Apple tools with a private key that is not located in the keychain of the Mac that is doing the signing.

The private key can be kept on a centralized server accessible via web APIs or comparable access. The server access can be controlled and audited in higher security environments. 

The use case is Macs that need to code sign apps but shouldn’t have access to the private keys for signing. This applies to developers, CI Integration servers, and build farms. 

The project of 3 main components: CryptoTokenKit (CTK) and CCID drivers, Status Menu, and command line tool (currently a shell script for flexibility):

  • Drivers: The CTK and CCID drivers are used to make the certificate available via the keychain API and to perform the signing operations when called by tools that use the keychain API.
  • Status Menu: The CTK driver resides inside the Status Menu app and is registered on first launch of the Status Menu app.  The Status Menu also provides a view of currently available certificates and provides a refresh when certificates change. The Status Menu does not need to be running, but it does need to be launched at least once to register the driver.
  • Command Line Tool (located in ~/Library/Application Scripts/com.twocanoes.tcscryptotoken.tcstoken/): The command line tool, token.sh, provides 2 important functions: presenting the signing certificate when requested and passing the hash that needs to be signed to the external system and returning the resultant hash. Using a script provides customization for the interface for the external device that does the signing (and potentially return the certificate associated with the private key). For testing, the private key and certificate can be located in PEM format in the same folder as the token.sh to test external signing. By default, token.sh will return the certificate and use the private key to sign. The token.sh, certificate and key are located in ~/Library/Application Scripts/com.twocanoes.tcscryptotoken.tcstoken/. This is required since CTK apps must be sandboxed and this location is available to run external code. Currently only RSA 2048 with SHA256 is supported since that is what is required for signing apps using Apple code signing certificates. 

See it in action

The follow video shows signing a macOS application without the private key being located in the keychain. The token.sh runs the “sign” tool to generate the signature. This operation could be located external to the Mac (probably via a webAPI).

If you are interested in solving this problem in your organization, let me know on Mac Admins Slack (tperfitt) or on twitter (@tperfitt)