Well, the answer to this is a bit tricky.... Apparently, there is an Apple known bug about this thing, with no known workaround (this is taken from Apple's DTS response).
The private key CAN be deleted if there's an ACL restricting access to it and allowing one and ONLY one application to access the key. So, Theoretically, it is possible to change the access object and restrict the ACL lists and then deleting it.
But.... Unfortunately, Trying to manipulate the identity's access object to have the same ACLs as when you change it manually by Keychain Access doesn't behave as nicely...
If you do manage to restrict by any chance then the rest is easy enough:
So here is a code snippet just in case anyone finds it useful:
OSStatus status = errSecSuccess;
CFTypeRef identityRef = NULL;
CFStringRef certLabel = NULL;
const char *certLabelString = "Some string identifying your certificate";
certLabel = CFStringCreateWithCString(NULL, certLabelString, kCFStringEncodingUTF8);
const void *keys[] = { kSecClass, kSecAttrLabel, kSecReturnRef };
const void *values[] = { kSecClassIdentity, certLabel, kCFBooleanTrue };
CFDictionaryRef query = CFDictionaryCreate(NULL, keys, values, 3, NULL, NULL);
// First we extract the identity out of the keychain
status = SecItemCopyMatching(query, &identityRef);
if (status != errSecSuccess)
{
s_log(SecCopyErrorMessageString(status, NULL));
CFRelease(certLabel);
CFRelease(query);
if (identityRef)
CFRelease(identityRef);
return -1;
}
CFRelease(certLabel);
CFRelease(query);
// We have obtained the identity so we can delete it
CFArrayRef itemList = CFArrayCreate(NULL, &identityRef, 1, NULL);
const void *keys2[] = { kSecClass, kSecMatchItemList, kSecMatchLimit };
const void *values2[] = { kSecClassIdentity, itemList, kSecMatchLimitAll };
CFDictionaryRef dict = CFDictionaryCreate(NULL, keys2, values2, 3, NULL, NULL);
status = SecItemDelete(dict);
if (status != errSecSuccess) {
s_log(SecCopyErrorMessageString(status, NULL));
CFRelease(dict);
CFRelease(itemList);
CFRelease(identityRef);
return -2;
}