Secure keychain syncing
When a user turns on iCloud Keychain for the first time on a two-factor authentication account, the device establishes and creates a syncing identity for itself. The syncing identity consists of asymmetric elliptical keys (using P-384), which are stored in the device’s keychain. Each device maintains its own list of syncing identities of the user’s other devices, and signs this list using one of its identity keys. These lists are stored in CloudKit, allowing the user’s devices to reach consensus on how to securely sync keychain data between themselves.
For compatibility with older iCloud devices, a similar syncing circle of trust is created and another syncing identity is formed. The public key of the syncing identity is put in the circle, and the circle is signed twice: first by the private key of the syncing identity, and then again with an asymmetric elliptical key (using P-256) derived from the user’s iCloud account password. Also stored with the circle are the parameters (random salt and iterations) used to create the key that’s based on the user’s iCloud password.
iCloud storage of the syncing circle
For two-factor authentication accounts, each device’s list of trusted devices is stored in CloudKit. The lists can’t be read without knowing the user’s iCloud password, and they can’t be modified without having the private keys of the owning device.
Similarly, the signed syncing circle is stored in the user’s iCloud key-value storage area, can’t be read without knowing the user’s iCloud password, and is unable to be validly modified without having the private key of the syncing identity of its member.
How a user’s other devices are added to the syncing circle
New devices, as they sign in to iCloud, join the iCloud Keychain syncing circle in one of two ways: either by pairing with and being sponsored by an existing iCloud Keychain device, or by using iCloud Keychain recovery.
During the pairing flows, the applicant device creates new syncing identities for both the syncing circle and the syncing lists (for two-factor authentication accounts) and presents them to the sponsor. The sponsor adds the public key of the new member to the syncing circle and signs it again with both its syncing identity and the key derived from the user’s iCloud password. The new syncing circle is placed in iCloud, where it’s similarly signed by the new member of the circle. In two-factor authentication accounts, the sponsor device also provides the joining device with a voucher signed by its identity keys, showing that the applicant device should be trusted. It then updates its individual list of trusted syncing identities to include the applicant.
There are now two members of the signing circle and each member has the public key of its peer. They now begin to exchange individual keychain items through CloudKit or iCloud key-value storage; whichever is most appropriate for the situation. If both circle members have updates to the same item, one or the other is chosen, resulting in eventual consistency. Each item that’s synced is encrypted so that it can be decrypted only by a device within the user’s circle of trust; it can’t be decrypted by any other devices nor by Apple.
As new devices join the syncing circle, this “join process” is repeated. For example, when a third device joins, it can be paired with either of the existing devices. As new peers are added, each peer syncs with the new one. This is designed to ensure that all members have the same keychain items.
Only certain items are synced
Some keychain items are device specific, such as iMessage keys, and so must stay on the device. To prevent unexpected data transport, every item that will sync must be explicitly marked with the kSecAttrSynchronizable
attribute.
Apple sets this attribute for Safari user data (including usernames, passwords and credit card numbers) as well as for Wi-Fi passwords, HomeKit encryption keys and other keychain items supporting end-to-end iCloud encryption.
Additionally, by default, keychain items added by third-party apps don’t sync. Developers must set the kSecAttrSynchronizable
attribute when adding items to the keychain.