diff options
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, |