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

Commit a99b8b5e authored by Alex Klyubin's avatar Alex Klyubin
Browse files

Do not require USE_FINGERPRINT for getAuthenticatorId.

This removes the requirement to hold the USE_FINGERPRINT permission
to successfully invoke FingerprintManager.getAuthenticatorId().

This is needed because Android Keystore classes which run inside app
processes occasionally need to access this authenticator ID. The
access however is not necessarily triggered by the developer using
APIs to do with fingerprints. Thus, if an app does not hold the
USE_FINGERPRINT permission and uses Android Keystore API, it may
unexpectedly encounter a SecurityException.

It's OK to provide access to authenticator ID without requiring
USE_FINGERPRINT permission because there are other ways to access
this ID without holding that permission, such as though hidden
KeyStore API.

Once Android Keystore code is restructured to no longer require
access to authenticator ID, this CL can be reverted.

Bug: 21030147
Change-Id: I9af29830abce34c46e29e5c1682cc3ab88c95c00
parent 8a265146
Loading
Loading
Loading
Loading
+5 −13
Original line number Diff line number Diff line
@@ -108,15 +108,10 @@ public class KeyStore {
    }

    public static Context getApplicationContext() {
        ActivityThread activityThread = ActivityThread.currentActivityThread();
        if (activityThread == null) {
            throw new IllegalStateException(
                    "Failed to obtain application Context: no ActivityThread");
        }
        Application application = activityThread.getApplication();
        Application application = ActivityThread.currentApplication();
        if (application == null) {
            throw new IllegalStateException(
                    "Failed to obtain application Context: no Application");
                    "Failed to obtain application Context from ActivityThread");
        }
        return application;
    }
@@ -698,16 +693,13 @@ public class KeyStore {
    }

    private long getFingerprintOnlySid() {
        FingerprintManager fingerprintManager =
                mContext.getSystemService(FingerprintManager.class);
        FingerprintManager fingerprintManager = mContext.getSystemService(FingerprintManager.class);
        if (fingerprintManager == null) {
            return 0;
        }

        if (!fingerprintManager.isHardwareDetected()) {
            return 0;
        }

        // TODO: Restore USE_FINGERPRINT permission check in
        // FingerprintManager.getAuthenticatorId once the ID is no longer needed here.
        return fingerprintManager.getAuthenticatorId();
    }

+4 −7
Original line number Diff line number Diff line
@@ -101,13 +101,10 @@ public abstract class KeymasterUtils {
            // fingerprint-only auth.
            FingerprintManager fingerprintManager =
                    KeyStore.getApplicationContext().getSystemService(FingerprintManager.class);
            if ((fingerprintManager == null) || (!fingerprintManager.isHardwareDetected())) {
                throw new IllegalStateException(
                        "This device does not support keys which require authentication for every"
                        + " use -- this requires fingerprint authentication which is not"
                        + " available on this device");
            }
            long fingerprintOnlySid = fingerprintManager.getAuthenticatorId();
            // TODO: Restore USE_FINGERPRINT permission check in
            // FingerprintManager.getAuthenticatorId once the ID is no longer needed here.
            long fingerprintOnlySid =
                    (fingerprintManager != null) ? fingerprintManager.getAuthenticatorId() : 0;
            if (fingerprintOnlySid == 0) {
                throw new IllegalStateException(
                        "At least one fingerprint must be enrolled to create keys requiring user"
+16 −3
Original line number Diff line number Diff line
@@ -706,9 +706,22 @@ public class FingerprintService extends SystemService implements IBinder.DeathRe

        @Override // Binder call
        public long getAuthenticatorId(String opPackageName) {
            if (!canUseFingerprint(opPackageName)) {
                return 0;
            }
            // 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.this.getAuthenticatorId();
        }
    }