Revert "Revert "Add option to allow key validity after fingerprint enrollment.""
This reverts commit 512c132f49
.
Change-Id: Iac381dfebcfe42f0468569eb2395ebeb97a95887
This commit is contained in:
@ -34112,6 +34112,7 @@ package android.security.keystore {
|
||||
method public java.lang.String[] getSignaturePaddings();
|
||||
method public int getUserAuthenticationValidityDurationSeconds();
|
||||
method public boolean isDigestsSpecified();
|
||||
method public boolean isInvalidatedByBiometricEnrollment();
|
||||
method public boolean isRandomizedEncryptionRequired();
|
||||
method public boolean isUserAuthenticationRequired();
|
||||
method public boolean isUserAuthenticationValidWhileOnBody();
|
||||
@ -34129,6 +34130,7 @@ package android.security.keystore {
|
||||
method public android.security.keystore.KeyGenParameterSpec.Builder setCertificateSubject(javax.security.auth.x500.X500Principal);
|
||||
method public android.security.keystore.KeyGenParameterSpec.Builder setDigests(java.lang.String...);
|
||||
method public android.security.keystore.KeyGenParameterSpec.Builder setEncryptionPaddings(java.lang.String...);
|
||||
method public android.security.keystore.KeyGenParameterSpec.Builder setInvalidatedByBiometricEnrollment(boolean);
|
||||
method public android.security.keystore.KeyGenParameterSpec.Builder setKeySize(int);
|
||||
method public android.security.keystore.KeyGenParameterSpec.Builder setKeyValidityEnd(java.util.Date);
|
||||
method public android.security.keystore.KeyGenParameterSpec.Builder setKeyValidityForConsumptionEnd(java.util.Date);
|
||||
@ -34155,6 +34157,7 @@ package android.security.keystore {
|
||||
method public java.lang.String[] getSignaturePaddings();
|
||||
method public int getUserAuthenticationValidityDurationSeconds();
|
||||
method public boolean isInsideSecureHardware();
|
||||
method public boolean isInvalidatedByBiometricEnrollment();
|
||||
method public boolean isUserAuthenticationRequired();
|
||||
method public boolean isUserAuthenticationRequirementEnforcedBySecureHardware();
|
||||
method public boolean isUserAuthenticationValidWhileOnBody();
|
||||
@ -34218,6 +34221,7 @@ package android.security.keystore {
|
||||
method public java.lang.String[] getSignaturePaddings();
|
||||
method public int getUserAuthenticationValidityDurationSeconds();
|
||||
method public boolean isDigestsSpecified();
|
||||
method public boolean isInvalidatedByBiometricEnrollment();
|
||||
method public boolean isRandomizedEncryptionRequired();
|
||||
method public boolean isUserAuthenticationRequired();
|
||||
method public boolean isUserAuthenticationValidWhileOnBody();
|
||||
@ -34229,6 +34233,7 @@ package android.security.keystore {
|
||||
method public android.security.keystore.KeyProtection.Builder setBlockModes(java.lang.String...);
|
||||
method public android.security.keystore.KeyProtection.Builder setDigests(java.lang.String...);
|
||||
method public android.security.keystore.KeyProtection.Builder setEncryptionPaddings(java.lang.String...);
|
||||
method public android.security.keystore.KeyProtection.Builder setInvalidatedByBiometricEnrollment(boolean);
|
||||
method public android.security.keystore.KeyProtection.Builder setKeyValidityEnd(java.util.Date);
|
||||
method public android.security.keystore.KeyProtection.Builder setKeyValidityForConsumptionEnd(java.util.Date);
|
||||
method public android.security.keystore.KeyProtection.Builder setKeyValidityForOriginationEnd(java.util.Date);
|
||||
|
@ -36608,6 +36608,7 @@ package android.security.keystore {
|
||||
method public java.lang.String[] getSignaturePaddings();
|
||||
method public int getUserAuthenticationValidityDurationSeconds();
|
||||
method public boolean isDigestsSpecified();
|
||||
method public boolean isInvalidatedByBiometricEnrollment();
|
||||
method public boolean isRandomizedEncryptionRequired();
|
||||
method public boolean isUserAuthenticationRequired();
|
||||
method public boolean isUserAuthenticationValidWhileOnBody();
|
||||
@ -36625,6 +36626,7 @@ package android.security.keystore {
|
||||
method public android.security.keystore.KeyGenParameterSpec.Builder setCertificateSubject(javax.security.auth.x500.X500Principal);
|
||||
method public android.security.keystore.KeyGenParameterSpec.Builder setDigests(java.lang.String...);
|
||||
method public android.security.keystore.KeyGenParameterSpec.Builder setEncryptionPaddings(java.lang.String...);
|
||||
method public android.security.keystore.KeyGenParameterSpec.Builder setInvalidatedByBiometricEnrollment(boolean);
|
||||
method public android.security.keystore.KeyGenParameterSpec.Builder setKeySize(int);
|
||||
method public android.security.keystore.KeyGenParameterSpec.Builder setKeyValidityEnd(java.util.Date);
|
||||
method public android.security.keystore.KeyGenParameterSpec.Builder setKeyValidityForConsumptionEnd(java.util.Date);
|
||||
@ -36651,6 +36653,7 @@ package android.security.keystore {
|
||||
method public java.lang.String[] getSignaturePaddings();
|
||||
method public int getUserAuthenticationValidityDurationSeconds();
|
||||
method public boolean isInsideSecureHardware();
|
||||
method public boolean isInvalidatedByBiometricEnrollment();
|
||||
method public boolean isUserAuthenticationRequired();
|
||||
method public boolean isUserAuthenticationRequirementEnforcedBySecureHardware();
|
||||
method public boolean isUserAuthenticationValidWhileOnBody();
|
||||
@ -36714,6 +36717,7 @@ package android.security.keystore {
|
||||
method public java.lang.String[] getSignaturePaddings();
|
||||
method public int getUserAuthenticationValidityDurationSeconds();
|
||||
method public boolean isDigestsSpecified();
|
||||
method public boolean isInvalidatedByBiometricEnrollment();
|
||||
method public boolean isRandomizedEncryptionRequired();
|
||||
method public boolean isUserAuthenticationRequired();
|
||||
method public boolean isUserAuthenticationValidWhileOnBody();
|
||||
@ -36725,6 +36729,7 @@ package android.security.keystore {
|
||||
method public android.security.keystore.KeyProtection.Builder setBlockModes(java.lang.String...);
|
||||
method public android.security.keystore.KeyProtection.Builder setDigests(java.lang.String...);
|
||||
method public android.security.keystore.KeyProtection.Builder setEncryptionPaddings(java.lang.String...);
|
||||
method public android.security.keystore.KeyProtection.Builder setInvalidatedByBiometricEnrollment(boolean);
|
||||
method public android.security.keystore.KeyProtection.Builder setKeyValidityEnd(java.util.Date);
|
||||
method public android.security.keystore.KeyProtection.Builder setKeyValidityForConsumptionEnd(java.util.Date);
|
||||
method public android.security.keystore.KeyProtection.Builder setKeyValidityForOriginationEnd(java.util.Date);
|
||||
|
@ -34127,6 +34127,7 @@ package android.security.keystore {
|
||||
method public java.lang.String[] getSignaturePaddings();
|
||||
method public int getUserAuthenticationValidityDurationSeconds();
|
||||
method public boolean isDigestsSpecified();
|
||||
method public boolean isInvalidatedByBiometricEnrollment();
|
||||
method public boolean isRandomizedEncryptionRequired();
|
||||
method public boolean isUserAuthenticationRequired();
|
||||
method public boolean isUserAuthenticationValidWhileOnBody();
|
||||
@ -34144,6 +34145,7 @@ package android.security.keystore {
|
||||
method public android.security.keystore.KeyGenParameterSpec.Builder setCertificateSubject(javax.security.auth.x500.X500Principal);
|
||||
method public android.security.keystore.KeyGenParameterSpec.Builder setDigests(java.lang.String...);
|
||||
method public android.security.keystore.KeyGenParameterSpec.Builder setEncryptionPaddings(java.lang.String...);
|
||||
method public android.security.keystore.KeyGenParameterSpec.Builder setInvalidatedByBiometricEnrollment(boolean);
|
||||
method public android.security.keystore.KeyGenParameterSpec.Builder setKeySize(int);
|
||||
method public android.security.keystore.KeyGenParameterSpec.Builder setKeyValidityEnd(java.util.Date);
|
||||
method public android.security.keystore.KeyGenParameterSpec.Builder setKeyValidityForConsumptionEnd(java.util.Date);
|
||||
@ -34170,6 +34172,7 @@ package android.security.keystore {
|
||||
method public java.lang.String[] getSignaturePaddings();
|
||||
method public int getUserAuthenticationValidityDurationSeconds();
|
||||
method public boolean isInsideSecureHardware();
|
||||
method public boolean isInvalidatedByBiometricEnrollment();
|
||||
method public boolean isUserAuthenticationRequired();
|
||||
method public boolean isUserAuthenticationRequirementEnforcedBySecureHardware();
|
||||
method public boolean isUserAuthenticationValidWhileOnBody();
|
||||
@ -34233,6 +34236,7 @@ package android.security.keystore {
|
||||
method public java.lang.String[] getSignaturePaddings();
|
||||
method public int getUserAuthenticationValidityDurationSeconds();
|
||||
method public boolean isDigestsSpecified();
|
||||
method public boolean isInvalidatedByBiometricEnrollment();
|
||||
method public boolean isRandomizedEncryptionRequired();
|
||||
method public boolean isUserAuthenticationRequired();
|
||||
method public boolean isUserAuthenticationValidWhileOnBody();
|
||||
@ -34244,6 +34248,7 @@ package android.security.keystore {
|
||||
method public android.security.keystore.KeyProtection.Builder setBlockModes(java.lang.String...);
|
||||
method public android.security.keystore.KeyProtection.Builder setDigests(java.lang.String...);
|
||||
method public android.security.keystore.KeyProtection.Builder setEncryptionPaddings(java.lang.String...);
|
||||
method public android.security.keystore.KeyProtection.Builder setInvalidatedByBiometricEnrollment(boolean);
|
||||
method public android.security.keystore.KeyProtection.Builder setKeyValidityEnd(java.util.Date);
|
||||
method public android.security.keystore.KeyProtection.Builder setKeyValidityForConsumptionEnd(java.util.Date);
|
||||
method public android.security.keystore.KeyProtection.Builder setKeyValidityForOriginationEnd(java.util.Date);
|
||||
|
@ -234,7 +234,8 @@ public abstract class AndroidKeyStoreKeyGeneratorSpi extends KeyGeneratorSpi {
|
||||
KeymasterUtils.addUserAuthArgs(new KeymasterArguments(),
|
||||
spec.isUserAuthenticationRequired(),
|
||||
spec.getUserAuthenticationValidityDurationSeconds(),
|
||||
spec.isUserAuthenticationValidWhileOnBody());
|
||||
spec.isUserAuthenticationValidWhileOnBody(),
|
||||
spec.isInvalidatedByBiometricEnrollment());
|
||||
} catch (IllegalStateException | IllegalArgumentException e) {
|
||||
throw new InvalidAlgorithmParameterException(e);
|
||||
}
|
||||
@ -273,7 +274,8 @@ public abstract class AndroidKeyStoreKeyGeneratorSpi extends KeyGeneratorSpi {
|
||||
KeymasterUtils.addUserAuthArgs(args,
|
||||
spec.isUserAuthenticationRequired(),
|
||||
spec.getUserAuthenticationValidityDurationSeconds(),
|
||||
spec.isUserAuthenticationValidWhileOnBody());
|
||||
spec.isUserAuthenticationValidWhileOnBody(),
|
||||
spec.isInvalidatedByBiometricEnrollment());
|
||||
KeymasterUtils.addMinMacLengthAuthorizationIfNecessary(
|
||||
args,
|
||||
mKeymasterAlgorithm,
|
||||
|
@ -345,7 +345,8 @@ public abstract class AndroidKeyStoreKeyPairGeneratorSpi extends KeyPairGenerato
|
||||
KeymasterUtils.addUserAuthArgs(new KeymasterArguments(),
|
||||
mSpec.isUserAuthenticationRequired(),
|
||||
mSpec.getUserAuthenticationValidityDurationSeconds(),
|
||||
mSpec.isUserAuthenticationValidWhileOnBody());
|
||||
mSpec.isUserAuthenticationValidWhileOnBody(),
|
||||
mSpec.isInvalidatedByBiometricEnrollment());
|
||||
} catch (IllegalArgumentException | IllegalStateException e) {
|
||||
throw new InvalidAlgorithmParameterException(e);
|
||||
}
|
||||
@ -531,7 +532,8 @@ public abstract class AndroidKeyStoreKeyPairGeneratorSpi extends KeyPairGenerato
|
||||
KeymasterUtils.addUserAuthArgs(args,
|
||||
mSpec.isUserAuthenticationRequired(),
|
||||
mSpec.getUserAuthenticationValidityDurationSeconds(),
|
||||
mSpec.isUserAuthenticationValidWhileOnBody());
|
||||
mSpec.isUserAuthenticationValidWhileOnBody(),
|
||||
mSpec.isInvalidatedByBiometricEnrollment());
|
||||
args.addDateIfNotNull(KeymasterDefs.KM_TAG_ACTIVE_DATETIME, mSpec.getKeyValidityStart());
|
||||
args.addDateIfNotNull(KeymasterDefs.KM_TAG_ORIGINATION_EXPIRE_DATETIME,
|
||||
mSpec.getKeyValidityForOriginationEnd());
|
||||
|
@ -17,10 +17,12 @@
|
||||
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.KeymasterDefs;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.security.InvalidKeyException;
|
||||
import java.security.ProviderException;
|
||||
import java.security.spec.InvalidKeySpecException;
|
||||
@ -91,6 +93,7 @@ public class AndroidKeyStoreSecretKeyFactorySpi extends SecretKeyFactorySpi {
|
||||
@KeyProperties.BlockModeEnum String[] blockModes;
|
||||
int keymasterSwEnforcedUserAuthenticators;
|
||||
int keymasterHwEnforcedUserAuthenticators;
|
||||
List<BigInteger> keymasterSecureUserIds;
|
||||
try {
|
||||
if (keyCharacteristics.hwEnforced.containsTag(KeymasterDefs.KM_TAG_ORIGIN)) {
|
||||
insideSecureHardware = true;
|
||||
@ -147,6 +150,8 @@ public class AndroidKeyStoreSecretKeyFactorySpi extends SecretKeyFactorySpi {
|
||||
keyCharacteristics.swEnforced.getEnum(KeymasterDefs.KM_TAG_USER_AUTH_TYPE, 0);
|
||||
keymasterHwEnforcedUserAuthenticators =
|
||||
keyCharacteristics.hwEnforced.getEnum(KeymasterDefs.KM_TAG_USER_AUTH_TYPE, 0);
|
||||
keymasterSecureUserIds =
|
||||
keyCharacteristics.getUnsignedLongs(KeymasterDefs.KM_TAG_USER_SECURE_ID);
|
||||
} catch (IllegalArgumentException e) {
|
||||
throw new ProviderException("Unsupported key characteristic", e);
|
||||
}
|
||||
@ -170,6 +175,15 @@ public class AndroidKeyStoreSecretKeyFactorySpi extends SecretKeyFactorySpi {
|
||||
boolean userAuthenticationValidWhileOnBody =
|
||||
keyCharacteristics.hwEnforced.getBoolean(KeymasterDefs.KM_TAG_ALLOW_WHILE_ON_BODY);
|
||||
|
||||
boolean invalidatedByBiometricEnrollment = false;
|
||||
if (keymasterSwEnforcedUserAuthenticators == KeymasterDefs.HW_AUTH_FINGERPRINT
|
||||
|| keymasterHwEnforcedUserAuthenticators == KeymasterDefs.HW_AUTH_FINGERPRINT) {
|
||||
// Fingerprint-only key; will be invalidated if the root SID isn't in the SID list.
|
||||
invalidatedByBiometricEnrollment = keymasterSecureUserIds != null
|
||||
&& !keymasterSecureUserIds.isEmpty()
|
||||
&& !keymasterSecureUserIds.contains(getGateKeeperSecureUserId());
|
||||
}
|
||||
|
||||
return new KeyInfo(entryAlias,
|
||||
insideSecureHardware,
|
||||
origin,
|
||||
@ -185,7 +199,16 @@ public class AndroidKeyStoreSecretKeyFactorySpi extends SecretKeyFactorySpi {
|
||||
userAuthenticationRequired,
|
||||
(int) userAuthenticationValidityDurationSeconds,
|
||||
userAuthenticationRequirementEnforcedBySecureHardware,
|
||||
userAuthenticationValidWhileOnBody);
|
||||
userAuthenticationValidWhileOnBody,
|
||||
invalidatedByBiometricEnrollment);
|
||||
}
|
||||
|
||||
private static BigInteger getGateKeeperSecureUserId() throws ProviderException {
|
||||
try {
|
||||
return BigInteger.valueOf(GateKeeper.getSecureUserId());
|
||||
} catch (IllegalStateException e) {
|
||||
throw new ProviderException("Failed to get GateKeeper secure user ID", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -499,7 +499,8 @@ public class AndroidKeyStoreSpi extends KeyStoreSpi {
|
||||
KeymasterUtils.addUserAuthArgs(importArgs,
|
||||
spec.isUserAuthenticationRequired(),
|
||||
spec.getUserAuthenticationValidityDurationSeconds(),
|
||||
spec.isUserAuthenticationValidWhileOnBody());
|
||||
spec.isUserAuthenticationValidWhileOnBody(),
|
||||
spec.isInvalidatedByBiometricEnrollment());
|
||||
importArgs.addDateIfNotNull(KeymasterDefs.KM_TAG_ACTIVE_DATETIME,
|
||||
spec.getKeyValidityStart());
|
||||
importArgs.addDateIfNotNull(KeymasterDefs.KM_TAG_ORIGINATION_EXPIRE_DATETIME,
|
||||
@ -694,7 +695,8 @@ public class AndroidKeyStoreSpi extends KeyStoreSpi {
|
||||
KeymasterUtils.addUserAuthArgs(args,
|
||||
params.isUserAuthenticationRequired(),
|
||||
params.getUserAuthenticationValidityDurationSeconds(),
|
||||
params.isUserAuthenticationValidWhileOnBody());
|
||||
params.isUserAuthenticationValidWhileOnBody(),
|
||||
params.isInvalidatedByBiometricEnrollment());
|
||||
KeymasterUtils.addMinMacLengthAuthorizationIfNecessary(
|
||||
args,
|
||||
keymasterAlgorithm,
|
||||
|
@ -253,6 +253,7 @@ public final class KeyGenParameterSpec implements AlgorithmParameterSpec {
|
||||
private final byte[] mAttestationChallenge;
|
||||
private final boolean mUniqueIdIncluded;
|
||||
private final boolean mUserAuthenticationValidWhileOnBody;
|
||||
private final boolean mInvalidatedByBiometricEnrollment;
|
||||
|
||||
/**
|
||||
* @hide should be built with Builder
|
||||
@ -279,7 +280,8 @@ public final class KeyGenParameterSpec implements AlgorithmParameterSpec {
|
||||
int userAuthenticationValidityDurationSeconds,
|
||||
byte[] attestationChallenge,
|
||||
boolean uniqueIdIncluded,
|
||||
boolean userAuthenticationValidWhileOnBody) {
|
||||
boolean userAuthenticationValidWhileOnBody,
|
||||
boolean invalidatedByBiometricEnrollment) {
|
||||
if (TextUtils.isEmpty(keyStoreAlias)) {
|
||||
throw new IllegalArgumentException("keyStoreAlias must not be empty");
|
||||
}
|
||||
@ -324,6 +326,7 @@ public final class KeyGenParameterSpec implements AlgorithmParameterSpec {
|
||||
mAttestationChallenge = Utils.cloneIfNotNull(attestationChallenge);
|
||||
mUniqueIdIncluded = uniqueIdIncluded;
|
||||
mUserAuthenticationValidWhileOnBody = userAuthenticationValidWhileOnBody;
|
||||
mInvalidatedByBiometricEnrollment = invalidatedByBiometricEnrollment;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -606,6 +609,19 @@ public final class KeyGenParameterSpec implements AlgorithmParameterSpec {
|
||||
return mUserAuthenticationValidWhileOnBody;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns {@code true} if the key is irreversibly invalidated when a new fingerprint is
|
||||
* enrolled or all enrolled fingerprints are removed. This has effect only for keys that
|
||||
* require fingerprint user authentication for every use.
|
||||
*
|
||||
* @see #isUserAuthenticationRequired()
|
||||
* @see #getUserAuthenticationValidityDurationSeconds()
|
||||
* @see Builder#setInvalidatedByBiometricEnrollment(boolean)
|
||||
*/
|
||||
public boolean isInvalidatedByBiometricEnrollment() {
|
||||
return mInvalidatedByBiometricEnrollment;
|
||||
}
|
||||
|
||||
/**
|
||||
* Builder of {@link KeyGenParameterSpec} instances.
|
||||
*/
|
||||
@ -633,6 +649,7 @@ public final class KeyGenParameterSpec implements AlgorithmParameterSpec {
|
||||
private byte[] mAttestationChallenge = null;
|
||||
private boolean mUniqueIdIncluded = false;
|
||||
private boolean mUserAuthenticationValidWhileOnBody;
|
||||
private boolean mInvalidatedByBiometricEnrollment = true;
|
||||
|
||||
/**
|
||||
* Creates a new instance of the {@code Builder}.
|
||||
@ -966,8 +983,10 @@ public final class KeyGenParameterSpec implements AlgorithmParameterSpec {
|
||||
* or when the secure lock screen is forcibly reset (e.g., by a Device Administrator).
|
||||
* Additionally, if the key requires that user authentication takes place for every use of
|
||||
* the key, it is also irreversibly invalidated once a new fingerprint is enrolled or once\
|
||||
* no more fingerprints are enrolled. Attempts to initialize cryptographic operations using
|
||||
* such keys will throw {@link KeyPermanentlyInvalidatedException}.</li>
|
||||
* no more fingerprints are enrolled, unless {@link
|
||||
* #setInvalidatedByBiometricEnrollment(boolean)} is used to allow validity after
|
||||
* enrollment. Attempts to initialize cryptographic operations using such keys will throw
|
||||
* {@link KeyPermanentlyInvalidatedException}.</li>
|
||||
* </ul>
|
||||
*
|
||||
* <p>This authorization applies only to secret key and private key operations. Public key
|
||||
@ -1109,6 +1128,30 @@ public final class KeyGenParameterSpec implements AlgorithmParameterSpec {
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets whether this key should be invalidated on fingerprint enrollment. This
|
||||
* applies only to keys which require user authentication (see {@link
|
||||
* #setUserAuthenticationRequired(boolean)}) and if no positive validity duration has been
|
||||
* set (see {@link #setUserAuthenticationValidityDurationSeconds(int)}, meaning the key is
|
||||
* valid for fingerprint authentication only.
|
||||
*
|
||||
* <p>By default, {@code invalidateKey} is {@code true}, so keys that are valid for
|
||||
* fingerprint authentication only are <em>irreversibly invalidated</em> when a new
|
||||
* fingerprint is enrolled, or when all existing fingerprints are deleted. That may be
|
||||
* changed by calling this method with {@code invalidateKey} set to {@code false}.
|
||||
*
|
||||
* <p>Invalidating keys on enrollment of a new finger or unenrollment of all fingers
|
||||
* improves security by ensuring that an unauthorized person who obtains the password can't
|
||||
* gain the use of fingerprint-authenticated keys by enrolling their own finger. However,
|
||||
* invalidating keys makes key-dependent operations impossible, requiring some fallback
|
||||
* procedure to authenticate the user and set up a new key.
|
||||
*/
|
||||
@NonNull
|
||||
public Builder setInvalidatedByBiometricEnrollment(boolean invalidateKey) {
|
||||
mInvalidatedByBiometricEnrollment = invalidateKey;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds an instance of {@code KeyGenParameterSpec}.
|
||||
*/
|
||||
@ -1136,7 +1179,8 @@ public final class KeyGenParameterSpec implements AlgorithmParameterSpec {
|
||||
mUserAuthenticationValidityDurationSeconds,
|
||||
mAttestationChallenge,
|
||||
mUniqueIdIncluded,
|
||||
mUserAuthenticationValidWhileOnBody);
|
||||
mUserAuthenticationValidWhileOnBody,
|
||||
mInvalidatedByBiometricEnrollment);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -80,6 +80,7 @@ public class KeyInfo implements KeySpec {
|
||||
private final int mUserAuthenticationValidityDurationSeconds;
|
||||
private final boolean mUserAuthenticationRequirementEnforcedBySecureHardware;
|
||||
private final boolean mUserAuthenticationValidWhileOnBody;
|
||||
private final boolean mInvalidatedByBiometricEnrollment;
|
||||
|
||||
/**
|
||||
* @hide
|
||||
@ -99,7 +100,8 @@ public class KeyInfo implements KeySpec {
|
||||
boolean userAuthenticationRequired,
|
||||
int userAuthenticationValidityDurationSeconds,
|
||||
boolean userAuthenticationRequirementEnforcedBySecureHardware,
|
||||
boolean userAuthenticationValidWhileOnBody) {
|
||||
boolean userAuthenticationValidWhileOnBody,
|
||||
boolean invalidatedByBiometricEnrollment) {
|
||||
mKeystoreAlias = keystoreKeyAlias;
|
||||
mInsideSecureHardware = insideSecureHardware;
|
||||
mOrigin = origin;
|
||||
@ -119,6 +121,7 @@ public class KeyInfo implements KeySpec {
|
||||
mUserAuthenticationRequirementEnforcedBySecureHardware =
|
||||
userAuthenticationRequirementEnforcedBySecureHardware;
|
||||
mUserAuthenticationValidWhileOnBody = userAuthenticationValidWhileOnBody;
|
||||
mInvalidatedByBiometricEnrollment = invalidatedByBiometricEnrollment;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -290,4 +293,12 @@ public class KeyInfo implements KeySpec {
|
||||
public boolean isUserAuthenticationValidWhileOnBody() {
|
||||
return mUserAuthenticationValidWhileOnBody;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns {@code true} if the key will be invalidated by enrollment of a new fingerprint or
|
||||
* removal of all fingerprints.
|
||||
*/
|
||||
public boolean isInvalidatedByBiometricEnrollment() {
|
||||
return mInvalidatedByBiometricEnrollment;
|
||||
}
|
||||
}
|
||||
|
@ -215,6 +215,7 @@ public final class KeyProtection implements ProtectionParameter {
|
||||
private final boolean mUserAuthenticationRequired;
|
||||
private final int mUserAuthenticationValidityDurationSeconds;
|
||||
private final boolean mUserAuthenticationValidWhileOnBody;
|
||||
private final boolean mInvalidatedByBiometricEnrollment;
|
||||
|
||||
private KeyProtection(
|
||||
Date keyValidityStart,
|
||||
@ -228,7 +229,8 @@ public final class KeyProtection implements ProtectionParameter {
|
||||
boolean randomizedEncryptionRequired,
|
||||
boolean userAuthenticationRequired,
|
||||
int userAuthenticationValidityDurationSeconds,
|
||||
boolean userAuthenticationValidWhileOnBody) {
|
||||
boolean userAuthenticationValidWhileOnBody,
|
||||
boolean invalidatedByBiometricEnrollment) {
|
||||
mKeyValidityStart = Utils.cloneIfNotNull(keyValidityStart);
|
||||
mKeyValidityForOriginationEnd = Utils.cloneIfNotNull(keyValidityForOriginationEnd);
|
||||
mKeyValidityForConsumptionEnd = Utils.cloneIfNotNull(keyValidityForConsumptionEnd);
|
||||
@ -243,6 +245,7 @@ public final class KeyProtection implements ProtectionParameter {
|
||||
mUserAuthenticationRequired = userAuthenticationRequired;
|
||||
mUserAuthenticationValidityDurationSeconds = userAuthenticationValidityDurationSeconds;
|
||||
mUserAuthenticationValidWhileOnBody = userAuthenticationValidWhileOnBody;
|
||||
mInvalidatedByBiometricEnrollment = invalidatedByBiometricEnrollment;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -411,6 +414,19 @@ public final class KeyProtection implements ProtectionParameter {
|
||||
return mUserAuthenticationValidWhileOnBody;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns {@code true} if the key is irreversibly invalidated when a new fingerprint is
|
||||
* enrolled or all enrolled fingerprints are removed. This has effect only for keys that
|
||||
* require fingerprint user authentication for every use.
|
||||
*
|
||||
* @see #isUserAuthenticationRequired()
|
||||
* @see #getUserAuthenticationValidityDurationSeconds()
|
||||
* @see Builder#setInvalidatedByBiometricEnrollment(boolean)
|
||||
*/
|
||||
public boolean isInvalidatedByBiometricEnrollment() {
|
||||
return mInvalidatedByBiometricEnrollment;
|
||||
}
|
||||
|
||||
/**
|
||||
* Builder of {@link KeyProtection} instances.
|
||||
*/
|
||||
@ -428,6 +444,7 @@ public final class KeyProtection implements ProtectionParameter {
|
||||
private boolean mUserAuthenticationRequired;
|
||||
private int mUserAuthenticationValidityDurationSeconds = -1;
|
||||
private boolean mUserAuthenticationValidWhileOnBody;
|
||||
private boolean mInvalidatedByBiometricEnrollment = true;
|
||||
|
||||
/**
|
||||
* Creates a new instance of the {@code Builder}.
|
||||
@ -638,9 +655,10 @@ public final class KeyProtection implements ProtectionParameter {
|
||||
* or when the secure lock screen is forcibly reset (e.g., by a Device Administrator).
|
||||
* Additionally, if the key requires that user authentication takes place for every use of
|
||||
* the key, it is also irreversibly invalidated once a new fingerprint is enrolled or once\
|
||||
* no more fingerprints are enrolled. Attempts to initialize cryptographic operations using
|
||||
* such keys will throw {@link KeyPermanentlyInvalidatedException}.</li>
|
||||
* </ul>
|
||||
* no more fingerprints are enrolled, unless {@link
|
||||
* #setInvalidatedByBiometricEnrollment(boolean)} is used to allow validity after
|
||||
* enrollment. Attempts to initialize cryptographic operations using such keys will throw
|
||||
* {@link KeyPermanentlyInvalidatedException}.</li> </ul>
|
||||
*
|
||||
* <p>This authorization applies only to secret key and private key operations. Public key
|
||||
* operations are not restricted.
|
||||
@ -728,6 +746,30 @@ public final class KeyProtection implements ProtectionParameter {
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets whether this key should be invalidated on fingerprint enrollment. This
|
||||
* applies only to keys which require user authentication (see {@link
|
||||
* #setUserAuthenticationRequired(boolean)}) and if no positive validity duration has been
|
||||
* set (see {@link #setUserAuthenticationValidityDurationSeconds(int)}, meaning the key is
|
||||
* valid for fingerprint authentication only.
|
||||
*
|
||||
* <p>By default, {@code invalidateKey} is {@code true}, so keys that are valid for
|
||||
* fingerprint authentication only are <em>irreversibly invalidated</em> when a new
|
||||
* fingerprint is enrolled, or when all existing fingerprints are deleted. That may be
|
||||
* changed by calling this method with {@code invalidateKey} set to {@code false}.
|
||||
*
|
||||
* <p>Invalidating keys on enrollment of a new finger or unenrollment of all fingers
|
||||
* improves security by ensuring that an unauthorized person who obtains the password can't
|
||||
* gain the use of fingerprint-authenticated keys by enrolling their own finger. However,
|
||||
* invalidating keys makes key-dependent operations impossible, requiring some fallback
|
||||
* procedure to authenticate the user and set up a new key.
|
||||
*/
|
||||
@NonNull
|
||||
public Builder setInvalidatedByBiometricEnrollment(boolean invalidateKey) {
|
||||
mInvalidatedByBiometricEnrollment = invalidateKey;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds an instance of {@link KeyProtection}.
|
||||
*
|
||||
@ -747,7 +789,8 @@ public final class KeyProtection implements ProtectionParameter {
|
||||
mRandomizedEncryptionRequired,
|
||||
mUserAuthenticationRequired,
|
||||
mUserAuthenticationValidityDurationSeconds,
|
||||
mUserAuthenticationValidWhileOnBody);
|
||||
mUserAuthenticationValidWhileOnBody,
|
||||
mInvalidatedByBiometricEnrollment);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -97,7 +97,8 @@ public abstract class KeymasterUtils {
|
||||
public static void addUserAuthArgs(KeymasterArguments args,
|
||||
boolean userAuthenticationRequired,
|
||||
int userAuthenticationValidityDurationSeconds,
|
||||
boolean userAuthenticationValidWhileOnBody) {
|
||||
boolean userAuthenticationValidWhileOnBody,
|
||||
boolean invalidatedByBiometricEnrollment) {
|
||||
if (!userAuthenticationRequired) {
|
||||
args.addBoolean(KeymasterDefs.KM_TAG_NO_AUTH_REQUIRED);
|
||||
return;
|
||||
@ -117,8 +118,20 @@ public abstract class KeymasterUtils {
|
||||
"At least one fingerprint must be enrolled to create keys requiring user"
|
||||
+ " authentication for every use");
|
||||
}
|
||||
args.addUnsignedLong(KeymasterDefs.KM_TAG_USER_SECURE_ID,
|
||||
KeymasterArguments.toUint64(fingerprintOnlySid));
|
||||
|
||||
long sid;
|
||||
if (invalidatedByBiometricEnrollment) {
|
||||
// The fingerprint-only SID will change on fingerprint enrollment or removal of all,
|
||||
// enrolled fingerprints, invalidating the key.
|
||||
sid = fingerprintOnlySid;
|
||||
} else {
|
||||
// The root SID will *not* change on fingerprint enrollment, or removal of all
|
||||
// enrolled fingerprints, allowing the key to remain valid.
|
||||
sid = getRootSid();
|
||||
}
|
||||
|
||||
args.addUnsignedLong(
|
||||
KeymasterDefs.KM_TAG_USER_SECURE_ID, KeymasterArguments.toUint64(sid));
|
||||
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 "
|
||||
@ -127,11 +140,7 @@ public abstract class KeymasterUtils {
|
||||
} 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 = GateKeeper.getSecureUserId();
|
||||
if (rootSid == 0) {
|
||||
throw new IllegalStateException("Secure lock screen must be enabled"
|
||||
+ " to create keys requiring user authentication");
|
||||
}
|
||||
long rootSid = getRootSid();
|
||||
args.addUnsignedLong(KeymasterDefs.KM_TAG_USER_SECURE_ID,
|
||||
KeymasterArguments.toUint64(rootSid));
|
||||
args.addEnum(KeymasterDefs.KM_TAG_USER_AUTH_TYPE,
|
||||
@ -184,4 +193,13 @@ public abstract class KeymasterUtils {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private static long getRootSid() {
|
||||
long rootSid = GateKeeper.getSecureUserId();
|
||||
if (rootSid == 0) {
|
||||
throw new IllegalStateException("Secure lock screen must be enabled"
|
||||
+ " to create keys requiring user authentication");
|
||||
}
|
||||
return rootSid;
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user