Revert "Revert "Add option to allow key validity after fingerprint enrollment.""

This reverts commit 512c132f49.

Change-Id: Iac381dfebcfe42f0468569eb2395ebeb97a95887
This commit is contained in:
Shawn Willden
2016-02-22 23:28:34 +00:00
parent f5725e6501
commit c38eae5229
11 changed files with 185 additions and 25 deletions

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -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,

View File

@ -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());

View File

@ -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

View File

@ -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,

View File

@ -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);
}
}
}

View File

@ -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;
}
}

View File

@ -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);
}
}
}

View File

@ -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;
}
}