diff --git a/api/current.txt b/api/current.txt index 5d28d2c3cd459..3a371cdf153d4 100644 --- a/api/current.txt +++ b/api/current.txt @@ -34094,6 +34094,7 @@ package android.security.keystore { method public boolean isDigestsSpecified(); method public boolean isRandomizedEncryptionRequired(); method public boolean isUserAuthenticationRequired(); + method public boolean isUserAuthenticationValidWhileOnBody(); } public static final class KeyGenParameterSpec.Builder { @@ -34116,6 +34117,7 @@ package android.security.keystore { method public android.security.keystore.KeyGenParameterSpec.Builder setRandomizedEncryptionRequired(boolean); method public android.security.keystore.KeyGenParameterSpec.Builder setSignaturePaddings(java.lang.String...); method public android.security.keystore.KeyGenParameterSpec.Builder setUserAuthenticationRequired(boolean); + method public android.security.keystore.KeyGenParameterSpec.Builder setUserAuthenticationValidWhileOnBody(boolean); method public android.security.keystore.KeyGenParameterSpec.Builder setUserAuthenticationValidityDurationSeconds(int); } @@ -34135,6 +34137,7 @@ package android.security.keystore { method public boolean isInsideSecureHardware(); method public boolean isUserAuthenticationRequired(); method public boolean isUserAuthenticationRequirementEnforcedBySecureHardware(); + method public boolean isUserAuthenticationValidWhileOnBody(); } public class KeyNotYetValidException extends java.security.InvalidKeyException { @@ -34197,6 +34200,7 @@ package android.security.keystore { method public boolean isDigestsSpecified(); method public boolean isRandomizedEncryptionRequired(); method public boolean isUserAuthenticationRequired(); + method public boolean isUserAuthenticationValidWhileOnBody(); } public static final class KeyProtection.Builder { @@ -34212,6 +34216,7 @@ package android.security.keystore { method public android.security.keystore.KeyProtection.Builder setRandomizedEncryptionRequired(boolean); method public android.security.keystore.KeyProtection.Builder setSignaturePaddings(java.lang.String...); method public android.security.keystore.KeyProtection.Builder setUserAuthenticationRequired(boolean); + method public android.security.keystore.KeyProtection.Builder setUserAuthenticationValidWhileOnBody(boolean); method public android.security.keystore.KeyProtection.Builder setUserAuthenticationValidityDurationSeconds(int); } diff --git a/api/system-current.txt b/api/system-current.txt index a2943ffe5b2e6..7ed4742419cf9 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -36583,6 +36583,7 @@ package android.security.keystore { method public boolean isDigestsSpecified(); method public boolean isRandomizedEncryptionRequired(); method public boolean isUserAuthenticationRequired(); + method public boolean isUserAuthenticationValidWhileOnBody(); } public static final class KeyGenParameterSpec.Builder { @@ -36605,6 +36606,7 @@ package android.security.keystore { method public android.security.keystore.KeyGenParameterSpec.Builder setRandomizedEncryptionRequired(boolean); method public android.security.keystore.KeyGenParameterSpec.Builder setSignaturePaddings(java.lang.String...); method public android.security.keystore.KeyGenParameterSpec.Builder setUserAuthenticationRequired(boolean); + method public android.security.keystore.KeyGenParameterSpec.Builder setUserAuthenticationValidWhileOnBody(boolean); method public android.security.keystore.KeyGenParameterSpec.Builder setUserAuthenticationValidityDurationSeconds(int); } @@ -36624,6 +36626,7 @@ package android.security.keystore { method public boolean isInsideSecureHardware(); method public boolean isUserAuthenticationRequired(); method public boolean isUserAuthenticationRequirementEnforcedBySecureHardware(); + method public boolean isUserAuthenticationValidWhileOnBody(); } public class KeyNotYetValidException extends java.security.InvalidKeyException { @@ -36686,6 +36689,7 @@ package android.security.keystore { method public boolean isDigestsSpecified(); method public boolean isRandomizedEncryptionRequired(); method public boolean isUserAuthenticationRequired(); + method public boolean isUserAuthenticationValidWhileOnBody(); } public static final class KeyProtection.Builder { @@ -36701,6 +36705,7 @@ package android.security.keystore { method public android.security.keystore.KeyProtection.Builder setRandomizedEncryptionRequired(boolean); method public android.security.keystore.KeyProtection.Builder setSignaturePaddings(java.lang.String...); method public android.security.keystore.KeyProtection.Builder setUserAuthenticationRequired(boolean); + method public android.security.keystore.KeyProtection.Builder setUserAuthenticationValidWhileOnBody(boolean); method public android.security.keystore.KeyProtection.Builder setUserAuthenticationValidityDurationSeconds(int); } diff --git a/api/test-current.txt b/api/test-current.txt index d42c18c10241f..cf7563cc1af01 100644 --- a/api/test-current.txt +++ b/api/test-current.txt @@ -34109,6 +34109,7 @@ package android.security.keystore { method public boolean isDigestsSpecified(); method public boolean isRandomizedEncryptionRequired(); method public boolean isUserAuthenticationRequired(); + method public boolean isUserAuthenticationValidWhileOnBody(); } public static final class KeyGenParameterSpec.Builder { @@ -34131,6 +34132,7 @@ package android.security.keystore { method public android.security.keystore.KeyGenParameterSpec.Builder setRandomizedEncryptionRequired(boolean); method public android.security.keystore.KeyGenParameterSpec.Builder setSignaturePaddings(java.lang.String...); method public android.security.keystore.KeyGenParameterSpec.Builder setUserAuthenticationRequired(boolean); + method public android.security.keystore.KeyGenParameterSpec.Builder setUserAuthenticationValidWhileOnBody(boolean); method public android.security.keystore.KeyGenParameterSpec.Builder setUserAuthenticationValidityDurationSeconds(int); } @@ -34150,6 +34152,7 @@ package android.security.keystore { method public boolean isInsideSecureHardware(); method public boolean isUserAuthenticationRequired(); method public boolean isUserAuthenticationRequirementEnforcedBySecureHardware(); + method public boolean isUserAuthenticationValidWhileOnBody(); } public class KeyNotYetValidException extends java.security.InvalidKeyException { @@ -34212,6 +34215,7 @@ package android.security.keystore { method public boolean isDigestsSpecified(); method public boolean isRandomizedEncryptionRequired(); method public boolean isUserAuthenticationRequired(); + method public boolean isUserAuthenticationValidWhileOnBody(); } public static final class KeyProtection.Builder { @@ -34227,6 +34231,7 @@ package android.security.keystore { method public android.security.keystore.KeyProtection.Builder setRandomizedEncryptionRequired(boolean); method public android.security.keystore.KeyProtection.Builder setSignaturePaddings(java.lang.String...); method public android.security.keystore.KeyProtection.Builder setUserAuthenticationRequired(boolean); + method public android.security.keystore.KeyProtection.Builder setUserAuthenticationValidWhileOnBody(boolean); method public android.security.keystore.KeyProtection.Builder setUserAuthenticationValidityDurationSeconds(int); } diff --git a/core/java/android/security/keymaster/KeymasterDefs.java b/core/java/android/security/keymaster/KeymasterDefs.java index e01f2a044ea7c..eb3d0312b2cfd 100644 --- a/core/java/android/security/keymaster/KeymasterDefs.java +++ b/core/java/android/security/keymaster/KeymasterDefs.java @@ -72,6 +72,7 @@ public final class KeymasterDefs { public static final int KM_TAG_NO_AUTH_REQUIRED = KM_BOOL | 503; public static final int KM_TAG_USER_AUTH_TYPE = KM_ENUM | 504; public static final int KM_TAG_AUTH_TIMEOUT = KM_UINT | 505; + public static final int KM_TAG_ALLOW_WHILE_ON_BODY = KM_BOOL | 506; public static final int KM_TAG_ALL_APPLICATIONS = KM_BOOL | 600; public static final int KM_TAG_APPLICATION_ID = KM_BYTES | 601; diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreKeyGeneratorSpi.java b/keystore/java/android/security/keystore/AndroidKeyStoreKeyGeneratorSpi.java index e6276a46bc3ae..1321a833acadf 100644 --- a/keystore/java/android/security/keystore/AndroidKeyStoreKeyGeneratorSpi.java +++ b/keystore/java/android/security/keystore/AndroidKeyStoreKeyGeneratorSpi.java @@ -233,7 +233,8 @@ public abstract class AndroidKeyStoreKeyGeneratorSpi extends KeyGeneratorSpi { // not set up). KeymasterUtils.addUserAuthArgs(new KeymasterArguments(), spec.isUserAuthenticationRequired(), - spec.getUserAuthenticationValidityDurationSeconds()); + spec.getUserAuthenticationValidityDurationSeconds(), + spec.isUserAuthenticationValidWhileOnBody()); } catch (IllegalStateException | IllegalArgumentException e) { throw new InvalidAlgorithmParameterException(e); } @@ -271,7 +272,8 @@ public abstract class AndroidKeyStoreKeyGeneratorSpi extends KeyGeneratorSpi { args.addEnums(KeymasterDefs.KM_TAG_DIGEST, mKeymasterDigests); KeymasterUtils.addUserAuthArgs(args, spec.isUserAuthenticationRequired(), - spec.getUserAuthenticationValidityDurationSeconds()); + spec.getUserAuthenticationValidityDurationSeconds(), + spec.isUserAuthenticationValidWhileOnBody()); KeymasterUtils.addMinMacLengthAuthorizationIfNecessary( args, mKeymasterAlgorithm, diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreKeyPairGeneratorSpi.java b/keystore/java/android/security/keystore/AndroidKeyStoreKeyPairGeneratorSpi.java index 3a0ff1c44ad92..830402a6a383a 100644 --- a/keystore/java/android/security/keystore/AndroidKeyStoreKeyPairGeneratorSpi.java +++ b/keystore/java/android/security/keystore/AndroidKeyStoreKeyPairGeneratorSpi.java @@ -344,7 +344,8 @@ public abstract class AndroidKeyStoreKeyPairGeneratorSpi extends KeyPairGenerato // not set up). KeymasterUtils.addUserAuthArgs(new KeymasterArguments(), mSpec.isUserAuthenticationRequired(), - mSpec.getUserAuthenticationValidityDurationSeconds()); + mSpec.getUserAuthenticationValidityDurationSeconds(), + mSpec.isUserAuthenticationValidWhileOnBody()); } catch (IllegalArgumentException | IllegalStateException e) { throw new InvalidAlgorithmParameterException(e); } @@ -529,7 +530,8 @@ public abstract class AndroidKeyStoreKeyPairGeneratorSpi extends KeyPairGenerato KeymasterUtils.addUserAuthArgs(args, mSpec.isUserAuthenticationRequired(), - mSpec.getUserAuthenticationValidityDurationSeconds()); + mSpec.getUserAuthenticationValidityDurationSeconds(), + mSpec.isUserAuthenticationValidWhileOnBody()); 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/AndroidKeyStoreSecretKeyFactorySpi.java b/keystore/java/android/security/keystore/AndroidKeyStoreSecretKeyFactorySpi.java index 8d606bf97d0c8..5f5f2c2441162 100644 --- a/keystore/java/android/security/keystore/AndroidKeyStoreSecretKeyFactorySpi.java +++ b/keystore/java/android/security/keystore/AndroidKeyStoreSecretKeyFactorySpi.java @@ -167,6 +167,8 @@ public class AndroidKeyStoreSecretKeyFactorySpi extends SecretKeyFactorySpi { boolean userAuthenticationRequirementEnforcedBySecureHardware = (userAuthenticationRequired) && (keymasterHwEnforcedUserAuthenticators != 0) && (keymasterSwEnforcedUserAuthenticators == 0); + boolean userAuthenticationValidWhileOnBody = + keyCharacteristics.hwEnforced.getBoolean(KeymasterDefs.KM_TAG_ALLOW_WHILE_ON_BODY); return new KeyInfo(entryAlias, insideSecureHardware, @@ -182,7 +184,8 @@ public class AndroidKeyStoreSecretKeyFactorySpi extends SecretKeyFactorySpi { blockModes, userAuthenticationRequired, (int) userAuthenticationValidityDurationSeconds, - userAuthenticationRequirementEnforcedBySecureHardware); + userAuthenticationRequirementEnforcedBySecureHardware, + userAuthenticationValidWhileOnBody); } @Override diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreSpi.java b/keystore/java/android/security/keystore/AndroidKeyStoreSpi.java index cdcc7a2db5b26..d6600208ecee5 100644 --- a/keystore/java/android/security/keystore/AndroidKeyStoreSpi.java +++ b/keystore/java/android/security/keystore/AndroidKeyStoreSpi.java @@ -498,7 +498,8 @@ public class AndroidKeyStoreSpi extends KeyStoreSpi { KeyProperties.SignaturePadding.allToKeymaster(spec.getSignaturePaddings())); KeymasterUtils.addUserAuthArgs(importArgs, spec.isUserAuthenticationRequired(), - spec.getUserAuthenticationValidityDurationSeconds()); + spec.getUserAuthenticationValidityDurationSeconds(), + spec.isUserAuthenticationValidWhileOnBody()); importArgs.addDateIfNotNull(KeymasterDefs.KM_TAG_ACTIVE_DATETIME, spec.getKeyValidityStart()); importArgs.addDateIfNotNull(KeymasterDefs.KM_TAG_ORIGINATION_EXPIRE_DATETIME, @@ -692,7 +693,8 @@ public class AndroidKeyStoreSpi extends KeyStoreSpi { args.addEnums(KeymasterDefs.KM_TAG_PADDING, keymasterPaddings); KeymasterUtils.addUserAuthArgs(args, params.isUserAuthenticationRequired(), - params.getUserAuthenticationValidityDurationSeconds()); + params.getUserAuthenticationValidityDurationSeconds(), + params.isUserAuthenticationValidWhileOnBody()); KeymasterUtils.addMinMacLengthAuthorizationIfNecessary( args, keymasterAlgorithm, diff --git a/keystore/java/android/security/keystore/KeyGenParameterSpec.java b/keystore/java/android/security/keystore/KeyGenParameterSpec.java index f3fd1299354a7..a84e7f34be8de 100644 --- a/keystore/java/android/security/keystore/KeyGenParameterSpec.java +++ b/keystore/java/android/security/keystore/KeyGenParameterSpec.java @@ -252,6 +252,7 @@ public final class KeyGenParameterSpec implements AlgorithmParameterSpec { private final int mUserAuthenticationValidityDurationSeconds; private final byte[] mAttestationChallenge; private final boolean mUniqueIdIncluded; + private final boolean mUserAuthenticationValidWhileOnBody; /** * @hide should be built with Builder @@ -277,7 +278,8 @@ public final class KeyGenParameterSpec implements AlgorithmParameterSpec { boolean userAuthenticationRequired, int userAuthenticationValidityDurationSeconds, byte[] attestationChallenge, - boolean uniqueIdIncluded) { + boolean uniqueIdIncluded, + boolean userAuthenticationValidWhileOnBody) { if (TextUtils.isEmpty(keyStoreAlias)) { throw new IllegalArgumentException("keyStoreAlias must not be empty"); } @@ -321,6 +323,7 @@ public final class KeyGenParameterSpec implements AlgorithmParameterSpec { mUserAuthenticationValidityDurationSeconds = userAuthenticationValidityDurationSeconds; mAttestationChallenge = Utils.cloneIfNotNull(attestationChallenge); mUniqueIdIncluded = uniqueIdIncluded; + mUserAuthenticationValidWhileOnBody = userAuthenticationValidWhileOnBody; } /** @@ -586,6 +589,23 @@ public final class KeyGenParameterSpec implements AlgorithmParameterSpec { return mUniqueIdIncluded; } + /** + * Returns {@code true} if the key will remain authorized while the device is on the user's + * body, even after the validity duration has expired. This option has no effect on keys that + * don't have an authentication validity duration, and has no effect if the device lacks a + * secure on-body sensor. + * + *

Authorization applies only to secret key and private key operations. Public key operations + * are not restricted. + * + * @see #isUserAuthenticationRequired() + * @see #getUserAuthenticationValidityDurationSeconds() + * @see Builder#setUserAuthenticationValidWhileOnBody(boolean) + */ + public boolean isUserAuthenticationValidWhileOnBody() { + return mUserAuthenticationValidWhileOnBody; + } + /** * Builder of {@link KeyGenParameterSpec} instances. */ @@ -612,6 +632,7 @@ public final class KeyGenParameterSpec implements AlgorithmParameterSpec { private int mUserAuthenticationValidityDurationSeconds = -1; private byte[] mAttestationChallenge = null; private boolean mUniqueIdIncluded = false; + private boolean mUserAuthenticationValidWhileOnBody; /** * Creates a new instance of the {@code Builder}. @@ -1060,6 +1081,34 @@ public final class KeyGenParameterSpec implements AlgorithmParameterSpec { return this; } + /** + * Sets whether the key is authorized for use after the authentication validity period is + * expired (see {@link #setUserAuthenticationValidityDurationSeconds} and {@link + * #setUserAuthenticationRequired}) if the device has a secure on-body sensor and if the + * device has not been removed from the user's body since the last successful + * authentication. + * + *

On devices that do not have a secure on-body sensor, creating a key with this + * parameter set to {@code true} will have no effect; the private or secret key will no + * longer be authorized for use after the validity period ends, and a fresh authentication + * will be required to use it again. + * + *

Note that "secure" on-body sensors are required by Android to have a secure path to + * the secure hardware, but the sensors themselves may not be difficult to fool. It is + * recommended that this feature be used to increase slightly the security of keys which + * would otherwise have to allow unauthenticated access, or have a very long validity + * period. Keys that require high assurance of user authorization should not use this + * feature and should set a short validity period. + * + * @param remainsValid if {@code true}, and if the device supports secure on-body detection, + * key will remain valid after authentication validity duration has expired. + */ + @NonNull + public Builder setUserAuthenticationValidWhileOnBody(boolean remainsValid) { + mUserAuthenticationValidWhileOnBody = remainsValid; + return this; + } + /** * Builds an instance of {@code KeyGenParameterSpec}. */ @@ -1086,7 +1135,8 @@ public final class KeyGenParameterSpec implements AlgorithmParameterSpec { mUserAuthenticationRequired, mUserAuthenticationValidityDurationSeconds, mAttestationChallenge, - mUniqueIdIncluded); + mUniqueIdIncluded, + mUserAuthenticationValidWhileOnBody); } } } diff --git a/keystore/java/android/security/keystore/KeyInfo.java b/keystore/java/android/security/keystore/KeyInfo.java index d72688079d0e1..f77b5bac0363b 100644 --- a/keystore/java/android/security/keystore/KeyInfo.java +++ b/keystore/java/android/security/keystore/KeyInfo.java @@ -79,6 +79,7 @@ public class KeyInfo implements KeySpec { private final boolean mUserAuthenticationRequired; private final int mUserAuthenticationValidityDurationSeconds; private final boolean mUserAuthenticationRequirementEnforcedBySecureHardware; + private final boolean mUserAuthenticationValidWhileOnBody; /** * @hide @@ -97,7 +98,8 @@ public class KeyInfo implements KeySpec { @KeyProperties.BlockModeEnum String[] blockModes, boolean userAuthenticationRequired, int userAuthenticationValidityDurationSeconds, - boolean userAuthenticationRequirementEnforcedBySecureHardware) { + boolean userAuthenticationRequirementEnforcedBySecureHardware, + boolean userAuthenticationValidWhileOnBody) { mKeystoreAlias = keystoreKeyAlias; mInsideSecureHardware = insideSecureHardware; mOrigin = origin; @@ -116,6 +118,7 @@ public class KeyInfo implements KeySpec { mUserAuthenticationValidityDurationSeconds = userAuthenticationValidityDurationSeconds; mUserAuthenticationRequirementEnforcedBySecureHardware = userAuthenticationRequirementEnforcedBySecureHardware; + mUserAuthenticationValidWhileOnBody = userAuthenticationValidWhileOnBody; } /** @@ -277,4 +280,14 @@ public class KeyInfo implements KeySpec { public boolean isUserAuthenticationRequirementEnforcedBySecureHardware() { return mUserAuthenticationRequirementEnforcedBySecureHardware; } + + /** + * Returns {@code true} if this key will remain usable after its specified validity duration + * for as long as the device remains on the user's body. This is possible only for keys with + * a specified validity duration. Always returns {@code false} on devices that lack a secure + * on-body sensor. + */ + public boolean isUserAuthenticationValidWhileOnBody() { + return mUserAuthenticationValidWhileOnBody; + } } diff --git a/keystore/java/android/security/keystore/KeyProtection.java b/keystore/java/android/security/keystore/KeyProtection.java index c98443978105e..4700b68261db1 100644 --- a/keystore/java/android/security/keystore/KeyProtection.java +++ b/keystore/java/android/security/keystore/KeyProtection.java @@ -214,6 +214,7 @@ public final class KeyProtection implements ProtectionParameter { private final boolean mRandomizedEncryptionRequired; private final boolean mUserAuthenticationRequired; private final int mUserAuthenticationValidityDurationSeconds; + private final boolean mUserAuthenticationValidWhileOnBody; private KeyProtection( Date keyValidityStart, @@ -226,7 +227,8 @@ public final class KeyProtection implements ProtectionParameter { @KeyProperties.BlockModeEnum String[] blockModes, boolean randomizedEncryptionRequired, boolean userAuthenticationRequired, - int userAuthenticationValidityDurationSeconds) { + int userAuthenticationValidityDurationSeconds, + boolean userAuthenticationValidWhileOnBody) { mKeyValidityStart = Utils.cloneIfNotNull(keyValidityStart); mKeyValidityForOriginationEnd = Utils.cloneIfNotNull(keyValidityForOriginationEnd); mKeyValidityForConsumptionEnd = Utils.cloneIfNotNull(keyValidityForConsumptionEnd); @@ -240,6 +242,7 @@ public final class KeyProtection implements ProtectionParameter { mRandomizedEncryptionRequired = randomizedEncryptionRequired; mUserAuthenticationRequired = userAuthenticationRequired; mUserAuthenticationValidityDurationSeconds = userAuthenticationValidityDurationSeconds; + mUserAuthenticationValidWhileOnBody = userAuthenticationValidWhileOnBody; } /** @@ -391,6 +394,23 @@ public final class KeyProtection implements ProtectionParameter { return mUserAuthenticationValidityDurationSeconds; } + /** + * Returns {@code true} if the key will remain authorized while the device is on the user's + * body, even after the validity duration has expired. This option has no effect on keys that + * don't have an authentication validity duration, and has no effect if the device lacks a + * secure on-body sensor. + * + *

Authorization applies only to secret key and private key operations. Public key operations + * are not restricted. + * + * @see #isUserAuthenticationRequired() + * @see #getUserAuthenticationValidityDurationSeconds() + * @see Builder#setUserAuthenticationValidWhileOnBody(boolean) + */ + public boolean isUserAuthenticationValidWhileOnBody() { + return mUserAuthenticationValidWhileOnBody; + } + /** * Builder of {@link KeyProtection} instances. */ @@ -407,6 +427,7 @@ public final class KeyProtection implements ProtectionParameter { private boolean mRandomizedEncryptionRequired = true; private boolean mUserAuthenticationRequired; private int mUserAuthenticationValidityDurationSeconds = -1; + private boolean mUserAuthenticationValidWhileOnBody; /** * Creates a new instance of the {@code Builder}. @@ -679,6 +700,34 @@ public final class KeyProtection implements ProtectionParameter { return this; } + /** + * Sets whether the key is authorized for use after the authentication validity period is + * expired (see {@link #setUserAuthenticationValidityDurationSeconds} and {@link + * #setUserAuthenticationRequired}) if the device has a secure on-body sensor and if the + * device has not been removed from the user's body since the last successful + * authentication. + * + *

On devices that do not have a secure on-body sensor, creating a key with this + * parameter set to {@code true} will have no effect; the private or secret key will no + * longer be authorized for use after the validity period ends, and a fresh authentication + * will be required to use it again. + * + *

Note that "secure" on-body sensors are required by Android to have a secure path to + * the secure hardware, but the sensors themselves may not be difficult to fool. It is + * recommended that this feature be used to increase slightly the security of keys which + * would otherwise have to allow unauthenticated access, or have a very long validity + * period. Keys that require high assurance of user authorization should not use this + * feature and should set a short validity period. + * + * @param remainsValid if {@code true}, and if the device supports secure on-body detection, + * key will remain valid after authentication validity duration has expired. + */ + @NonNull + public Builder setUserAuthenticationValidWhileOnBody(boolean remainsValid) { + mUserAuthenticationValidWhileOnBody = remainsValid; + return this; + } + /** * Builds an instance of {@link KeyProtection}. * @@ -697,7 +746,8 @@ public final class KeyProtection implements ProtectionParameter { mBlockModes, mRandomizedEncryptionRequired, mUserAuthenticationRequired, - mUserAuthenticationValidityDurationSeconds); + mUserAuthenticationValidityDurationSeconds, + mUserAuthenticationValidWhileOnBody); } } } diff --git a/keystore/java/android/security/keystore/KeymasterUtils.java b/keystore/java/android/security/keystore/KeymasterUtils.java index feafbfa653944..3a008bcf68324 100644 --- a/keystore/java/android/security/keystore/KeymasterUtils.java +++ b/keystore/java/android/security/keystore/KeymasterUtils.java @@ -96,7 +96,8 @@ public abstract class KeymasterUtils { */ public static void addUserAuthArgs(KeymasterArguments args, boolean userAuthenticationRequired, - int userAuthenticationValidityDurationSeconds) { + int userAuthenticationValidityDurationSeconds, + boolean userAuthenticationValidWhileOnBody) { if (!userAuthenticationRequired) { args.addBoolean(KeymasterDefs.KM_TAG_NO_AUTH_REQUIRED); return; @@ -119,6 +120,10 @@ public abstract class KeymasterUtils { args.addUnsignedLong(KeymasterDefs.KM_TAG_USER_SECURE_ID, KeymasterArguments.toUint64(fingerprintOnlySid)); args.addEnum(KeymasterDefs.KM_TAG_USER_AUTH_TYPE, KeymasterDefs.HW_AUTH_FINGERPRINT); + if (userAuthenticationValidWhileOnBody) { + throw new ProviderException("Key validity extension while device is on-body is not " + + "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. @@ -133,6 +138,9 @@ public abstract class KeymasterUtils { KeymasterDefs.HW_AUTH_PASSWORD | KeymasterDefs.HW_AUTH_FINGERPRINT); args.addUnsignedInt(KeymasterDefs.KM_TAG_AUTH_TIMEOUT, userAuthenticationValidityDurationSeconds); + if (userAuthenticationValidWhileOnBody) { + args.addBoolean(KeymasterDefs.KM_TAG_ALLOW_WHILE_ON_BODY); + } } }