Restrict access to keychain using non-standard access control policy

Hi,

I'd like to allow only a specific process to read sensitive items from keychain (based on process signature using method SecItemCopyMatching), and fail any other read attempt.

Is it possible, what are the access control rules I can define for keychain access if this is not possible ?

I'm now using the default user keychain, perhaps I should create a different keychain with non-trivial access control, so that not all processes that are running with user context or even with root privileges, would be able to get the data.

Thanks

Here's my read example :

    func read(service: String, account: String) -> Data? {
        
        let query = [
            kSecAttrService: service,
            kSecAttrAccount: account,
            kSecClass: kSecClassGenericPassword,
            kSecReturnData: true
        ] as CFDictionary
        
        var result: AnyObject?
        SecItemCopyMatching(query, &result)
        
        return (result as? Data)
    }
Answered by DTS Engineer in 752707022

except for the fact that any privileged user can directly access the keychain item

This is not about being privileged. A user can use Keychain Access to access their own keychain items in the data protection keychain. They can’t access other user’s keychain items.

FWIW, the same is true for the file-based keychain.

Preventing that takes you out of the realm of security and into the realm of DRM. You want to put something on the user’s system and prevent the user from accessing it. That’s not possible in theory so, if you want to solve this problem, you have to decide how much you want to protect this secret from the user. Options range from the simple (set kSecAttrIsInvisible so that the user has to choose View > Show Invisible Items) to the reasonable (entangle the actual value with a fixed value built into your code) to the silly (that is, what most people think of when you say “DRM”).

Share and Enjoy

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

I'd like to allow only a specific process to read sensitive items from keychain

What platform are you targeting?

This matters because, on macOS, the data protection and file-based keychains have a very different access control model. See TN3137 On Mac keychain APIs and implementations.

Share and Enjoy

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

Hi, I'm referring to macOS platform.

I'm referring to macOS platform.

OK. In that case the first step is to decide whether you want to use the file-based or the data protection keychain. To that end…

I'd like to allow only a specific process to read sensitive items from keychain

Is this process running a main executable that you created?

based on process signature

You mean the code signature of the main executable that the process is running, right?

Also, is all of this code running in the same GUI login context?

Share and Enjoy

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

My process can be either a bundled application (under /Application), or a sub-bundle application that can run as launchAgent (in user context) I've programmed those applications, so I can tell they haver main.m source file.

Also, is all of this code running in the same GUI login context?

Yes, all my applications are running in the same user context (launchAgent or standalone application) I wonder if use the application's keychain group to be able to exclusively access specific private items in keychain.

I've noticed that when I create a keychain's item (using secItemAdd command), it can be accessed/deleted from keychain app UI and I want to prevent that and allow only the app with a specific group ID an exclusive access to this item.

Given those requirements, I recommend that you use the data protection keychain. You can then set up a keychain access group that’s shared between your app and your launchd agent, secure in the knowledge that no other programs will be able to access it (other than macOS itself).

Share and Enjoy

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

Hi Quinn and thanks for the answer, it indeed seems like the right solution for me, except for the fact that any privileged user can directly access the keychain item (see attached)

Perhaps there's a way to prevent this ?

Do I need the file-based keychain in this case, and create a dedicated keychain for this item with unique password that only the process will posses ?

Or perhaps I can achieve my goal my simply using a different item (not password) that limit content viewing from outside the keychain API ?

Thanks

Accepted Answer

except for the fact that any privileged user can directly access the keychain item

This is not about being privileged. A user can use Keychain Access to access their own keychain items in the data protection keychain. They can’t access other user’s keychain items.

FWIW, the same is true for the file-based keychain.

Preventing that takes you out of the realm of security and into the realm of DRM. You want to put something on the user’s system and prevent the user from accessing it. That’s not possible in theory so, if you want to solve this problem, you have to decide how much you want to protect this secret from the user. Options range from the simple (set kSecAttrIsInvisible so that the user has to choose View > Show Invisible Items) to the reasonable (entangle the actual value with a fixed value built into your code) to the silly (that is, what most people think of when you say “DRM”).

Share and Enjoy

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

Just a follow up question since you mentioned the concept DRM.

So I've read the technical document about Apple version of DRM called "Apple FairPlay" and It looks like it's not good for application verification.

I wonder if there's any built-in signing certificate in the keychain that is non-exportable (and is kept in the secure-enclave) and I can use it with my app to proof that the device i'm running my program from, is an expected device. This way, I can at least verify that the app is not installed in unauthorized machine...

See App Attest in the DeviceCheck framework.

Share and Enjoy

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

Restrict access to keychain using non-standard access control policy
 
 
Q