Hello, I have a problem with SecItemDelete when trying to delete a private key stored using the data protection keychain on macOS 13.5 (testing on MB Pro 2023).
Everything else works:
- adding the item (using
SecKeyCreateRandomKey) - getting a reference to the item using
SecItemCopyMatchingand reading the data
But calling SecItemDelete with kSecValueRef and a reference received from SecItemCopyMatching fails with errSecItemNotFound.
What's even more interesting, the call to SecItemDelete fails with that error even if passed the exact same search dictionary (omitting the kSecReturnRef key) that results in successfully getting an item reference when passed to SecItemCopyMatching (the documentation of SecItemDelete refers to the SecItemCopyMatching documentation on construction a search dictionary, so, in theory, it should accept the same parameters).
I am at a dead end here honestly, and, despite knowing better, I'm starting to suspect this might be a bug in the API implementation. Any help is appreciated.
SecItemCopyMatching call:
auto params = cf::create_dict({{kSecClass, kSecClassKey},
{kSecAttrKeyClass, kSecAttrKeyClassPrivate},
{kSecAttrLabel, cf::from_string(create_key_name(name))},
{kSecReturnRef, kCFBooleanTrue}});
SecKeyRef key_ref{nullptr};
auto status = ::SecItemCopyMatching(params.get(), (CFTypeRef*)&key_ref);
SecItemDeleteCall with ref from SecItemCopyMatching:
auto query = cf::create_dict({{kSecValueRef, key}});
sec::throw_if_fail(::SecItemDelete(query));
SecItemDeleteCall with search by key label:
auto query = cf::create_dict({{kSecClass, kSecClassKey},
{kSecAttrKeyClass, kSecAttrKeyClassPrivate},
{kSecAttrLabel, cf::from_string(create_key_name(name))}
});
sec::throw_if_fail(::SecItemDelete(query));
Private key creation params for SecKeyCreateRandomKey:
{kSecClass, kSecClassKey},
{kSecAttrKeyType, kSecAttrKeyTypeECSECPrimeRandom},
{kSecAttrKeySizeInBits, cf::make_guarded(::CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &bit_length.at(key_spec.curve)))},
{kSecAttrIsPermanent, kCFBooleanTrue},
{kSecUseDataProtectionKeychain, kCFBooleanTrue},
{kSecAttrLabel, cf::from_string(create_key_name(name))},
{kSecAttrIsExtractable, storage_spec.exportable ? kCFBooleanTrue : kCFBooleanFalse}