Understanding Keychain Errors in Mobile Banking App

Hi,

We use the iOS Keychain in our mobile app to securely store and retrieve data, which is tightly coupled with the initialization of some app features within the application.

  • This issue is encountered during app launch
  • We retrieve during Splash Screen UI controller at viewDidApper()

The logic we use to access the Keychain is as follows:

NSDate *NSDate_CD;
NSString *account = [NSString stringWithUTF8String:@"SOME_KEY_ACCOUNT"];
NSString *attrgen = [NSString stringWithUTF8String:@"SOME_KEY"];

NSMutableDictionary *query = [[NSMutableDictionary alloc] init];
[query setObject:(__bridge id)(kSecClassGenericPassword) forKey:(__bridge id<NSCopying>)(kSecClass)];

[query setObject:attrgen forKey:(__bridge id<NSCopying>)(kSecAttrGeneric)];

[query setObject:(__bridge id)(kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly) forKey:(__bridge id<NSCopying>)(kSecAttrAccessible)];

[query setObject: [NSBundle mainBundle].bundleIdentifier forKey:(__bridge id<NSCopying>)(kSecAttrService)];

[query setObject:account forKey:(__bridge id<NSCopying>)(kSecAttrAccount)];

[query setObject:@YES forKey:(__bridge id<NSCopying>)(kSecReturnAttributes)];

[query setObject:@YES forKey:(__bridge id<NSCopying>)(kSecReturnData)];

CFDictionaryRef valueAttributes = NULL;

OSStatus status = SecItemCopyMatching((__bridge CFDictionaryRef)query, (CFTypeRef *)&valueAttributes);

NSDictionary *attributes = (__bridge_transfer NSDictionary *)valueAttributes;

if(status==errSecSuccess) {
    NSDate_CD = [attributes objectForKey:(__bridge id)kSecAttrCreationDate];
} else {
    NSLog(@"Key chain query failed");
}

However, some users have reported intermittent failures during app launch. Upon investigation, we discovered that these failures are caused by exceptions thrown by the iOS Keychain, which the app is currently not handling. Unfortunately, we do not log the exception or the Keychain error code in the app logs at the moment, but we plan to implement this logging feature in the near future. For now, we are trying to better understand the nature of these errors.

Could you help clarify the following Keychain errors, which might be encountered from the code above?

  1. errSecServiceNotAvailable (-25307)
  2. errSecAllocate (-108)
  3. errSecNotAvailable (-25291)

If these errors are encountered, are they typically persistent or are they temporary states that could resolve on their own?

Your insights would be greatly appreciated. Thank you.

Answered by DTS Engineer in 821972022

Debugging keychain problems coming in from the field is tricky. For my general advice on that topic, see Investigating hard-to-reproduce keychain problems.

The logic we use to access the Keychain is as follows:

Your use of kSecAttrGeneric is a concern. That attribute doesn’t contribute to the item’s uniqueness, and thus it’s rarely useful, and sometimes very confusing, to include it in a query dictionary. I talked about this in the Uniqueness section of SecItem: Fundamentals. I recommend that you read that and its companion post, SecItem: Pitfalls and Best Practices.

Could you help clarify the following Keychain errors, which might be encountered from the code above?

Not really. The issue here is that the keychain has a long history, which means that the errors you get back don’t always make a lot of sense. For an example of that, errSecAllocate is the keychain equivalent of memFullErr, an error code that dates to the original Mac in 1984! And due to the limited set of error codes available, these errors can be repurposed as the keychain implementation evolves. For example, the data protection keychain implementation [1] is currently based on SQLite and it remaps many SQLite errors to errSecNotAvailable [2].

Share and Enjoy

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

[1] Which is the only keychain implementation on iOS. On macOS the situation is even more complex. See TN3137 On Mac keychain APIs and implementations if you dare! (-:

[2] Much of the Security framework is available in Darwin, so you can actually see this remapping in the source code.

Debugging keychain problems coming in from the field is tricky. For my general advice on that topic, see Investigating hard-to-reproduce keychain problems.

The logic we use to access the Keychain is as follows:

Your use of kSecAttrGeneric is a concern. That attribute doesn’t contribute to the item’s uniqueness, and thus it’s rarely useful, and sometimes very confusing, to include it in a query dictionary. I talked about this in the Uniqueness section of SecItem: Fundamentals. I recommend that you read that and its companion post, SecItem: Pitfalls and Best Practices.

Could you help clarify the following Keychain errors, which might be encountered from the code above?

Not really. The issue here is that the keychain has a long history, which means that the errors you get back don’t always make a lot of sense. For an example of that, errSecAllocate is the keychain equivalent of memFullErr, an error code that dates to the original Mac in 1984! And due to the limited set of error codes available, these errors can be repurposed as the keychain implementation evolves. For example, the data protection keychain implementation [1] is currently based on SQLite and it remaps many SQLite errors to errSecNotAvailable [2].

Share and Enjoy

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

[1] Which is the only keychain implementation on iOS. On macOS the situation is even more complex. See TN3137 On Mac keychain APIs and implementations if you dare! (-:

[2] Much of the Security framework is available in Darwin, so you can actually see this remapping in the source code.

Understanding Keychain Errors in Mobile Banking App
 
 
Q