Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 057b743f authored by Kevin Chyn's avatar Kevin Chyn
Browse files

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
parent 353eab92
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -154,7 +154,7 @@ public final class KeymasterDefs {

    // 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;
+25 −1
Original line number Diff line number Diff line
@@ -23,6 +23,7 @@ import android.app.Application;
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 @@ public class KeyStore {
                    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 @@ public class KeyStore {
                    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 @@ 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)) {
+2 −2
Original line number Diff line number Diff line
@@ -182,8 +182,8 @@ public class AndroidKeyStoreSecretKeyFactorySpi extends SecretKeyFactorySpi {
                    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()
+26 −15
Original line number Diff line number Diff line
@@ -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.KeymasterArguments;
import android.security.keymaster.KeymasterDefs;

import java.security.ProviderException;
import java.util.ArrayList;
import java.util.List;

/**
 * @hide
@@ -121,35 +123,44 @@ public abstract class KeymasterUtils {

        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());
            }

            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);

            args.addUnsignedLong(
                    KeymasterDefs.KM_TAG_USER_SECURE_ID, KeymasterArguments.toUint64(sid));
            args.addEnum(KeymasterDefs.KM_TAG_USER_AUTH_TYPE, KeymasterDefs.HW_AUTH_FINGERPRINT);
            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 @@ public abstract class KeymasterUtils {
            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()) {