SecItemCopyMatching without FaceID via kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly - ios

I'm trying to unlock data from the keychain / secure enclave via FaceID and make it accessible for the duration of the User session (without additional unlocks).
Per the documentation for kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly:
After the first unlock, the data remains accessible until the next restart. This is recommended for items that need to be accessed by background applications. Items with this attribute do not migrate to a new device.
Yet, whenever I call SecItemCopyMatching() (documentation), I'm always prompted to perform a FaceID authorization.
Can someone explain what I might be doing wrong (or misunderstanding)?

The data protection class and the access control flags assigned to a keychain item are separate.
In your question you have detailed the data protection class that you have assigned, but the behaviour you are describing is resulting from the access control flags that were specified.
The data protection class refers to the lock state of the device, not the keychain item.
If you specify one or more of these values then the specified authentication (biometric and/or passcode) is required each time the keychain item is accessed.
If you only want the user to authenticate their presence the first time the item is accessed then you could specify no access control for the item and use the local authentication framework directly. Set a flag once the user has successfully authenticated and do not prompt them again in that session (or until a certain time hasn't elapsed or whatever logic you like).

Related

How to fire device PIN dialog?

I working on an app that is designed to be protected from unauthorized access (like, for instance, bank apps do). There are two protection options: by using biometrics (default one) and by user password. I wonder, what the best practices are to handle the situation when a user forget thier password.
I'm thinking to prompt user to enter device PIN in order to remind them the password, but I can't figure out how to do that.
I guess it really depends on exactly how sensible the information is and how you're currently storing/validating the password. But assuming your threat model is okay with a user being able to get access back just with the current device password, you could use the keychain API (not the friendliest of APIs) and store some kind of flag. When adding such item you would use SecAccessControlCreateFlag.devicePasscode which will always prompt the user for their iPhone passcode before accessing such entry. So say the user needs to reset it, if you're able to access the keychain entry, you know they entered the right device passcode and thus you should allow them to reset their app password. The main caveat would be that the user disabling their passcode or not having one would invalidate your flag so they would be locked out forever if they ever forget their app password. Of course there's a lot of additional nuance to the Keychain like whether the items get synced to other devices or not, when it's available, etc. but hopefully this is somewhat useful.

The claim process removes the secretKey, how to restore it if I do a reclaim?

We're using the thingsboard CE for a smarthome application. We're considering the claim process to let the user to add a new device. We developed a proof of concept following the process described in here: https://thingsboard.io/docs/user-guide/claiming-devices/
Now we're considering the use case of removing the device to let another user to add it (like selling the device to another person), but when we reclaim the device (according to "Device Reclaiming API Request") the device doesn't have the secretKey, so, we cannot let another user claim the device.
Are we missing something? Is there another way to do what we want?
I'd suggest handling it in the rule chain. One solution would be to have a button on a management dashboard. Clicking the button sets a "reclaim flag" to true (or you can do it direct from default attribute edit window). The rule chain receives this action, notices the flag and does the following:
Adds a secretKey attribute
Re-enables device claiming (I think once a device is claimed it can't be reclaimed again by default)
Flips the "reclaim flag" back to false
Changes the "owner" of the device back to the tenant (optional but I recommend it).
Alternatively, if you didn't want to deal with the flag bit, you could have the rule chain listen for any time an device has it's owner changed to the tenant. Might be a little less secure though.

Apple TouchID - Detect authentication with newly added fingerprints

I'm integrating TouchID into my app, for security reasons I need to block the user when he is trying to authenticate with newly added fingerprints [Which is added after enabling TouchID authentication in my app].
I can detect the biometry changes using LAContext's evaluatedPolicyDomainState. but this only says either biometric database was modified (fingers or faces were removed or added) or not.
Is there any other way I can find whether user has authenticated using newly added fingerprint
[added after enabling TouchID in my app] or not.
Any thoughts on this? appreciate any help and thanks in advance.
It is not possible to determine whether the biometric authentication took place with a "new" or "old" finger. This is a hardware limitation.
The biometric validation takes place in the Secure Enclave. The Secure Enclave simply returns a yes/no answer to the main processor. The main processor does not have any access to the actual biometric data that was validated.
You can, as you have noted, determine if the biometric database has been updated since you last evaluated the domain state. The best you can do is invalidate all biometric access if you determine that the database has been modified, even if that modification was the removal of a finger.

Is it enough to save Pin code (string) value to iOS Keychain to be secure?

I am working on the app that require protection screen for the app.
This screen looks like :
I already done all features expect one. It is proper saving of the pin code.
I read about iOS Keychain and think it is quite suitable approach to save sensitive information.
But I would like to hear opinion from others is it enough? Or what should i use to protect this (pin code) information.
Now it is working like:
Set
Pin -> Keychain
Get
Keychain -> Pin
Also I consider hashing:
Set
Pin->Encode->Keychain
Get
Keychain->Decode->Pin
Saving a PIN is similar to saving a user password - one should never do this in plain text even when you store it protected like in the keychain.
At least save it as salted hash, better use a password hashing scheme (one-way security function designed for processing passwords and PINs) like PBKDF2, bcrypt, scrypt or Argon.
In most cases the keychain should be enough. But there is no 100 percentage solution. If an attacker has access to the hardware and software you can only make it harder to get the data, not impossible.
That means in your case an attacker already needs access to the device and the device pin code / touchid (if set) to install a jailbreak. Only then it's possible to get access to the content of the keychain and your stored data inside.
An additional encoding of your keychain data requires to store the key for the encode/decode somewhere. You have to save it somewhere else, e.g.in the user defaults, but the keychain already has the highest security level. Encoding makes sense for the real user data (the data you want to secure with the pin: access token, file encryption password, ...), because for these data it may be importend to destroy them in app deinstall/reinstall process. The user defaults will be removed when deinstall, the keychain not.
Scenario: User deletes app and sell his/her phone without resetting it in device settings. Buyer installs jailbreak -> old data in keychain should be garbage/unreadable.
Conclusion:
Think about it: What user data do you wanna secure with the pin? These data are also located inside of the keychain, even if it's only an access token for web requests or a password for an encryption. You don't need a higher security level for the pin than for your data ;)
In case of a pin your solution should be enough. But it's imported that your real user data should use the same security level or a higher one.
Update
There is a higher security level than the keychain: "Secure Enclave". It's mainly used for saving the touch id informations. Apple do not documented it, so I wouldn't recomend to use it yet.
There is a project called Tidas to make it accessible for the community.

How Do I Force An iOS TouchID To Re-Authorize After Each Access, or Check If It is Unlocked?

OK. I suspect I just need to be directed to the appropriate "M" for "RTFM." I'm not new to iOS, but fairly new to keychain use. I am using a good keychain wrapper called "FXKeychain."
I have an app that includes a login, with a password stored in the default keychain.
I use TouchID to validate the user and fill in the password.
In order to do this, I display a "thumbprint" button, with an IBAction handler that runs the standard code:
self.s_authenticationContext.evaluatePolicy(LAPolicy.DeviceOwnerAuthenticationWithBiometrics, localizedReason: "Yo. Gimmie ur thumb.", reply: self.touchIDCallback)
The issue is, that once it is unlocked, subsequent touches of the button, using the above, skip the alert, and simply fall through.
This is an issue because the same button is displayed, even after the user is validated. I'd like to either:
Re-lock after entering the password, so the user must re-authenticate each time (preferred), or
Display a different button image that indicates the thumbprint is no longer necessary.
That means that I need to:
Find a way to re-lock the TouchID, or
Find out if the user is unlocked.
Any ideas?
Thanks!
It is your authentication context rather than the keychain that is 'unlocked'. If you allocate a new authentication context before calling evaluatePolicy then the touchID dialog will be shown again.
You can, however, actually use touchID to authenticate access to a keychain item directly. The Apple sample code demonstrates how to do this - https://developer.apple.com/library/ios/samplecode/KeychainTouchID/Introduction/Intro.html#//apple_ref/doc/uid/TP40014530-Intro-DontLinkElementID_2

Resources