Rules for modified signed App accessing Keychain

Greetings,


I'm contributor and heavy user of Eclipse Java IDE. For a couple of releases now we are having some issues with our signed app bundle not able to access MacOS Keychain.

https://bugs.eclipse.org/391455


The problem is that Eclipse is capable of updating itself. Also during initial startup it updates some configuration files. Given that it's a cross-platform Java app, we don't have too much customizations in place for MacOS app bundles. The recent requirements for signed apps make it hard for us to keep up with. It's unlikely that we'll be capable of stopping Eclipse from writing to folders inside the app bundle. That's too much work to keep up with.


As it works right now, the signed app and dmg we ship/distribute is valid upon first start of the app. After that the app bundle has some modifications. Previously we excluded those with a resource list but that's no longer possible.


Anyway, a recent experience made me wonder what the actual rules are for accessing the Keychain?


We have an integration that stores a master password in Keychain. That master password is used to decrypt sensitive information Eclipse stores in its secure store. On my desktop (where I have been using Eclipse for many years know) the signature broke at some point preventing the app from accessing Keychain.


I recently got a new Macbook Pro as well. I use ChronoSync to keep my desktop and laptop in sync. I also sync the Eclipse.app bundle (as a whole) in order to not having to update them separately. Thus I copied the whole app bundle to the new Macbook Pro. Surprisingly, the modified app bundle is capable of accessing the Keychain without issues. It generated its master password and stored it in Keychain. Even a few updates (modifications of the app bundle) later it can still access its master password in Keychain.


Any ideas what's going on? Why would the same app bundle work on one system but fail on another?


That makes be believe that Gatekeeper has an internal database where it stores some data for makeing decisions. Is there a way to reset it?

Accepted Reply

Anyway, a recent experience made me wonder what the actual rules are for accessing the Keychain?

The rules for keychain access vary based on whether you’re using the traditional file-based keychain or the new iOS-style keychain:

  • In both cases your code signature must be valid. If your code is incorrectly signed, or you change the app on disk in a way that invalidates the code signature, nothing is going to work reliably.

    Note Way back in the day the keychain [1] was able to deal with unsigned programs. A lot of the code to handle that situation is still present in the OS, and it probably works more-or-less, but it’s not something you want to rely on. These days the vast majority of shipping code is properly code signed, and thus that’s the code path that we all rely on.

  • In a file-based keychain, items are protected by an access control list (ACL). By default this ACL lists one app, the app that created the item. The ACL references that app using its designated requirement (DR). You can see this using the

    codesign
    tool:
    $ codesign -d --requirements - /Applications/1Password.app
    Executable=/Applications/1Password.app/Contents/MacOS/1Password
    designated => (anchor apple generic and certificate leaf[field.1.2.840.113635.100.6.1.9] /* exists */ or anchor apple generic and certificate 1[field.1.2.840.113635.100.6.2.6] /* exists */ and certificate leaf[field.1.2.840.113635.100.6.1.13] /* exists */ and certificate leaf[subject.OU] = "2BUA8C4S2C") and identifier "com.agilebits.onepassword-osx"

    This looks complicated but it’s really just saying that the code:

    • Was signed by Apple

    • Is a Mac App Store app from Team ID 2BUA8C4S2C

    • Has the code signing identity of

      com.agilebits.onepassword-osx

    Any code that satisfies this DR can access the keychain. This is what allows keychain access to persist across app updates, because the keychain doesn’t store, say, a checksum of the app, meaning that version 1.1 of the app is treated just like version 1.0.

  • The iOS-style keychain uses iOS-style rules:

    • The app must be signed as either a Mac App Store or Developer ID app.

    • That means the app has a Team ID and an application identifier, both of which can be trusted because they’re guaranteed by the provisioning profile.

    • The app’s entitlements form a set of keychain access groups — see this post for info on how that list is formed — and the app can access any item that’s in those groups.

Coming back to your actual issue, you wrote:

It's unlikely that we'll be capable of stopping Eclipse from writing to folders inside the app bundle.

That’s a major stumbling block. Self-modifying apps have been unsupported on the Mac since… well… forever. macOS’s increasingly stringent code signing rules are just the latest in a long line of problems that self-modifying apps have encountered over the years [2]. It’s hard to predict the future with 100% accuracy, but I’m quite confident that these problems are going to get worse over time.

There are probably ways you could get around your keychain problem (for example, you could create a helper tool that you always use for your keychain access, and then sign that tool consistently from release to release) but I think that’s the wrong path to pursue. It might provide short-term relief for this specific problem, but in the long term it’s clear that Apple platforms must be able to reliably identify the code that they’re running.

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"

[1] And this is the file-based keychain of course, because this is before the days of iOS.

[2] I believe that the first time this caused problems was with the introduction of the AppleShare file server in 1987. Oh wait, no, you could encounter this problem on a dual floppy original Mac (from 1984) if you ran the app from the external drive and the disk was locked.

Replies

Anyway, a recent experience made me wonder what the actual rules are for accessing the Keychain?

The rules for keychain access vary based on whether you’re using the traditional file-based keychain or the new iOS-style keychain:

  • In both cases your code signature must be valid. If your code is incorrectly signed, or you change the app on disk in a way that invalidates the code signature, nothing is going to work reliably.

    Note Way back in the day the keychain [1] was able to deal with unsigned programs. A lot of the code to handle that situation is still present in the OS, and it probably works more-or-less, but it’s not something you want to rely on. These days the vast majority of shipping code is properly code signed, and thus that’s the code path that we all rely on.

  • In a file-based keychain, items are protected by an access control list (ACL). By default this ACL lists one app, the app that created the item. The ACL references that app using its designated requirement (DR). You can see this using the

    codesign
    tool:
    $ codesign -d --requirements - /Applications/1Password.app
    Executable=/Applications/1Password.app/Contents/MacOS/1Password
    designated => (anchor apple generic and certificate leaf[field.1.2.840.113635.100.6.1.9] /* exists */ or anchor apple generic and certificate 1[field.1.2.840.113635.100.6.2.6] /* exists */ and certificate leaf[field.1.2.840.113635.100.6.1.13] /* exists */ and certificate leaf[subject.OU] = "2BUA8C4S2C") and identifier "com.agilebits.onepassword-osx"

    This looks complicated but it’s really just saying that the code:

    • Was signed by Apple

    • Is a Mac App Store app from Team ID 2BUA8C4S2C

    • Has the code signing identity of

      com.agilebits.onepassword-osx

    Any code that satisfies this DR can access the keychain. This is what allows keychain access to persist across app updates, because the keychain doesn’t store, say, a checksum of the app, meaning that version 1.1 of the app is treated just like version 1.0.

  • The iOS-style keychain uses iOS-style rules:

    • The app must be signed as either a Mac App Store or Developer ID app.

    • That means the app has a Team ID and an application identifier, both of which can be trusted because they’re guaranteed by the provisioning profile.

    • The app’s entitlements form a set of keychain access groups — see this post for info on how that list is formed — and the app can access any item that’s in those groups.

Coming back to your actual issue, you wrote:

It's unlikely that we'll be capable of stopping Eclipse from writing to folders inside the app bundle.

That’s a major stumbling block. Self-modifying apps have been unsupported on the Mac since… well… forever. macOS’s increasingly stringent code signing rules are just the latest in a long line of problems that self-modifying apps have encountered over the years [2]. It’s hard to predict the future with 100% accuracy, but I’m quite confident that these problems are going to get worse over time.

There are probably ways you could get around your keychain problem (for example, you could create a helper tool that you always use for your keychain access, and then sign that tool consistently from release to release) but I think that’s the wrong path to pursue. It might provide short-term relief for this specific problem, but in the long term it’s clear that Apple platforms must be able to reliably identify the code that they’re running.

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"

[1] And this is the file-based keychain of course, because this is before the days of iOS.

[2] I believe that the first time this caused problems was with the introduction of the AppleShare file server in 1987. Oh wait, no, you could encounter this problem on a dual floppy original Mac (from 1984) if you ran the app from the external drive and the disk was locked.