Private Key Access Control List

I have a certificate + private key in the Apple Keychain on a macOS 12 machine. The access control for the private key has been modified to add my program binary to the "Always allow access by these applications:" list. My program uses this certificate to do mTLS authentication using OpenSSL. Also inside the program I disable the Keychain UI temporarily while accessing items stored in there to disable any prompts. All this was working fine. I could even update this binary from a .pkg file installer to the same path and the access would still be inherited.

But that is no longer the case. If I upgrade the binary now at the same path, the Keychain does not allow the program to access that private key. I have to go into the Keychain access application and manually remove the earlier entry and re-add the binary at the same path again into the list.

Not sure if this is a macOS issue or by binary has changed somehow. There have been no major code base changes to the program.

If this is something by design, is there a command line to add certain binaries to the Access List for the private key? So that I can automate this process somehow and not have to re-add the binary at the same path again every time.

The most common cause of this problem is that your code doesn’t have a stable signing identity, so the keychain can’t tell that version N+1 of your program is the ‘same code’ as version N.

How are you signing your program?

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

We do not code sign any of the macOS binaries. But I ran a load of upgrade tests for different versions of the .pkg file. We recently upgraded our macOS build machine to a newer macOS 12.0 one and any packages built using this one are not getting upgraded with access to the private key in the keychain. However, any packages that were built using our older macOS build machine (running OS X El Capitan, I know very old) are upgrading fine with access to the private key being inherited without problems.

I reported this issue when trying to upgrade from a binary built using the older build machine to the binary built using the newer build machine

Apart from this, unlike the packages built by the older El Capitan machine which are upgrading fine with the private key access inherited, the packages being built by the newer macOS are never able to inherit that private key access even though they come from the same machine. This was not the case with the packages from the older El Capitan build machine.

We do not code sign any of the macOS binaries.

That’s going to have to change. At a minimum, Apple silicon code must be signed in order to run, so you’ll have to tackle this problem at some point [1]. Even if you ignore that [2], unsigned code is increasingly uncommon on the Mac and, as time goes by, you’ll find more and more subsystems that have problems with it. Rather than spend time hunting down each individual problem, I recommend that you update your processes to sign your code with a stable signing identity.

If you need help signing your code, I’m happy to wade in. If you’re using Xcode, or xcodebuild from the command line, that takes care of most of the details. If not, you can find my standard advice in Creating Distribution-Signed Code for Mac.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

[1] Apple silicon will accept ad hoc signatures (Signed to Run Locally in Xcode terms) but such signatures are not stable.

[2] And I strongly advise you not to do that. While Apple silicon Macs are currently able to run Intel code using Rosetta 2, that’s not something you want to rely on in the long term. AFAIK Apple hasn’t announced an official timeline here, so the best you can do is look at what happened the last time around. Oh, and heed this advice from About the Rosetta Translation Environment:

Rosetta is meant to ease the transition to Apple silicon, giving you time to create a universal binary for your app. It is not a substitute for creating a native version of your app.

I have imported a Developer ID Application and Installer identity in my Keychain and using the codesign -s command, I am able to run a script manually and sign my binaries. The identities are present both in my login keychain as well as the System keychain with the codesign and pkgbuild executables given access to the private keys.

The problem now is my build server which automates running this script on the macOS machine, errors out when code signing with errors:

security: SecKeychainUnlock <NULL>: The user name or passphrase you entered is not correct.
2022-04-28 21:54:04.567 pkgbuild[69984:6020269] SignData failed: Error Domain=NSOSStatusErrorDomain Code=-25308 "CSSM Exception: -2147415840 CSSMERR_CSP_NO_USER_INTERACTION" (errKCInteractionNotAllowed / errSecInteractionNotAllowed:  / Interaction is not allowed with the Security Server.) UserInfo={numberOfErrorsDeep=0, NSDescription=CSSM Exception: -2147415840 CSSMERR_CSP_NO_USER_INTERACTION}

Is there a way to give access to the identities to the codesign and pkgbuild utilities when I am not actively using the machine? So that all this can happen in the background without me having to enter my passphrase or anything like that.

Bah, I really need to look into this CI issues in more detail. My understanding is that this issue is caused by the fact that logging in over SSH doesn’t unlock your keychain. To fix that, you must unlock the keychain yourself by running security with the unlock-keychain subcommand.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

Private Key Access Control List
 
 
Q