1 /* 2 * Copyright (C) 2020 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.sensors; 18 19 import android.annotation.IntDef; 20 import android.annotation.NonNull; 21 import android.annotation.Nullable; 22 import android.app.ActivityTaskManager; 23 import android.app.TaskStackListener; 24 import android.content.Context; 25 import android.content.pm.ApplicationInfo; 26 import android.hardware.biometrics.AuthenticateOptions; 27 import android.hardware.biometrics.BiometricAuthenticator; 28 import android.hardware.biometrics.BiometricConstants; 29 import android.hardware.biometrics.BiometricManager; 30 import android.hardware.biometrics.BiometricOverlayConstants; 31 import android.os.IBinder; 32 import android.os.RemoteException; 33 import android.security.KeyStore; 34 import android.util.EventLog; 35 import android.util.Slog; 36 37 import com.android.server.biometrics.BiometricsProto; 38 import com.android.server.biometrics.Utils; 39 import com.android.server.biometrics.log.BiometricContext; 40 import com.android.server.biometrics.log.BiometricLogger; 41 42 import java.util.ArrayList; 43 import java.util.function.Supplier; 44 45 /** 46 * A class to keep track of the authentication state for a given client. 47 */ 48 public abstract class AuthenticationClient<T, O extends AuthenticateOptions> 49 extends AcquisitionClient<T> implements AuthenticationConsumer { 50 51 // New, has not started yet 52 public static final int STATE_NEW = 0; 53 // Framework/HAL have started this operation 54 public static final int STATE_STARTED = 1; 55 // Operation is started, but requires some user action to start (such as finger lift & re-touch) 56 public static final int STATE_STARTED_PAUSED = 2; 57 // Same as above, except auth was attempted (rejected, timed out, etc). 58 public static final int STATE_STARTED_PAUSED_ATTEMPTED = 3; 59 // Done, errored, canceled, etc. HAL/framework are not running this sensor anymore. 60 public static final int STATE_STOPPED = 4; 61 62 @IntDef({STATE_NEW, 63 STATE_STARTED, 64 STATE_STARTED_PAUSED, 65 STATE_STARTED_PAUSED_ATTEMPTED, 66 STATE_STOPPED}) 67 @interface State {} 68 private static final String TAG = "Biometrics/AuthenticationClient"; 69 protected final long mOperationId; 70 private final boolean mIsStrongBiometric; 71 private final boolean mRequireConfirmation; 72 private final ActivityTaskManager mActivityTaskManager; 73 private final BiometricManager mBiometricManager; 74 @Nullable 75 private final TaskStackListener mTaskStackListener; 76 private final LockoutTracker mLockoutTracker; 77 private final O mOptions; 78 private final boolean mIsRestricted; 79 private final boolean mAllowBackgroundAuthentication; 80 // TODO: This is currently hard to maintain, as each AuthenticationClient subclass must update 81 // the state. We should think of a way to improve this in the future. 82 @State 83 protected int mState = STATE_NEW; 84 private long mStartTimeMs; 85 private boolean mAuthAttempted; 86 private boolean mAuthSuccess = false; 87 private final int mSensorStrength; 88 // This is used to determine if we should use the old lockout counter (HIDL) or the new lockout 89 // counter implementation (AIDL) 90 private final boolean mShouldUseLockoutTracker; 91 AuthenticationClient(@onNull Context context, @NonNull Supplier<T> lazyDaemon, @NonNull IBinder token, @NonNull ClientMonitorCallbackConverter listener, long operationId, boolean restricted, @NonNull O options, int cookie, boolean requireConfirmation, @NonNull BiometricLogger biometricLogger, @NonNull BiometricContext biometricContext, boolean isStrongBiometric, @Nullable TaskStackListener taskStackListener, @NonNull LockoutTracker lockoutTracker, boolean allowBackgroundAuthentication, boolean shouldVibrate, int sensorStrength)92 public AuthenticationClient(@NonNull Context context, @NonNull Supplier<T> lazyDaemon, 93 @NonNull IBinder token, @NonNull ClientMonitorCallbackConverter listener, 94 long operationId, boolean restricted, @NonNull O options, 95 int cookie, boolean requireConfirmation, 96 @NonNull BiometricLogger biometricLogger, @NonNull BiometricContext biometricContext, 97 boolean isStrongBiometric, @Nullable TaskStackListener taskStackListener, 98 @NonNull LockoutTracker lockoutTracker, boolean allowBackgroundAuthentication, 99 boolean shouldVibrate, int sensorStrength) { 100 super(context, lazyDaemon, token, listener, options.getUserId(), 101 options.getOpPackageName(), cookie, options.getSensorId(), shouldVibrate, 102 biometricLogger, biometricContext); 103 mIsStrongBiometric = isStrongBiometric; 104 mOperationId = operationId; 105 mRequireConfirmation = requireConfirmation; 106 mActivityTaskManager = getActivityTaskManager(); 107 mBiometricManager = context.getSystemService(BiometricManager.class); 108 mTaskStackListener = taskStackListener; 109 mLockoutTracker = lockoutTracker; 110 mIsRestricted = restricted; 111 mAllowBackgroundAuthentication = allowBackgroundAuthentication; 112 mShouldUseLockoutTracker = lockoutTracker != null; 113 mSensorStrength = sensorStrength; 114 mOptions = options; 115 } 116 117 @LockoutTracker.LockoutMode handleFailedAttempt(int userId)118 public int handleFailedAttempt(int userId) { 119 return LockoutTracker.LOCKOUT_NONE; 120 } 121 getStartTimeMs()122 protected long getStartTimeMs() { 123 return mStartTimeMs; 124 } 125 getActivityTaskManager()126 protected ActivityTaskManager getActivityTaskManager() { 127 return ActivityTaskManager.getInstance(); 128 } 129 130 @Override binderDied()131 public void binderDied() { 132 final boolean clearListener = !isBiometricPrompt(); 133 binderDiedInternal(clearListener); 134 } 135 getOperationId()136 public long getOperationId() { 137 return mOperationId; 138 } 139 isRestricted()140 public boolean isRestricted() { 141 return mIsRestricted; 142 } 143 isKeyguard()144 public boolean isKeyguard() { 145 return Utils.isKeyguard(getContext(), getOwnerString()); 146 } 147 isSettings()148 private boolean isSettings() { 149 return Utils.isSettings(getContext(), getOwnerString()); 150 } 151 152 /** The options requested at the start of the operation. */ getOptions()153 protected O getOptions() { 154 return mOptions; 155 } 156 157 @Override isCryptoOperation()158 protected boolean isCryptoOperation() { 159 return mOperationId != 0; 160 } 161 162 @Override onAuthenticated(BiometricAuthenticator.Identifier identifier, boolean authenticated, ArrayList<Byte> hardwareAuthToken)163 public void onAuthenticated(BiometricAuthenticator.Identifier identifier, 164 boolean authenticated, ArrayList<Byte> hardwareAuthToken) { 165 getLogger().logOnAuthenticated(getContext(), getOperationContext(), 166 authenticated, mRequireConfirmation, getTargetUserId(), isBiometricPrompt()); 167 168 final ClientMonitorCallbackConverter listener = getListener(); 169 170 if (DEBUG) { 171 Slog.v(TAG, "onAuthenticated(" + authenticated + ")" 172 + ", ID:" + identifier.getBiometricId() 173 + ", Owner: " + getOwnerString() 174 + ", isBP: " + isBiometricPrompt() 175 + ", listener: " + listener 176 + ", requireConfirmation: " + mRequireConfirmation 177 + ", user: " + getTargetUserId() 178 + ", clientMonitor: " + this); 179 } 180 181 final PerformanceTracker pm = PerformanceTracker.getInstanceForSensorId(getSensorId()); 182 if (isCryptoOperation()) { 183 pm.incrementCryptoAuthForUser(getTargetUserId(), authenticated); 184 } else { 185 pm.incrementAuthForUser(getTargetUserId(), authenticated); 186 } 187 188 if (mAllowBackgroundAuthentication) { 189 Slog.w(TAG, "Allowing background authentication," 190 + " this is allowed only for platform or test invocations"); 191 } 192 193 // Ensure authentication only succeeds if the client activity is on top. 194 boolean isBackgroundAuth = false; 195 if (!mAllowBackgroundAuthentication && authenticated 196 && !Utils.isKeyguard(getContext(), getOwnerString()) 197 && !Utils.isSystem(getContext(), getOwnerString())) { 198 isBackgroundAuth = Utils.isBackground(getOwnerString()); 199 } 200 201 // Fail authentication if we can't confirm the client activity is on top. 202 if (isBackgroundAuth) { 203 Slog.e(TAG, "Failing possible background authentication"); 204 authenticated = false; 205 206 // SafetyNet logging for exploitation attempts of b/159249069. 207 final ApplicationInfo appInfo = getContext().getApplicationInfo(); 208 EventLog.writeEvent(0x534e4554, "159249069", appInfo != null ? appInfo.uid : -1, 209 "Attempted background authentication"); 210 } 211 212 if (authenticated) { 213 // SafetyNet logging for b/159249069 if constraint is violated. 214 if (isBackgroundAuth) { 215 final ApplicationInfo appInfo = getContext().getApplicationInfo(); 216 EventLog.writeEvent(0x534e4554, "159249069", appInfo != null ? appInfo.uid : -1, 217 "Successful background authentication!"); 218 } 219 220 mAuthSuccess = true; 221 markAlreadyDone(); 222 223 if (mTaskStackListener != null) { 224 mActivityTaskManager.unregisterTaskStackListener(mTaskStackListener); 225 } 226 227 final byte[] byteToken = new byte[hardwareAuthToken.size()]; 228 for (int i = 0; i < hardwareAuthToken.size(); i++) { 229 byteToken[i] = hardwareAuthToken.get(i); 230 } 231 232 if (mIsStrongBiometric) { 233 mBiometricManager.resetLockoutTimeBound(getToken(), 234 getContext().getOpPackageName(), 235 getSensorId(), getTargetUserId(), byteToken); 236 } 237 238 // For BP, BiometricService will add the authToken to Keystore. 239 if (!isBiometricPrompt() && mIsStrongBiometric) { 240 final int result = KeyStore.getInstance().addAuthToken(byteToken); 241 if (result != KeyStore.NO_ERROR) { 242 Slog.d(TAG, "Error adding auth token : " + result); 243 } else { 244 Slog.d(TAG, "addAuthToken: " + result); 245 } 246 } else { 247 Slog.d(TAG, "Skipping addAuthToken"); 248 } 249 try { 250 if (listener != null) { 251 if (!mIsRestricted) { 252 listener.onAuthenticationSucceeded(getSensorId(), identifier, byteToken, 253 getTargetUserId(), mIsStrongBiometric); 254 } else { 255 listener.onAuthenticationSucceeded(getSensorId(), null /* identifier */, 256 byteToken, 257 getTargetUserId(), mIsStrongBiometric); 258 } 259 } else { 260 Slog.e(TAG, "Received successful auth, but client was not listening"); 261 } 262 } catch (RemoteException e) { 263 Slog.e(TAG, "Unable to notify listener", e); 264 mCallback.onClientFinished(this, false); 265 return; 266 } 267 } else { 268 if (isBackgroundAuth) { 269 Slog.e(TAG, "Sending cancel to client(Due to background auth)"); 270 if (mTaskStackListener != null) { 271 mActivityTaskManager.unregisterTaskStackListener(mTaskStackListener); 272 } 273 sendCancelOnly(getListener()); 274 mCallback.onClientFinished(this, false); 275 } else { 276 // Allow system-defined limit of number of attempts before giving up 277 if (mShouldUseLockoutTracker) { 278 @LockoutTracker.LockoutMode final int lockoutMode = 279 handleFailedAttempt(getTargetUserId()); 280 if (lockoutMode != LockoutTracker.LOCKOUT_NONE) { 281 markAlreadyDone(); 282 } 283 } 284 285 try { 286 if (listener != null) { 287 listener.onAuthenticationFailed(getSensorId()); 288 } else { 289 Slog.e(TAG, "Received failed auth, but client was not listening"); 290 } 291 } catch (RemoteException e) { 292 Slog.e(TAG, "Unable to notify listener", e); 293 mCallback.onClientFinished(this, false); 294 return; 295 } 296 } 297 } 298 AuthenticationClient.this.handleLifecycleAfterAuth(authenticated); 299 } 300 sendCancelOnly(@ullable ClientMonitorCallbackConverter listener)301 private void sendCancelOnly(@Nullable ClientMonitorCallbackConverter listener) { 302 if (listener == null) { 303 Slog.e(TAG, "Unable to sendAuthenticationCanceled, listener null"); 304 return; 305 } 306 try { 307 listener.onError(getSensorId(), 308 getCookie(), 309 BiometricConstants.BIOMETRIC_ERROR_CANCELED, 310 0 /* vendorCode */); 311 } catch (RemoteException e) { 312 Slog.e(TAG, "Remote exception", e); 313 } 314 } 315 316 @Override onAcquired(int acquiredInfo, int vendorCode)317 public void onAcquired(int acquiredInfo, int vendorCode) { 318 super.onAcquired(acquiredInfo, vendorCode); 319 } 320 321 @Override onError(@iometricConstants.Errors int errorCode, int vendorCode)322 public void onError(@BiometricConstants.Errors int errorCode, int vendorCode) { 323 super.onError(errorCode, vendorCode); 324 mState = STATE_STOPPED; 325 } 326 327 /** 328 * Start authentication 329 */ 330 @Override start(@onNull ClientMonitorCallback callback)331 public void start(@NonNull ClientMonitorCallback callback) { 332 super.start(callback); 333 334 final @LockoutTracker.LockoutMode int lockoutMode; 335 if (mShouldUseLockoutTracker) { 336 lockoutMode = mLockoutTracker.getLockoutModeForUser(getTargetUserId()); 337 } else { 338 lockoutMode = getBiometricContext().getAuthSessionCoordinator() 339 .getLockoutStateFor(getTargetUserId(), mSensorStrength); 340 } 341 342 if (lockoutMode != LockoutTracker.LOCKOUT_NONE) { 343 Slog.v(TAG, "In lockout mode(" + lockoutMode + ") ; disallowing authentication"); 344 int errorCode = lockoutMode == LockoutTracker.LOCKOUT_TIMED 345 ? BiometricConstants.BIOMETRIC_ERROR_LOCKOUT 346 : BiometricConstants.BIOMETRIC_ERROR_LOCKOUT_PERMANENT; 347 onError(errorCode, 0 /* vendorCode */); 348 return; 349 } 350 351 if (mTaskStackListener != null) { 352 mActivityTaskManager.registerTaskStackListener(mTaskStackListener); 353 } 354 355 Slog.d(TAG, "Requesting auth for " + getOwnerString()); 356 357 mStartTimeMs = System.currentTimeMillis(); 358 mAuthAttempted = true; 359 startHalOperation(); 360 } 361 362 @Override cancel()363 public void cancel() { 364 super.cancel(); 365 if (mTaskStackListener != null) { 366 mActivityTaskManager.unregisterTaskStackListener(mTaskStackListener); 367 } 368 } 369 370 /** 371 * Handles lifecycle, e.g. {@link BiometricScheduler} after authentication. This is necessary 372 * as different clients handle the lifecycle of authentication success/reject differently. I.E. 373 * Fingerprint does not finish authentication when it is rejected. 374 */ handleLifecycleAfterAuth(boolean authenticated)375 protected abstract void handleLifecycleAfterAuth(boolean authenticated); 376 377 /** 378 * @return true if a user was detected (i.e. face was found, fingerprint sensor was touched. 379 * etc) 380 */ wasUserDetected()381 public abstract boolean wasUserDetected(); 382 383 @State getState()384 public int getState() { 385 return mState; 386 } 387 388 @Override getProtoEnum()389 public int getProtoEnum() { 390 return BiometricsProto.CM_AUTHENTICATE; 391 } 392 393 @Override interruptsPrecedingClients()394 public boolean interruptsPrecedingClients() { 395 return true; 396 } 397 wasAuthAttempted()398 public boolean wasAuthAttempted() { 399 return mAuthAttempted; 400 } 401 402 /** If an auth attempt completed successfully. */ wasAuthSuccessful()403 public boolean wasAuthSuccessful() { 404 return mAuthSuccess; 405 } 406 getSensorStrength()407 protected int getSensorStrength() { 408 return mSensorStrength; 409 } 410 getLockoutTracker()411 protected LockoutTracker getLockoutTracker() { 412 return mLockoutTracker; 413 } 414 getShowOverlayReason()415 protected int getShowOverlayReason() { 416 if (isKeyguard()) { 417 return BiometricOverlayConstants.REASON_AUTH_KEYGUARD; 418 } else if (isBiometricPrompt()) { 419 // BP reason always takes precedent over settings, since callers from within 420 // settings can always invoke BP. 421 return BiometricOverlayConstants.REASON_AUTH_BP; 422 } else if (isSettings()) { 423 // This is pretty much only for FingerprintManager#authenticate usage from 424 // FingerprintSettings. 425 return BiometricOverlayConstants.REASON_AUTH_SETTINGS; 426 } else { 427 return BiometricOverlayConstants.REASON_AUTH_OTHER; 428 } 429 } 430 } 431