kSecUseOperationPrompt Text not displayed (iOS 13 only)

In my app i use the iOS keychain to store a private key (ec-256) for message signature.

The code is working since iOS 11, but I can experience with iOS 13, that the TouchID popup when accessing the private key in the keychain is missing the custom text. It only shows one line: TouchID for "<APP NAME>", the custom text is not displayed. Using iOS 11 and iOS 12, there is a second line in the TouchID popup below that line.


Code to generate/store the key in the keychain:

let access: SecAccessControl
if #available(iOS 11.3, *) {
  access = SecAccessControlCreateWithFlags(kCFAllocatorDefault, kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly, [.privateKeyUsage, .biometryCurrentSet], nil)!
} else {
  access = SecAccessControlCreateWithFlags(kCFAllocatorDefault, kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly, [.privateKeyUsage, .touchIDCurrentSet], nil)!
}
let attributes = [
  kSecAttrKeyClass: kSecAttrKeyClassPrivate,
  kSecAttrKeyType: kSecAttrKeyTypeECSECPrimeRandom,
  kSecAttrKeySizeInBits: 256,
  kSecAttrTokenID: kSecAttrTokenIDSecureEnclave,
  kSecPrivateKeyAttrs: [
  kSecAttrIsPermanent: true,
  kSecAttrApplicationTag: keyTag,
  kSecAttrAccessControl: access
  ]  as [String: Any]
] as [String: Any]
var error: Unmanaged<CFError>?
guard let privateKey = SecKeyCreateRandomKey(attributes as CFDictionary, &error) else {
  throw error!.takeRetainedValue() as Error
}

Code to retrieve the private key to sign a message:

let authenticationText = NSLocalizedString("BIOMETRICS_LOGIN__FINGERPRINT_REQUEST_MESSAGE", comment: "")
let query = [
  kSecClass: kSecClassKey,
  kSecAttrKeyClass: kSecAttrKeyClassPrivate,
  kSecUseOperationPrompt: "\(authenticationText) \(accountId)",
  kSecAttrApplicationTag: keyTag,
  kSecAttrKeyType: kSecAttrKeyTypeECSECPrimeRandom,
  kSecReturnRef: true
] as [String: Any]
var item: CFTypeRef?
let status = SecItemCopyMatching(query as CFDictionary, &item)
guard status == errSecSuccess else {
  throw AccountStorageError.privateKeyNotFound        
}
let privateKey = item as! SecKey


The above code works in all supported iOS versions (11, 12, 13 up to 13.2.3), private keys can be stored and retrieved, but only on iOS 13 devices, the text specified in kSecUseOperationPrompt is not displayed in the TouchID popup.


Is there something wrong or is this a known issue in iOS 13?

Accepted Reply

reto’s bug came back with an explanation of the expected behaviour here. The issue is one of passwords versus keys. kSecUseOperationPrompt is used when you Touch ID protect a password in the keychain. Passwords triggers Touch ID authentication at the point where you call SecItemCopyMatching, and this applies kSecUseOperationPrompt. In contrast, for a key item, Touch ID authentication happens at the point where you use the key. To set that prompt, do the following:
  1. Create a Location Authentication context (LAContext).

  2. Set the prompt in its localizedReason property.

  3. Pass the context to SecItemCopyMatching via kSecUseAuthenticationContext key.

Share and Enjoy

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

Replies

Is there something wrong or is this a known issue in iOS 13?

My recommendation here is that you file a bug about this change.

Please post your bug number, just for the record.

Share and Enjoy

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

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

I filed the bug with id 7477206. I hope it is al right this way, since the feedback assistant tool is quite confusing

Is there anybody out there facing the same issue? I never got any feedback regarding the filed bug. I still observe the same issue, on iOS 13 (13.6). The text specified in kSecUseOperationPrompt is not displayed. On a iOS 12 device running the very same code, the text is displayed in the TouchID prompt.
I had a look at your bug (FB7477206) and, alas, there’s no progress to report.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@apple.com"
Can we get a link to this issue? Also is there any progress on this?
reto’s bug came back with an explanation of the expected behaviour here. The issue is one of passwords versus keys. kSecUseOperationPrompt is used when you Touch ID protect a password in the keychain. Passwords triggers Touch ID authentication at the point where you call SecItemCopyMatching, and this applies kSecUseOperationPrompt. In contrast, for a key item, Touch ID authentication happens at the point where you use the key. To set that prompt, do the following:
  1. Create a Location Authentication context (LAContext).

  2. Set the prompt in its localizedReason property.

  3. Pass the context to SecItemCopyMatching via kSecUseAuthenticationContext key.

Share and Enjoy

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