Small percentage of users getting errSecItemNotFound when retrieving data from the Keychain
Asked Answered
E

1

7

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 :]

Earleanearleen answered 20/1, 2015 at 16:3 Comment(1)
hi!! i'm having exacly the same issue... Does UICKeyChainStore lib solved this? Thanks!!Electrocorticogram
P
5

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.

Plerre answered 2/2, 2015 at 12:39 Comment(5)
Note that I'm already using kSecAttrService as well (kSecAttrService + kSecAttrAccount + kSecAttrGeneric). Shouldn't the additional (and redundant) kSecAttrGeneric attribute be ignored?Earleanearleen
The key seems to be that account and service must be unique as a pair. If not then you run the danger of them being overwritten or removed somewhere else. I tracked down where I saw this originally: useyourloaf.com/blog/2010/04/28/…Plerre
You are right however in that given you are using all 3 and you are setting AttrGeneric to the same value as AttrAccount it should work even if AttrGeneric is ignored. Given your error seems to be not found, it might imply the entry has been changed somewhere else. Is your value for AttrService key a nice unique value? Any way it could be getting set to @"" say or corrupted when updated which would then result in a fail next time its queried?Plerre
UICKeyChainStore just got updated with a major lib rewrite. It no longer uses kSecAttrGeneric, so I'll start testing right away. I'll accept your answer, though, since everything points to it being the correct one. Thanks!Earleanearleen
@Earleanearleen Did you have time to test and did the latest version of UICKeyChainStore fixed the issue? Thanks in advance ;)Friar

© 2022 - 2024 — McMap. All rights reserved.