Hi everyone,
I’m working an Objective-C lib that performs Keychain operations, such as generating cryptographic keys and signing data. The lib will be used by my team in a Java program for macOS via JNI.
When working with the traditional file-based Keychain (i.e., without access control flags), everything works smoothly, no issues at all.
However, as soon as I try to generate a key using access control flags SecAccessControlCreateWithFlags, the Data Protection Keychain returns error -34018 (errSecMissingEntitlement) during SecKeyCreateRandomKey. This behavior is expected.
To address this, I attempted to codesign my native dynamic library (.dylib) with an entitlement plist specifying various combinations of:
- keychain-access-groups
- com.apple.security.keychain
- etc.
with:
- My Apple Development certificate
- Developer ID Application certificate
- Apple Distribution certificate
None of these combinations made a difference, the error persists.
I’d love to clarify:
- Is it supported to access Data Protection Keychain / Secure Enclave Keys in this type of use case?
- If so, what exact entitlements does macOS expect when calling SecKeyCreateRandomKey from a native library?
I’d really appreciate any guidance or clarification. Thanks in advance!
Best regards, Neil
I attempted to codesign my native dynamic library (.dylib) with an entitlement
That won’t work. Entitlements are only relevant to a main executable. If you sign library code with an entitlement it is, at best, ignored. Creating distribution-signed code for macOS has general guidelines for signing Mac code and it specifically calls this out.
Expanding on this a little, when a process runs an executable, the system checks the entitlements claimed by that executable. If all the entitlements are authorised by the executable’s profile [1], the process starts running that program and gains those entitlements. If not, the system kills the process [2].
So, to get this to work you have to change how you sign your app as a whole. This can be tricky. I usually recommend that Java developers start Java by way of a native trampoline. See the info and links in the TCC and Main Executables section of On File System Permissions. However, that trampoline ultimately calls execve
to run the java
executable, which replaces the process’s current entitlements with those of the java
executable. So you have to sign the java
executable with entitlements, which is tricky because these entitlements must be authorised by a profile and the java
executable is not packaged in an app-like structure.
I’m not entirely sure how to square this circle. The ‘obvious’ solution is to rework your app so the app bundle’s main executable is actually the main executable, that is, the executable that keeps running and ends up using these entitlements. However, historically that’s been hard with Java. I don’t really keep tabs on the Java world, so perhaps this has improved in recent years. I recommend that you research that on the Java side.
If it hasn’t, come back here and I’ll zen further on this issue.
Share and Enjoy
—
Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"
[1] On macOS there are some unrestricted entitlements. TN3125 Inside Code Signing: Provisioning Profiles goes into this in more detail.
[2] Again, macOS is weird here. See the Entitlements-Validated Flag section of App Groups: macOS vs iOS: Working Towards Harmony.