Merge changes from topic "biometric-and-credential"
* changes: Always start AuthController Clean up biometric system server
This commit is contained in:
@@ -922,17 +922,11 @@ public final class SystemServiceRegistry {
|
||||
@Override
|
||||
public BiometricManager createService(ContextImpl ctx)
|
||||
throws ServiceNotFoundException {
|
||||
if (BiometricManager.hasBiometrics(ctx)) {
|
||||
final IBinder binder =
|
||||
ServiceManager.getServiceOrThrow(Context.AUTH_SERVICE);
|
||||
final IAuthService service =
|
||||
IAuthService.Stub.asInterface(binder);
|
||||
return new BiometricManager(ctx.getOuterContext(), service);
|
||||
} else {
|
||||
// Allow access to the manager when service is null. This saves memory
|
||||
// on devices without biometric hardware.
|
||||
return new BiometricManager(ctx.getOuterContext(), null);
|
||||
}
|
||||
final IBinder binder =
|
||||
ServiceManager.getServiceOrThrow(Context.AUTH_SERVICE);
|
||||
final IAuthService service =
|
||||
IAuthService.Stub.asInterface(binder);
|
||||
return new BiometricManager(ctx.getOuterContext(), service);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -25,7 +25,6 @@ import android.annotation.RequiresPermission;
|
||||
import android.annotation.SystemApi;
|
||||
import android.annotation.SystemService;
|
||||
import android.content.Context;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.os.RemoteException;
|
||||
import android.util.Slog;
|
||||
|
||||
@@ -160,19 +159,6 @@ public class BiometricManager {
|
||||
|
||||
private final Context mContext;
|
||||
private final IAuthService mService;
|
||||
private final boolean mHasHardware;
|
||||
|
||||
/**
|
||||
* @param context
|
||||
* @return
|
||||
* @hide
|
||||
*/
|
||||
public static boolean hasBiometrics(Context context) {
|
||||
final PackageManager pm = context.getPackageManager();
|
||||
return pm.hasSystemFeature(PackageManager.FEATURE_FINGERPRINT)
|
||||
|| pm.hasSystemFeature(PackageManager.FEATURE_IRIS)
|
||||
|| pm.hasSystemFeature(PackageManager.FEATURE_FACE);
|
||||
}
|
||||
|
||||
/**
|
||||
* @hide
|
||||
@@ -182,8 +168,6 @@ public class BiometricManager {
|
||||
public BiometricManager(Context context, IAuthService service) {
|
||||
mContext = context;
|
||||
mService = service;
|
||||
|
||||
mHasHardware = hasBiometrics(context);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -249,12 +233,8 @@ public class BiometricManager {
|
||||
throw e.rethrowFromSystemServer();
|
||||
}
|
||||
} else {
|
||||
if (!mHasHardware) {
|
||||
return BIOMETRIC_ERROR_NO_HARDWARE;
|
||||
} else {
|
||||
Slog.w(TAG, "hasEnrolledBiometrics(): Service not connected");
|
||||
return BIOMETRIC_ERROR_HW_UNAVAILABLE;
|
||||
}
|
||||
Slog.w(TAG, "hasEnrolledBiometrics(): Service not connected");
|
||||
return BIOMETRIC_ERROR_HW_UNAVAILABLE;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -331,5 +311,25 @@ public class BiometricManager {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a list of AuthenticatorIDs for biometric authenticators which have 1) enrolled templates,
|
||||
* and 2) meet the requirements for integrating with Keystore. The AuthenticatorIDs are known
|
||||
* in Keystore land as SIDs, and are used during key generation.
|
||||
* @hide
|
||||
*/
|
||||
@RequiresPermission(USE_BIOMETRIC_INTERNAL)
|
||||
public long[] getAuthenticatorIds() {
|
||||
if (mService != null) {
|
||||
try {
|
||||
return mService.getAuthenticatorIds();
|
||||
} catch (RemoteException e) {
|
||||
throw e.rethrowFromSystemServer();
|
||||
}
|
||||
} else {
|
||||
Slog.w(TAG, "getAuthenticatorIds(): Service not connected");
|
||||
return new long[0];
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -898,29 +898,24 @@ public class BiometricPrompt implements BiometricAuthenticator, BiometricConstan
|
||||
mExecutor = executor;
|
||||
mAuthenticationCallback = callback;
|
||||
final long sessionId = crypto != null ? crypto.getOpId() : 0;
|
||||
if (BiometricManager.hasBiometrics(mContext)) {
|
||||
final Bundle bundle;
|
||||
if (crypto != null) {
|
||||
// Allowed authenticators should default to BIOMETRIC_STRONG for crypto auth.
|
||||
// Note that we use a new bundle here so as to not overwrite the application's
|
||||
// preference, since it is possible that the same prompt configuration be used
|
||||
// without a crypto object later.
|
||||
bundle = new Bundle(mBundle);
|
||||
bundle.putInt(KEY_AUTHENTICATORS_ALLOWED,
|
||||
mBundle.getInt(KEY_AUTHENTICATORS_ALLOWED,
|
||||
Authenticators.BIOMETRIC_STRONG));
|
||||
} else {
|
||||
bundle = mBundle;
|
||||
}
|
||||
|
||||
mService.authenticate(mToken, sessionId, userId, mBiometricServiceReceiver,
|
||||
mContext.getOpPackageName(), bundle);
|
||||
final Bundle bundle;
|
||||
if (crypto != null) {
|
||||
// Allowed authenticators should default to BIOMETRIC_STRONG for crypto auth.
|
||||
// Note that we use a new bundle here so as to not overwrite the application's
|
||||
// preference, since it is possible that the same prompt configuration be used
|
||||
// without a crypto object later.
|
||||
bundle = new Bundle(mBundle);
|
||||
bundle.putInt(KEY_AUTHENTICATORS_ALLOWED,
|
||||
mBundle.getInt(KEY_AUTHENTICATORS_ALLOWED,
|
||||
Authenticators.BIOMETRIC_STRONG));
|
||||
} else {
|
||||
mExecutor.execute(() -> {
|
||||
callback.onAuthenticationError(BiometricPrompt.BIOMETRIC_ERROR_HW_NOT_PRESENT,
|
||||
mContext.getString(R.string.biometric_error_hw_unavailable));
|
||||
});
|
||||
bundle = mBundle;
|
||||
}
|
||||
|
||||
mService.authenticate(mToken, sessionId, userId, mBiometricServiceReceiver,
|
||||
mContext.getOpPackageName(), bundle);
|
||||
|
||||
} catch (RemoteException e) {
|
||||
Log.e(TAG, "Remote exception while authenticating", e);
|
||||
mExecutor.execute(() -> {
|
||||
|
||||
@@ -51,4 +51,9 @@ interface IAuthService {
|
||||
|
||||
// Reset the lockout when user authenticates with strong auth (e.g. PIN, pattern or password)
|
||||
void resetLockout(in byte [] token);
|
||||
|
||||
// Get a list of AuthenticatorIDs for authenticators which have enrolled templates and meet
|
||||
// the requirements for integrating with Keystore. The AuthenticatorID are known in Keystore
|
||||
// land as SIDs, and are used during key generation.
|
||||
long[] getAuthenticatorIds();
|
||||
}
|
||||
|
||||
@@ -55,4 +55,7 @@ interface IBiometricAuthenticator {
|
||||
|
||||
// Explicitly set the active user (for enrolling work profile)
|
||||
void setActiveUser(int uid);
|
||||
|
||||
// Gets the authenticator ID representing the current set of enrolled templates
|
||||
long getAuthenticatorId();
|
||||
}
|
||||
|
||||
@@ -61,4 +61,9 @@ interface IBiometricService {
|
||||
|
||||
// Reset the lockout when user authenticates with strong auth (e.g. PIN, pattern or password)
|
||||
void resetLockout(in byte [] token);
|
||||
|
||||
// Get a list of AuthenticatorIDs for authenticators which have enrolled templates and meet
|
||||
// the requirements for integrating with Keystore. The AuthenticatorID are known in Keystore
|
||||
// land as SIDs, and are used during key generation.
|
||||
long[] getAuthenticatorIds();
|
||||
}
|
||||
|
||||
@@ -586,25 +586,6 @@ public class FaceManager implements BiometricAuthenticator, BiometricFaceConstan
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the authenticator token for binding keys to the lifecycle
|
||||
* of the calling user's face. Used only by internal clients.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public long getAuthenticatorId() {
|
||||
if (mService != null) {
|
||||
try {
|
||||
return mService.getAuthenticatorId(mContext.getOpPackageName());
|
||||
} catch (RemoteException e) {
|
||||
throw e.rethrowFromSystemServer();
|
||||
}
|
||||
} else {
|
||||
Log.w(TAG, "getAuthenticatorId(): Service not connected!");
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
|
||||
@@ -90,7 +90,7 @@ interface IFaceService {
|
||||
// long getHardwareDevice(int i);
|
||||
|
||||
// Gets the authenticator ID for face
|
||||
long getAuthenticatorId(String opPackageName);
|
||||
long getAuthenticatorId();
|
||||
|
||||
// Reset the lockout when user authenticates with strong auth (e.g. PIN, pattern or password)
|
||||
void resetLockout(in byte [] token);
|
||||
|
||||
@@ -768,26 +768,6 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the authenticator token for binding keys to the lifecycle
|
||||
* of the calling user's fingerprints. Used only by internal clients.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
@UnsupportedAppUsage
|
||||
public long getAuthenticatorId() {
|
||||
if (mService != null) {
|
||||
try {
|
||||
return mService.getAuthenticatorId(mContext.getOpPackageName());
|
||||
} catch (RemoteException e) {
|
||||
throw e.rethrowFromSystemServer();
|
||||
}
|
||||
} else {
|
||||
Slog.w(TAG, "getAuthenticatorId(): Service not connected!");
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
|
||||
@@ -91,7 +91,7 @@ interface IFingerprintService {
|
||||
// long getHardwareDevice(int i);
|
||||
|
||||
// Gets the authenticator ID for fingerprint
|
||||
long getAuthenticatorId(String opPackageName);
|
||||
long getAuthenticatorId();
|
||||
|
||||
// Reset the timeout when user authenticates with strong auth (e.g. PIN, pattern or password)
|
||||
void resetTimeout(in byte [] cryptoToken);
|
||||
|
||||
@@ -21,9 +21,7 @@ import android.app.Application;
|
||||
import android.app.KeyguardManager;
|
||||
import android.compat.annotation.UnsupportedAppUsage;
|
||||
import android.content.Context;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.hardware.face.FaceManager;
|
||||
import android.hardware.fingerprint.FingerprintManager;
|
||||
import android.hardware.biometrics.BiometricManager;
|
||||
import android.os.Binder;
|
||||
import android.os.Build;
|
||||
import android.os.IBinder;
|
||||
@@ -1348,19 +1346,26 @@ public class KeyStore {
|
||||
return new UserNotAuthenticatedException();
|
||||
}
|
||||
|
||||
final long fingerprintOnlySid = getFingerprintOnlySid();
|
||||
if ((fingerprintOnlySid != 0)
|
||||
&& (keySids.contains(KeymasterArguments.toUint64(fingerprintOnlySid)))) {
|
||||
// One of the key's SIDs is the current fingerprint SID -- user can be
|
||||
// authenticated against that SID.
|
||||
return new UserNotAuthenticatedException();
|
||||
final BiometricManager bm = mContext.getSystemService(BiometricManager.class);
|
||||
long[] biometricSids = bm.getAuthenticatorIds();
|
||||
|
||||
// The key must contain every biometric SID. This is because the current API surface
|
||||
// treats all biometrics (capable of keystore integration) equally. e.g. if the
|
||||
// device has multiple keystore-capable sensors, and one of the sensor's SIDs
|
||||
// changed, 1) there is no way for a developer to specify authentication with a
|
||||
// specific sensor (the one that hasn't changed), and 2) currently the only
|
||||
// signal to developers is the UserNotAuthenticatedException, which doesn't
|
||||
// indicate a specific sensor.
|
||||
boolean canUnlockViaBiometrics = true;
|
||||
for (long sid : biometricSids) {
|
||||
if (!keySids.contains(KeymasterArguments.toUint64(sid))) {
|
||||
canUnlockViaBiometrics = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
final long faceOnlySid = getFaceOnlySid();
|
||||
if ((faceOnlySid != 0)
|
||||
&& (keySids.contains(KeymasterArguments.toUint64(faceOnlySid)))) {
|
||||
// One of the key's SIDs is the current face SID -- user can be
|
||||
// authenticated against that SID.
|
||||
if (canUnlockViaBiometrics) {
|
||||
// All of the biometric SIDs are contained in the key's SIDs.
|
||||
return new UserNotAuthenticatedException();
|
||||
}
|
||||
|
||||
@@ -1374,36 +1379,6 @@ public class KeyStore {
|
||||
}
|
||||
}
|
||||
|
||||
private long getFaceOnlySid() {
|
||||
final PackageManager packageManager = mContext.getPackageManager();
|
||||
if (!packageManager.hasSystemFeature(PackageManager.FEATURE_FACE)) {
|
||||
return 0;
|
||||
}
|
||||
FaceManager faceManager = mContext.getSystemService(FaceManager.class);
|
||||
if (faceManager == null) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// TODO: Restore USE_BIOMETRIC or USE_BIOMETRIC_INTERNAL permission check in
|
||||
// FaceManager.getAuthenticatorId once the ID is no longer needed here.
|
||||
return faceManager.getAuthenticatorId();
|
||||
}
|
||||
|
||||
private long getFingerprintOnlySid() {
|
||||
final PackageManager packageManager = mContext.getPackageManager();
|
||||
if (!packageManager.hasSystemFeature(PackageManager.FEATURE_FINGERPRINT)) {
|
||||
return 0;
|
||||
}
|
||||
FingerprintManager fingerprintManager = mContext.getSystemService(FingerprintManager.class);
|
||||
if (fingerprintManager == null) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// TODO: Restore USE_FINGERPRINT permission check in
|
||||
// FingerprintManager.getAuthenticatorId once the ID is no longer needed here.
|
||||
return fingerprintManager.getAuthenticatorId();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an {@link InvalidKeyException} corresponding to the provided keystore/keymaster error
|
||||
* code.
|
||||
|
||||
@@ -16,9 +16,7 @@
|
||||
|
||||
package android.security.keystore;
|
||||
|
||||
import android.content.pm.PackageManager;
|
||||
import android.hardware.face.FaceManager;
|
||||
import android.hardware.fingerprint.FingerprintManager;
|
||||
import android.hardware.biometrics.BiometricManager;
|
||||
import android.security.GateKeeper;
|
||||
import android.security.KeyStore;
|
||||
import android.security.keymaster.KeymasterArguments;
|
||||
@@ -115,28 +113,16 @@ public abstract class KeymasterUtils {
|
||||
}
|
||||
|
||||
if (spec.getUserAuthenticationValidityDurationSeconds() == 0) {
|
||||
PackageManager pm = KeyStore.getApplicationContext().getPackageManager();
|
||||
// Every use of this key needs to be authorized by the user. This currently means
|
||||
// fingerprint or face auth.
|
||||
FingerprintManager fingerprintManager = null;
|
||||
FaceManager faceManager = null;
|
||||
// Every use of this key needs to be authorized by the user.
|
||||
final BiometricManager bm = KeyStore.getApplicationContext()
|
||||
.getSystemService(BiometricManager.class);
|
||||
|
||||
if (pm.hasSystemFeature(PackageManager.FEATURE_FINGERPRINT)) {
|
||||
fingerprintManager = KeyStore.getApplicationContext()
|
||||
.getSystemService(FingerprintManager.class);
|
||||
}
|
||||
if (pm.hasSystemFeature(PackageManager.FEATURE_FACE)) {
|
||||
faceManager = KeyStore.getApplicationContext().getSystemService(FaceManager.class);
|
||||
}
|
||||
// TODO: Restore permission check in getAuthenticatorIds once the ID is no longer
|
||||
// needed here.
|
||||
|
||||
// TODO: Restore USE_FINGERPRINT permission check in
|
||||
// FingerprintManager.getAuthenticatorId once the ID is no longer needed here.
|
||||
final long fingerprintOnlySid =
|
||||
(fingerprintManager != null) ? fingerprintManager.getAuthenticatorId() : 0;
|
||||
final long faceOnlySid =
|
||||
(faceManager != null) ? faceManager.getAuthenticatorId() : 0;
|
||||
final long[] biometricSids = bm.getAuthenticatorIds();
|
||||
|
||||
if (fingerprintOnlySid == 0 && faceOnlySid == 0) {
|
||||
if (biometricSids.length == 0) {
|
||||
throw new IllegalStateException(
|
||||
"At least one biometric must be enrolled to create keys requiring user"
|
||||
+ " authentication for every use");
|
||||
@@ -148,8 +134,9 @@ public abstract class KeymasterUtils {
|
||||
} else if (spec.isInvalidatedByBiometricEnrollment()) {
|
||||
// The biometric-only SIDs will change on biometric enrollment or removal of all
|
||||
// enrolled templates, invalidating the key.
|
||||
sids.add(fingerprintOnlySid);
|
||||
sids.add(faceOnlySid);
|
||||
for (long sid : biometricSids) {
|
||||
sids.add(sid);
|
||||
}
|
||||
} else {
|
||||
// The root SID will *not* change on fingerprint enrollment, or removal of all
|
||||
// enrolled fingerprints, allowing the key to remain valid.
|
||||
|
||||
@@ -28,7 +28,6 @@ import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.res.Configuration;
|
||||
import android.hardware.biometrics.BiometricConstants;
|
||||
import android.hardware.biometrics.BiometricPrompt;
|
||||
@@ -238,20 +237,15 @@ public class AuthController extends SystemUI implements CommandQueue.Callbacks,
|
||||
|
||||
@Override
|
||||
public void start() {
|
||||
final PackageManager pm = mContext.getPackageManager();
|
||||
if (pm.hasSystemFeature(PackageManager.FEATURE_FINGERPRINT)
|
||||
|| pm.hasSystemFeature(PackageManager.FEATURE_FACE)
|
||||
|| pm.hasSystemFeature(PackageManager.FEATURE_IRIS)) {
|
||||
mCommandQueue.addCallback(this);
|
||||
mWindowManager = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);
|
||||
mActivityTaskManager = mInjector.getActivityTaskManager();
|
||||
mCommandQueue.addCallback(this);
|
||||
mWindowManager = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);
|
||||
mActivityTaskManager = mInjector.getActivityTaskManager();
|
||||
|
||||
try {
|
||||
mTaskStackListener = new BiometricTaskStackListener();
|
||||
mActivityTaskManager.registerTaskStackListener(mTaskStackListener);
|
||||
} catch (RemoteException e) {
|
||||
Log.w(TAG, "Unable to register task stack listener", e);
|
||||
}
|
||||
try {
|
||||
mTaskStackListener = new BiometricTaskStackListener();
|
||||
mActivityTaskManager.registerTaskStackListener(mTaskStackListener);
|
||||
} catch (RemoteException e) {
|
||||
Log.w(TAG, "Unable to register task stack listener", e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -265,6 +265,32 @@ public class AuthService extends SystemService {
|
||||
Binder.restoreCallingIdentity(identity);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public long[] getAuthenticatorIds() throws RemoteException {
|
||||
// In this method, we're not checking whether the caller is permitted to use face
|
||||
// API because current authenticator ID is leaked (in a more contrived way) via Android
|
||||
// Keystore (android.security.keystore package): the user of that API can create a key
|
||||
// which requires face authentication for its use, and then query the key's
|
||||
// characteristics (hidden API) which returns, among other things, face
|
||||
// authenticator ID which was active at key creation time.
|
||||
//
|
||||
// Reason: The part of Android Keystore which runs inside an app's process invokes this
|
||||
// method in certain cases. Those cases are not always where the developer demonstrates
|
||||
// explicit intent to use biometric functionality. Thus, to avoiding throwing an
|
||||
// unexpected SecurityException this method does not check whether its caller is
|
||||
// permitted to use face API.
|
||||
//
|
||||
// The permission check should be restored once Android Keystore no longer invokes this
|
||||
// method from inside app processes.
|
||||
|
||||
final long identity = Binder.clearCallingIdentity();
|
||||
try {
|
||||
return mBiometricService.getAuthenticatorIds();
|
||||
} finally {
|
||||
Binder.restoreCallingIdentity(identity);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public AuthService(Context context) {
|
||||
@@ -305,8 +331,8 @@ public class AuthService extends SystemService {
|
||||
case TYPE_FINGERPRINT:
|
||||
final IFingerprintService fingerprintService = mInjector.getFingerprintService();
|
||||
if (fingerprintService == null) {
|
||||
Slog.e(TAG, "Attempting to register with null FingerprintService. Please check"
|
||||
+ " your device configuration.");
|
||||
Slog.e(TAG, "Attempting to register with null FingerprintService."
|
||||
+ " Please check your device configuration.");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -317,8 +343,8 @@ public class AuthService extends SystemService {
|
||||
case TYPE_FACE:
|
||||
final IFaceService faceService = mInjector.getFaceService();
|
||||
if (faceService == null) {
|
||||
Slog.e(TAG, "Attempting to register with null FaceService. Please check your"
|
||||
+ " device configuration.");
|
||||
Slog.e(TAG, "Attempting to register with null FaceService. Please check "
|
||||
+ " your device configuration.");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -329,8 +355,8 @@ public class AuthService extends SystemService {
|
||||
case TYPE_IRIS:
|
||||
final IIrisService irisService = mInjector.getIrisService();
|
||||
if (irisService == null) {
|
||||
Slog.e(TAG, "Attempting to register with null IrisService. Please check your"
|
||||
+ " device configuration.");
|
||||
Slog.e(TAG, "Attempting to register with null IrisService. Please check"
|
||||
+ " your device configuration.");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -347,7 +373,6 @@ public class AuthService extends SystemService {
|
||||
authenticator);
|
||||
}
|
||||
|
||||
|
||||
private void checkInternalPermission() {
|
||||
getContext().enforceCallingOrSelfPermission(USE_BIOMETRIC_INTERNAL,
|
||||
"Must have USE_BIOMETRIC_INTERNAL permission");
|
||||
|
||||
@@ -825,6 +825,33 @@ public class BiometricService extends SystemService {
|
||||
Slog.e(TAG, "Remote exception", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override // Binder call
|
||||
public long[] getAuthenticatorIds() {
|
||||
checkInternalPermission();
|
||||
|
||||
final List<Long> ids = new ArrayList<>();
|
||||
for (AuthenticatorWrapper authenticator : mAuthenticators) {
|
||||
try {
|
||||
final long id = authenticator.impl.getAuthenticatorId();
|
||||
if (Utils.isAtLeastStrength(authenticator.getActualStrength(),
|
||||
Authenticators.BIOMETRIC_STRONG) && id != 0) {
|
||||
ids.add(id);
|
||||
} else {
|
||||
Slog.d(TAG, "Authenticator " + authenticator + ", authenticatorID " + id
|
||||
+ " cannot participate in Keystore operations");
|
||||
}
|
||||
} catch (RemoteException e) {
|
||||
Slog.e(TAG, "RemoteException", e);
|
||||
}
|
||||
}
|
||||
|
||||
long[] result = new long[ids.size()];
|
||||
for (int i = 0; i < ids.size(); i++) {
|
||||
result[i] = ids.get(i);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
private void checkInternalPermission() {
|
||||
|
||||
@@ -16,7 +16,6 @@
|
||||
|
||||
package com.android.server.biometrics;
|
||||
|
||||
import static android.Manifest.permission.USE_BIOMETRIC_INTERNAL;
|
||||
import static android.app.ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND_SERVICE;
|
||||
|
||||
import android.app.ActivityManager;
|
||||
@@ -1228,16 +1227,11 @@ public abstract class BiometricServiceBase extends SystemService
|
||||
}
|
||||
|
||||
/***
|
||||
* @param opPackageName the name of the calling package
|
||||
* @return authenticator id for the calling user
|
||||
*/
|
||||
protected long getAuthenticatorId(String opPackageName) {
|
||||
if (isKeyguard(opPackageName)) {
|
||||
// If an app tells us it's keyguard, check that it actually is.
|
||||
checkPermission(USE_BIOMETRIC_INTERNAL);
|
||||
}
|
||||
|
||||
final int userId = getUserOrWorkProfileId(opPackageName, UserHandle.getCallingUserId());
|
||||
protected long getAuthenticatorId() {
|
||||
final int userId = getUserOrWorkProfileId(null /* clientPackage */,
|
||||
UserHandle.getCallingUserId());
|
||||
return mAuthenticatorIds.getOrDefault(userId, 0L);
|
||||
}
|
||||
|
||||
|
||||
@@ -130,8 +130,24 @@ public class Utils {
|
||||
* @return true only if the sensor is at least as strong as the requested strength
|
||||
*/
|
||||
public static boolean isAtLeastStrength(int sensorStrength, int requestedStrength) {
|
||||
// Clear out any bits that are not reserved for biometric
|
||||
sensorStrength &= Authenticators.BIOMETRIC_MIN_STRENGTH;
|
||||
|
||||
// If the authenticator contains bits outside of the requested strength, it is too weak.
|
||||
return (~requestedStrength & sensorStrength) == 0;
|
||||
if ((sensorStrength & ~requestedStrength) != 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (int i = Authenticators.BIOMETRIC_MAX_STRENGTH;
|
||||
i <= requestedStrength; i = (i << 1) | 1) {
|
||||
if (i == sensorStrength) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
Slog.e(BiometricService.TAG, "Unknown sensorStrength: " + sensorStrength
|
||||
+ ", requestedStrength: " + requestedStrength);
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -72,4 +72,9 @@ public final class FaceAuthenticator extends IBiometricAuthenticator.Stub {
|
||||
public void setActiveUser(int uid) throws RemoteException {
|
||||
mFaceService.setActiveUser(uid);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getAuthenticatorId() throws RemoteException {
|
||||
return mFaceService.getAuthenticatorId();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -611,24 +611,9 @@ public class FaceService extends BiometricServiceBase {
|
||||
}
|
||||
|
||||
@Override // Binder call
|
||||
public long getAuthenticatorId(String opPackageName) {
|
||||
// In this method, we're not checking whether the caller is permitted to use face
|
||||
// API because current authenticator ID is leaked (in a more contrived way) via Android
|
||||
// Keystore (android.security.keystore package): the user of that API can create a key
|
||||
// which requires face authentication for its use, and then query the key's
|
||||
// characteristics (hidden API) which returns, among other things, face
|
||||
// authenticator ID which was active at key creation time.
|
||||
//
|
||||
// Reason: The part of Android Keystore which runs inside an app's process invokes this
|
||||
// method in certain cases. Those cases are not always where the developer demonstrates
|
||||
// explicit intent to use face functionality. Thus, to avoiding throwing an
|
||||
// unexpected SecurityException this method does not check whether its caller is
|
||||
// permitted to use face API.
|
||||
//
|
||||
// The permission check should be restored once Android Keystore no longer invokes this
|
||||
// method from inside app processes.
|
||||
|
||||
return FaceService.this.getAuthenticatorId(opPackageName);
|
||||
public long getAuthenticatorId() {
|
||||
checkPermission(USE_BIOMETRIC_INTERNAL);
|
||||
return FaceService.this.getAuthenticatorId();
|
||||
}
|
||||
|
||||
@Override // Binder call
|
||||
|
||||
@@ -72,4 +72,9 @@ public final class FingerprintAuthenticator extends IBiometricAuthenticator.Stub
|
||||
public void setActiveUser(int uid) throws RemoteException {
|
||||
mFingerprintService.setActiveUser(uid);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getAuthenticatorId() throws RemoteException {
|
||||
return mFingerprintService.getAuthenticatorId();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -411,24 +411,9 @@ public class FingerprintService extends BiometricServiceBase {
|
||||
}
|
||||
|
||||
@Override // Binder call
|
||||
public long getAuthenticatorId(String opPackageName) {
|
||||
// In this method, we're not checking whether the caller is permitted to use fingerprint
|
||||
// API because current authenticator ID is leaked (in a more contrived way) via Android
|
||||
// Keystore (android.security.keystore package): the user of that API can create a key
|
||||
// which requires fingerprint authentication for its use, and then query the key's
|
||||
// characteristics (hidden API) which returns, among other things, fingerprint
|
||||
// authenticator ID which was active at key creation time.
|
||||
//
|
||||
// Reason: The part of Android Keystore which runs inside an app's process invokes this
|
||||
// method in certain cases. Those cases are not always where the developer demonstrates
|
||||
// explicit intent to use fingerprint functionality. Thus, to avoiding throwing an
|
||||
// unexpected SecurityException this method does not check whether its caller is
|
||||
// permitted to use fingerprint API.
|
||||
//
|
||||
// The permission check should be restored once Android Keystore no longer invokes this
|
||||
// method from inside app processes.
|
||||
|
||||
return FingerprintService.super.getAuthenticatorId(opPackageName);
|
||||
public long getAuthenticatorId() {
|
||||
checkPermission(USE_BIOMETRIC_INTERNAL);
|
||||
return FingerprintService.this.getAuthenticatorId();
|
||||
}
|
||||
|
||||
@Override // Binder call
|
||||
|
||||
@@ -65,4 +65,9 @@ public final class IrisAuthenticator extends IBiometricAuthenticator.Stub {
|
||||
@Override
|
||||
public void setActiveUser(int uid) throws RemoteException {
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getAuthenticatorId() throws RemoteException {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1908,16 +1908,14 @@ public final class SystemServer {
|
||||
t.traceEnd();
|
||||
}
|
||||
|
||||
if (hasFeatureFace || hasFeatureIris || hasFeatureFingerprint) {
|
||||
// Start this service after all biometric services.
|
||||
t.traceBegin("StartBiometricService");
|
||||
mSystemServiceManager.startService(BiometricService.class);
|
||||
t.traceEnd();
|
||||
// Start this service after all biometric services.
|
||||
t.traceBegin("StartBiometricService");
|
||||
mSystemServiceManager.startService(BiometricService.class);
|
||||
t.traceEnd();
|
||||
|
||||
t.traceBegin("StartAuthService");
|
||||
mSystemServiceManager.startService(AuthService.class);
|
||||
t.traceEnd();
|
||||
}
|
||||
t.traceBegin("StartAuthService");
|
||||
mSystemServiceManager.startService(AuthService.class);
|
||||
t.traceEnd();
|
||||
|
||||
|
||||
t.traceBegin("StartBackgroundDexOptService");
|
||||
|
||||
@@ -201,6 +201,16 @@ public class UtilsTest {
|
||||
|
||||
requestedStrength = Authenticators.BIOMETRIC_WEAK;
|
||||
assertTrue(Utils.isAtLeastStrength(sensorStrength, requestedStrength));
|
||||
|
||||
|
||||
// Test invalid inputs
|
||||
|
||||
sensorStrength = Authenticators.BIOMETRIC_STRONG;
|
||||
requestedStrength = Authenticators.DEVICE_CREDENTIAL;
|
||||
assertFalse(Utils.isAtLeastStrength(sensorStrength, requestedStrength));
|
||||
|
||||
requestedStrength = 1 << 2;
|
||||
assertFalse(Utils.isAtLeastStrength(sensorStrength, requestedStrength));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
Reference in New Issue
Block a user