From 59ced28f0f722d2517afc65d755ebb388902f76b Mon Sep 17 00:00:00 2001 From: Rubin Xu Date: Mon, 30 Jan 2017 23:39:12 +0000 Subject: [PATCH] Add hidden KeyProtection API to specify SID Allows the caller to specify which SID the given key should be bound to, overriding the default rule of binding to the current root/fingerprint SID. This is a prerequsite for introducing synthetic password based authentication flow. Test: cts-tradefed run cts -m CtsKeystoreTestCases Bug: 33126414 Change-Id: Ide03c0f4fd33ecca7a169ea763c3d4d0b173d1dd --- .../java/android/security/GateKeeper.java | 2 + .../AndroidKeyStoreKeyGeneratorSpi.java | 7 ++- .../AndroidKeyStoreKeyPairGeneratorSpi.java | 7 ++- .../security/keystore/AndroidKeyStoreSpi.java | 6 ++- .../security/keystore/KeyProtection.java | 48 ++++++++++++++++++- .../security/keystore/KeymasterUtils.java | 25 +++++++--- 6 files changed, 80 insertions(+), 15 deletions(-) diff --git a/keystore/java/android/security/GateKeeper.java b/keystore/java/android/security/GateKeeper.java index 7a2cbd06eb924..03df5de9b4842 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 b234d0f81a894..9701b0ea9308a 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 1818f52c4fda8..dba3949ba98f9 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 fcbb553c72144..64b10ab6eacb6 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 e70d33a3385c4..2592a97468d36 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; } /** @@ -435,6 +439,24 @@ public final class KeyProtection implements ProtectionParameter { return mInvalidatedByBiometricEnrollment; } + /** + * 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. */ @@ -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}. * @@ -773,6 +796,26 @@ public final class KeyProtection implements ProtectionParameter { return this; } + /** + * 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}. * @@ -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 f5272aa233e98..34c8d1f75f603 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,