4

The documentation for Keychain Services is horribly incomplete and I keep getting unhelpful errors when I try to use the SecItem*() functions. Currently I'm trying to delete an identity I've previously added to the keychain:

// Identity ref is a persistent reference to the identity I want to delete.
NSData *identityRef = ...
NSDictionary *query = @{ (id)kSecClass: (id)kSecClassIdentity,
                         (id)kSecValuePersistentRef: identityRef };
OSStatus status = SecItemDelete((CFDictionaryRef)query);
// Fails with errSecParam (-50) under iOS 6
// Fails with errSecNotAvailable (-25291) under iOS 7

However, the required (and recommended) parameters for each of the various security item classes are not documented anywhere as far as I can tell. What should I be specifying in order to successfully work with identities in the keychain?

EDIT

I have also tried using kSecMatchItemList as documented:

NSDictionary *query = @{ (id)kSecClass: (id)kSecClassIdentity,
                         (id)kSecMatchItemList: @[identityRef] };
OSStatus status = SecItemDelete((CFDictionaryRef)query);
// Fails with errSecParam (-50)

I have also tried specifying the suggested primary keys from this SO question:

NSDictionary *attrs = nil;
NSDictionary *attrsQuery = @{ (id)kSecClass: (id)kSecClassIdentity,
                              (id)kSecValuePersistentRef: identityRef };
SecItemCopyMatching(attrsQuery, (CFTypeRef *)&attrs);
NSDictionary *query = @{ (id)kSecClass: (id)kSecClassIdentity,
                         (id)kSecAttrCertificateType: attrs[(id)kSecAttrCertificateType],
                         (id)kSecAttrIssuer: attrs[(id)kSecAttrIssuer],
                         (id)kSecAttrSerialNumber: attrs[(id)kSecAttrSerialNumber],
                         (id)kSecAttrApplicationLabel: attrs[(id)kSecAttrApplicationLabel],
                         (id)kSecAttrApplicationTag: attrs[(id)kSecAttrApplicationTag],
                         (id)kSecAttrKeyType: attrs[(id)kSecAttrKeyType],
                         (id)kSecAttrKeySizeInBits: attrs[(id)kSecAttrKeySizeInBits],
                         (id)kSecAttrEffectiveKeySize: attrs[(id)kSecAttrEffectiveKeySize] };
OSStatus status = SecItemDelete(query);
// Still fails with errSecParam (-50)
Community
  • 1
  • 1
Greg
  • 10,360
  • 6
  • 44
  • 67

2 Answers2

4

It appears I was overspecifying the item to delete. If you include the kSecClass key in the query when deleting an identity from the keychain, Keychain Services gets confused. This code works:

NSData *identityRef = ...
NSDictionary *query = @{ (id)kSecValuePersistentRef: identityRef };
OSStatus status = SecItemDelete((CFDictionaryRef)query); // Success!
Greg
  • 10,360
  • 6
  • 44
  • 67
0

Keychain can be seen as a database with many tables (kSecClass).

Since you're using kSecClassIdentity this "table" has two primary keys which are kSecClassKey and kSecClassCertificate.

You should always specify those values when you do operations with an entry. In your case your query dictionary is missing those values.

You can check this SO post for more information on primary keys of keychain classes

What makes a keychain item unique (in iOS)?

Community
  • 1
  • 1
streem
  • 9,044
  • 5
  • 30
  • 41
  • How can I specify the certificate and key? I can't have multiple values for `kSecValueRef` in my query. I've tried specifying `kSecAttrCertificateType`, `kSecAttrIssuer`, `kSecAttrSerialNumber`, `kSecAttrApplicationLabel`, `kSecAttrApplicationTag`, `kSecAttrKeyType`, `kSecAttrKeySizeInBits`, and `kSecAttrEffectiveKeySize` like the linked post says, but I still get an `errSecParam` error. – Greg May 20 '14 at 15:16
  • If i were you, and if you don't mind losing the data, i'd clear the whole keychain for the class identity. What do you need to save by the way ? Are you sure kSecClassIdentity is the right one for you ? – streem May 20 '14 at 15:19
  • Yes, I'm storing multiple TLS client certificates and keys to let the user connect to different servers using different identities. In order to not fill up the keychain with crap I'm trying to let the user delete unused identities. – Greg May 20 '14 at 15:24
  • OK, well i'm not familiar with that class but i guess it's not very different from kSecClassGenericPassword. Your query should contain 3 attributes (precisely) in SecItemCopyMatching and SecItemDelete which are the primary keys (kSecClassKey and kSecClassCertificate) and the class kSecClassIdentity. – streem May 20 '14 at 15:31
  • That being said, have you been able to clear your keychain ? If it's corrupted there is not much you can do. – streem May 20 '14 at 15:32