diff options
Diffstat (limited to 'keystore/java')
11 files changed, 250 insertions, 12 deletions
diff --git a/keystore/java/android/security/AndroidKeyStore.java b/keystore/java/android/security/AndroidKeyStore.java index fcee9fc..b931774 100644 --- a/keystore/java/android/security/AndroidKeyStore.java +++ b/keystore/java/android/security/AndroidKeyStore.java @@ -531,6 +531,10 @@ public class AndroidKeyStore extends KeyStoreSpi { KeyStoreKeyProperties.UserAuthenticator.allToKeymaster( params.getUserAuthenticators())); } + if (params.isInvalidatedOnNewFingerprintEnrolled()) { + // TODO: Add the invalidate on fingerprint enrolled constraint once Keymaster supports + // that. + } if (params.getUserAuthenticationValidityDurationSeconds() != -1) { args.addInt(KeymasterDefs.KM_TAG_AUTH_TIMEOUT, params.getUserAuthenticationValidityDurationSeconds()); diff --git a/keystore/java/android/security/KeyChain.java b/keystore/java/android/security/KeyChain.java index dfa41e8..e9c24dd 100644 --- a/keystore/java/android/security/KeyChain.java +++ b/keystore/java/android/security/KeyChain.java @@ -127,6 +127,12 @@ public final class KeyChain { * Extra for use with {@link #ACTION_CHOOSER} * @hide Also used by KeyChainActivity implementation */ + public static final String EXTRA_URL = "url"; + + /** + * Extra for use with {@link #ACTION_CHOOSER} + * @hide Also used by KeyChainActivity implementation + */ public static final String EXTRA_ALIAS = "alias"; /** @@ -224,6 +230,51 @@ public final class KeyChain { * selected alias or null will be returned via the * KeyChainAliasCallback callback. * + * <p>The device or profile owner can intercept this before the activity + * is shown, to pick a specific private key alias. + * + * <p>{@code keyTypes} and {@code issuers} may be used to + * highlight suggested choices to the user, although to cope with + * sometimes erroneous values provided by servers, the user may be + * able to override these suggestions. + * + * <p>{@code host} and {@code port} may be used to give the user + * more context about the server requesting the credentials. + * + * <p>{@code alias} allows the chooser to preselect an existing + * alias which will still be subject to user confirmation. + * + * @param activity The {@link Activity} context to use for + * launching the new sub-Activity to prompt the user to select + * a private key; used only to call startActivity(); must not + * be null. + * @param response Callback to invoke when the request completes; + * must not be null + * @param keyTypes The acceptable types of asymmetric keys such as + * "RSA" or "DSA", or a null array. + * @param issuers The acceptable certificate issuers for the + * certificate matching the private key, or null. + * @param host The host name of the server requesting the + * certificate, or null if unavailable. + * @param port The port number of the server requesting the + * certificate, or -1 if unavailable. + * @param alias The alias to preselect if available, or null if + * unavailable. + */ + public static void choosePrivateKeyAlias(Activity activity, KeyChainAliasCallback response, + String[] keyTypes, Principal[] issuers, String host, int port, String alias) { + choosePrivateKeyAlias(activity, response, keyTypes, issuers, host, port, null, alias); + } + + /** + * Launches an {@code Activity} for the user to select the alias + * for a private key and certificate pair for authentication. The + * selected alias or null will be returned via the + * KeyChainAliasCallback callback. + * + * <p>The device or profile owner can intercept this before the activity + * is shown, to pick a specific private key alias.</p> + * * <p>{@code keyTypes} and {@code issuers} may be used to * highlight suggested choices to the user, although to cope with * sometimes erroneous values provided by servers, the user may be @@ -249,12 +300,14 @@ public final class KeyChain { * certificate, or null if unavailable. * @param port The port number of the server requesting the * certificate, or -1 if unavailable. + * @param url The full url the server is requesting the certificate + * for, or null if unavailable. * @param alias The alias to preselect if available, or null if * unavailable. */ public static void choosePrivateKeyAlias(Activity activity, KeyChainAliasCallback response, String[] keyTypes, Principal[] issuers, - String host, int port, + String host, int port, String url, String alias) { /* * TODO currently keyTypes, issuers are unused. They are meant @@ -283,6 +336,7 @@ public final class KeyChain { intent.putExtra(EXTRA_RESPONSE, new AliasResponse(response)); intent.putExtra(EXTRA_HOST, host); intent.putExtra(EXTRA_PORT, port); + intent.putExtra(EXTRA_URL, url); intent.putExtra(EXTRA_ALIAS, alias); // the PendingIntent is used to get calling package name intent.putExtra(EXTRA_SENDER, PendingIntent.getActivity(activity, 0, new Intent(), 0)); diff --git a/keystore/java/android/security/KeyGeneratorSpec.java b/keystore/java/android/security/KeyGeneratorSpec.java index a22c31c..22db83e 100644 --- a/keystore/java/android/security/KeyGeneratorSpec.java +++ b/keystore/java/android/security/KeyGeneratorSpec.java @@ -55,6 +55,7 @@ public class KeyGeneratorSpec implements AlgorithmParameterSpec { private final boolean mRandomizedEncryptionRequired; private final @KeyStoreKeyProperties.UserAuthenticatorEnum int mUserAuthenticators; private final int mUserAuthenticationValidityDurationSeconds; + private final boolean mInvalidatedOnNewFingerprintEnrolled; private KeyGeneratorSpec( Context context, @@ -69,7 +70,8 @@ public class KeyGeneratorSpec implements AlgorithmParameterSpec { String[] blockModes, boolean randomizedEncryptionRequired, @KeyStoreKeyProperties.UserAuthenticatorEnum int userAuthenticators, - int userAuthenticationValidityDurationSeconds) { + int userAuthenticationValidityDurationSeconds, + boolean invalidatedOnNewFingerprintEnrolled) { if (context == null) { throw new IllegalArgumentException("context == null"); } else if (TextUtils.isEmpty(keyStoreAlias)) { @@ -94,6 +96,7 @@ public class KeyGeneratorSpec implements AlgorithmParameterSpec { mRandomizedEncryptionRequired = randomizedEncryptionRequired; mUserAuthenticators = userAuthenticators; mUserAuthenticationValidityDurationSeconds = userAuthenticationValidityDurationSeconds; + mInvalidatedOnNewFingerprintEnrolled = invalidatedOnNewFingerprintEnrolled; } /** @@ -208,6 +211,19 @@ public class KeyGeneratorSpec implements AlgorithmParameterSpec { } /** + * Returns {@code true} if this key must be permanently invalidated once a new fingerprint is + * enrolled. This constraint only has effect if fingerprint reader is one of the user + * authenticators protecting access to this key. + * + * @see #getUserAuthenticators() + * + * @hide + */ + public boolean isInvalidatedOnNewFingerprintEnrolled() { + return mInvalidatedOnNewFingerprintEnrolled; + } + + /** * Returns {@code true} if the key must be encrypted in the {@link java.security.KeyStore}. */ public boolean isEncryptionRequired() { @@ -228,6 +244,7 @@ public class KeyGeneratorSpec implements AlgorithmParameterSpec { private boolean mRandomizedEncryptionRequired = true; private @KeyStoreKeyProperties.UserAuthenticatorEnum int mUserAuthenticators; private int mUserAuthenticationValidityDurationSeconds = -1; + private boolean mInvalidatedOnNewFingerprintEnrolled; /** * Creates a new instance of the {@code Builder} with the given {@code context}. The @@ -436,6 +453,22 @@ public class KeyGeneratorSpec implements AlgorithmParameterSpec { } /** + * Sets whether this key must be invalidated (permanently) once a new fingerprint is + * enrolled. This only has effect if fingerprint reader is one of the user authenticators + * protecting access to the key. + * + * <p>By default, enrolling a new fingerprint does not invalidate the key. + * + * @see #setUserAuthenticators(Set) + * + * @hide + */ + public Builder setInvalidatedOnNewFingerprintEnrolled(boolean invalidated) { + mInvalidatedOnNewFingerprintEnrolled = invalidated; + return this; + } + + /** * Builds a new instance instance of {@code KeyGeneratorSpec}. * * @throws IllegalArgumentException if a required field is missing or violates a constraint. @@ -453,7 +486,8 @@ public class KeyGeneratorSpec implements AlgorithmParameterSpec { mBlockModes, mRandomizedEncryptionRequired, mUserAuthenticators, - mUserAuthenticationValidityDurationSeconds); + mUserAuthenticationValidityDurationSeconds, + mInvalidatedOnNewFingerprintEnrolled); } } } diff --git a/keystore/java/android/security/KeyPairGeneratorSpec.java b/keystore/java/android/security/KeyPairGeneratorSpec.java index 9d6701a..ed2d856 100644 --- a/keystore/java/android/security/KeyPairGeneratorSpec.java +++ b/keystore/java/android/security/KeyPairGeneratorSpec.java @@ -94,6 +94,8 @@ public final class KeyPairGeneratorSpec implements AlgorithmParameterSpec { private final int mUserAuthenticationValidityDurationSeconds; + private final boolean mInvalidatedOnNewFingerprintEnrolled; + /** * Parameter specification for the "{@code AndroidKeyPairGenerator}" * instance of the {@link java.security.KeyPairGenerator} API. The @@ -139,7 +141,8 @@ public final class KeyPairGeneratorSpec implements AlgorithmParameterSpec { String[] blockModes, boolean randomizedEncryptionRequired, @KeyStoreKeyProperties.UserAuthenticatorEnum int userAuthenticators, - int userAuthenticationValidityDurationSeconds) { + int userAuthenticationValidityDurationSeconds, + boolean invalidatedOnNewFingerprintEnrolled) { if (context == null) { throw new IllegalArgumentException("context == null"); } else if (TextUtils.isEmpty(keyStoreAlias)) { @@ -182,6 +185,7 @@ public final class KeyPairGeneratorSpec implements AlgorithmParameterSpec { mRandomizedEncryptionRequired = randomizedEncryptionRequired; mUserAuthenticators = userAuthenticators; mUserAuthenticationValidityDurationSeconds = userAuthenticationValidityDurationSeconds; + mInvalidatedOnNewFingerprintEnrolled = invalidatedOnNewFingerprintEnrolled; } /** @@ -191,6 +195,7 @@ public final class KeyPairGeneratorSpec implements AlgorithmParameterSpec { public KeyPairGeneratorSpec(Context context, String keyStoreAlias, String keyType, int keySize, AlgorithmParameterSpec spec, X500Principal subjectDN, BigInteger serialNumber, Date startDate, Date endDate, int flags) { + this(context, keyStoreAlias, keyType, @@ -211,7 +216,8 @@ public final class KeyPairGeneratorSpec implements AlgorithmParameterSpec { null, // block modes false, // randomized encryption required 0, // user authenticators - -1 // user authentication validity duration (seconds) + -1, // user authentication validity duration (seconds) + false // invalidate on new fingerprint enrolled ); } @@ -427,6 +433,19 @@ public final class KeyPairGeneratorSpec implements AlgorithmParameterSpec { } /** + * Returns {@code true} if this key must be permanently invalidated once a new fingerprint is + * enrolled. This constraint only has effect if fingerprint reader is one of the user + * authenticators protecting access to this key. + * + * @see #getUserAuthenticators() + * + * @hide + */ + public boolean isInvalidatedOnNewFingerprintEnrolled() { + return mInvalidatedOnNewFingerprintEnrolled; + } + + /** * Builder class for {@link KeyPairGeneratorSpec} objects. * <p> * This will build a parameter spec for use with the <a href="{@docRoot} @@ -490,6 +509,8 @@ public final class KeyPairGeneratorSpec implements AlgorithmParameterSpec { private int mUserAuthenticationValidityDurationSeconds = -1; + private boolean mInvalidatedOnNewFingerprintEnrolled; + /** * Creates a new instance of the {@code Builder} with the given * {@code context}. The {@code context} passed in may be used to pop up @@ -812,6 +833,22 @@ public final class KeyPairGeneratorSpec implements AlgorithmParameterSpec { } /** + * Sets whether this key must be invalidated (permanently) once a new fingerprint is + * enrolled. This only has effect if fingerprint reader is one of the user authenticators + * protecting access to the key. + * + * <p>By default, enrolling a new fingerprint does not invalidate the key. + * + * @see #setUserAuthenticators(Set) + * + * @hide + */ + public Builder setInvalidatedOnNewFingerprintEnrolled(boolean invalidated) { + mInvalidatedOnNewFingerprintEnrolled = invalidated; + return this; + } + + /** * Builds the instance of the {@code KeyPairGeneratorSpec}. * * @throws IllegalArgumentException if a required field is missing @@ -838,7 +875,8 @@ public final class KeyPairGeneratorSpec implements AlgorithmParameterSpec { mBlockModes, mRandomizedEncryptionRequired, mUserAuthenticators, - mUserAuthenticationValidityDurationSeconds); + mUserAuthenticationValidityDurationSeconds, + mInvalidatedOnNewFingerprintEnrolled); } } } diff --git a/keystore/java/android/security/KeyStore.java b/keystore/java/android/security/KeyStore.java index 84a664e..5af0527 100644 --- a/keystore/java/android/security/KeyStore.java +++ b/keystore/java/android/security/KeyStore.java @@ -552,6 +552,9 @@ public class KeyStore { return new KeyNotYetValidException(); case KeymasterDefs.KM_ERROR_KEY_USER_NOT_AUTHENTICATED: return new UserNotAuthenticatedException(); + // TODO: Handle TBD Keymaster error code "invalid key: new fingerprint enrolled" + // case KeymasterDefs.KM_ERROR_TBD + // return new NewFingerprintEnrolledException(); default: return new CryptoOperationException("Crypto operation failed", e); } diff --git a/keystore/java/android/security/KeyStoreKeyGeneratorSpi.java b/keystore/java/android/security/KeyStoreKeyGeneratorSpi.java index 87e7ee6..3b28045 100644 --- a/keystore/java/android/security/KeyStoreKeyGeneratorSpi.java +++ b/keystore/java/android/security/KeyStoreKeyGeneratorSpi.java @@ -168,6 +168,10 @@ public abstract class KeyStoreKeyGeneratorSpi extends KeyGeneratorSpi { KeyStoreKeyProperties.UserAuthenticator.allToKeymaster( spec.getUserAuthenticators())); } + if (spec.isInvalidatedOnNewFingerprintEnrolled()) { + // TODO: Add the invalidate on fingerprint enrolled constraint once Keymaster supports + // that. + } if (spec.getUserAuthenticationValidityDurationSeconds() != -1) { args.addInt(KeymasterDefs.KM_TAG_AUTH_TIMEOUT, spec.getUserAuthenticationValidityDurationSeconds()); diff --git a/keystore/java/android/security/KeyStoreKeyProperties.java b/keystore/java/android/security/KeyStoreKeyProperties.java index d8ad1d3..7f3f1a4 100644 --- a/keystore/java/android/security/KeyStoreKeyProperties.java +++ b/keystore/java/android/security/KeyStoreKeyProperties.java @@ -125,7 +125,7 @@ public abstract class KeyStoreKeyProperties { @Retention(RetentionPolicy.SOURCE) @IntDef(flag = true, - value = {UserAuthenticator.LOCK_SCREEN}) + value = {UserAuthenticator.LOCK_SCREEN, UserAuthenticator.FINGERPRINT_READER}) public @interface UserAuthenticatorEnum {} /** @@ -137,6 +137,9 @@ public abstract class KeyStoreKeyProperties { /** Lock screen. */ public static final int LOCK_SCREEN = 1 << 0; + /** Fingerprint reader/sensor. */ + public static final int FINGERPRINT_READER = 1 << 1; + /** * @hide */ @@ -144,6 +147,8 @@ public abstract class KeyStoreKeyProperties { switch (userAuthenticator) { case LOCK_SCREEN: return KeymasterDefs.HW_AUTH_PASSWORD; + case FINGERPRINT_READER: + return KeymasterDefs.HW_AUTH_FINGERPRINT; default: throw new IllegalArgumentException( "Unknown user authenticator: " + userAuthenticator); @@ -157,6 +162,8 @@ public abstract class KeyStoreKeyProperties { switch (userAuthenticator) { case KeymasterDefs.HW_AUTH_PASSWORD: return LOCK_SCREEN; + case KeymasterDefs.HW_AUTH_FINGERPRINT: + return FINGERPRINT_READER; default: throw new IllegalArgumentException( "Unknown user authenticator: " + userAuthenticator); @@ -202,6 +209,8 @@ public abstract class KeyStoreKeyProperties { switch (userAuthenticator) { case LOCK_SCREEN: return "LOCK_SCREEN"; + case FINGERPRINT_READER: + return "FINGERPRINT_READER"; default: throw new IllegalArgumentException( "Unknown user authenticator: " + userAuthenticator); diff --git a/keystore/java/android/security/KeyStoreKeySpec.java b/keystore/java/android/security/KeyStoreKeySpec.java index 861ed34..2ff1a64 100644 --- a/keystore/java/android/security/KeyStoreKeySpec.java +++ b/keystore/java/android/security/KeyStoreKeySpec.java @@ -41,7 +41,7 @@ public class KeyStoreKeySpec implements KeySpec { private final @KeyStoreKeyProperties.UserAuthenticatorEnum int mUserAuthenticators; private final @KeyStoreKeyProperties.UserAuthenticatorEnum int mTeeEnforcedUserAuthenticators; private final int mUserAuthenticationValidityDurationSeconds; - + private final boolean mInvalidatedOnNewFingerprintEnrolled; /** * @hide @@ -60,7 +60,8 @@ public class KeyStoreKeySpec implements KeySpec { String[] blockModes, @KeyStoreKeyProperties.UserAuthenticatorEnum int userAuthenticators, @KeyStoreKeyProperties.UserAuthenticatorEnum int teeEnforcedUserAuthenticators, - int userAuthenticationValidityDurationSeconds) { + int userAuthenticationValidityDurationSeconds, + boolean invalidatedOnNewFingerprintEnrolled) { mKeystoreAlias = keystoreKeyAlias; mTeeBacked = teeBacked; mOrigin = origin; @@ -78,6 +79,7 @@ public class KeyStoreKeySpec implements KeySpec { mUserAuthenticators = userAuthenticators; mTeeEnforcedUserAuthenticators = teeEnforcedUserAuthenticators; mUserAuthenticationValidityDurationSeconds = userAuthenticationValidityDurationSeconds; + mInvalidatedOnNewFingerprintEnrolled = invalidatedOnNewFingerprintEnrolled; } /** @@ -200,4 +202,15 @@ public class KeyStoreKeySpec implements KeySpec { public int getUserAuthenticationValidityDurationSeconds() { return mUserAuthenticationValidityDurationSeconds; } + + /** + * Returns {@code true} if this key will be permanently invalidated once a new fingerprint is + * enrolled. This constraint only has effect if fingerprint reader is one of the user + * authenticators protecting access to this key. + * + * @see #getUserAuthenticators() + */ + public boolean isInvalidatedOnNewFingerprintEnrolled() { + return mInvalidatedOnNewFingerprintEnrolled; + } } diff --git a/keystore/java/android/security/KeyStoreParameter.java b/keystore/java/android/security/KeyStoreParameter.java index 9fce177..a04bc6c 100644 --- a/keystore/java/android/security/KeyStoreParameter.java +++ b/keystore/java/android/security/KeyStoreParameter.java @@ -51,6 +51,7 @@ public final class KeyStoreParameter implements ProtectionParameter { private final boolean mRandomizedEncryptionRequired; private final @KeyStoreKeyProperties.UserAuthenticatorEnum int mUserAuthenticators; private final int mUserAuthenticationValidityDurationSeconds; + private final boolean mInvalidatedOnNewFingerprintEnrolled; private KeyStoreParameter(int flags, Date keyValidityStart, @@ -63,7 +64,8 @@ public final class KeyStoreParameter implements ProtectionParameter { String[] blockModes, boolean randomizedEncryptionRequired, @KeyStoreKeyProperties.UserAuthenticatorEnum int userAuthenticators, - int userAuthenticationValidityDurationSeconds) { + int userAuthenticationValidityDurationSeconds, + boolean invalidatedOnNewFingerprintEnrolled) { if ((userAuthenticationValidityDurationSeconds < 0) && (userAuthenticationValidityDurationSeconds != -1)) { throw new IllegalArgumentException( @@ -84,6 +86,7 @@ public final class KeyStoreParameter implements ProtectionParameter { mRandomizedEncryptionRequired = randomizedEncryptionRequired; mUserAuthenticators = userAuthenticators; mUserAuthenticationValidityDurationSeconds = userAuthenticationValidityDurationSeconds; + mInvalidatedOnNewFingerprintEnrolled = invalidatedOnNewFingerprintEnrolled; } /** @@ -239,6 +242,19 @@ public final class KeyStoreParameter implements ProtectionParameter { } /** + * Returns {@code true} if this key must be permanently invalidated once a new fingerprint is + * enrolled. This constraint only has effect if fingerprint reader is one of the user + * authenticators protecting access to this key. + * + * @see #getUserAuthenticators() + * + * @hide + */ + public boolean isInvalidatedOnNewFingerprintEnrolled() { + return mInvalidatedOnNewFingerprintEnrolled; + } + + /** * Builder class for {@link KeyStoreParameter} objects. * <p> * This will build protection parameters for use with the @@ -268,6 +284,7 @@ public final class KeyStoreParameter implements ProtectionParameter { private boolean mRandomizedEncryptionRequired = true; private @KeyStoreKeyProperties.UserAuthenticatorEnum int mUserAuthenticators; private int mUserAuthenticationValidityDurationSeconds = -1; + private boolean mInvalidatedOnNewFingerprintEnrolled; /** * Creates a new instance of the {@code Builder} with the given @@ -505,6 +522,22 @@ public final class KeyStoreParameter implements ProtectionParameter { } /** + * Sets whether this key must be invalidated (permanently) whenever a new fingerprint is + * enrolled. This only has effect if fingerprint reader is one of the user authenticators + * protecting access to the key. + * + * <p>By default, enrolling a new fingerprint does not invalidate the key. + * + * @see #setUserAuthenticators(Set) + * + * @hide + */ + public Builder setInvalidatedOnNewFingerprintEnrolled(boolean invalidated) { + mInvalidatedOnNewFingerprintEnrolled = invalidated; + return this; + } + + /** * Builds the instance of the {@code KeyStoreParameter}. * * @throws IllegalArgumentException if a required field is missing @@ -522,7 +555,8 @@ public final class KeyStoreParameter implements ProtectionParameter { mBlockModes, mRandomizedEncryptionRequired, mUserAuthenticators, - mUserAuthenticationValidityDurationSeconds); + mUserAuthenticationValidityDurationSeconds, + mInvalidatedOnNewFingerprintEnrolled); } } } diff --git a/keystore/java/android/security/KeyStoreSecretKeyFactorySpi.java b/keystore/java/android/security/KeyStoreSecretKeyFactorySpi.java index 33073a4..4be0638 100644 --- a/keystore/java/android/security/KeyStoreSecretKeyFactorySpi.java +++ b/keystore/java/android/security/KeyStoreSecretKeyFactorySpi.java @@ -160,6 +160,9 @@ public class KeyStoreSecretKeyFactorySpi extends SecretKeyFactorySpi { int userAuthenticationValidityDurationSeconds = keyCharacteristics.getInt(KeymasterDefs.KM_TAG_AUTH_TIMEOUT, -1); + // TODO: Populate the value below from key characteristics once Keymaster is ready. + boolean invalidatedOnNewFingerprintEnrolled = false; + return new KeyStoreKeySpec(entryAlias, teeBacked, origin, @@ -174,7 +177,8 @@ public class KeyStoreSecretKeyFactorySpi extends SecretKeyFactorySpi { blockModes, userAuthenticators, teeEnforcedUserAuthenticators, - userAuthenticationValidityDurationSeconds); + userAuthenticationValidityDurationSeconds, + invalidatedOnNewFingerprintEnrolled); } @Override diff --git a/keystore/java/android/security/NewFingerprintEnrolledException.java b/keystore/java/android/security/NewFingerprintEnrolledException.java new file mode 100644 index 0000000..6da4a2a --- /dev/null +++ b/keystore/java/android/security/NewFingerprintEnrolledException.java @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.security; + +/** + * Indicates that a cryptographic operation could not be performed because the key used by the + * operation is permanently invalid because a new fingerprint was enrolled. + * + * @hide + */ +public class NewFingerprintEnrolledException extends CryptoOperationException { + + /** + * Constructs a new {@code NewFingerprintEnrolledException} without detail message and cause. + */ + public NewFingerprintEnrolledException() { + super("Invalid key: new fingerprint enrolled"); + } + + /** + * Constructs a new {@code NewFingerprintEnrolledException} with the provided detail message and + * no cause. + */ + public NewFingerprintEnrolledException(String message) { + super(message); + } +} |