iCloud keychain backup/restore behaving differently on iOS 11?
Asked Answered
M

0

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: https://mcmap.net/q/698615/-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
    }
Mellon answered 5/10, 2017 at 2:36 Comment(7)
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 which you should set to kCFBooleanTrue if you want to enable iCloud synching. But I'm not sure if I understood your Question correctly.Tibbetts
@Tibbetts 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?Mellon
@Sausage_dioxide As explained in the iOS Security Guide (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?Tibbetts
@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).Mellon
Did you solve this? We observe similiar behaviour - on some of our devices keychain is restored, on others no.Inlaid
No I didn’t. I haven’t tried with 11.1 or 11.2 to see if it is still presentMellon
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?Dialyze

© 2022 - 2024 — McMap. All rights reserved.