When I add a password to the keychain as follows:
attempts to access via SecItemCopyMatching as below work fine. The user is prompted to enter device PIN and errSecSuccess is returned.
When I add an identity using this similar code:
attempts to access via SecItemCopyMatching as below fails. The user is prompted to enter device PIN and errSecItemNotFound is returned.
When I replace the kSecAttrAccessControl item in the dictionary passed SecItemAdd with the below, I can access the identity with no issue.
What's the trick for adding identities with user presence required for access?
Code Block SecAccessControlRef sacObject = SecAccessControlCreateWithFlags(kCFAllocatorDefault, kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly, kSecAccessControlUserPresence, &error); NSDictionary *attributes = @{ (bridge id)kSecClass: (bridge id)kSecClassGenericPassword, (bridge id)kSecValueData: [@"password" dataUsingEncoding:NSUTF8StringEncoding], (bridge id)kSecAttrLabel: @"passwordWithACL", (bridge id)kSecUseNoAuthenticationUI: @YES, (bridge id)kSecAttrAccessControl: (bridge_transfer id)sacObject }; OSStatus status = SecItemAdd((bridge CFDictionaryRef)attributes, nil);
attempts to access via SecItemCopyMatching as below work fine. The user is prompted to enter device PIN and errSecSuccess is returned.
Code Block NSDictionary *attributes2 = @{ (bridge id)kSecClass: (bridge id)kSecClassGenericPassword, (bridge id)kSecReturnData: @YES, (bridge id)kSecUseOperationPrompt: @"Authenticate", (bridge id)kSecAttrLabel: @"passwordWithACL", }; CFTypeRef dataTypeRef = NULL; OSStatus status = SecItemCopyMatching((bridge CFDictionaryRef)(attributes2), &dataTypeRef);
When I add an identity using this similar code:
Code Block SecAccessControlRef access = SecAccessControlCreateWithFlags(kCFAllocatorDefault, kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly, kSecAccessControlUserPresence, nil); NSMutableDictionary* dict = [[NSMutableDictionary alloc]init]; [dict setObject:(id)kCFBooleanTrue forKey:(id)kSecReturnPersistentRef]; [dict setObject:(bridge id)identity forKey:(id)kSecValueRef]; [dict setObject:@"identityWithACL" forKey:(id)kSecAttrLabel]; [dict setObject:(bridge id)access forKey:(id)kSecAttrAccessControl]; CFTypeRef persistent_ref; OSStatus status = SecItemAdd((CFDictionaryRef)dict, &persistent_ref);
attempts to access via SecItemCopyMatching as below fails. The user is prompted to enter device PIN and errSecItemNotFound is returned.
Code Block NSMutableDictionary * query = [[NSMutableDictionary alloc] init]; [query setObject:(id)kSecClassIdentity forKey:(id)kSecClass]; [query setObject:(id)kCFBooleanTrue forKey:(id)kSecReturnRef]; [query setObject:(id)kCFBooleanTrue forKey:(id)kSecReturnData]; [query setObject:@"Authenticate to access identity" forKey:(id)kSecUseOperationPrompt]; [query setObject:@"identityWithACL" forKey:(id)kSecAttrLabel]; CFTypeRef items = nil; OSStatus status = SecItemCopyMatching((CFDictionaryRef)query, (CFTypeRef *)&items);
When I replace the kSecAttrAccessControl item in the dictionary passed SecItemAdd with the below, I can access the identity with no issue.
Code Block [dict setObject:(id)kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly forKey:(id)kSecAttrAccessible];
What's the trick for adding identities with user presence required for access?
I suspect that the issue here is that identities aren’t stored in the keychain as a real item but rather the private key and certificate are stored separately. If you get the private key and the certificate from the identity (using SecIdentityCopyPrivateKey and SecIdentityCopyCertificate) and then add them separately, specifying the access control object when you add the key, does that work?
Share and Enjoy
—
Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@apple.com"
Share and Enjoy
—
Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@apple.com"