Hello!
Hoping to get some new insight on this issue, which I’ll try to explain as simply as possible.
Issue Summary
- We are seeing a crash in production while trying to retrieve data from the keychain
- Error is
-25308 (errSecInteractionNotAllowed) - It seems to happen when the phone is in the background / locked state
- We use the
kSecAttrAccessibleAfterFirstUnlockThisDeviceOnlyattribute on the data - Have not been able to reproduce it locally
Platform: iOS Version: 14-16
Code Snippets
Retrieving the data
NSMutableDictionary *searchDict = GenericKeychainDictionary();
[searchDict setObject:(__bridge id)kSecMatchLimitOne forKey:(__bridge id)kSecMatchLimit];
[searchDict setObject:(__bridge id)kCFBooleanTrue forKey:(__bridge id)kSecReturnData];
// This next line was previously missing, but was added in an attempt to solve the issue
[searchDict setObject:(__bridge id)kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly forKey:(__bridge id)kSecAttrAccessible];
CFDataRef data = nil;
OSStatus status = SecItemCopyMatching((__bridge CFDictionaryRef)searchDict, (CFTypeRef *)&data);
if (status != errSecSuccess) {
...
Adding the data if we can't retrieve it
NSMutableDictionary *creationAttributes = GenericKeychainDictionary();
NSData *myData = [NSData dataWithBytes:generatedContent
length:sizeof(generatedContent)-1];
creationAttributes[(__bridge id)kSecValueData] = myData;
creationAttributes[(__bridge id)kSecAttrAccessible] = (__bridge id)kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly;
OSStatus status = errSecNotInitialized;
status = SecItemAdd((__bridge CFDictionaryRef)creationAttributes, NULL);
if (status != errSecSuccess) {
...
And just for good measure, here is the definition of GenericKeychainDictionary
NSMutableDictionary *GenericKeychainDictionary()
{
NSMutableDictionary *searchDict = [NSMutableDictionary dictionary];
[searchDict setObject:(__bridge id)kSecClassGenericPassword forKey:(__bridge id)kSecClass];
[searchDict setObject:[@"app.base" dataUsingEncoding:NSUTF8StringEncoding] forKey:(__bridge id)kSecAttrService];
[searchDict setObject:[@"my.info" dataUsingEncoding:NSUTF8StringEncoding] forKey:(__bridge id)kSecAttrAccount];
return searchDict;
}
Additional Notes
I have looked at these previous posts and believe I am following the guidance therein https://developer.apple.com/forums/thread/78372 https://developer.apple.com/forums/thread/114159
And have found another individual with very similar behavior on Stack Overflow that seemingly went unresolved
https://stackoverflow.com/questions/48068325/keychain-access-error-25308-errsecinteractionnotallowed
Additionally, after adding some more logging we found that in some cases we got -25300 (errSecItemNotFound) when trying to retrieve the data, but fail to add it because of -2599 (errSecDuplicateItem) which is odd.
But it’s not yet determined if this behavior is somehow related to the changes that accompanied the logging or not.
Found a similar post:
https://developer.apple.com/forums/thread/77074
But still no luck.