7

If a backup to iCloud is made from one device then restored onto another device then items stored in the keychain aren't restored. This isn't what was expected, AFAIA a "ThisDeviceOnly" access setting isn't used, kSecAttrAccessibleAfterFirstUnlock is used (as opposed to kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly) which should have resulted in items being restored onto the other device?

class func createKey() -> NSData?
{
    let keychainIdentifierData = kKeychainIdentifier.data(using: String.Encoding.utf8, allowLossyConversion: false)!

    let keyData = NSMutableData(length: 64)!
    let result = SecRandomCopyBytes(kSecRandomDefault, 64, keyData.mutableBytes.bindMemory(to: UInt8.self, capacity: 64))
    if (result != 0)
    {
        return nil
    }

    // Store the key in the keychain
    let query: [NSString: AnyObject]  = [
        kSecClass: kSecClassKey,
        kSecAttrApplicationTag: keychainIdentifierData as AnyObject,
        kSecAttrKeySizeInBits: 512 as AnyObject,
        kSecValueData: keyData,
        kSecAttrAccessible: kSecAttrAccessibleAfterFirstUnlock
    ]

    let status = SecItemAdd(query as CFDictionary, nil)
    if (status != errSecSuccess)
    {
        return nil
    }
    return keyData
}



    class func getKey() -> NSData?
    {
        let keychainIdentifierData = kKeychainIdentifier.data(using: String.Encoding.utf8, allowLossyConversion: false)!

        // First check in the keychain for an existing key
        let query: [NSString: AnyObject] = [
            kSecClass: kSecClassKey,
            kSecAttrApplicationTag: keychainIdentifierData as AnyObject,
            kSecAttrKeySizeInBits: 512 as AnyObject,
            kSecReturnData: true as AnyObject
        ]

        // To avoid Swift optimization bug, should use withUnsafeMutablePointer() function to retrieve the keychain item
        // See also: http://stackoverflow.com/questions/24145838/querying-ios-keychain-using-swift/27721328#27721328
        var dataTypeRef: AnyObject?
        let status = withUnsafeMutablePointer(to: &dataTypeRef) { SecItemCopyMatching(query as CFDictionary, UnsafeMutablePointer($0)) }
        if status == errSecSuccess {
            return (dataTypeRef as! NSData)
        }
        return nil
    }
Gruntcakes
  • 37,738
  • 44
  • 184
  • 378
  • `kSecAttrAccessibleAfterFirstUnlock` makes the Keychain entry accessible after the first unlock after restarting the device. It has nothing to do with synchronization via iCloud. What you are looking for is presumably [`kSecAttrSynchronizable`](https://developer.apple.com/documentation/security/ksecattrsynchronizable) which you should set to `kCFBooleanTrue` if you want to enable iCloud synching. But I'm not sure if I understood your Question correctly. – Max Oct 11 '17 at 06:51
  • 1
    @Max What I am finding is that I backup device A to iCloud and then reset that device and restore the backup to it, then the keychain item is present (even though kSecAttrSynchronizable is not set anywhere). But if I reset device B and restore the same backup to device B then the keychain item is not present. So this is a difference in behavior between restoring the same backup to device A then to device B, after resetting both devices shouldn't the behavior be identical? But its not? – Gruntcakes Oct 11 '17 at 17:00
  • @Sausage_dioxide As explained in the [iOS Security Guide](https://www.apple.com/business/docs/iOS_Security_Guide.pdf) (p. 17) Keychain entries in iCloud backups are handled like unencrypted iTunes backups: "[N]on-migratory Keychain items [are] inaccessible on a different device." As you said, the `kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly` counterpart makes entries non-migatory. Therefore you should be able to access the entry. I see nothing obviously wrong with the code. Are you using the same `kKeychainIdentifier`? – Max Oct 13 '17 at 11:25
  • @Max, Hi, yes the kKeychainIdentifier is the same in both createKey and getKey (otherwise getKey wouldn't be able to retrieve the item from the keychain when running on a restoration to the same device, which it can. Its only when restored to a different device that it doesn't work). – Gruntcakes Oct 15 '17 at 19:48
  • 1
    Did you solve this? We observe similiar behaviour - on some of our devices keychain is restored, on others no. – Petr Nov 08 '17 at 07:38
  • No I didn’t. I haven’t tried with 11.1 or 11.2 to see if it is still present – Gruntcakes Nov 08 '17 at 14:35
  • Petr, I'm having the exact same problem. A user of my app could transfer the credentials from an SE to the X. But when he switched from an X to a new X, the credentials were lost. I'm looking to store it on iCloud keychain and see if it will work. Did you solve the problem? – Henry Ngan Jan 26 '18 at 02:24

0 Answers0