I have an iOS app that stores an access token in the Keychain. In the last few months, I've noticed that around 2% of the users get an errSecItemNotFound when trying to retrieve the token.
All the relevant StackOverflow threads point to background tasks being the culprit (iOS KeyChain not retrieving values from background) or including invalid params in the query string (Keychain: Item reported as errSecItemNotFound, but receive errSecDuplicateItem on addition).
I'm using kSecAttrAccessibleAfterFirstUnlock so background tasks should be able to access the Keychain just fine.
Moreover, the search query looks like this:
NSMutableDictionary *query = [[NSMutableDictionary alloc] init];
[query setObject:(__bridge id)kSecClassGenericPassword forKey:(__bridge id)kSecClass];
[query setObject:(__bridge id)kCFBooleanTrue forKey:(__bridge id)kSecReturnData];
[query setObject:(__bridge id)kSecMatchLimitOne forKey:(__bridge id)kSecMatchLimit];
[query setObject:service forKey:(__bridge id)kSecAttrService];
[query setObject:key forKey:(__bridge id)kSecAttrGeneric];
[query setObject:key forKey:(__bridge id)kSecAttrAccount];
(Setting kSecAttrGeneric is probably redundant, but it does not affect the outcome of the query anyway)
For the record, I've experienced this bug with both SSKeyChain and UICKeychainStore.
Any hints would be highly appreciated :]
I was using KDJKeychainItemWrapper and had similar issues. In the end I replaced its use of kSecAttrGeneric to use kSecAttrService. This fixed all my issues of not finding entries and duplicates due to service not being defined.
I believe that the primary keys for kSecClassGenericPassword are just kSecAttrAccount and kSecAttrService.
If you move to not using kSecAttrGeneric it should sort itself out with perhaps the user having to put their password in again.
Also pick a service name which will not clash with anything else.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With