summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--keystore/java/android/security/GateKeeper.java2
-rw-r--r--keystore/java/android/security/keystore/AndroidKeyStoreKeyGeneratorSpi.java7
-rw-r--r--keystore/java/android/security/keystore/AndroidKeyStoreKeyPairGeneratorSpi.java7
-rw-r--r--keystore/java/android/security/keystore/AndroidKeyStoreSpi.java6
-rw-r--r--keystore/java/android/security/keystore/KeyProtection.java48
-rw-r--r--keystore/java/android/security/keystore/KeymasterUtils.java25
6 files changed, 80 insertions, 15 deletions
diff --git a/keystore/java/android/security/GateKeeper.java b/keystore/java/android/security/GateKeeper.java
index 7a2cbd06eb92..03df5de9b484 100644
--- a/keystore/java/android/security/GateKeeper.java
+++ b/keystore/java/android/security/GateKeeper.java
@@ -29,6 +29,8 @@ import android.service.gatekeeper.IGateKeeperService;
*/
public abstract class GateKeeper {
+ public static final long INVALID_SECURE_USER_ID = 0;
+
private GateKeeper() {}
public static IGateKeeperService getService() {
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreKeyGeneratorSpi.java b/keystore/java/android/security/keystore/AndroidKeyStoreKeyGeneratorSpi.java
index b234d0f81a89..9701b0ea9308 100644
--- a/keystore/java/android/security/keystore/AndroidKeyStoreKeyGeneratorSpi.java
+++ b/keystore/java/android/security/keystore/AndroidKeyStoreKeyGeneratorSpi.java
@@ -17,6 +17,7 @@
package android.security.keystore;
import android.security.Credentials;
+import android.security.GateKeeper;
import android.security.KeyStore;
import android.security.keymaster.KeyCharacteristics;
import android.security.keymaster.KeymasterArguments;
@@ -235,7 +236,8 @@ public abstract class AndroidKeyStoreKeyGeneratorSpi extends KeyGeneratorSpi {
spec.isUserAuthenticationRequired(),
spec.getUserAuthenticationValidityDurationSeconds(),
spec.isUserAuthenticationValidWhileOnBody(),
- spec.isInvalidatedByBiometricEnrollment());
+ spec.isInvalidatedByBiometricEnrollment(),
+ GateKeeper.INVALID_SECURE_USER_ID /* boundToSpecificSecureUserId */);
} catch (IllegalStateException | IllegalArgumentException e) {
throw new InvalidAlgorithmParameterException(e);
}
@@ -275,7 +277,8 @@ public abstract class AndroidKeyStoreKeyGeneratorSpi extends KeyGeneratorSpi {
spec.isUserAuthenticationRequired(),
spec.getUserAuthenticationValidityDurationSeconds(),
spec.isUserAuthenticationValidWhileOnBody(),
- spec.isInvalidatedByBiometricEnrollment());
+ spec.isInvalidatedByBiometricEnrollment(),
+ GateKeeper.INVALID_SECURE_USER_ID /* boundToSpecificSecureUserId */);
KeymasterUtils.addMinMacLengthAuthorizationIfNecessary(
args,
mKeymasterAlgorithm,
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreKeyPairGeneratorSpi.java b/keystore/java/android/security/keystore/AndroidKeyStoreKeyPairGeneratorSpi.java
index 1818f52c4fda..dba3949ba98f 100644
--- a/keystore/java/android/security/keystore/AndroidKeyStoreKeyPairGeneratorSpi.java
+++ b/keystore/java/android/security/keystore/AndroidKeyStoreKeyPairGeneratorSpi.java
@@ -18,6 +18,7 @@ package android.security.keystore;
import android.annotation.Nullable;
import android.security.Credentials;
+import android.security.GateKeeper;
import android.security.KeyPairGeneratorSpec;
import android.security.KeyStore;
import android.security.keymaster.KeyCharacteristics;
@@ -346,7 +347,8 @@ public abstract class AndroidKeyStoreKeyPairGeneratorSpi extends KeyPairGenerato
mSpec.isUserAuthenticationRequired(),
mSpec.getUserAuthenticationValidityDurationSeconds(),
mSpec.isUserAuthenticationValidWhileOnBody(),
- mSpec.isInvalidatedByBiometricEnrollment());
+ mSpec.isInvalidatedByBiometricEnrollment(),
+ GateKeeper.INVALID_SECURE_USER_ID /* boundToSpecificSecureUserId */);
} catch (IllegalArgumentException | IllegalStateException e) {
throw new InvalidAlgorithmParameterException(e);
}
@@ -533,7 +535,8 @@ public abstract class AndroidKeyStoreKeyPairGeneratorSpi extends KeyPairGenerato
mSpec.isUserAuthenticationRequired(),
mSpec.getUserAuthenticationValidityDurationSeconds(),
mSpec.isUserAuthenticationValidWhileOnBody(),
- mSpec.isInvalidatedByBiometricEnrollment());
+ mSpec.isInvalidatedByBiometricEnrollment(),
+ GateKeeper.INVALID_SECURE_USER_ID /* boundToSpecificSecureUserId */);
args.addDateIfNotNull(KeymasterDefs.KM_TAG_ACTIVE_DATETIME, mSpec.getKeyValidityStart());
args.addDateIfNotNull(KeymasterDefs.KM_TAG_ORIGINATION_EXPIRE_DATETIME,
mSpec.getKeyValidityForOriginationEnd());
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreSpi.java b/keystore/java/android/security/keystore/AndroidKeyStoreSpi.java
index fcbb553c7214..64b10ab6eacb 100644
--- a/keystore/java/android/security/keystore/AndroidKeyStoreSpi.java
+++ b/keystore/java/android/security/keystore/AndroidKeyStoreSpi.java
@@ -500,7 +500,8 @@ public class AndroidKeyStoreSpi extends KeyStoreSpi {
spec.isUserAuthenticationRequired(),
spec.getUserAuthenticationValidityDurationSeconds(),
spec.isUserAuthenticationValidWhileOnBody(),
- spec.isInvalidatedByBiometricEnrollment());
+ spec.isInvalidatedByBiometricEnrollment(),
+ spec.getBoundToSpecificSecureUserId());
importArgs.addDateIfNotNull(KeymasterDefs.KM_TAG_ACTIVE_DATETIME,
spec.getKeyValidityStart());
importArgs.addDateIfNotNull(KeymasterDefs.KM_TAG_ORIGINATION_EXPIRE_DATETIME,
@@ -696,7 +697,8 @@ public class AndroidKeyStoreSpi extends KeyStoreSpi {
params.isUserAuthenticationRequired(),
params.getUserAuthenticationValidityDurationSeconds(),
params.isUserAuthenticationValidWhileOnBody(),
- params.isInvalidatedByBiometricEnrollment());
+ params.isInvalidatedByBiometricEnrollment(),
+ params.getBoundToSpecificSecureUserId());
KeymasterUtils.addMinMacLengthAuthorizationIfNecessary(
args,
keymasterAlgorithm,
diff --git a/keystore/java/android/security/keystore/KeyProtection.java b/keystore/java/android/security/keystore/KeyProtection.java
index e70d33a3385c..2592a97468d3 100644
--- a/keystore/java/android/security/keystore/KeyProtection.java
+++ b/keystore/java/android/security/keystore/KeyProtection.java
@@ -21,6 +21,7 @@ import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.KeyguardManager;
import android.hardware.fingerprint.FingerprintManager;
+import android.security.GateKeeper;
import java.security.Key;
import java.security.Signature;
@@ -225,6 +226,7 @@ public final class KeyProtection implements ProtectionParameter {
private final int mUserAuthenticationValidityDurationSeconds;
private final boolean mUserAuthenticationValidWhileOnBody;
private final boolean mInvalidatedByBiometricEnrollment;
+ private final long mBoundToSecureUserId;
private KeyProtection(
Date keyValidityStart,
@@ -239,7 +241,8 @@ public final class KeyProtection implements ProtectionParameter {
boolean userAuthenticationRequired,
int userAuthenticationValidityDurationSeconds,
boolean userAuthenticationValidWhileOnBody,
- boolean invalidatedByBiometricEnrollment) {
+ boolean invalidatedByBiometricEnrollment,
+ long boundToSecureUserId) {
mKeyValidityStart = Utils.cloneIfNotNull(keyValidityStart);
mKeyValidityForOriginationEnd = Utils.cloneIfNotNull(keyValidityForOriginationEnd);
mKeyValidityForConsumptionEnd = Utils.cloneIfNotNull(keyValidityForConsumptionEnd);
@@ -255,6 +258,7 @@ public final class KeyProtection implements ProtectionParameter {
mUserAuthenticationValidityDurationSeconds = userAuthenticationValidityDurationSeconds;
mUserAuthenticationValidWhileOnBody = userAuthenticationValidWhileOnBody;
mInvalidatedByBiometricEnrollment = invalidatedByBiometricEnrollment;
+ mBoundToSecureUserId = boundToSecureUserId;
}
/**
@@ -436,6 +440,24 @@ public final class KeyProtection implements ProtectionParameter {
}
/**
+ * Return the secure user id that this key should be bound to.
+ *
+ * Normally an authentication-bound key is tied to the secure user id of the current user
+ * (either the root SID from GateKeeper for auth-bound keys with a timeout, or the authenticator
+ * id of the current fingerprint set for keys requiring explicit fingerprint authorization).
+ * If this parameter is set (this method returning non-zero value), the key should be tied to
+ * the specified secure user id, overriding the logic above.
+ *
+ * This is only applicable when {@link #isUserAuthenticationRequired} is {@code true}
+ *
+ * @see KeymasterUtils#addUserAuthArgs
+ * @hide
+ */
+ public long getBoundToSpecificSecureUserId() {
+ return mBoundToSecureUserId;
+ }
+
+ /**
* Builder of {@link KeyProtection} instances.
*/
public final static class Builder {
@@ -454,6 +476,7 @@ public final class KeyProtection implements ProtectionParameter {
private boolean mUserAuthenticationValidWhileOnBody;
private boolean mInvalidatedByBiometricEnrollment = true;
+ private long mBoundToSecureUserId = GateKeeper.INVALID_SECURE_USER_ID;
/**
* Creates a new instance of the {@code Builder}.
*
@@ -774,6 +797,26 @@ public final class KeyProtection implements ProtectionParameter {
}
/**
+ * Set the secure user id that this key should be bound to.
+ *
+ * Normally an authentication-bound key is tied to the secure user id of the current user
+ * (either the root SID from GateKeeper for auth-bound keys with a timeout, or the
+ * authenticator id of the current fingerprint set for keys requiring explicit fingerprint
+ * authorization). If this parameter is set (this method returning non-zero value), the key
+ * should be tied to the specified secure user id, overriding the logic above.
+ *
+ * This is only applicable when {@link #setUserAuthenticationRequired} is set to
+ * {@code true}
+ *
+ * @see KeyProtection#getBoundToSpecificSecureUserId()
+ * @hide
+ */
+ public Builder setBoundToSpecificSecureUserId(long secureUserId) {
+ mBoundToSecureUserId = secureUserId;
+ return this;
+ }
+
+ /**
* Builds an instance of {@link KeyProtection}.
*
* @throws IllegalArgumentException if a required field is missing
@@ -793,7 +836,8 @@ public final class KeyProtection implements ProtectionParameter {
mUserAuthenticationRequired,
mUserAuthenticationValidityDurationSeconds,
mUserAuthenticationValidWhileOnBody,
- mInvalidatedByBiometricEnrollment);
+ mInvalidatedByBiometricEnrollment,
+ mBoundToSecureUserId);
}
}
}
diff --git a/keystore/java/android/security/keystore/KeymasterUtils.java b/keystore/java/android/security/keystore/KeymasterUtils.java
index f5272aa233e9..34c8d1f75f60 100644
--- a/keystore/java/android/security/keystore/KeymasterUtils.java
+++ b/keystore/java/android/security/keystore/KeymasterUtils.java
@@ -89,7 +89,10 @@ public abstract class KeymasterUtils {
* @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.
- *
+ * @param boundToSpecificSecureUserId if non-zero, specify which SID the key will be bound to,
+ * overriding the default logic in this method where the key is bound to either the root
+ * SID of the current user, or the fingerprint SID if explicit fingerprint authorization
+ * is requested.
* @throws IllegalStateException if user authentication is required but the system is in a wrong
* state (e.g., secure lock screen not set up) for generating or importing keys that
* require user authentication.
@@ -98,7 +101,8 @@ public abstract class KeymasterUtils {
boolean userAuthenticationRequired,
int userAuthenticationValidityDurationSeconds,
boolean userAuthenticationValidWhileOnBody,
- boolean invalidatedByBiometricEnrollment) {
+ boolean invalidatedByBiometricEnrollment,
+ long boundToSpecificSecureUserId) {
if (!userAuthenticationRequired) {
args.addBoolean(KeymasterDefs.KM_TAG_NO_AUTH_REQUIRED);
return;
@@ -120,7 +124,9 @@ public abstract class KeymasterUtils {
}
long sid;
- if (invalidatedByBiometricEnrollment) {
+ if (boundToSpecificSecureUserId != GateKeeper.INVALID_SECURE_USER_ID) {
+ sid = boundToSpecificSecureUserId;
+ } else if (invalidatedByBiometricEnrollment) {
// The fingerprint-only SID will change on fingerprint enrollment or removal of all,
// enrolled fingerprints, invalidating the key.
sid = fingerprintOnlySid;
@@ -138,11 +144,16 @@ public abstract class KeymasterUtils {
+ "supported for keys requiring fingerprint authentication");
}
} 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();
+ long sid;
+ if (boundToSpecificSecureUserId != GateKeeper.INVALID_SECURE_USER_ID) {
+ sid = boundToSpecificSecureUserId;
+ } 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.
+ sid = getRootSid();
+ }
args.addUnsignedLong(KeymasterDefs.KM_TAG_USER_SECURE_ID,
- KeymasterArguments.toUint64(rootSid));
+ KeymasterArguments.toUint64(sid));
args.addEnum(KeymasterDefs.KM_TAG_USER_AUTH_TYPE,
KeymasterDefs.HW_AUTH_PASSWORD | KeymasterDefs.HW_AUTH_FINGERPRINT);
args.addUnsignedInt(KeymasterDefs.KM_TAG_AUTH_TIMEOUT,