Align AndroidKeyStore API with user auth API.

This simplifies the AndroidKeyStore API around user authentication: no
more explicit control over which user authenticators are bound to
which keys.

User-authenticated keys with timeout are unlocked by whatever unlocks
the secure lock screen (currently, password/PIN/pattern or
fingerprint). User-authenticated keys that need authentication for
every use are unlocked by fingerprint only.

Bug: 20526234
Bug: 20642549
Change-Id: I1e5e6c988f32657d820797ad5696797477a9ebe9
diff --git a/keystore/java/android/security/KeymasterUtils.java b/keystore/java/android/security/KeymasterUtils.java
index 67f75c2..7bf5475 100644
--- a/keystore/java/android/security/KeymasterUtils.java
+++ b/keystore/java/android/security/KeymasterUtils.java
@@ -16,7 +16,14 @@
 
 package android.security;
 
+import android.content.Context;
+import android.hardware.fingerprint.FingerprintManager;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.os.UserHandle;
+import android.security.keymaster.KeymasterArguments;
 import android.security.keymaster.KeymasterDefs;
+import android.service.gatekeeper.IGateKeeperService;
 
 import libcore.util.EmptyArray;
 
@@ -339,4 +346,72 @@
         }
         return result;
     }
+
+    private static long getRootSid() {
+        IGateKeeperService gatekeeperService = IGateKeeperService.Stub.asInterface(
+                ServiceManager.getService("android.service.gatekeeper.IGateKeeperService"));
+        if (gatekeeperService == null) {
+            throw new IllegalStateException("Gatekeeper service not available");
+        }
+
+        try {
+            return gatekeeperService.getSecureUserId(UserHandle.myUserId());
+        } catch (RemoteException e) {
+            throw new IllegalStateException("Failed to obtain root SID");
+        }
+    }
+
+    /**
+     * Adds keymaster arguments to express the key's authorization policy supported by user
+     * authentication.
+     *
+     * @param userAuthenticationRequired whether user authentication is required to authorize the
+     *        use of the key.
+     * @param userAuthenticationValidityDurationSeconds duration of time (seconds) for which user
+     *        authentication is valid as authorization for using the key or {@code -1} if every
+     *        use of the key needs authorization.
+     */
+    public static void addUserAuthArgs(KeymasterArguments args,
+            Context context,
+            boolean userAuthenticationRequired,
+            int userAuthenticationValidityDurationSeconds) {
+        if (!userAuthenticationRequired) {
+            args.addBoolean(KeymasterDefs.KM_TAG_NO_AUTH_REQUIRED);
+            return;
+        }
+
+        if (userAuthenticationValidityDurationSeconds == -1) {
+            // Every use of this key needs to be authorized by the user. This currently means
+            // fingerprint-only auth.
+            FingerprintManager fingerprintManager =
+                    context.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();
+            if (fingerprintOnlySid == 0) {
+                throw new IllegalStateException(
+                        "At least one fingerprint must be enrolled to create keys requiring user"
+                        + " authentication for every use");
+            }
+            args.addLong(KeymasterDefs.KM_TAG_USER_SECURE_ID, fingerprintOnlySid);
+            args.addInt(KeymasterDefs.KM_TAG_USER_AUTH_TYPE, KeymasterDefs.HW_AUTH_FINGERPRINT);
+        } else {
+            // The key is authorized for use for the specified amount of time after the user has
+            // authenticated. Whatever unlocks the secure lock screen should authorize this key.
+            long rootSid = getRootSid();
+            if (rootSid == 0) {
+                throw new IllegalStateException("Secure lock screen must be enabled"
+                        + " to create keys requiring user authentication");
+            }
+            args.addLong(KeymasterDefs.KM_TAG_USER_SECURE_ID, rootSid);
+            args.addInt(KeymasterDefs.KM_TAG_USER_AUTH_TYPE,
+                    KeymasterDefs.HW_AUTH_PASSWORD | KeymasterDefs.HW_AUTH_FINGERPRINT);
+            args.addInt(KeymasterDefs.KM_TAG_AUTH_TIMEOUT,
+                    userAuthenticationValidityDurationSeconds);
+        }
+    }
 }