Can’t access keychain despite “AccessibleAfterFirstUnlock”: -25308

Hello!

Hoping to get some new insight on this issue, which I’ll try to explain as simply as possible.

Issue Summary

  1. We are seeing a crash in production while trying to retrieve data from the keychain
  2. Error is -25308 (errSecInteractionNotAllowed)
  3. It seems to happen when the phone is in the background / locked state
  4. We use the kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly attribute on the data
  5. 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.

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.

This is a common pitfall. See the Queries and the Uniqueness Constraints section of my SecItem Pitfalls and Best Practices post.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

Hi Quinn,

Thanks so much for pointing me to the post, excited to check it out!

Just to clarify, the -25300 and -25299 combo only happened in a subset of cases and potentially as a result of a change we have since reverted. I'm curious if you have any additional thoughts on what has been the primary error, -25308, unless you think that is also covered in the post.

Well I think one might be the cause of the other. If you failed to find the item because of a kSecAttrAccessible mismatch, that suggests that someone, at some time, wrote an item with the wrong value for kSecAttrAccessible, which would explain why you’re getting errSecInteractionNotAllowed.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

Can’t access keychain despite “AccessibleAfterFirstUnlock”: -25308
 
 
Q