I have an app which generates couple of private keys. When user needs to sign data, they have to authenticate with biometrics and Secure Enclave signs it with the proper private key. Simple.
I got a new requirement - the app needs to be able to sign multiple pieces of data as they arrive in the device and user should authenticate only when signing the first piece.
So my questions are:
Is possible to create a private key that stays unlocked for certain amount of time after user authenticates with biometrics? If so, how?
Is possible to create a private key that stays unlocked until program tells Secure Enclave to lock it? If so, how?
I searched documentation and stack overflow thoroughly, but without any luck. Any help is much appreciated!
CodePudding user response:
Alright, so after a lot of testing I found the answer to my questions. Normally (in my case), user needs to authenticate each time the private key is used.
In order to be able to do batch operations, we need to use LAContext
and set reuse duration:
let context = LAContext()
context.touchIDAuthenticationAllowableReuseDuration = 10.0 // 10 seconds
Add the context into attributes while loading the private key:
let attributes: [CFString: Any] = [
// ...
kSecUseAuthenticationContext: context
// ...
]
var item: CFTypeRef?
let status = SecItemCopyMatching(query as CFDictionary, &item)
This, however, has an unexpected behavior. The private key remains "unlocked" even after the time limit has passed. Invalidating the context to lock the private key doesn't work either.
In order to lock the key after the batch signing is done, we need to:
- Deallocate the context, or reinitialize for future use
- Reload the private key with the new context (or without context), because the private key is holding strong reference to the context.
Only after that, the user will need to authenticate with biometrics again, so keep that on mind.
It's also fair to say that there's no need to generate new keys. This approach works with existing keys.