Search code examples
iosipadios-simulatortouch-idbiometrics

Some iPad devices return biometrics not available with this code, why?


I'm having some issues understanding the return values I'm getting even with a fresh project with only the below code.

- (void)viewDidLoad {
    [super viewDidLoad];

    LAContext*   touchContext          = [LAContext new];
    NSError*     policyEvaluationError = nil;

    [touchContext canEvaluatePolicy:LAPolicyDeviceOwnerAuthenticationWithBiometrics
                                            error:&policyEvaluationError];

    NSLog(@"\n\n %@", policyEvaluationError);
}

These are the results on just iPad simulators, iOS 10.3.1 - 11.3.

iPad (5th Generation) - "Biometry is not available on this device."

iPad Air - "Biometry is not available on this device."

iPad Air 2 - “No identities are enrolled."

iPad Pro (9.7-inch) - "Biometry is not available on this device."

iPad Pro (12.9-inch) (2nd generation) - "Biometry is not available on this device."

These results of "Biometry is not available on this device." happen when these devices are enrolled or not.

All iPhone device types tested also return "No identities are enrolled." like iPad Air 2, which I would expect when they are not enrolled but possess touchID hardware. When enrolled, there simply is no error.

On some actual iPad devices, the results seem to vary as well, but not in the same way. Without fingerprints stored, some devices return "Biometry is not available on this device." while others simply return the enrolled/nil. With fingerprints stored, they all seem to behave as I would expect.

As far as I'm aware, we've been using this code in production for quite some time without complaints related to this topic, but we've only recently noticed it within development/QA.

Is this code just not reliable across all devices, has something changed possibly, or am I doing something wrong here?


Solution

  • This is a bug in Apple's frameworks, and I've filed rdar://problem/46148637 to that effect. If you're curious, here's the full text of that report:

    iPad Pro (12.9-inch) (2nd generation) simulator thinks it doesn't have Touch ID
    
    Summary:
    LAContext().canEvaluatePolicy(_:error:) with the policy LAPolicy.deviceOwnerAuthenticationWithBiometrics fails with LAError.Code. biometryNotAvailable on the iPad Pro (12.9-inch) (2nd generation) simulator. A bit of digging suggests that:
    
    • LAContext().canEvaluatePolicy(_:error:), from LocalAuthentication.framework, ends up communicating with coreauthd to evaluate the policy.
    • The specific error is generated in -[BiometryHelper deviceHasBiometryWithError:] in DaemonUtils.framework, which is loaded into coreauthd.
    • -[BiometryHelper deviceHasBiometryWithError:] returns this error when -BiometryHelper._device is nil.
    • BiometryHelper._device is the first object grabbed from +[BKDeviceManager availableDevices], in BiometricKit.framework.
    • +[BKDeviceManager availableDevices] *should* create a Touch ID device descriptor if it finds that the device supports Touch ID, which it checks by calling MGGetBoolAnswer(@"touch-id").
    • MGGetBoolAnswer(@"touch-id") returns NO (!)
    • The device believes it does not have a Touch ID sensor.
    • LAContext().canEvaluatePolicy(_:error:) returns false because it believes the device cannot evaluate this policy.
    
    Steps to Reproduce:
    1. Try to evaluate a biometric policy on the  iPad Pro (12.9-inch) (2nd generation) simulator.
    
    Expected Results:
    I either receive a success, or something about being unenrolled.
    
    Actual Results:
    I'm told that this iPad doesn't have a Touch ID sensor, when clearly should have one.
    
    Version/Build:
    Xcode Version 10.1 (10B61)
    
    Configuration:
    Xcode Version 10.1 (10B61)/macOS Mojave 10.14.2 Beta (18C48a)