Create a Query Dictionary

When you generate keys yourself, as described in Generating New Cryptographic Keys, you can store them in the keychain as an implicit part of that process. If you obtain a key by some other means, you can still store it in the keychain. To do this, begin by creating a query dictionary containing and describing the item:

This query dictionary uses the kSecClassKey value for the kSecClass entry to indicate a key item (as opposed to a certificate, identity, or password). You also apply an application tag that lets you distinguish the key from others when later searching for it.

The above dictionary indicates that the key should be of type kSecAttrKeyTypeRSA, as in Creating an Asymmetric Key Pair, and that it should have the tag used in that example and above. The last line says that the retrieval should return a key reference (as opposed, for example, to the actual key data).

Note

This is a simple query that doesn’t refine the search as much as you may need. For additional ways to do that, see Refine the Search below.

You use this query with the SecItemCopyMatching function to execute a search and populate an empty reference that you supply:

If the call is successful, as indicated by the status result, you can then use the returned key reference to carry out cryptographic operations. In Objective-C, after you’re done with any keys that you retrieve this way, you’re responsible for freeing their memory. In Swift, the system manages the object’s memory.

Refine the Search

The query in the example above doesn’t restrict the search to a particular key class (public, private, or symmetric) or to any other key characteristic. It matches only for tag and type, returning a reference to the first successful match. Unless you use unique tags for all of your keys of a given type, you might not get the key you were looking for when you run the search. That's because only the first key that matches is returned, and that may or may not be the one you wanted.

There are several ways to deal with this. For example, you can:

Widen the search. If you add the kSecMatchLimit entry to the query dictionary with a value of kSecMatchLimitAll, instead of a single key reference, SecItemCopyMatching produces an array of key references, which you can inspect to find the key of interest.

Narrow the search. If you have other attributes that distinguish your keys, such as key size or key class, add the corresponding entries to the query dictionary before conducting the search.

Avoid reusing tags in the first place. Before adding a key with a given tag and type (or whatever other distinguishing characteristic you have), read existing keys from the keychain with those same characteristics. If you find a potential duplicate, either reuse the original key and skip creating a new one, create the new key using a different tag, or delete the old key using the SecItemDelete function before adding a new one.