iOS Keychain randomly returning -25300

I am facing a strange issue in my app. My code saves a string password in the iOS keychain to be accessed later on. It works just fine most of the times and I am able to fetch the password back after reinstallation or device restart or both.

Problem: Sometimes which is actually rare and hard to reproduce, it does NOT return the password and instead it returns null and error status:-25300(errSecItemNotFound). Another thing is that this problem got prominent after iOS 9 update. Happening on iOS 9.1 too.


Code for setting:


NSMutableDictionary *query = [self _queryForService:service account:account]; 
[query setObject:password forKey:(__bridge id)kSecValueData]; 
status = SecItemAdd((__bridge CFDictionaryRef)query, NULL);

if (status != errSecSuccess && error != NULL) { 
*error = [NSError errorWithDomain:kAppKeychainErrorDomain code:status userInfo:nil]; } 
return (status == noErr);


Code for fetching:


CFTypeRef result = NULL; 
NSMutableDictionary *query = [self _queryForService:service account:account]; 
[query setObject:(__bridge id)kCFBooleanTrue forKey:(__bridge id)kSecReturnData]; 
[query setObject:(__bridge id)kSecMatchLimitOne forKey:(__bridge id)kSecMatchLimit]; 
status = SecItemCopyMatching((__bridge CFDictionaryRef)query, &result);

if (status != errSecSuccess && error != NULL) { 
*error = [NSError errorWithDomain:kAppKeychainErrorDomain code:status userInfo:nil]; 
return nil; 
} 
return (__bridge_transfer NSData *)result;


Has anyone got any ideas why this is happening? Many thanks.

Post not yet marked as solved Up vote post of captalvins Down vote post of captalvins
25k views

Replies

Most problems like this are related to folks getting confused by the difference between the dictionary you use to run a keychain query versus the dictionary you use to add keychain items. In your case it’s hard to say what’s going on because you elided

-_queryForService:account:
, which is the most critical part of your code (-:

Share and Enjoy

Quinn "The Eskimo!"
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"

Thanks for your reply.

I get your point and here are the final queries for both the cases:


Final dict for setting:

{ acct = user; 
class = genp; 
svce = "myBundleIdentifier"; 
"v_Data" = <36314541 38463339 2d363737 462d3445 34372d42 4339452d 31324633 46463937 35374546>;}


Final query dict for fetching:

{ acct = user; 
class = genp; 
"m_Limit" = "m_LimitOne"; 
"r_Data" = 1; 
svce = "myBundleIdentifier";}


I hope that can help you suggest further.

Those look fine.

Can you elaborate on “rare and hard to reproduce”? Are you seeing this during development? Or getting reports from users in the field? If it’s the latter, do the users experiencing the problem have anything in common? And, once a user sees the problem, are they more likely to see it again?

Share and Enjoy

Quinn "The Eskimo!"
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"

Thanks for the reply.

Can you elaborate on “rare and hard to reproduce”?

>We have around 2.86mn devices using it and out of those there are around 8000 devices affected.

Are you seeing this during development?

>Yes. However during development, this has been only happened 4-5 times in 3 months (4 devices monitored).

Or getting reports from users in the field?

>Yes, answer to #1 is the number of users in the field.

If it’s the latter, do the users experiencing the problem have anything in common?

>Not any we can narrow down to. However, this issue is definitly more prominent in iOS 9.0 and above.

And, once a user sees the problem, are they more likely to see it again?

>I would say yes. Atleast that seems to be the pattern, as it is the same users that have been affected multiple times in many cases.

Just to add, the main scenario that this happens is when we uninstall and install the app again. At that time, the application tries to query the keychain and resulting in the error.

Yeah, problems like this are hard to track down. There’s basically two possibilities:

  • The keychain is actually functioning properly but the keychain items are configured in a totally unexpected way causing your code to fail (A).

  • The keychain is not functioning properly (B)>

To distinguish between these I recommend that you add a ‘keychain dump’ feature to your app, that dumps all the keychain items you have access to. A user can then send you the dump and you can look to see if there’s anything that might be causing problem A.

Once you rule that out, and you’ve concluded this is problem B, a keychain dump would be a useful attachment for the bug report you file.

IMPORTANT It should go without saying that the dump shouldn’t include any user secrets.

Share and Enjoy

Quinn "The Eskimo!"
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"

Thanks for the reply Quinn,


I will do that and update you. Keep an eye on this thread!

Hi Quinn,


I have been trying to dump Keychain contents but all the tools and ways I have stumbled upon and tried a few(searching over the internet) seems to require a jailbroken device or seems to be only doable on a simultor. Neither of these scenarios is an actual and generic scneraio for us.

Can you guide me on how can I do it on a real non-jailbroken iPhone?


Thanks.

You can’t dump the keychain with a tool; you will have to write code to do this. The Credentials class in the AdvancedURLConnections sample code shows what I’m talking about (although it’s probably best not to copy the code verbatim because it’s old and crufty).

Share and Enjoy

Quinn "The Eskimo!"
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"

Hi Quinn,


Happy New Year!


I have the keychain dumps from 4 different devices(below), they look fine to me.

If you can quickly scan them? If all looks normal to you too, I will file the bug.


Device 1:

identities:

certificates:

keys:

Internet:

generic:

0

description = ''

label = ''

account = ''

service = ''

generic = 'WLUUID'

1

account = 'user'

service = 'co.comp.samplevm.v4'

URL credential storage:

------------------------------------------------------

Device 2:

identities:

certificates:

keys:

Internet:

generic:

0

account = 'user'

service = 'co.comp.samplevm.v4'

URL credential storage:

------------------------------------------------------

Device 3:

identities:

certificates:

keys:

Internet:

generic:

0

account = 'user'

service = 'co.comp.samplevm.v4'

URL credential storage:

----------------------------------------------------

Device 4:

identities:

certificates:

keys:

Internet:

generic:

0

account = 'user'

service = 'co.comp.samplevm.v4'

URL credential storage:

--------------------------------------------------


Thanks.

I am seeing the same issue with our application. I've only been able to test it on 64 bit devices at the moment, but here are some things to note:

- Keychain sharing is on. We share our keychain with one additional group, the group is second in the list

- relevant data is stored as kSecClassGenericPassword

Using the "keychain dump" routine as mentioned above, there are two entries at '..didFinishLaunching...'

generic:

0

label = 'mobilecare'

account = 'password'

service = 'mobilecare'

1

label = 'mobilecare'

account = 'keyVersion4'

service = 'mobilecare'

While the app is running, dumping shows 3 (Notice that the "keyVersion4" item is now missing, but is was there earlier)

generic:

0

label = 'mobilecare'

account = 'mrn'

service = 'mobilecare'

1

label = 'mobilecare'

account = 'userName'

service = 'mobilecare'

2

label = 'mobilecare'

account = 'password'

service = 'mobilecare'

But when it is re-run again we are back to only the two items above ("keyVersion4" has reappeared, but "mrn" and "userName" are gone).

Hi,


Coupld you try the test I did and add an item to the keychain to see if the values are there the next time the app is run?

I have now replicated this problem on a 1st gen iPad Mini (32 bit device).


It also appears that the inclusion of the the "LocalAuthenticaion.framework" has a roll in creating this defect. We did not have this issue in our previuos version which did not include TouchID. However, this bug shows up regarless of whether the user activates Touch ID for the app or not.

We've been able to isolate our occurance of this issue to a 3rd party libary, so our app does not have this particular issue.

Thanks fo the updates!

If you can please share the name of the 3rd party Library? Also, how did you isolate the issue from your app and the culprit library?

Hi - unfortunately due to agreements I can not disclose it. Also the 3rd party is still attempting to replicate, so technically I could still be wrong (I doubt it).


To make a long story short on how I was able to Isolate it, we had a release where this rarely happenned, followed by a release where this always happened. I played the "what's changed" game and discovered that a library upgrade from a 3rd party provider triggered the issue. I could swap the libraries in and out from old to new and thew new did it all the time; back to the old, no bug; re-install new, bug. etc. No other code/settings/etc. Just that library.


I might add that "Keychain Sharing" could be a culprit in this. Would love to hear from Apple on this. Or if 9.2.1 has any effect on this issue. In general I'm highly befudddled by this bug.