Question

I'm trying to delete a certificate with its paired private key from the keychain through the keychain API. I can delete the certificate easily but the private key is always left behind. How can I remove it from the keychain??? I've tried several ways but even with the SecKeyRef in hand, once I run SecItemDelete (for instance), the function returns with status of errSecSuccess but the key is still there in the keychain!!!

Any help is much appreciated, and if there's any sample code please post it. Errrrr! This is so frustrating...

Thanks..

Was it helpful?

Solution

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;
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top