SecItemCopyMatching for Touch ID without passcode

2020-02-24 07:57发布

问题:

I am using SecItemCopyMatching to fetch a keychain item protected by Touch ID.

However, if Touch ID unlocking fails (or the user selects "Enter Passcode"), I want to present my own PIN-entry UI.

I do not want the user to be presented with the system passcode entry UI at any point.

LAContext's evaluatePolicy method provides this, but does not offer any actual keychain security, merely local authentication.

I therefore will not use LAContext to achieve this. Is this possible with SecItemCopyMatching?

回答1:

On iOS 8.3 and above, the passcode fallback option is hidden initially but still appears if the first finger presented is not recognised.

For iOS 9, two new policies have been added that do not fallback to passcode. These policies are kSecAccessControlTouchIDAny and kSecAccessControlTouchIDCurrentSet



回答2:

We had similar dilemma while working on one of our in-production app. We realised that we need touch ID unlock as well as custom fallback mechanism (which requires server API for unlocking) which is stronger than 4 digit unlock password.

So, Let me try to explain how we achieve it. Similar is expectedly done by Apple for Appstore purchase and 1Password app.

Background:

Two mechanisms to integrate Touch ID:

  1. Use Touch ID to access credentials stored in the keychain

    Issue:

    If a device has Touch ID as well, the preferred method is to authenticate with Touch ID and passcode is the backup mechanism

    No other fallback mechanism is permitted and Apple does not allow customisation of the fallback user interface

  2. Use Touch ID to authenticate with the app directly (called Local Authentication)

    Issue:

    No permission is granted to store secrets into or retrieve secrets from the Secure Enclave

    Contrary to the keychain access case, Apple does not allow device passcode authentication as a backup Every application needs to provide its own fallback to handle failed Touch ID case with custom UI

Concern:

About storing sensitive information in the keychain:

We were tempted to use this approach but were taken aback by realising the only fallback for failing to authenticate with Touch ID is the device passcode. iOS users usually configure a four digit passcode, which is less secure than users custom passwords.

Facelifting examples:

Apple uses your iCloud account password [custom fallback mechanism] as a fallback mechanism for itunes store purchase if user fails to authenticate with Touch ID.

1Password app also has similar approach.


Conclusion

In our app we authenticate with Touch ID via LocalAuthentication, we use our 'app specific PIN unlock feature' or the client's password as the fallback mechanism.

We don't store the password on the device, failure to authenticate with Touch ID requires full authentication through servers API, if device does not have a PIN configured within app.

Sample code:

[self.laContext evaluatePolicy:LAPolicyDeviceOwnerAuthenticationWithBiometrics
               localizedReason:reason
                         reply:^(BOOL success, NSError *error) {
                             if (success)
                                 dispatch_async(dispatch_get_main_queue(), ^{ successBlock(); });
                             else
                                 dispatch_async(dispatch_get_main_queue(), ^{ fallbackBlock(error); });
                             self.laContext = nil;
                         }
];


回答3:

This should probably be a comment to bllakjakk, but my reputation does not allow me to do so yet.

I am only adding this answer because the question was specifically asking about:

fetch a keychain item protected by Touch ID

The accepted answer mentions a scenario where no credentials are stored on the device.

For completeness I wanted to mention that if your app needs to authenticate to some external entity, and you therefore have to store credentials somewhere, then the Key-Chain option is the one to consider over Local Authentication.

The fear of somebody being able to authenticate via fallback for Key-Chain if they know the device pass-code (potentially weak four-digit and so on) is a moot point because nothing keeps a user from adding their own fingerprint to the device if they possess the pass-code, and then authenticating via Key-Chain or Local Authentication without having to select the fallback.

So if you are using Local Authentication over Key-Chain because you feel that the fallback mechanism is safer, you might be overlooking that minor detail and therefore be passing up on the opportunity to store credentials in the secure enclave.

We are about to implement TouchID for a financial application and are opting for Key-Chain. The intent is to educate our users about the need for strong device pass-codes at the time when they try to enable TouchID for our app.

I hope this helps you in making a decision.



回答4:

You can try hiding the Enter Password button by doing the following:

1) define global function

static bool new_isFallbackButtonVisible(id self, SEL _cmd)
{
    return NO;
}

2) in your application:didFinishLaunchingWithOptions: replace isFallbackButtonVisible method of LAContext class with your new implementation by calling

class_replaceMethod(NSClassFromString(@"LAContext"), NSSelectorFromString(@"isFallbackButtonVisible"), (IMP)new_isFallbackButtonVisible, "v@:B");


回答5:

There is no way to disable fallback mechanism using passcode in Keychain TouchID integration. Use LocalAuthentication instead (But LocalAuthentication just provides a TouchID auth UI though not related to the Keychain).



回答6:

You can hide/customize the "Enter Password" option by setting:

LAContext *context = [[LAContext alloc] init];
context.localizedFallbackTitle = @"";

and the option will disappear, or:

LAContext *context = [[LAContext alloc] init];
context.localizedFallbackTitle = @"Disable TouchID";

to customize the option text. While I know this isn't exactly what the OP was asking, it's most certainly related and could "fallback" into wanting minds.