Keychain API : iOS vs OSX

Hi all


I am trying to implement the Keychain API for both iOS and OSX and I'm scratching my head around some issues :


  • SecItemDelete + kSecMatchLimitAll : iOS give OSStatus error -50 if this parameter is set, but OSX requires the parameter to be set (if you want to delete more than one item of course)
  • SecItemCopyMatching + kSecClassIdentity : OSX only returns the {certificate, privatekey} pairs, while iOS returns both the {certificate, privatekey} and {certificate, publickey} pairs
  • SecItemAdd + kSecClassCertificate + kSecAttrLabel : OSX ignores the kSecAttrLabel, while iOS records it
  • SecKeyGeneratePair + kSecAttrIsPermanent : Both iOS and OSX ignore kSecAttrIsPermanent if set to false. Items are added to the keychain whatever happens. OSX crashes if SecKeyRefs arguments are provided as NULLs while iOS accept it.
  • SecItemCopyMatching + kSecAttrKeyClassPublic + kSecReturnData true : iOS returns the content of the public key in ASN.1 encoded format, OSX returns an internal byte array that cannot be decoded
  • SecItemCopyMatching + kSecAttrLabel : OSX performs a strict evaluation of the label parameter (returns only the matching labels) while iOS performs a lazy evaluation (returns all items that contain the words in the parameter)


Am I right to assume the above, or is there something which I am doing awfully wrong ?

Accepted Reply

You’re not doing anything wrong. Our platforms support two different implementations of the SecItem API:

  • iOS style (A)

  • macOS compatibility shim (B)

Implementation A is used on all iOS-based platforms. It also kicks in on macOS when you use iCloud Keychain. Implementation B is a macOS compatibility shim that supports roughly the same API on top of macOS’s older keychain infrastructure. That shim has many places where its behaviour is different from implementation A.

I encourage you to file bug reports about any such differences you encounter. Please post any bug numbers, just for the record.

Most of the problems you listed have fairly obvious workarounds. However, there is one I specifically want to call out:

SecItemCopyMatching + kSecAttrKeyClassPublic + kSecReturnData true : iOS returns the content of the public key in ASN.1 encoded format, OSX returns an internal byte array that cannot be decoded

The fact that iOS returns the public key bits in this situation is more an accident of the implementation than a specific design goạl. On current systems you can use the shiny new

SecKeyCopyExternalRepresentation
to export a key. On older systems you should do the following:
  • for implementation A, continue using

    SecItemCopyMatching
  • for implementation B, use the APIs in

    <Security/SecImportExport.h>

Share and Enjoy

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

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

Replies

You’re not doing anything wrong. Our platforms support two different implementations of the SecItem API:

  • iOS style (A)

  • macOS compatibility shim (B)

Implementation A is used on all iOS-based platforms. It also kicks in on macOS when you use iCloud Keychain. Implementation B is a macOS compatibility shim that supports roughly the same API on top of macOS’s older keychain infrastructure. That shim has many places where its behaviour is different from implementation A.

I encourage you to file bug reports about any such differences you encounter. Please post any bug numbers, just for the record.

Most of the problems you listed have fairly obvious workarounds. However, there is one I specifically want to call out:

SecItemCopyMatching + kSecAttrKeyClassPublic + kSecReturnData true : iOS returns the content of the public key in ASN.1 encoded format, OSX returns an internal byte array that cannot be decoded

The fact that iOS returns the public key bits in this situation is more an accident of the implementation than a specific design goạl. On current systems you can use the shiny new

SecKeyCopyExternalRepresentation
to export a key. On older systems you should do the following:
  • for implementation A, continue using

    SecItemCopyMatching
  • for implementation B, use the APIs in

    <Security/SecImportExport.h>

Share and Enjoy

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

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

Hi eskimo,


Thanks for your quick reply.

I am happy to hear about `SecKeyCopyExternalRepresentation`.

Honestly fetching the raw DER representation from the CFDataRef bits felt like a ugly hack !


Can you confirm whether this a valid public API ?

The function doesn't seem to be referenced on Apple's website

(no mention here : https://developer.apple.com/reference/security/1658642-keychain_services)


Can you give some details about the result in the case of EC keys.

SecKey.h tells us to look at www.secg.org, but their website is down.


When you say 'older' systems, do you mean 'apps compiled with old SDKs' or 'apps running on old OSes' ?

For instance if I'm using iOS SDK 10 but targeting iOS 8, will it fail ?


Many thanks

Honestly fetching the raw DER representation from the CFDataRef bits felt like a ugly hack !

Amen!

Can you confirm whether this a valid public API ?

Yes it is. The best rule of thumb for this is whether the API is in the iOS SDK, which it is.

The function doesn't seem to be referenced on Apple's website …

It does show up in the API Reference but the page is empty. Please file a bug against the docs about that.

Can you give some details about the result in the case of EC keys. SecKey.h tells us to look at www.secg.org, but their website is down.

Honestly, I’d prefer you get this info directly from SECG rather than have me reinterpret it. I know a lot about crypto APIs but my understanding of these low-level details is quite poor )-:

btw The SECG site is up for me right now.

When you say 'older' systems, do you mean 'apps compiled with old SDKs' or 'apps running on old OSes' ?

SecKeyCopyExternalRepresentation
is new in iOS 10 (and wachOS 3, tvOS 10 and macOS 10.12). You’ll have to use the iOS 10 SDK to access it, but that does not magically make it available on iOS 9 and earlier. You’ll need a compatibility strategy for those systems. Typically this means using
SecKeyCopyExternalRepresentation
if it’s available and then falling back to your current code if it’s not.

Share and Enjoy

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

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

Bug report filed : 28733803

Thanks.

You are extremely helpful.