I'm trying to find a specific entry in my Mac OS X keychain, based on it's name (kSecAttrLabel), but it looks like SecItemCopyMatching is broken and applies no filtering whatsoever when looking for items of type: kSecClassIdentity.
This piece of code will return all identities found in all keychains, despite the kSecAttrLabel: @"MyIdentity" parameter:
NSDictionary *query = @{ (__bridge id)kSecClass: (__bridge NSString*)kSecClassIdentity,
(__bridge id)kSecAttrLabel: @"MyIdentity",
(__bridge id)kSecMatchLimit: (__bridge id)kSecMatchLimitAll,
(__bridge id)kSecReturnAttributes: @YES,
(__bridge id)kSecReturnRef: @YES };
OSStatus status;
status = SecItemCopyMatching((__bridge CFDictionaryRef)query, (CFTypeRef *)&privateKey);
Granted, I can then find the one identity I'm looking for by filtering manually the returned array, however, beside the fact that, IMHO, it should just work, I also would like to remove this identity from my keychain using SecItemDelete(), which takes a query as parameter, just like SecItemCopyMatching.
If filtering doesn't work for SecItemCopyMatching, then it is likely that it won't work for SecItemDelete and this mean I will simply erase the content of my keychain if I try to call SecItemDelete with this query.
What am I doing wrong?
I think I have just found a solution. It was suggested on on another forum that
Using labels on an identity is tricky because identities are not stored in the keychain as an atomic item but are store as a separate private key and certificate, and those items use labels in different ways.
This made me realise that a solution is to search for a certificate by label using SecItemCopyMatching, and then create the identity using SecIdentityCreateWithCertificate. The latter call should find the matching private key in the Keychain. Here is the full code (in C++) that seems to work for me on macOS Mojave:
SecIdentityRef identity = nullptr;
const char* certificateName = ...;
const void* keys[] = {
kSecClass,
kSecMatchLimit,
kSecReturnRef,
kSecAttrLabel
};
const void* values[] = {
kSecClassCertificate,
kSecMatchLimitOne,
kCFBooleanTrue,
CFStringCreateWithCString(nullptr, certificateName, kCFStringEncodingUTF8)
};
CFDictionaryRef query = CFDictionaryCreate(nullptr, keys, values, 4, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
CFTypeRef result;
OSStatus status = SecItemCopyMatching(query, &result);
CFRelease(query);
CFRelease(values[3]);
if (status) {
// error
}
else {
SecCertificateRef certificate = (SecCertificateRef)result;
status = SecIdentityCreateWithCertificate(nullptr, certificate, &identity);
CFRelease(certificate);
if (status) {
// error
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With