Correct Way to Check If SecKey Requires User Interaction?

What's the best/correct/current way of checking if a SecKey (or any keychain item) is allowed to be accessed (decrypted) by the current process? This would apply to signing or decrypting for a private key, or the data/contents of a password item (or key).

Given the number of APIs deprecated, and that some of the listed interaction mechanisms don't seem to work (FB11153260), I was wondering if there was some SecItemCopyMatching magic, or something related to LAContext.

In this use-case the SecKey is provided to this code, or it may fall back to enumeration by hostname (common name), so a persistent reference doesn't apply (though I realize that's a best practice). It looks like kSecUseAuthenticationUI doesn't work, and neither does kSecUseAuthenticationContext with interactionNotAllowed set to false. The deprecated SecKeychainSetUserInteractionAllowed still works though.

In the past it was possible to enumerate the ACLs of an item using SecKeychainItemCopyAccess, but there doesn't seem to be an alternative. I was hoping it was possible to use kSecUseItemList with one of the kSecUseAuthentication* options in SecItemCopyMatching to return an error or an empty list, but that doesn't seem to work. Same with kSecMatchItemList. LAContext itself has a way to evaluate operations, but not with reference to a particular item.

Either examination of the item (e.g. ACLs), evaluation of a policy (can sign?), or failure from something like SecItemCopyMatching would be fine, but it must work with interaction suppressed.

Replies

What platform is this on? And if it’s on the Mac, what keychain implementation is the item coming from? For more about the latter, see On Mac Keychains.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

I've tagged the thread "macOS", which I hope is the correct way to indicate these things.

I'm not specifying the data protection keychain (though I know it's possible with a query dictionary). These keys could be provided from any source to this code, which is part of the issue. Is there a good way to check if a SecKey in-hand came from a particular source? Given the risk of an operation on an item becoming trapped in user authentication (if running in a context where that is possible), it seems like a good idea to be able to preflight and return an error code early regardless of source, item type, or usage.

If it helps, assume the System keychain is involved here. I didn't realize kSecUseAuthentication* might be data-protection-only.

These keys could be provided from any source to this code, which is part of the issue.

Right.

If it helps, assume the System keychain is involved here.

That simplifies things considerably, because you then know that the data protection keychain isn’t involved. Which means that kSecUseAuthenticationContext, and all of its deprecated predecessors, are irrelevant because those only apply to the data protection keychain.

Did you try kSecUseNoAuthenticationUI?

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

I did try kSecUseNoAuthenticationUI with kCFBooleanTrue and it has the same issue with SecItemCopyMatching. My own temporary test is to set user interaction to false and attempt to sign some random data. The query succeeds and returns a SecKey, which then fails the signature test.

I did try kSecUseNoAuthenticationUI with kCFBooleanTrue and it has the same issue

I don’t think I’ll have to time to get you a proper answer in the context of DevForums )-: I recommend that you open a DTS tech support incident so that I can allocate more time to investigating this properly.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"