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