Accessing "iCloud" keychain using Keychain Services

Reading Keychain Services docs on and on and I can’t seem to find a way to access the keychain, which in Keychain Access application appears as “iCloud”. I’ve got no idea what its path could be so I could use SecKeychainOpen(), it isn’t in the default list returned by SecKeychainCopySearchList(), I can’t get it using SecKeychainCopyDefault(), even though it’s listed as “Default Keychains” in the Keychain Access,…

I assume I should be looking completely elsewhere, but I’d appreciate any hint where that could be.

Thanks,
  • - Dragan

Accepted Reply

So in essence, what I'm trying to do isn't possible. I assumed that…

Thanks for your answer.

Replies

OK, let’s start by untangling some terminology:
  • macOS supports two different keychain implementations, the file-based keychain and the iOS-style database keychain. The latter is also called data protection keychain.

  • iCloud Keychain is a user-level term that refers to the iOS-style keychain when iCloud Keychain is enabled. If the user disables iCloud Keychain this stops being called iCloud Keychain and instead shows up in Keychain Access as Local Items.

  • The <Security/SecItem.h> API can access both keychain implementations.

The iOS-style keychain is not filed based, and hence concepts like SecKeychainOpen don’t apply. You access this keychain by setting one of two attributes on your requests:
  • kSecAttrSynchronizable if you want the item to synchronise via iCloud (if the user has enabled iCloud Keychain)

  • kSecUseDataProtectionKeychain if not

Be aware that the iOS-style keychain uses iOS-style access control, that is, you can only access keychain items that are in an access group for which you have entitlements. Sharing Access to Keychain Items Among a Collection of Apps explains how that access group list is built.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"
Thanks Quinn. However, your response yields some further question and I think the best way going forward is to explain what I'm actually trying to do.

Let's say a user uses password protected SSH keys and ssh-agent for secure connection to remote servers. ssh-agent configuration file has a line:
Code Block
UseKeychain yes

The first time ssh-agent establishes a connection using a certain key, it asks for a password for that key and if entered correctly, the password is saved in the keychain. Inspecting it in Keychain Access application reveals the password is saved in "iCloud" (iOS-style) keychain with account private_key_full_file_path and service OpenSSH. I'm actually trying to access that password.

My application also makes secure connections, but I can't use ssh-agent, since the application is sandboxed. I ask user to select a private key file (thus gaining access to it through Powerbox and saving it in security scoped bookmark for further access), but then comes its password. I can ask for the password and optionally offer a possibility to save it in the (default, login) keychain and that's what I currently do. But I'd like to conveniently access the same password in the "iCloud" keychain, already saved by ssh-agent.

Again inspecting it in Keychain Access, the password has one access group, com.apple.ssh.passphrases. Hence I wanted to add that keychain entitlement to my application, like:
Code Block
<key>keychain-access-groups</key>
<array>
<string>com.apple.ssh.passphrases</string>
</array>

I'm not even sure if that would work, but even before trying I realised adding keychain-access-groups entitlement requires adding a provisioning profile as well. I tried two profiles; the first one is meant for development only, created with a wildcard (*) for App ID, my Apple Development certificate and my registered M1 Mac as a target device. That profile (once downloaded) fails to install with error message "Provisioning profile does not allow this device."

The other profile is for deployment, created with application bundle identifier (prefixed with my Team ID) for App ID, my Developer ID: Application certificate and again my M1 Mac as a target device. This profile installs successfully, but in its summary I can see something like:
Code Block
<key>keychain-access-groups</key>
<array>
<string>My_Team_ID.*</string>
</array>

This clearly indicates using that profile I won't be able to access a keychain item with access group com.apple.ssh.passphrases.

So my question now is whether what I'm trying to do is possible at all or not. And if so, how to do it.

Thanks,
  • - Dragan

Inspecting it in Keychain Access application reveals the password is
saved in "iCloud" (iOS-style) keychain with account
private_key_full_file_path and service OpenSSH. I'm actually trying
to access that password.

There’s no supported way to do that.

The iOS-style keychain uses iOS-style keychain access groups. Your access to these groups is determined by your entitlements; see Set Your App’s Access Groups in Sharing Access to Keychain Items Among a Collection of Apps for the details (1). These entitlements must be allowlisted by your provisioning profile, and Apple won’t issue you a provisioning profile that allows you access to the com.apple.ssh.passphrases keychain access group.

Share and Enjoy

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

(1) Be aware that the third item in that list, Application groups, is for iOS-based platforms only. The text says this (“Starting in iOS 8”) but it’s easy to misinterpret.
So in essence, what I'm trying to do isn't possible. I assumed that…

Thanks for your answer.