Error adding Key item to macOS keychain

I have following code:


let keyData = UUID().uuidString.data(using: .utf8)!

var attributes: [NSString: Any] = [
    kSecClass: kSecClassKey,
    kSecAttrApplicationTag: keyData,
    ]
let st1 = SecItemDelete(attributes as CFDictionary)
attributes[kSecValueData] = keyData
let st2 = SecItemAdd(attributes as CFDictionary, nil)


I am trying to add item to the keychain with type kSecClassKey. For some reason this code works perfectly in iOS and doesn't work in macOS.

In macOS st1 is -25300 (which means The item cannot be found.) and st2 is -25299 (which means The item already exists.)

What can I do to make this code work?


P.S. Generating Keys usign Security framework API doesn't fit to my needs, cause I use my own crypto libraries and want to store keys from my application's memory

The immediate cause of your problem is confusion about keychain query dictionaries and keychain attribute dictionaries.

SecItemDelete
takes a query dictionary and
SecItemAdd
takes an attribute dictionary (which typically contains a superset of the keys found in the query dictionary). If you use the same dictionary for both you can run afoul of keychain item uniqueness problems. I discussed the issue of keychain item uniqueness in detail in this post.

In your case, putting

kSecAttrApplicationTag
in the query dictionary passed to
SecItemDelete
means that you only want to delete a key if its
kSecAttrApplicationTag
matches the supplied value, so the delete fails with
errSecItemNotFound
. However, when you go to add it back there’s obviously some other key with the same values for the ‘must be unique’ attributes as the key you’re adding, hence the
errSecDuplicateItem
.

Taking a step back, you wrote:

Generating Keys usign Security framework API doesn't fit to my needs, cause I use my own crypto libraries and want to store keys from my application's memory

Can you explain more about your high-level goal here. To start, are you talking about symmetric or asymmetric keys? If you’re dealing with asymmetric keys, you may be able to opt out of the whole keychain business by creating the key directly from the data you have using

SecKeyCreateWithData
.

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"

Thank you for your answer.

I have read your post with great explanation, but unfortunarely that didn't help solve my problem.

1. My query dictionary:

{ "atag": randomData, "class": kSecClassKey }

Please, pay attention that "atag" value is purely random, so chances that such key already exists in my keychain is near 0. Thus, keychain API response with "Item not found".

2. My attributes dictionary:

{ "atag": randomData, "class": kSecClassKey, "v_Data": somedata }

"v_Data" is not obliged to be unique, so knowing we don't have keys with { "atag": randomData, "class": kSecClassKey } in keychain from step 1, we should be able to add this key.

There is also possibility that I have some mess with other primary keys which are stated here https://developer.apple.com/reference/security/errsecduplicateitem

Can you please provide code sample which adds item with kSecClass = kSecClassKey to macOS keychain? I haven't seen such in any apple documentation, WWDC or on the internet at all...

Btw, as I can see other developers don't bother themselfs dealing with keys in keychain and just store them in Passwords section, is there any Security drawbacks

And thank you for SecKeyCreateWithData reference, I will check this part of the Security API

Are you dealing with symmetric or asymmetric keys? If it’s asymmetric, is it a private key or a public key?

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"

Private key

Private key

Oi vey! Is the code you included in your first post the actual code you’re using on iOS? If so, that’s seriously broken. There’s no reliably way to export and import private keys via the SecItem API on iOS. The problem is with just adding the key data to the keychain is that it fails to set a bunch of keychain attributes that the system assumes are present.

Ironically this stuff is actually easier to do on macOS, where has a good API for importing and exporting key material. However, before we go there I’d like to step back and talk about the big picture. Back on 4 May you wrote:

P.S. Generating Keys usign Security framework API doesn't fit to my needs, cause I use my own crypto libraries and want to store keys from my application's memory

Can you explain more about the flow of key material through your app? Specifically:

  • Where do these private keys come from? And in what format are they delivered to your app?

  • Are you using any system APIs that need a

    SecKey
    object? Or are you using your own code that needs raw key bits?
  • Do you need to persist the private keys? Or is your usage solely transitory?

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"

Thanks for your reply

1. These keys are generated using my own crypto library which internally uses mbed tls.

2. All crypto operations are performed using my own crypto library, all I need at this moment is secure key storage.


P.S. Actual iOS source file can be found here. It is tested and works great on both simulator and device.

https://github.com/VirgilSecurity/virgil-sdk-x/blob/master/Source/KeyStorage/VSSKeyStorage.m

Accepted Answer

all I need at this moment is secure key storage.

In that case I’d store the keys as generic passwords (

kSecClassGenericPassword
). Given that your app is the only one that needs to be able to read and write these keys, there’s no point dealing with the many complexities of
kSecClassKey
.

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"

What would happen if this knowledge was used to access a keychain causing it to fail ?

What would happen if this knowledge was used to access a keychain causing it to fail ?

I’m not sure what you mean by this. Please elaborate.

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"
Error adding Key item to macOS keychain
 
 
Q