Update KeyStore for new biometric modalities
Biometrics are now generic from KeyStore point of view
Bug: 113624536
Test: Unable to create keys when no templates enrolled
Test: Able to create keys when templates are enrolled
Test: No regression in Fingerprint
Keys are invalidated after enrolling another FP
Change-Id: I6bdc20eb58c8a0c10a986519d4ba9e1843ebc89d
diff --git a/core/java/android/security/keymaster/KeymasterDefs.java b/core/java/android/security/keymaster/KeymasterDefs.java
index f4dcce1..15ded8d 100644
--- a/core/java/android/security/keymaster/KeymasterDefs.java
+++ b/core/java/android/security/keymaster/KeymasterDefs.java
@@ -154,7 +154,7 @@
// User authenticators.
public static final int HW_AUTH_PASSWORD = 1 << 0;
- public static final int HW_AUTH_FINGERPRINT = 1 << 1;
+ public static final int HW_AUTH_BIOMETRIC = 1 << 1;
// Error codes.
public static final int KM_ERROR_OK = 0;
diff --git a/keystore/java/android/security/KeyStore.java b/keystore/java/android/security/KeyStore.java
index 0a4ac8c..7308f3b 100644
--- a/keystore/java/android/security/KeyStore.java
+++ b/keystore/java/android/security/KeyStore.java
@@ -23,6 +23,7 @@
import android.app.KeyguardManager;
import android.content.Context;
import android.content.pm.PackageManager;
+import android.hardware.face.FaceManager;
import android.hardware.fingerprint.FingerprintManager;
import android.os.Binder;
import android.os.IBinder;
@@ -913,7 +914,7 @@
return new UserNotAuthenticatedException();
}
- long fingerprintOnlySid = getFingerprintOnlySid();
+ 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
@@ -921,6 +922,14 @@
return new UserNotAuthenticatedException();
}
+ 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.
+ return new UserNotAuthenticatedException();
+ }
+
// None of the key's SIDs can ever be authenticated
return new KeyPermanentlyInvalidatedException();
}
@@ -931,6 +940,21 @@
}
}
+ 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)) {
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreSecretKeyFactorySpi.java b/keystore/java/android/security/keystore/AndroidKeyStoreSecretKeyFactorySpi.java
index 7bbc099..a2d2355 100644
--- a/keystore/java/android/security/keystore/AndroidKeyStoreSecretKeyFactorySpi.java
+++ b/keystore/java/android/security/keystore/AndroidKeyStoreSecretKeyFactorySpi.java
@@ -182,8 +182,8 @@
KeymasterDefs.KM_TAG_TRUSTED_USER_PRESENCE_REQUIRED);
boolean invalidatedByBiometricEnrollment = false;
- if (keymasterSwEnforcedUserAuthenticators == KeymasterDefs.HW_AUTH_FINGERPRINT
- || keymasterHwEnforcedUserAuthenticators == KeymasterDefs.HW_AUTH_FINGERPRINT) {
+ if (keymasterSwEnforcedUserAuthenticators == KeymasterDefs.HW_AUTH_BIOMETRIC
+ || keymasterHwEnforcedUserAuthenticators == KeymasterDefs.HW_AUTH_BIOMETRIC) {
// Fingerprint-only key; will be invalidated if the root SID isn't in the SID list.
invalidatedByBiometricEnrollment = keymasterSecureUserIds != null
&& !keymasterSecureUserIds.isEmpty()
diff --git a/keystore/java/android/security/keystore/KeymasterUtils.java b/keystore/java/android/security/keystore/KeymasterUtils.java
index f829bb7..52896b5 100644
--- a/keystore/java/android/security/keystore/KeymasterUtils.java
+++ b/keystore/java/android/security/keystore/KeymasterUtils.java
@@ -16,7 +16,7 @@
package android.security.keystore;
-import android.app.ActivityManager;
+import android.hardware.face.FaceManager;
import android.hardware.fingerprint.FingerprintManager;
import android.security.GateKeeper;
import android.security.KeyStore;
@@ -24,6 +24,8 @@
import android.security.keymaster.KeymasterDefs;
import java.security.ProviderException;
+import java.util.ArrayList;
+import java.util.List;
/**
* @hide
@@ -121,35 +123,44 @@
if (spec.getUserAuthenticationValidityDurationSeconds() == -1) {
// Every use of this key needs to be authorized by the user. This currently means
- // fingerprint-only auth.
+ // fingerprint or face auth.
FingerprintManager fingerprintManager =
KeyStore.getApplicationContext().getSystemService(FingerprintManager.class);
+ FaceManager faceManager =
+ KeyStore.getApplicationContext().getSystemService(FaceManager.class);
// TODO: Restore USE_FINGERPRINT permission check in
// FingerprintManager.getAuthenticatorId once the ID is no longer needed here.
- long fingerprintOnlySid =
+ final long fingerprintOnlySid =
(fingerprintManager != null) ? fingerprintManager.getAuthenticatorId() : 0;
- if (fingerprintOnlySid == 0) {
+ final long faceOnlySid =
+ (faceManager != null) ? faceManager.getAuthenticatorId() : 0;
+
+ if (fingerprintOnlySid == 0 && faceOnlySid == 0) {
throw new IllegalStateException(
- "At least one fingerprint must be enrolled to create keys requiring user"
+ "At least one biometric must be enrolled to create keys requiring user"
+ " authentication for every use");
}
- long sid;
+ List<Long> sids = new ArrayList<>();
if (spec.getBoundToSpecificSecureUserId() != GateKeeper.INVALID_SECURE_USER_ID) {
- sid = spec.getBoundToSpecificSecureUserId();
+ sids.add(spec.getBoundToSpecificSecureUserId());
} else if (spec.isInvalidatedByBiometricEnrollment()) {
- // The fingerprint-only SID will change on fingerprint enrollment or removal of all,
- // enrolled fingerprints, invalidating the key.
- sid = fingerprintOnlySid;
+ // The biometric-only SIDs will change on biometric enrollment or removal of all
+ // enrolled templates, invalidating the key.
+ sids.add(fingerprintOnlySid);
+ sids.add(faceOnlySid);
} else {
// The root SID will *not* change on fingerprint enrollment, or removal of all
// enrolled fingerprints, allowing the key to remain valid.
- sid = getRootSid();
+ sids.add(getRootSid());
}
- args.addUnsignedLong(
- KeymasterDefs.KM_TAG_USER_SECURE_ID, KeymasterArguments.toUint64(sid));
- args.addEnum(KeymasterDefs.KM_TAG_USER_AUTH_TYPE, KeymasterDefs.HW_AUTH_FINGERPRINT);
+ for (int i = 0; i < sids.size(); i++) {
+ args.addUnsignedLong(KeymasterDefs.KM_TAG_USER_SECURE_ID,
+ KeymasterArguments.toUint64(sids.get(i)));
+ }
+ args.addEnum(KeymasterDefs.KM_TAG_USER_AUTH_TYPE, KeymasterDefs.HW_AUTH_BIOMETRIC);
+
if (spec.isUserAuthenticationValidWhileOnBody()) {
throw new ProviderException("Key validity extension while device is on-body is not "
+ "supported for keys requiring fingerprint authentication");
@@ -166,7 +177,7 @@
args.addUnsignedLong(KeymasterDefs.KM_TAG_USER_SECURE_ID,
KeymasterArguments.toUint64(sid));
args.addEnum(KeymasterDefs.KM_TAG_USER_AUTH_TYPE,
- KeymasterDefs.HW_AUTH_PASSWORD | KeymasterDefs.HW_AUTH_FINGERPRINT);
+ KeymasterDefs.HW_AUTH_PASSWORD | KeymasterDefs.HW_AUTH_BIOMETRIC);
args.addUnsignedInt(KeymasterDefs.KM_TAG_AUTH_TIMEOUT,
spec.getUserAuthenticationValidityDurationSeconds());
if (spec.isUserAuthenticationValidWhileOnBody()) {