1

SecItemCopyMatching returns errSecNotAvailable when trying to read a kSecClassIdentity Keychain item on a physical device (iPhone 6S) when the item is saved with kSecAccessControlUserPresence.

When I run the code, the device asks me to authenticate using TouchID. I use my finger and the prompt goes away, but then it takes a relatively long time for SecItemCopyMatching to return, and when it does, it gives errSecNotAvailable.

This is weird, because TouchID works when I use LocalAuthentication (without using Keychain). Retrieving the certificate also works if I save it without the access control attribute. But I want to use kSecAccessControlUserPresence. Any idea why I get the error?

Adding certificate:

- (BOOL)keychainAddIdentity:(SecIdentityRef)identity withLabel:(NSString *)label {
    CFErrorRef error = NULL;
    SecAccessControlRef sacObject = SecAccessControlCreateWithFlags(kCFAllocatorDefault, kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly, kSecAccessControlUserPresence, &error);
    NSLog(@"SecAccessControlCreateWithFlags error: %@", error); // always null
    NSDictionary *attributes = @{
        (id)kSecAttrLabel: label,
        (id)kSecValueRef: (__bridge id)identity,
        (id)kSecAttrAccessControl: (__bridge id)sacObject
    };
    OSStatus status = SecItemAdd((CFDictionaryRef)attributes, NULL);
    [self printOSStatus:status]; // errSecSuccess
    return status == errSecSuccess;
}

Reading certificate:

- (SecIdentityRef)keychainGetIdentityWithLabel:(NSString *)label userPromptMessage:(NSString *)message {
    NSDictionary *query = @{
        (id)kSecClass: (id)kSecClassIdentity,
        (id)kSecAttrLabel: label,
        (id)kSecReturnRef: @YES,
        (id)kSecUseOperationPrompt: message
    };
    SecIdentityRef identity = NULL;
    OSStatus status = SecItemCopyMatching((CFDictionaryRef)query, (CFTypeRef *)&identity);
    [self printOSStatus:status]; // errSecNotAvailable
    return identity;
}

Test code:

SecIdentityRef identity = [... load certificate file ...];
BOOL certSaved = [self saveCertificate:identity]; // YES
SecIdentityRef cert = [self loadCertificate]; // (null)

So when adding the certificate without sacObject, everything works fine, but with it, I get errSecNotAvailable. Why?

Alex
  • 1,574
  • 17
  • 36

2 Answers2

0

It appears that you're missing the key/value for kSecClass: kSecClassIdentity attribute when saving the identity to the keychain. Without specifying the class on the way in I don't think there's any way to read it later.

0

To my background, keychain data should be able to use the keychain after 200ms after launch of the app. So, when you want to reach this data? Do you have enough time to fetch this data.

Also keychain data can tie to your TouchID or faceID. But, maybe iphone6s's sensor is not good(we had one formerly, It'd not been working perfectly). To be ensure, you should try to reach this data with normal login.

And I'm sure, apple do not update keychain data documentation when It's changed. I met some scenario related to keychain, and sometimes apple documents has wrong info. (for example wrong keychain info in Apple document)

As a result, your job is not easy, please try above suggestions. If it doesn't work try another way to accomplish your requirements.

Emre Gürses
  • 1,992
  • 1
  • 23
  • 28