System extension does not prompt for permission when accessing keychains

Hi,

I run a PacketTunnelProvider embedded within a system extension. We have been having success using this; however we have problems with accessing certificates/private keys manually imported in the file-based keychain.

As per this, we are explicitly targeting the file-based keychain.

However when attempting to access the certificate and private key we get the following error:

System error using certificate key from keychain: Error Domain=NSOSStatusErrorDomain Code=-25308 "CSSM Exception: -2147415840 CSSMERR_CSP_NO_USER_INTERACTION" (errKCInteractionNotAllowed / errSecInteractionNotAllowed: / Interaction is not allowed

As per the online documentation, I would expect to be prompted for the access to the application:

When an app attempts to access a keychain item for a particular purpose—like using a private key to sign a document—the system looks for an entry in the item’s ACL containing the operation. If there’s no entry that lists the operation, then the system denies access and it’s up to the calling app to try something else or to notify the user.

If there is an entry that lists the operation, the system checks whether the calling app is among the entry’s trusted apps. If so, the system grants access. Otherwise, the system prompts the user for confirmation. The user may choose to Deny, Allow, or Always Allow the access. In the latter case, the system adds the app to the list of trusted apps for that entry, enabling the app to gain access in the future without prompting the user again

But I do not see that prompt, and I only see the permission denied error in my program.

I can work around this one of two ways

  1. Change the access control of the keychain item to Allow all applications to access this item. This is not preferable, as it essentially disables any ACLs for this item.
  2. Embed the certificate in a configuration profile that is pushed down to the device via MDM or something similar. This works at a larger scale, but if I'm trying to manually test out a certificate, I don't always want to have to set this up.

Is there another way that I go about adding my application to the ACL of the keychain item?

Thanks!

Answered by DTS Engineer in 850470022

OK. So there are two types of permissions to be concerned with here:

  • File system permissions
  • ACLs

You’re targeting the System keychain so file system permissions aren’t a problem. The System keychain file is accessible to system extensions, and launchd daemons in general.

The issue here is the private key ACL. Keychain Access sets the ACL to a default value, which doesn’t allow for access by your sysex. You can change the ACL in Keychain Access (select the private key, choose File > Get Info, and then switch to the Access Control tab) but my experience is that this is tricky to get right. Specifically, Keychain Access has never been updated to deal with partition lists properly. Quoting the security man page:

The "partition list" is an extra parameter in the ACL which limits access to the key based on an application's code signature.

So I’m not sure that adding your sysex to the ACL will be sufficient. You might have to run security to tweak the partition list.

I generally try to avoid messing around with ACLs. They are tightly bound to the file-based keychain and it’s future is not bright [1], so any ACL code you write today has a limited lifespan.

The best way to avoid ACLs is to have a single program deal with your digital identity. In your case that means the sysex. So, you could do something like:

  1. Add an ‘import PKCS#12’ menu item to your app.
  2. Have it send the PKCS#12 data and the password to your sysex via XPC.
  3. Have the sysex import the PKCS#12 into the System keychain.

The import process sets the ACL to include the current program, your sysex, and thus it won’t have any problems using the private key.

However, this is a bunch of extra code. If this were the standard way that folks are expected to use your app then I’d say that code was justified. But I wouldn’t go down this path if you’re just trying to cobble things together for testing.

Share and Enjoy

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

[1] For more on this, see TN3137 On Mac keychain APIs and implementations. One day we’ll allow daemons to use the data protection keychain. One day…

I would expect to be prompted for the access to the application

You’ve missed a subtlety here. Note that the doc says app. An app is running in a GUI context and thus can present a dialog to ask the user to confirm the access. Your system extension is running in a daemon context and thus can’t present UI, which means the request fails with errSecInteractionNotAllowed [1].

Using the keychain is a sysex is tricky. The sysex is a daemon and thus only has access to the System keychain. Which brings me to this:

however we have problems with accessing certificates/private keys manually imported in the file-based keychain.

Manually imported how? Using Keychain Access?

Share and Enjoy

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

[1] That’s not the only thing that can go wrong though. The file-based keychain… well… file based, and thus your access can alse be blocked by file system permissions, which will yield different errors.

@DTS Engineer we are manually importing it using keychain access, taking care to make sure that it's imported into the System keychain.

Accepted Answer

OK. So there are two types of permissions to be concerned with here:

  • File system permissions
  • ACLs

You’re targeting the System keychain so file system permissions aren’t a problem. The System keychain file is accessible to system extensions, and launchd daemons in general.

The issue here is the private key ACL. Keychain Access sets the ACL to a default value, which doesn’t allow for access by your sysex. You can change the ACL in Keychain Access (select the private key, choose File > Get Info, and then switch to the Access Control tab) but my experience is that this is tricky to get right. Specifically, Keychain Access has never been updated to deal with partition lists properly. Quoting the security man page:

The "partition list" is an extra parameter in the ACL which limits access to the key based on an application's code signature.

So I’m not sure that adding your sysex to the ACL will be sufficient. You might have to run security to tweak the partition list.

I generally try to avoid messing around with ACLs. They are tightly bound to the file-based keychain and it’s future is not bright [1], so any ACL code you write today has a limited lifespan.

The best way to avoid ACLs is to have a single program deal with your digital identity. In your case that means the sysex. So, you could do something like:

  1. Add an ‘import PKCS#12’ menu item to your app.
  2. Have it send the PKCS#12 data and the password to your sysex via XPC.
  3. Have the sysex import the PKCS#12 into the System keychain.

The import process sets the ACL to include the current program, your sysex, and thus it won’t have any problems using the private key.

However, this is a bunch of extra code. If this were the standard way that folks are expected to use your app then I’d say that code was justified. But I wouldn’t go down this path if you’re just trying to cobble things together for testing.

Share and Enjoy

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

[1] For more on this, see TN3137 On Mac keychain APIs and implementations. One day we’ll allow daemons to use the data protection keychain. One day…

System extension does not prompt for permission when accessing keychains
 
 
Q