Keychain returns errSecNotAvailable when using access control

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?
Keychain returns errSecNotAvailable when using access control
 
 
Q