Binding Keychain Items to Passcode and Touch ID - Security - iOS 9 Swift Programming Cookbook (2015)

iOS 9 Swift Programming Cookbook (2015)

Chapter 11. Security

11.2 Binding Keychain Items to Passcode and Touch ID

Problem

You want to create a secure item in the keychain that is accessible only if the user has set a passcode on her device and has enrolled into using the device with Touch ID. So at least one finger has to have been registered.

Solution

Follow these steps:

1. Create your access control flags with the SecAccessControlCreateWithFlags function. Pass the value of kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly as the protection parameter and the value of SecAccessControlCreateFlags.TouchIDAny as theflags parameter.

2. In your secure dictionary, add a key named kSecUseAuthenticationUI and set its value to kSecUseAuthenticationUIAllow. This allows the user to unlock the secure key with her device passcode or Touch ID.

3. In your secure dictionary, add a key named kSecAttrAccessControl and set its value to the return value of the SecAccessControlCreateWithFlags function that you called earlier.

Discussion

For extra security, you might want to sometimes bind secure items in the keychain to Touch ID and a passcode on a device. As explained before, you’d have to first create your access control flags with the SecAccessControlCreateWithFlags function and then proceed to use theSecItemAdd function as you normally would, to add the secure item to the keychain.

The following example saves a string (as a password) into the keychain, and binds it to the user’s passcode and Touch ID. First, start off by creating the access control flags:

guard let flags =

SecAccessControlCreateWithFlags(kCFAllocatorDefault,

kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly,

SecAccessControlCreateFlags.TouchIDAny, nil) else{

print("Could not create the access control flags")

return

}

Then define the data that you want to store in the keychain:

let password = "some string"

guard let data = password.dataUsingEncoding(NSUTF8StringEncoding) else{

print("Could not get data from string")

return

}

The next step is to create the dictionary that you need to pass to the SecItemAdd function later with all your flags:

let service = "onlinePasswords"

let attrs = [

kSecClass.str() : kSecClassGenericPassword.str(),

kSecAttrService.str() : service,

kSecValueData.str() : data,

kSecUseAuthenticationUI.str() : kSecUseAuthenticationUIAllow.str(),

kSecAttrAccessControl.str() : flags,

]

Last but not least, asynchronously add the item to the keychain:

NSOperationQueue().addOperationWithBlock{

guard SecItemAdd(attrs, nil) == errSecSuccess else{

print("Could not add the item to the keychain")

return

}

print("Successfully added the item to keychain")

}

Earlier, we used the value of SecAccessControlCreateFlags.TouchIDAny in the flags parameter of the SecAccessControlCreateWithFlags function to specify that we need Touch ID to be enabled on the current device before our secure item can be read. There is another value in SecAccessControlCreateFlags that you might find useful: TouchIDCurrentSet. If you use this value, your secure item will still require Touch ID, but it will be invalidated by a change to the current set of enrolled Touch ID fingers. If the user adds a new finger to Touch ID or removes an existing one, your item will be invalidated and won’t be readale.

See Also