blob: aec754048ed02272a266afdbff93198faf709017 [file] [log] [blame]
Kevin Chyn4858da42019-04-11 13:02:56 -07001/*
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
17package com.android.server.biometrics;
18
Curtis Belmonte13eb5812019-10-22 14:17:30 -070019import static android.hardware.biometrics.BiometricManager.Authenticators;
20
Kevin Chyn4858da42019-04-11 13:02:56 -070021import android.content.Context;
Ilya Matyukhin30f1dd82019-11-18 18:08:56 -080022import android.hardware.biometrics.BiometricConstants;
23import android.hardware.biometrics.BiometricManager;
Kevin Chync70d6b82019-10-03 15:32:37 -070024import android.hardware.biometrics.BiometricPrompt;
Curtis Belmonte6601bc32020-01-09 17:46:31 -080025import android.hardware.biometrics.BiometricPrompt.AuthenticationResultType;
Ilya Matyukhinef410e32020-02-04 13:39:48 -080026import android.hardware.biometrics.IBiometricNativeHandle;
Kevin Chyn4858da42019-04-11 13:02:56 -070027import android.os.Build;
Kevin Chync70d6b82019-10-03 15:32:37 -070028import android.os.Bundle;
Ilya Matyukhinef410e32020-02-04 13:39:48 -080029import android.os.NativeHandle;
Kevin Chyn16cac92f2019-06-12 12:52:16 -070030import android.os.UserHandle;
Kevin Chyn4858da42019-04-11 13:02:56 -070031import android.provider.Settings;
Ilya Matyukhin30f1dd82019-11-18 18:08:56 -080032import android.util.Slog;
Kevin Chyn4858da42019-04-11 13:02:56 -070033
Ilya Matyukhinef410e32020-02-04 13:39:48 -080034import java.io.FileDescriptor;
35import java.io.IOException;
36
Kevin Chyn4858da42019-04-11 13:02:56 -070037public class Utils {
38 public static boolean isDebugEnabled(Context context, int targetUserId) {
Kevin Chyn16cac92f2019-06-12 12:52:16 -070039 if (targetUserId == UserHandle.USER_NULL) {
40 return false;
41 }
42
Kevin Chyn4858da42019-04-11 13:02:56 -070043 if (!(Build.IS_ENG || Build.IS_USERDEBUG)) {
44 return false;
45 }
46
47 if (Settings.Secure.getIntForUser(context.getContentResolver(),
48 Settings.Secure.BIOMETRIC_DEBUG_ENABLED, 0,
49 targetUserId) == 0) {
50 return false;
51 }
52 return true;
53 }
Kevin Chync70d6b82019-10-03 15:32:37 -070054
55 /**
Curtis Belmonte13eb5812019-10-22 14:17:30 -070056 * Combines {@link BiometricPrompt#KEY_ALLOW_DEVICE_CREDENTIAL} with
57 * {@link BiometricPrompt#KEY_AUTHENTICATORS_ALLOWED}, as the former is not flexible enough.
Kevin Chync70d6b82019-10-03 15:32:37 -070058 */
59 public static void combineAuthenticatorBundles(Bundle bundle) {
Curtis Belmonte13eb5812019-10-22 14:17:30 -070060 // Cache and remove explicit ALLOW_DEVICE_CREDENTIAL boolean flag from the bundle.
61 final boolean deviceCredentialAllowed =
62 bundle.getBoolean(BiometricPrompt.KEY_ALLOW_DEVICE_CREDENTIAL, false);
Kevin Chync70d6b82019-10-03 15:32:37 -070063 bundle.remove(BiometricPrompt.KEY_ALLOW_DEVICE_CREDENTIAL);
64
Curtis Belmonte13eb5812019-10-22 14:17:30 -070065 final @Authenticators.Types int authenticators;
66 if (bundle.containsKey(BiometricPrompt.KEY_AUTHENTICATORS_ALLOWED)) {
67 // Ignore ALLOW_DEVICE_CREDENTIAL flag if AUTH_TYPES_ALLOWED is defined.
68 authenticators = bundle.getInt(BiometricPrompt.KEY_AUTHENTICATORS_ALLOWED, 0);
69 } else {
70 // Otherwise, use ALLOW_DEVICE_CREDENTIAL flag along with Weak+ biometrics by default.
71 authenticators = deviceCredentialAllowed
72 ? Authenticators.DEVICE_CREDENTIAL | Authenticators.BIOMETRIC_WEAK
73 : Authenticators.BIOMETRIC_WEAK;
Kevin Chync70d6b82019-10-03 15:32:37 -070074 }
Curtis Belmonte13eb5812019-10-22 14:17:30 -070075
Kevin Chync70d6b82019-10-03 15:32:37 -070076 bundle.putInt(BiometricPrompt.KEY_AUTHENTICATORS_ALLOWED, authenticators);
77 }
78
79 /**
Ilya Matyukhin30f1dd82019-11-18 18:08:56 -080080 * @param authenticators composed of one or more values from {@link Authenticators}
81 * @return true if device credential is allowed.
82 */
Kevin Chyn98e92252020-02-06 16:28:33 -080083 public static boolean isCredentialRequested(@Authenticators.Types int authenticators) {
Ilya Matyukhin30f1dd82019-11-18 18:08:56 -080084 return (authenticators & Authenticators.DEVICE_CREDENTIAL) != 0;
85 }
86
87 /**
Kevin Chync70d6b82019-10-03 15:32:37 -070088 * @param bundle should be first processed by {@link #combineAuthenticatorBundles(Bundle)}
Ilya Matyukhin30f1dd82019-11-18 18:08:56 -080089 * @return true if device credential is allowed.
Kevin Chync70d6b82019-10-03 15:32:37 -070090 */
Kevin Chyn98e92252020-02-06 16:28:33 -080091 public static boolean isCredentialRequested(Bundle bundle) {
92 return isCredentialRequested(bundle.getInt(BiometricPrompt.KEY_AUTHENTICATORS_ALLOWED));
Ilya Matyukhin30f1dd82019-11-18 18:08:56 -080093 }
94
95 /**
Kevin Chynd04b43d2019-12-13 12:56:41 -080096 * Checks if any of the publicly defined strengths are set.
97 *
Ilya Matyukhin30f1dd82019-11-18 18:08:56 -080098 * @param authenticators composed of one or more values from {@link Authenticators}
99 * @return minimal allowed biometric strength or 0 if biometric authentication is not allowed.
100 */
Kevin Chynd04b43d2019-12-13 12:56:41 -0800101 public static int getPublicBiometricStrength(@Authenticators.Types int authenticators) {
Ilya Matyukhin30f1dd82019-11-18 18:08:56 -0800102 // Only biometrics WEAK and above are allowed to integrate with the public APIs.
103 return authenticators & Authenticators.BIOMETRIC_WEAK;
104 }
105
106 /**
Kevin Chynd04b43d2019-12-13 12:56:41 -0800107 * Checks if any of the publicly defined strengths are set.
108 *
Ilya Matyukhin30f1dd82019-11-18 18:08:56 -0800109 * @param bundle should be first processed by {@link #combineAuthenticatorBundles(Bundle)}
110 * @return minimal allowed biometric strength or 0 if biometric authentication is not allowed.
111 */
Kevin Chynd04b43d2019-12-13 12:56:41 -0800112 public static int getPublicBiometricStrength(Bundle bundle) {
113 return getPublicBiometricStrength(
114 bundle.getInt(BiometricPrompt.KEY_AUTHENTICATORS_ALLOWED));
Ilya Matyukhin30f1dd82019-11-18 18:08:56 -0800115 }
116
117 /**
Kevin Chynd04b43d2019-12-13 12:56:41 -0800118 * Checks if any of the publicly defined strengths are set.
119 *
Ilya Matyukhin30f1dd82019-11-18 18:08:56 -0800120 * @param bundle should be first processed by {@link #combineAuthenticatorBundles(Bundle)}
121 * @return true if biometric authentication is allowed.
122 */
Kevin Chyn98e92252020-02-06 16:28:33 -0800123 public static boolean isBiometricRequested(Bundle bundle) {
Kevin Chynd04b43d2019-12-13 12:56:41 -0800124 return getPublicBiometricStrength(bundle) != 0;
Ilya Matyukhin30f1dd82019-11-18 18:08:56 -0800125 }
126
127 /**
128 * @param sensorStrength the strength of the sensor
129 * @param requestedStrength the strength that it must meet
130 * @return true only if the sensor is at least as strong as the requested strength
131 */
132 public static boolean isAtLeastStrength(int sensorStrength, int requestedStrength) {
Kevin Chyn7d07c892020-02-18 18:18:17 -0800133 // Clear out any bits that are not reserved for biometric
134 sensorStrength = sensorStrength & Authenticators.BIOMETRIC_MIN_STRENGTH;
135
Ilya Matyukhin30f1dd82019-11-18 18:08:56 -0800136 // If the authenticator contains bits outside of the requested strength, it is too weak.
Kevin Chyn7d07c892020-02-18 18:18:17 -0800137 if ((sensorStrength & ~requestedStrength) != 0) {
138 return false;
139 }
140
141 for (int i = Authenticators.BIOMETRIC_MAX_STRENGTH;
142 i <= requestedStrength; i = i << 1 | 1) {
143 if (i == sensorStrength) {
144 return true;
145 }
146 }
147
148 Slog.e(BiometricService.TAG, "Unknown sensorStrength: " + sensorStrength
149 + ", requestedStrength: " + requestedStrength);
150 return false;
Ilya Matyukhin30f1dd82019-11-18 18:08:56 -0800151 }
152
153 /**
Kevin Chynd04b43d2019-12-13 12:56:41 -0800154 * Checks if the authenticator configuration is a valid combination of the public APIs
155 * @param bundle
156 * @return
157 */
158 public static boolean isValidAuthenticatorConfig(Bundle bundle) {
159 final int authenticators = bundle.getInt(BiometricPrompt.KEY_AUTHENTICATORS_ALLOWED);
160 return isValidAuthenticatorConfig(authenticators);
161 }
162
163 /**
164 * Checks if the authenticator configuration is a valid combination of the public APIs
165 * @param authenticators
166 * @return
167 */
168 public static boolean isValidAuthenticatorConfig(int authenticators) {
169 // The caller is not required to set the authenticators. But if they do, check the below.
170 if (authenticators == 0) {
171 return true;
172 }
173
174 // Check if any of the non-biometric and non-credential bits are set. If so, this is
175 // invalid.
176 final int testBits = ~(Authenticators.DEVICE_CREDENTIAL
177 | Authenticators.BIOMETRIC_MIN_STRENGTH);
178 if ((authenticators & testBits) != 0) {
179 Slog.e(BiometricService.TAG, "Non-biometric, non-credential bits found."
180 + " Authenticators: " + authenticators);
181 return false;
182 }
183
184 // Check that biometrics bits are either NONE, WEAK, or STRONG. If NONE, DEVICE_CREDENTIAL
185 // should be set.
186 final int biometricBits = authenticators & Authenticators.BIOMETRIC_MIN_STRENGTH;
187 if (biometricBits == Authenticators.EMPTY_SET
Kevin Chyn98e92252020-02-06 16:28:33 -0800188 && isCredentialRequested(authenticators)) {
Kevin Chynd04b43d2019-12-13 12:56:41 -0800189 return true;
190 } else if (biometricBits == Authenticators.BIOMETRIC_STRONG) {
191 return true;
192 } else if (biometricBits == Authenticators.BIOMETRIC_WEAK) {
193 return true;
194 }
195
196 Slog.e(BiometricService.TAG, "Unsupported biometric flags. Authenticators: "
197 + authenticators);
198 // Non-supported biometric flags are being used
199 return false;
200 }
201
202 /**
Ilya Matyukhin30f1dd82019-11-18 18:08:56 -0800203 * Converts error codes from BiometricConstants, which are used in most of the internal plumbing
204 * and eventually returned to {@link BiometricPrompt.AuthenticationCallback} to public
205 * {@link BiometricManager} constants, which are used by APIs such as
206 * {@link BiometricManager#canAuthenticate(int)}
207 *
208 * @param biometricConstantsCode see {@link BiometricConstants}
209 * @return see {@link BiometricManager}
210 */
211 public static int biometricConstantsToBiometricManager(int biometricConstantsCode) {
212 final int biometricManagerCode;
213
214 switch (biometricConstantsCode) {
215 case BiometricConstants.BIOMETRIC_SUCCESS:
216 biometricManagerCode = BiometricManager.BIOMETRIC_SUCCESS;
217 break;
218 case BiometricConstants.BIOMETRIC_ERROR_NO_BIOMETRICS:
219 case BiometricConstants.BIOMETRIC_ERROR_NO_DEVICE_CREDENTIAL:
220 biometricManagerCode = BiometricManager.BIOMETRIC_ERROR_NONE_ENROLLED;
221 break;
222 case BiometricConstants.BIOMETRIC_ERROR_HW_UNAVAILABLE:
223 biometricManagerCode = BiometricManager.BIOMETRIC_ERROR_HW_UNAVAILABLE;
224 break;
225 case BiometricConstants.BIOMETRIC_ERROR_HW_NOT_PRESENT:
226 biometricManagerCode = BiometricManager.BIOMETRIC_ERROR_NO_HARDWARE;
227 break;
Kevin Chyn98e92252020-02-06 16:28:33 -0800228 case BiometricConstants.BIOMETRIC_ERROR_SECURITY_UPDATE_REQUIRED:
229 biometricManagerCode = BiometricManager.BIOMETRIC_ERROR_SECURITY_UPDATE_REQUIRED;
230 break;
Ilya Matyukhin30f1dd82019-11-18 18:08:56 -0800231 default:
232 Slog.e(BiometricService.TAG, "Unhandled result code: " + biometricConstantsCode);
233 biometricManagerCode = BiometricManager.BIOMETRIC_ERROR_HW_UNAVAILABLE;
234 break;
235 }
236 return biometricManagerCode;
Kevin Chync70d6b82019-10-03 15:32:37 -0700237 }
Curtis Belmonte6601bc32020-01-09 17:46:31 -0800238
239 /**
240 * Converts a {@link BiometricPrompt} dismissal reason to an authentication type at the level of
241 * granularity supported by {@link BiometricPrompt.AuthenticationResult}.
242 *
243 * @param reason The reason that the {@link BiometricPrompt} was dismissed. Must be one of:
244 * {@link BiometricPrompt#DISMISSED_REASON_CREDENTIAL_CONFIRMED},
245 * {@link BiometricPrompt#DISMISSED_REASON_BIOMETRIC_CONFIRMED}, or
246 * {@link BiometricPrompt#DISMISSED_REASON_BIOMETRIC_CONFIRM_NOT_REQUIRED}
247 * @return An integer representing the authentication type for {@link
248 * BiometricPrompt.AuthenticationResult}.
249 * @throws IllegalArgumentException if given an invalid dismissal reason.
250 */
251 public static @AuthenticationResultType int getAuthenticationTypeForResult(int reason) {
252 switch (reason) {
253 case BiometricPrompt.DISMISSED_REASON_CREDENTIAL_CONFIRMED:
254 return BiometricPrompt.AUTHENTICATION_RESULT_TYPE_DEVICE_CREDENTIAL;
255
256 case BiometricPrompt.DISMISSED_REASON_BIOMETRIC_CONFIRMED:
257 case BiometricPrompt.DISMISSED_REASON_BIOMETRIC_CONFIRM_NOT_REQUIRED:
258 return BiometricPrompt.AUTHENTICATION_RESULT_TYPE_BIOMETRIC;
259
260 default:
261 throw new IllegalArgumentException("Unsupported dismissal reason: " + reason);
262 }
263 }
Ilya Matyukhinef410e32020-02-04 13:39:48 -0800264
265 /**
266 * Converts an {@link IBiometricNativeHandle} to a {@link NativeHandle} by duplicating the
267 * the underlying file descriptors.
268 *
269 * Both the original and new handle must be closed after use.
270 *
271 * @param h {@link IBiometricNativeHandle} received as a binder call argument. Usually used to
272 * identify a WindowManager window. Can be null.
273 * @return A {@link NativeHandle} representation of {@code h}. Will be null if either {@code h}
274 * or its contents are null.
275 */
276 public static NativeHandle dupNativeHandle(IBiometricNativeHandle h) {
277 NativeHandle handle = null;
278 if (h != null && h.fds != null && h.ints != null) {
279 FileDescriptor[] fds = new FileDescriptor[h.fds.length];
280 for (int i = 0; i < h.fds.length; ++i) {
281 try {
282 fds[i] = h.fds[i].dup().getFileDescriptor();
283 } catch (IOException e) {
284 return null;
285 }
286 }
287 handle = new NativeHandle(fds, h.ints, true /* own */);
288 }
289 return handle;
290 }
Kevin Chyn4858da42019-04-11 13:02:56 -0700291}