1 /*
2  * Copyright (C) 2019 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.server.biometrics;
18 
19 import static android.hardware.biometrics.BiometricManager.Authenticators;
20 
21 import static junit.framework.Assert.assertEquals;
22 import static junit.framework.Assert.assertFalse;
23 import static junit.framework.Assert.assertTrue;
24 
25 import android.hardware.biometrics.BiometricAuthenticator;
26 import android.hardware.biometrics.BiometricConstants;
27 import android.hardware.biometrics.BiometricManager;
28 import android.hardware.biometrics.BiometricPrompt;
29 import android.hardware.biometrics.PromptInfo;
30 import android.platform.test.annotations.Presubmit;
31 
32 import androidx.test.filters.SmallTest;
33 
34 import org.junit.Test;
35 
36 @Presubmit
37 @SmallTest
38 public class UtilsTest {
39 
40     @Test
testCombineAuthenticatorBundles_withKeyDeviceCredential_andKeyAuthenticators()41     public void testCombineAuthenticatorBundles_withKeyDeviceCredential_andKeyAuthenticators() {
42         final boolean allowDeviceCredential = false;
43         final @Authenticators.Types int authenticators =
44                 Authenticators.DEVICE_CREDENTIAL | Authenticators.BIOMETRIC_WEAK;
45         final PromptInfo promptInfo = new PromptInfo();
46 
47         promptInfo.setDeviceCredentialAllowed(allowDeviceCredential);
48         promptInfo.setAuthenticators(authenticators);
49         Utils.combineAuthenticatorBundles(promptInfo);
50 
51         assertFalse(promptInfo.isDeviceCredentialAllowed());
52         assertEquals(authenticators, promptInfo.getAuthenticators());
53     }
54 
55     @Test
testCombineAuthenticatorBundles_withNoKeyDeviceCredential_andKeyAuthenticators()56     public void testCombineAuthenticatorBundles_withNoKeyDeviceCredential_andKeyAuthenticators() {
57         final @Authenticators.Types int authenticators =
58                 Authenticators.DEVICE_CREDENTIAL | Authenticators.BIOMETRIC_WEAK;
59         final PromptInfo promptInfo = new PromptInfo();
60 
61         promptInfo.setAuthenticators(authenticators);
62         Utils.combineAuthenticatorBundles(promptInfo);
63 
64         assertFalse(promptInfo.isDeviceCredentialAllowed());
65         assertEquals(authenticators, promptInfo.getAuthenticators());
66     }
67 
68     @Test
testCombineAuthenticatorBundles_withKeyDeviceCredential_andNoKeyAuthenticators()69     public void testCombineAuthenticatorBundles_withKeyDeviceCredential_andNoKeyAuthenticators() {
70         final boolean allowDeviceCredential = true;
71         final PromptInfo promptInfo = new PromptInfo();
72 
73         promptInfo.setDeviceCredentialAllowed(allowDeviceCredential);
74         Utils.combineAuthenticatorBundles(promptInfo);
75 
76         assertFalse(promptInfo.isDeviceCredentialAllowed());
77         assertEquals(Authenticators.DEVICE_CREDENTIAL | Authenticators.BIOMETRIC_WEAK,
78                 promptInfo.getAuthenticators());
79     }
80 
81     @Test
testCombineAuthenticatorBundles_withNoKeyDeviceCredential_andNoKeyAuthenticators()82     public void testCombineAuthenticatorBundles_withNoKeyDeviceCredential_andNoKeyAuthenticators() {
83         final PromptInfo promptInfo = new PromptInfo();
84 
85         Utils.combineAuthenticatorBundles(promptInfo);
86 
87         assertFalse(promptInfo.isDeviceCredentialAllowed());
88         assertEquals(Authenticators.BIOMETRIC_WEAK, promptInfo.getAuthenticators());
89     }
90 
91     @Test
testIsDeviceCredentialAllowed_withIntegerFlags()92     public void testIsDeviceCredentialAllowed_withIntegerFlags() {
93         int authenticators = 0;
94         assertFalse(Utils.isCredentialRequested(authenticators));
95 
96         authenticators |= Authenticators.DEVICE_CREDENTIAL;
97         assertTrue(Utils.isCredentialRequested(authenticators));
98 
99         authenticators |= Authenticators.BIOMETRIC_WEAK;
100         assertTrue(Utils.isCredentialRequested(authenticators));
101     }
102 
103     @Test
testIsDeviceCredentialAllowed_withBundle()104     public void testIsDeviceCredentialAllowed_withBundle() {
105         PromptInfo promptInfo = new PromptInfo();
106         assertFalse(Utils.isCredentialRequested(promptInfo));
107 
108         int authenticators = 0;
109         promptInfo.setAuthenticators(authenticators);
110         assertFalse(Utils.isCredentialRequested(promptInfo));
111 
112         authenticators |= Authenticators.DEVICE_CREDENTIAL;
113         promptInfo.setAuthenticators(authenticators);
114         assertTrue(Utils.isCredentialRequested(promptInfo));
115 
116         authenticators |= Authenticators.BIOMETRIC_WEAK;
117         promptInfo.setAuthenticators(authenticators);
118         assertTrue(Utils.isCredentialRequested(promptInfo));
119     }
120 
121     @Test
testGetBiometricStrength_removeUnrelatedBits()122     public void testGetBiometricStrength_removeUnrelatedBits() {
123         // BIOMETRIC_MIN_STRENGTH uses all of the allowed bits for biometric strength, so any other
124         // bits aside from these should be clipped off.
125 
126         int authenticators = Integer.MAX_VALUE;
127         assertEquals(Authenticators.BIOMETRIC_WEAK,
128                 Utils.getPublicBiometricStrength(authenticators));
129 
130         PromptInfo promptInfo = new PromptInfo();
131         promptInfo.setAuthenticators(authenticators);
132         assertEquals(Authenticators.BIOMETRIC_WEAK, Utils.getPublicBiometricStrength(promptInfo));
133     }
134 
135     @Test
testIsBiometricAllowed()136     public void testIsBiometricAllowed() {
137         // Only the lowest 8 bits (BIOMETRIC_WEAK mask) are allowed to integrate with the
138         // Biometric APIs
139         PromptInfo promptInfo = new PromptInfo();
140         for (int i = 0; i <= 7; i++) {
141             int authenticators = 1 << i;
142             promptInfo.setAuthenticators(authenticators);
143             assertTrue(Utils.isBiometricRequested(promptInfo));
144         }
145 
146         // The rest of the bits are not allowed to integrate with the public APIs
147         for (int i = 8; i < 32; i++) {
148             int authenticators = 1 << i;
149             promptInfo.setAuthenticators(authenticators);
150             assertFalse(Utils.isBiometricRequested(promptInfo));
151         }
152     }
153 
154     @Test
testIsValidAuthenticatorConfig()155     public void testIsValidAuthenticatorConfig() {
156         assertTrue(Utils.isValidAuthenticatorConfig(Authenticators.EMPTY_SET));
157 
158         assertTrue(Utils.isValidAuthenticatorConfig(Authenticators.BIOMETRIC_STRONG));
159 
160         assertTrue(Utils.isValidAuthenticatorConfig(Authenticators.BIOMETRIC_WEAK));
161 
162         assertTrue(Utils.isValidAuthenticatorConfig(Authenticators.DEVICE_CREDENTIAL));
163 
164         assertTrue(Utils.isValidAuthenticatorConfig(Authenticators.DEVICE_CREDENTIAL
165                 | Authenticators.BIOMETRIC_STRONG));
166 
167         assertTrue(Utils.isValidAuthenticatorConfig(Authenticators.DEVICE_CREDENTIAL
168                 | Authenticators.BIOMETRIC_WEAK));
169 
170         assertFalse(Utils.isValidAuthenticatorConfig(Authenticators.BIOMETRIC_CONVENIENCE));
171 
172         assertFalse(Utils.isValidAuthenticatorConfig(Authenticators.BIOMETRIC_CONVENIENCE
173                 | Authenticators.DEVICE_CREDENTIAL));
174 
175         assertFalse(Utils.isValidAuthenticatorConfig(Authenticators.BIOMETRIC_MAX_STRENGTH));
176 
177         assertFalse(Utils.isValidAuthenticatorConfig(Authenticators.BIOMETRIC_MIN_STRENGTH));
178 
179         // The rest of the bits are not allowed to integrate with the public APIs
180         for (int i = 8; i < 32; i++) {
181             final int authenticator = 1 << i;
182             if (authenticator == Authenticators.DEVICE_CREDENTIAL) {
183                 continue;
184             }
185             assertFalse(Utils.isValidAuthenticatorConfig(1 << i));
186         }
187     }
188 
189     @Test
testIsAtLeastStrength()190     public void testIsAtLeastStrength() {
191         int sensorStrength = Authenticators.BIOMETRIC_STRONG;
192         int requestedStrength = Authenticators.BIOMETRIC_WEAK;
193         assertTrue(Utils.isAtLeastStrength(sensorStrength, requestedStrength));
194 
195         requestedStrength = Authenticators.BIOMETRIC_STRONG;
196         assertTrue(Utils.isAtLeastStrength(sensorStrength, requestedStrength));
197 
198         sensorStrength = Authenticators.BIOMETRIC_WEAK;
199         requestedStrength = Authenticators.BIOMETRIC_STRONG;
200         assertFalse(Utils.isAtLeastStrength(sensorStrength, requestedStrength));
201 
202         requestedStrength = Authenticators.BIOMETRIC_WEAK;
203         assertTrue(Utils.isAtLeastStrength(sensorStrength, requestedStrength));
204 
205 
206         // Test invalid inputs
207 
208         sensorStrength = Authenticators.BIOMETRIC_STRONG;
209         requestedStrength = Authenticators.DEVICE_CREDENTIAL;
210         assertFalse(Utils.isAtLeastStrength(sensorStrength, requestedStrength));
211 
212         requestedStrength = 1 << 2;
213         assertFalse(Utils.isAtLeastStrength(sensorStrength, requestedStrength));
214     }
215 
216     @Test
testBiometricConstantsConversion()217     public void testBiometricConstantsConversion() {
218         final int[][] testCases = {
219                 {BiometricConstants.BIOMETRIC_SUCCESS,
220                         BiometricManager.BIOMETRIC_SUCCESS},
221                 {BiometricConstants.BIOMETRIC_ERROR_NO_BIOMETRICS,
222                         BiometricManager.BIOMETRIC_ERROR_NONE_ENROLLED},
223                 {BiometricConstants.BIOMETRIC_ERROR_NO_DEVICE_CREDENTIAL,
224                         BiometricManager.BIOMETRIC_ERROR_NONE_ENROLLED},
225                 {BiometricConstants.BIOMETRIC_ERROR_HW_UNAVAILABLE,
226                         BiometricManager.BIOMETRIC_ERROR_HW_UNAVAILABLE},
227                 {BiometricConstants.BIOMETRIC_ERROR_HW_NOT_PRESENT,
228                         BiometricManager.BIOMETRIC_ERROR_NO_HARDWARE},
229                 {BiometricConstants.BIOMETRIC_ERROR_LOCKOUT,
230                         BiometricManager.BIOMETRIC_SUCCESS},
231                 {BiometricConstants.BIOMETRIC_ERROR_LOCKOUT_PERMANENT,
232                         BiometricManager.BIOMETRIC_SUCCESS}
233         };
234 
235         for (int i = 0; i < testCases.length; i++) {
236             assertEquals(testCases[i][1],
237                     Utils.biometricConstantsToBiometricManager(testCases[i][0]));
238         }
239     }
240 
241     @Test
testGetAuthenticationTypeForResult_getsCorrectType()242     public void testGetAuthenticationTypeForResult_getsCorrectType() {
243         assertEquals(Utils.getAuthenticationTypeForResult(
244                 BiometricPrompt.DISMISSED_REASON_CREDENTIAL_CONFIRMED),
245                 BiometricPrompt.AUTHENTICATION_RESULT_TYPE_DEVICE_CREDENTIAL);
246         assertEquals(Utils.getAuthenticationTypeForResult(
247                 BiometricPrompt.DISMISSED_REASON_BIOMETRIC_CONFIRMED),
248                 BiometricPrompt.AUTHENTICATION_RESULT_TYPE_BIOMETRIC);
249         assertEquals(Utils.getAuthenticationTypeForResult(
250                 BiometricPrompt.DISMISSED_REASON_BIOMETRIC_CONFIRM_NOT_REQUIRED),
251                 BiometricPrompt.AUTHENTICATION_RESULT_TYPE_BIOMETRIC);
252     }
253 
254     @Test(expected = IllegalArgumentException.class)
testGetAuthResultType_throwsForInvalidReason()255     public void testGetAuthResultType_throwsForInvalidReason() {
256         Utils.getAuthenticationTypeForResult(BiometricPrompt.DISMISSED_REASON_NEGATIVE);
257     }
258 
259     @Test
testConfirmationSupported()260     public void testConfirmationSupported() {
261         assertTrue(Utils.isConfirmationSupported(BiometricAuthenticator.TYPE_FACE));
262         assertTrue(Utils.isConfirmationSupported(BiometricAuthenticator.TYPE_IRIS));
263         assertFalse(Utils.isConfirmationSupported(BiometricAuthenticator.TYPE_FINGERPRINT));
264     }
265 
266     @Test
testRemoveBiometricBits()267     public void testRemoveBiometricBits() {
268         @Authenticators.Types int authenticators = Integer.MAX_VALUE;
269         authenticators = Utils.removeBiometricBits(authenticators);
270         // All biometric bits are removed
271         assertEquals(0, authenticators & Authenticators.BIOMETRIC_MIN_STRENGTH);
272     }
273 }
274