How to write entries to the system keychain in macos 12+

We have an application that requires writing to the system keychain and we used SecKeychainOpen like this

var keychain: SecKeychain?
let path = "/Library/Keychains/System.keychain"
SecKeychainOpen(path, &keychain)

then in the query

baseQuery[kSecUseKeychain as String] = keychain

This approach solved my requirements, as we are able to read and write from the system keychain.

From macOS 12+ SecKeychainOpen API is getting deprecated. Is there any way to achieve the same now?

kSecUseKeychain is still allowed so, I need. a way to get the reference of system keychain am I wrong?

Minimum deployment version: 10.15+ Runs in root context , non sandboxed app

Thank you

Accepted Reply

The System keychain should be in your search list by default. There’s no need to open it. Moreover, hard coding its path is less than ideal.

You can get a reference to the System keychain without such limitations with this code:

func systemKeychain() -> SecKeychain? {
    var searchListQ: CFArray? = nil
    let err = SecKeychainCopyDomainSearchList(.system, &searchListQ)
    guard err == errSecSuccess else {
        return nil
    }
    let searchList = searchListQ! as! [SecKeychain]
    return searchList.first
}

Still, there’s a bigger issue in play here. This isn't simply a case of SecKeychainOpen being deprecated. Rather, the deprecation of that API is the first step along a path to deprecate the whole concept of the file-based keychain. The data protection keychain is the way forward here. See On Mac Keychains for more background to this.

We have not fully deprecated the the file-based keychain yet because there are still places where it’s your only option. You wrote:

Runs in root context , non sandboxed app

That is one place where you have to continue using the file-base keychain. Right now the data protection keychain is not available to launchd daemons and similar code.

We hope to resolve that issue in the future. If and when that happens, you may end up needing to revisit this code. However, we haven’t announce any concrete plans for this.

Share and Enjoy

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

  • Thanks for the reply this answers, most of my doubts. The last one can you elaborate on what's the difference between these two approaches 1.) As you suggested above we can get the ref of SecKeyChain and use query[kSecUseKeychain as String] = systemKeyChain()!, then SecItemAdd(query.......) 2.) Calling SecKeychainSetPreferenceDomain(.system) just before SecItemAdd(query ....) .here query doesnt have kSecUseKeychain attribute .

    Are there any major differences rather than the fact just the first one has more control, as there is no need to change the preferred domain in total

Add a Comment

Replies

From macOS 12+ SecKeychainOpen API is getting deprecated. Is there any way to achieve the same now?

Right, the idea here is that an MDM configuration or a user would be interacting with the System Keychain and not a custom API. If your application needs to write an identity to the System Keychain then use an MDM configuration profile to do this and not a custom API.

Matt Eaton
DTS Engineering, CoreOS
meaton3@apple.com
  • Thanks for the quick reply, I did some quick googling, and tests, then figured out that, if I use SecKeychainSetPreferenceDomain(.system) before SecItemAdd. it's writing to the system keychain(passwords section) which is my requirement. Am I doing something wrong here?

    query[kSecClass as String] = kSecClassGenericPassword query[kSecAttrService as String] = serviceName query[kSecAttrAccessible as String] = kSecAttrAccessibleAfterFirstUnlock query[kSecAttrAccount as String] = key query[kSecValueData as String] = value SecKeychainSetPreferenceDomain(.system) SecItemAdd(query as CFDictionary, &result)

    This is the order I am following and looks like it writing to the system keychain. Please correct me if I doing something that I am not supposed to. Sorry for bad formatting

Add a Comment

back soon

The System keychain should be in your search list by default. There’s no need to open it. Moreover, hard coding its path is less than ideal.

You can get a reference to the System keychain without such limitations with this code:

func systemKeychain() -> SecKeychain? {
    var searchListQ: CFArray? = nil
    let err = SecKeychainCopyDomainSearchList(.system, &searchListQ)
    guard err == errSecSuccess else {
        return nil
    }
    let searchList = searchListQ! as! [SecKeychain]
    return searchList.first
}

Still, there’s a bigger issue in play here. This isn't simply a case of SecKeychainOpen being deprecated. Rather, the deprecation of that API is the first step along a path to deprecate the whole concept of the file-based keychain. The data protection keychain is the way forward here. See On Mac Keychains for more background to this.

We have not fully deprecated the the file-based keychain yet because there are still places where it’s your only option. You wrote:

Runs in root context , non sandboxed app

That is one place where you have to continue using the file-base keychain. Right now the data protection keychain is not available to launchd daemons and similar code.

We hope to resolve that issue in the future. If and when that happens, you may end up needing to revisit this code. However, we haven’t announce any concrete plans for this.

Share and Enjoy

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

  • Thanks for the reply this answers, most of my doubts. The last one can you elaborate on what's the difference between these two approaches 1.) As you suggested above we can get the ref of SecKeyChain and use query[kSecUseKeychain as String] = systemKeyChain()!, then SecItemAdd(query.......) 2.) Calling SecKeychainSetPreferenceDomain(.system) just before SecItemAdd(query ....) .here query doesnt have kSecUseKeychain attribute .

    Are there any major differences rather than the fact just the first one has more control, as there is no need to change the preferred domain in total

Add a Comment

Are there any major differences rather than the fact just the first one has more control, as there is no need to change the preferred domain in total

Well, those a pretty big differences. I prefer kSecUseKeychain because a) it’s explicit, and b) it doesn’t change process-wide state. That does not, however, make it any more futureproof.

Share and Enjoy

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

@eskimo Looks like SecKeychainCopyDomainSearchList is deprecated as well.

What's the recommended approach to get a reference of system keychain?

My scenario is similar, I'm using SecPKCS12Import to import an identity into system keychain. It allows me access to System keychain only when I get a reference of it using SecKeychainRef as shown in the below code:

SecKeychainOpen is deprecated and also SecKeychainCopyDomainSearchList. How can I go about getting the reference now?

What's the recommended approach to get a reference of system keychain?

I’m going to stand by the code snippet I posted above.

SecKeychainOpen is deprecated

You shouldn’t need that.

and also SecKeychainCopyDomainSearchList.

Yep.

How can I go about getting the reference now?

Using SecKeychainCopyDomainSearchList.

The issue here isn’t that this specific API is deprecated, but rather than the entire concept of the file-based keychain is on the road to deprecation. The deprecation of routines like SecKeychainCopyDomainSearchList is just the first step on that path.

We recommend that folks switch to the data protection keychain. Most app developers can do that just fine. However, there are cases where that’s not possible, for example, if you’re building a daemon. If you’re building a daemon you should continue using the file-based keychain until Apple has a data protection keychain solution that works for you. And that means that you’ll need to use this deprecated API.

You can find more backstory on this topic in TN3137 On Mac keychain APIs and implementations.

Share and Enjoy

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