The Story So Far
Four months ago, I posted this question because the upgrade to iOS 13 was breaking my keychain-related code.
My code stores the user's password in the keychain using class kSecClassGenericPassword
and access attribute kSecAttrAccessibleWhenUnlocked
. As explained in my own answer to that question, I finally got my code to work also on iOS 13 by cleaning up the query dictionaries a bit.
The Current Problem
A few weeks ago, I was asked to disable backing up of the password data to enhance security, so I changed the access attribute to kSecAttrAccessibleWhenUnlockedThisDeviceOnly
(unlike kSecAttrAccessibleWhenUnlocked
, the password in the keychain is not transferred to another device during backups).
Now, my code fails and the user has to enter their password every time. (tested on iOS 13.0, iPhone 8 Plus)
When the user logs in using their password, my code first deletes any previously stored password using SecItemDelete()
, and then proceeds to store the entered password using SecItemMatch()
.
Since changing the access attribute to kSecAttrAccessibleWhenUnlockedThisDeviceOnly
, SecItemDelete()
"succeeds" with errSecItemNotFound
(i.e., "Nothing to delete"), but SecItemAdd()
fails with errSecDuplicateItem
!
Note, this isn't an issue of trying to retrieve a password previously stored with kSecAttrAccessibleWhenUnlocked
using kSecAttrAccessibleWhenUnlockedThisDeviceOnly
(i.e., different query dictionaries for store and load); I deleted the app from the device and tried from the start with the new code, and SecItemAdd()
always fails.
What's Going On?