I could never get kSecMatchEmailAddressIfPresent
to work properly but found an alternative solution.
There are attributes that can be set when storing items in the keychain. Therefore when I am storing a certificate, I set kSecAttrLabel
to the email address.
NSMutableDictionary *query = [[NSMutableDictionary alloc] init];
[query setValue:(__bridge id)kCFBooleanTrue forKey:(__bridge id)kSecReturnPersistentRef];
[query setValue:(__bridge id)item forKey:(__bridge id)kSecValueRef];
[query setValue:(id)emailAddress forKey:(__bridge id)kSecAttrLabel];
NSData *returnData = nil;
status = SecItemAdd((__bridge CFDictionaryRef)query, (void *)&returnData);
Then when looking up the certificate, I would include the kSecAttrLabel
as a search parameter.
NSMutableDictionary *query = [[NSMutableDictionary alloc] init];
[query setValue:(__bridge id)kSecMatchLimitAll forKey:(__bridge id)kSecMatchLimit];
[query setValue:(__bridge id)kCFBooleanTrue forKey:(__bridge id)kSecReturnPersistentRef];
[query setValue:(__bridge id)classType forKey:(__bridge id)kSecClass];
[query setValue:(id)emailAddress forKey:(__bridge id)kSecAttrLabel];
CFArrayRef result = nil;
status = SecItemCopyMatching((__bridge CFDictionaryRef)(query), (CFTypeRef *)&result);
This works for me because I already know the email address that the certificate is tied to before hand. However if you didn't know the email before hand, you might be able to extract it from kSecPolicyName (Security Policy Keys) or with openssl.