diff options
-rw-r--r-- | api/current.txt | 32 | ||||
-rw-r--r-- | api/system-current.txt | 32 | ||||
-rw-r--r-- | core/java/android/security/keymaster/KeyCharacteristics.java | 8 | ||||
-rw-r--r-- | docs/html/training/articles/keystore.jd | 28 | ||||
-rw-r--r-- | keystore/java/android/security/AndroidKeyStore.java | 25 | ||||
-rw-r--r-- | keystore/java/android/security/KeyGeneratorSpec.java | 80 | ||||
-rw-r--r-- | keystore/java/android/security/KeyPairGeneratorSpec.java | 89 | ||||
-rw-r--r-- | keystore/java/android/security/KeyStoreKeyGeneratorSpi.java | 25 | ||||
-rw-r--r-- | keystore/java/android/security/KeyStoreKeyProperties.java | 95 | ||||
-rw-r--r-- | keystore/java/android/security/KeyStoreKeySpec.java | 50 | ||||
-rw-r--r-- | keystore/java/android/security/KeyStoreParameter.java | 107 | ||||
-rw-r--r-- | keystore/java/android/security/KeyStoreSecretKeyFactorySpi.java | 32 | ||||
-rw-r--r-- | keystore/java/android/security/KeymasterUtils.java | 75 |
13 files changed, 265 insertions, 413 deletions
diff --git a/api/current.txt b/api/current.txt index b41906440af6..2bf91a4c17e5 100644 --- a/api/current.txt +++ b/api/current.txt @@ -28526,10 +28526,9 @@ package android.security { method public java.lang.String getKeystoreAlias(); method public int getPurposes(); method public int getUserAuthenticationValidityDurationSeconds(); - method public int getUserAuthenticators(); method public boolean isEncryptionRequired(); - method public boolean isInvalidatedOnNewFingerprintEnrolled(); method public boolean isRandomizedEncryptionRequired(); + method public boolean isUserAuthenticationRequired(); } public static class KeyGeneratorSpec.Builder { @@ -28539,7 +28538,6 @@ package android.security { method public android.security.KeyGeneratorSpec.Builder setBlockModes(java.lang.String...); method public android.security.KeyGeneratorSpec.Builder setEncryptionPaddings(java.lang.String...); method public android.security.KeyGeneratorSpec.Builder setEncryptionRequired(boolean); - method public android.security.KeyGeneratorSpec.Builder setInvalidatedOnNewFingerprintEnrolled(boolean); method public android.security.KeyGeneratorSpec.Builder setKeySize(int); method public android.security.KeyGeneratorSpec.Builder setKeyValidityEnd(java.util.Date); method public android.security.KeyGeneratorSpec.Builder setKeyValidityForConsumptionEnd(java.util.Date); @@ -28547,8 +28545,8 @@ package android.security { method public android.security.KeyGeneratorSpec.Builder setKeyValidityStart(java.util.Date); method public android.security.KeyGeneratorSpec.Builder setPurposes(int); method public android.security.KeyGeneratorSpec.Builder setRandomizedEncryptionRequired(boolean); + method public android.security.KeyGeneratorSpec.Builder setUserAuthenticationRequired(boolean); method public android.security.KeyGeneratorSpec.Builder setUserAuthenticationValidityDurationSeconds(int); - method public android.security.KeyGeneratorSpec.Builder setUserAuthenticators(int); } public class KeyNotYetValidException extends java.security.InvalidKeyException { @@ -28576,10 +28574,9 @@ package android.security { method public java.util.Date getStartDate(); method public javax.security.auth.x500.X500Principal getSubjectDN(); method public int getUserAuthenticationValidityDurationSeconds(); - method public int getUserAuthenticators(); method public boolean isEncryptionRequired(); - method public boolean isInvalidatedOnNewFingerprintEnrolled(); method public boolean isRandomizedEncryptionRequired(); + method public boolean isUserAuthenticationRequired(); } public static final class KeyPairGeneratorSpec.Builder { @@ -28592,7 +28589,6 @@ package android.security { method public android.security.KeyPairGeneratorSpec.Builder setEncryptionPaddings(java.lang.String...); method public android.security.KeyPairGeneratorSpec.Builder setEncryptionRequired(); method public android.security.KeyPairGeneratorSpec.Builder setEndDate(java.util.Date); - method public android.security.KeyPairGeneratorSpec.Builder setInvalidatedOnNewFingerprintEnrolled(boolean); method public android.security.KeyPairGeneratorSpec.Builder setKeySize(int); method public android.security.KeyPairGeneratorSpec.Builder setKeyType(java.lang.String) throws java.security.NoSuchAlgorithmException; method public android.security.KeyPairGeneratorSpec.Builder setKeyValidityEnd(java.util.Date); @@ -28605,8 +28601,8 @@ package android.security { method public android.security.KeyPairGeneratorSpec.Builder setSignaturePaddings(java.lang.String...); method public android.security.KeyPairGeneratorSpec.Builder setStartDate(java.util.Date); method public android.security.KeyPairGeneratorSpec.Builder setSubject(javax.security.auth.x500.X500Principal); + method public android.security.KeyPairGeneratorSpec.Builder setUserAuthenticationRequired(boolean); method public android.security.KeyPairGeneratorSpec.Builder setUserAuthenticationValidityDurationSeconds(int); - method public android.security.KeyPairGeneratorSpec.Builder setUserAuthenticators(int); } public abstract class KeyStoreKeyProperties { @@ -28631,14 +28627,6 @@ package android.security { public static abstract class KeyStoreKeyProperties.PurposeEnum implements java.lang.annotation.Annotation { } - public static abstract class KeyStoreKeyProperties.UserAuthenticator { - field public static final int FINGERPRINT_READER = 2; // 0x2 - field public static final int LOCK_SCREEN = 1; // 0x1 - } - - public static abstract class KeyStoreKeyProperties.UserAuthenticatorEnum implements java.lang.annotation.Annotation { - } - public class KeyStoreKeySpec implements java.security.spec.KeySpec { method public java.lang.String[] getBlockModes(); method public java.lang.String[] getDigests(); @@ -28651,15 +28639,15 @@ package android.security { method public int getOrigin(); method public int getPurposes(); method public java.lang.String[] getSignaturePaddings(); - method public int getTeeEnforcedUserAuthenticators(); method public int getUserAuthenticationValidityDurationSeconds(); - method public int getUserAuthenticators(); - method public boolean isInvalidatedOnNewFingerprintEnrolled(); method public boolean isTeeBacked(); + method public boolean isUserAuthenticationRequired(); + method public boolean isUserAuthenticationRequirementTeeEnforced(); } public final class KeyStoreParameter implements java.security.KeyStore.ProtectionParameter { method public java.lang.String[] getBlockModes(); + method public android.content.Context getContext(); method public java.lang.String[] getDigests(); method public java.lang.String[] getEncryptionPaddings(); method public java.util.Date getKeyValidityForConsumptionEnd(); @@ -28668,11 +28656,10 @@ package android.security { method public int getPurposes(); method public java.lang.String[] getSignaturePaddings(); method public int getUserAuthenticationValidityDurationSeconds(); - method public int getUserAuthenticators(); method public boolean isDigestsSpecified(); method public boolean isEncryptionRequired(); - method public boolean isInvalidatedOnNewFingerprintEnrolled(); method public boolean isRandomizedEncryptionRequired(); + method public boolean isUserAuthenticationRequired(); } public static final class KeyStoreParameter.Builder { @@ -28682,7 +28669,6 @@ package android.security { method public android.security.KeyStoreParameter.Builder setDigests(java.lang.String...); method public android.security.KeyStoreParameter.Builder setEncryptionPaddings(java.lang.String...); method public android.security.KeyStoreParameter.Builder setEncryptionRequired(boolean); - method public android.security.KeyStoreParameter.Builder setInvalidatedOnNewFingerprintEnrolled(boolean); method public android.security.KeyStoreParameter.Builder setKeyValidityEnd(java.util.Date); method public android.security.KeyStoreParameter.Builder setKeyValidityForConsumptionEnd(java.util.Date); method public android.security.KeyStoreParameter.Builder setKeyValidityForOriginationEnd(java.util.Date); @@ -28690,8 +28676,8 @@ package android.security { method public android.security.KeyStoreParameter.Builder setPurposes(int); method public android.security.KeyStoreParameter.Builder setRandomizedEncryptionRequired(boolean); method public android.security.KeyStoreParameter.Builder setSignaturePaddings(java.lang.String...); + method public android.security.KeyStoreParameter.Builder setUserAuthenticationRequired(boolean); method public android.security.KeyStoreParameter.Builder setUserAuthenticationValidityDurationSeconds(int); - method public android.security.KeyStoreParameter.Builder setUserAuthenticators(int); } public class NetworkSecurityPolicy { diff --git a/api/system-current.txt b/api/system-current.txt index 9df8b98ecd52..9d34060ba789 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -30533,10 +30533,9 @@ package android.security { method public java.lang.String getKeystoreAlias(); method public int getPurposes(); method public int getUserAuthenticationValidityDurationSeconds(); - method public int getUserAuthenticators(); method public boolean isEncryptionRequired(); - method public boolean isInvalidatedOnNewFingerprintEnrolled(); method public boolean isRandomizedEncryptionRequired(); + method public boolean isUserAuthenticationRequired(); } public static class KeyGeneratorSpec.Builder { @@ -30546,7 +30545,6 @@ package android.security { method public android.security.KeyGeneratorSpec.Builder setBlockModes(java.lang.String...); method public android.security.KeyGeneratorSpec.Builder setEncryptionPaddings(java.lang.String...); method public android.security.KeyGeneratorSpec.Builder setEncryptionRequired(boolean); - method public android.security.KeyGeneratorSpec.Builder setInvalidatedOnNewFingerprintEnrolled(boolean); method public android.security.KeyGeneratorSpec.Builder setKeySize(int); method public android.security.KeyGeneratorSpec.Builder setKeyValidityEnd(java.util.Date); method public android.security.KeyGeneratorSpec.Builder setKeyValidityForConsumptionEnd(java.util.Date); @@ -30554,8 +30552,8 @@ package android.security { method public android.security.KeyGeneratorSpec.Builder setKeyValidityStart(java.util.Date); method public android.security.KeyGeneratorSpec.Builder setPurposes(int); method public android.security.KeyGeneratorSpec.Builder setRandomizedEncryptionRequired(boolean); + method public android.security.KeyGeneratorSpec.Builder setUserAuthenticationRequired(boolean); method public android.security.KeyGeneratorSpec.Builder setUserAuthenticationValidityDurationSeconds(int); - method public android.security.KeyGeneratorSpec.Builder setUserAuthenticators(int); } public class KeyNotYetValidException extends java.security.InvalidKeyException { @@ -30583,10 +30581,9 @@ package android.security { method public java.util.Date getStartDate(); method public javax.security.auth.x500.X500Principal getSubjectDN(); method public int getUserAuthenticationValidityDurationSeconds(); - method public int getUserAuthenticators(); method public boolean isEncryptionRequired(); - method public boolean isInvalidatedOnNewFingerprintEnrolled(); method public boolean isRandomizedEncryptionRequired(); + method public boolean isUserAuthenticationRequired(); } public static final class KeyPairGeneratorSpec.Builder { @@ -30599,7 +30596,6 @@ package android.security { method public android.security.KeyPairGeneratorSpec.Builder setEncryptionPaddings(java.lang.String...); method public android.security.KeyPairGeneratorSpec.Builder setEncryptionRequired(); method public android.security.KeyPairGeneratorSpec.Builder setEndDate(java.util.Date); - method public android.security.KeyPairGeneratorSpec.Builder setInvalidatedOnNewFingerprintEnrolled(boolean); method public android.security.KeyPairGeneratorSpec.Builder setKeySize(int); method public android.security.KeyPairGeneratorSpec.Builder setKeyType(java.lang.String) throws java.security.NoSuchAlgorithmException; method public android.security.KeyPairGeneratorSpec.Builder setKeyValidityEnd(java.util.Date); @@ -30612,8 +30608,8 @@ package android.security { method public android.security.KeyPairGeneratorSpec.Builder setSignaturePaddings(java.lang.String...); method public android.security.KeyPairGeneratorSpec.Builder setStartDate(java.util.Date); method public android.security.KeyPairGeneratorSpec.Builder setSubject(javax.security.auth.x500.X500Principal); + method public android.security.KeyPairGeneratorSpec.Builder setUserAuthenticationRequired(boolean); method public android.security.KeyPairGeneratorSpec.Builder setUserAuthenticationValidityDurationSeconds(int); - method public android.security.KeyPairGeneratorSpec.Builder setUserAuthenticators(int); } public abstract class KeyStoreKeyProperties { @@ -30638,14 +30634,6 @@ package android.security { public static abstract class KeyStoreKeyProperties.PurposeEnum implements java.lang.annotation.Annotation { } - public static abstract class KeyStoreKeyProperties.UserAuthenticator { - field public static final int FINGERPRINT_READER = 2; // 0x2 - field public static final int LOCK_SCREEN = 1; // 0x1 - } - - public static abstract class KeyStoreKeyProperties.UserAuthenticatorEnum implements java.lang.annotation.Annotation { - } - public class KeyStoreKeySpec implements java.security.spec.KeySpec { method public java.lang.String[] getBlockModes(); method public java.lang.String[] getDigests(); @@ -30658,15 +30646,15 @@ package android.security { method public int getOrigin(); method public int getPurposes(); method public java.lang.String[] getSignaturePaddings(); - method public int getTeeEnforcedUserAuthenticators(); method public int getUserAuthenticationValidityDurationSeconds(); - method public int getUserAuthenticators(); - method public boolean isInvalidatedOnNewFingerprintEnrolled(); method public boolean isTeeBacked(); + method public boolean isUserAuthenticationRequired(); + method public boolean isUserAuthenticationRequirementTeeEnforced(); } public final class KeyStoreParameter implements java.security.KeyStore.ProtectionParameter { method public java.lang.String[] getBlockModes(); + method public android.content.Context getContext(); method public java.lang.String[] getDigests(); method public java.lang.String[] getEncryptionPaddings(); method public java.util.Date getKeyValidityForConsumptionEnd(); @@ -30675,11 +30663,10 @@ package android.security { method public int getPurposes(); method public java.lang.String[] getSignaturePaddings(); method public int getUserAuthenticationValidityDurationSeconds(); - method public int getUserAuthenticators(); method public boolean isDigestsSpecified(); method public boolean isEncryptionRequired(); - method public boolean isInvalidatedOnNewFingerprintEnrolled(); method public boolean isRandomizedEncryptionRequired(); + method public boolean isUserAuthenticationRequired(); } public static final class KeyStoreParameter.Builder { @@ -30689,7 +30676,6 @@ package android.security { method public android.security.KeyStoreParameter.Builder setDigests(java.lang.String...); method public android.security.KeyStoreParameter.Builder setEncryptionPaddings(java.lang.String...); method public android.security.KeyStoreParameter.Builder setEncryptionRequired(boolean); - method public android.security.KeyStoreParameter.Builder setInvalidatedOnNewFingerprintEnrolled(boolean); method public android.security.KeyStoreParameter.Builder setKeyValidityEnd(java.util.Date); method public android.security.KeyStoreParameter.Builder setKeyValidityForConsumptionEnd(java.util.Date); method public android.security.KeyStoreParameter.Builder setKeyValidityForOriginationEnd(java.util.Date); @@ -30697,8 +30683,8 @@ package android.security { method public android.security.KeyStoreParameter.Builder setPurposes(int); method public android.security.KeyStoreParameter.Builder setRandomizedEncryptionRequired(boolean); method public android.security.KeyStoreParameter.Builder setSignaturePaddings(java.lang.String...); + method public android.security.KeyStoreParameter.Builder setUserAuthenticationRequired(boolean); method public android.security.KeyStoreParameter.Builder setUserAuthenticationValidityDurationSeconds(int); - method public android.security.KeyStoreParameter.Builder setUserAuthenticators(int); } public class NetworkSecurityPolicy { diff --git a/core/java/android/security/keymaster/KeyCharacteristics.java b/core/java/android/security/keymaster/KeyCharacteristics.java index b3a3aada7ec4..458f1530dce0 100644 --- a/core/java/android/security/keymaster/KeyCharacteristics.java +++ b/core/java/android/security/keymaster/KeyCharacteristics.java @@ -105,11 +105,11 @@ public class KeyCharacteristics implements Parcelable { } } - public boolean getBoolean(KeyCharacteristics keyCharacteristics, int tag) { - if (keyCharacteristics.hwEnforced.containsTag(tag)) { - return keyCharacteristics.hwEnforced.getBoolean(tag, false); + public boolean getBoolean(int tag) { + if (hwEnforced.containsTag(tag)) { + return hwEnforced.getBoolean(tag, false); } else { - return keyCharacteristics.swEnforced.getBoolean(tag, false); + return swEnforced.getBoolean(tag, false); } } } diff --git a/docs/html/training/articles/keystore.jd b/docs/html/training/articles/keystore.jd index a4fc2d23adfe..217db8149aee 100644 --- a/docs/html/training/articles/keystore.jd +++ b/docs/html/training/articles/keystore.jd @@ -29,7 +29,9 @@ page.title=Android Keystore System <p>The Android Keystore system lets you store cryptographic keys in a container to make it more difficult to extract from the device. Once keys are in the keystore, they can be used for cryptographic operations with the key material - remaining non-exportable.</p> + remaining non-exportable. Moreover, it offers facilities to restrict when and + how keys can be used, such as requiring user authentication for key use or + restricting encryption keys to be used only in certain block modes.</p> <p>The Keystore system is used by the {@link android.security.KeyChain} API as well as the Android @@ -112,3 +114,27 @@ and {@link java.security.KeyPairGenerator} or <p>Similarly, verify data with the {@link java.security.Signature#verify(byte[])} method:</p> {@sample development/samples/ApiDemos/src/com/example/android/apis/security/KeyStoreUsage.java verify} + +<h3 id="UserAuthentication">Requiring User Authentication For Key Use</h3> + +<p>When generating or importing a key into the {@code AndroidKeyStore} you can specify that the key +can only be used if user has been authenticated. The user is authenticated using a subset of their +secure lock screen credentials. This is a security measure which makes it possible to generate +cryptographic assertions about the user having been authenticated. + +<p>When a key is configured to require user authentication, it is also configured to operate in one +of the two modes: +<ul> +<li>User authentication is valid for a duration of time. All keys in this mode are authorized + for use as soon as the user unlocks the secure lock screen or confirms their secure lock screen + credentials using the {@link android.app.KeyguardManager#createConfirmDeviceCredentialIntent(CharSequence, CharSequence) KeyguardManager.createConfirmDeviceCredentialIntent} + flow. Each key specifies for how long the authorization remains valid for that key. Such keys + can only be generated or imported if the secure lock screen is enabled (see {@link android.app.KeyguardManager#isKeyguardSecure Keyguard.isKeyguardSecure}). + These keys become permanently invalidated once the secure lock screen is disabled or forcibly + reset (e.g. by a Device Admin).</li> +<li>User authentication is required for every use of the key. In this mode, a specific operation + involving a specific key is authorized by the user. Currently, the only means of such + authorization is fingerprint authentication: {@link android.hardware.fingerprint.FingerprintManager#authenticate(CryptoObject, CancellationSignal, AuthenticationCallback, int) FingerprintManager.authenticate}. + Such keys can only be generated or imported if at least one fingerprint is enrolled (see {@link android.hardware.fingerprint.FingerprintManager#hasEnrolledFingerprints() FingerprintManager.hasEnrolledFingerprints}). + These keys become permanently invalidated once all fingerprints are unenrolled.</li> +</ul> diff --git a/keystore/java/android/security/AndroidKeyStore.java b/keystore/java/android/security/AndroidKeyStore.java index c259c25b0e5c..ed91d7080054 100644 --- a/keystore/java/android/security/AndroidKeyStore.java +++ b/keystore/java/android/security/AndroidKeyStore.java @@ -529,27 +529,10 @@ public class AndroidKeyStore extends KeyStoreSpi { KeymasterUtils.getKeymasterPaddingsFromJcaSignaturePaddings( params.getSignaturePaddings())); args.addInts(KeymasterDefs.KM_TAG_PADDING, keymasterPaddings); - if (params.getUserAuthenticators() == 0) { - args.addBoolean(KeymasterDefs.KM_TAG_NO_AUTH_REQUIRED); - } else { - args.addInt(KeymasterDefs.KM_TAG_USER_AUTH_TYPE, - KeyStoreKeyProperties.UserAuthenticator.allToKeymaster( - params.getUserAuthenticators())); - long secureUserId = GateKeeper.getSecureUserId(); - if (secureUserId == 0) { - throw new IllegalStateException("Secure lock screen must be enabled" - + " to import keys requiring user authentication"); - } - args.addLong(KeymasterDefs.KM_TAG_USER_SECURE_ID, secureUserId); - } - 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()); - } + KeymasterUtils.addUserAuthArgs(args, + params.getContext(), + params.isUserAuthenticationRequired(), + params.getUserAuthenticationValidityDurationSeconds()); args.addDate(KeymasterDefs.KM_TAG_ACTIVE_DATETIME, (params.getKeyValidityStart() != null) ? params.getKeyValidityStart() : new Date(0)); diff --git a/keystore/java/android/security/KeyGeneratorSpec.java b/keystore/java/android/security/KeyGeneratorSpec.java index 7ecc47e4014f..8f135a6f4b7b 100644 --- a/keystore/java/android/security/KeyGeneratorSpec.java +++ b/keystore/java/android/security/KeyGeneratorSpec.java @@ -51,9 +51,8 @@ public class KeyGeneratorSpec implements AlgorithmParameterSpec { private final String[] mEncryptionPaddings; private final String[] mBlockModes; private final boolean mRandomizedEncryptionRequired; - private final @KeyStoreKeyProperties.UserAuthenticatorEnum int mUserAuthenticators; + private final boolean mUserAuthenticationRequired; private final int mUserAuthenticationValidityDurationSeconds; - private final boolean mInvalidatedOnNewFingerprintEnrolled; private KeyGeneratorSpec( Context context, @@ -67,9 +66,8 @@ public class KeyGeneratorSpec implements AlgorithmParameterSpec { String[] encryptionPaddings, String[] blockModes, boolean randomizedEncryptionRequired, - @KeyStoreKeyProperties.UserAuthenticatorEnum int userAuthenticators, - int userAuthenticationValidityDurationSeconds, - boolean invalidatedOnNewFingerprintEnrolled) { + boolean userAuthenticationRequired, + int userAuthenticationValidityDurationSeconds) { if (context == null) { throw new IllegalArgumentException("context == null"); } else if (TextUtils.isEmpty(keyStoreAlias)) { @@ -92,9 +90,8 @@ public class KeyGeneratorSpec implements AlgorithmParameterSpec { ArrayUtils.cloneIfNotEmpty(ArrayUtils.nullToEmpty(encryptionPaddings)); mBlockModes = ArrayUtils.cloneIfNotEmpty(ArrayUtils.nullToEmpty(blockModes)); mRandomizedEncryptionRequired = randomizedEncryptionRequired; - mUserAuthenticators = userAuthenticators; + mUserAuthenticationRequired = userAuthenticationRequired; mUserAuthenticationValidityDurationSeconds = userAuthenticationValidityDurationSeconds; - mInvalidatedOnNewFingerprintEnrolled = invalidatedOnNewFingerprintEnrolled; } /** @@ -188,18 +185,17 @@ public class KeyGeneratorSpec implements AlgorithmParameterSpec { } /** - * Gets the set of user authenticators which protect access to this key. The key can only be - * used iff the user has authenticated to at least one of these user authenticators. + * Returns {@code true} if user authentication is required for this key to be used. * - * @return user authenticators or {@code 0} if the key can be used without user authentication. + * @see #getUserAuthenticationValidityDurationSeconds() */ - public @KeyStoreKeyProperties.UserAuthenticatorEnum int getUserAuthenticators() { - return mUserAuthenticators; + public boolean isUserAuthenticationRequired() { + return mUserAuthenticationRequired; } /** - * Gets the duration of time (seconds) for which this key can be used after the user - * successfully authenticates to one of the associated user authenticators. + * Gets the duration of time (seconds) for which this key can be used after the user is + * successfully authenticated. * * @return duration in seconds or {@code -1} if not restricted. {@code 0} means authentication * is required for every use of the key. @@ -209,17 +205,6 @@ 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() - */ - public boolean isInvalidatedOnNewFingerprintEnrolled() { - return mInvalidatedOnNewFingerprintEnrolled; - } - - /** * Returns {@code true} if the key must be encrypted in the {@link java.security.KeyStore}. */ public boolean isEncryptionRequired() { @@ -238,9 +223,8 @@ public class KeyGeneratorSpec implements AlgorithmParameterSpec { private String[] mEncryptionPaddings; private String[] mBlockModes; private boolean mRandomizedEncryptionRequired = true; - private @KeyStoreKeyProperties.UserAuthenticatorEnum int mUserAuthenticators; + private boolean mUserAuthenticationRequired; private int mUserAuthenticationValidityDurationSeconds = -1; - private boolean mInvalidatedOnNewFingerprintEnrolled; /** * Creates a new instance of the {@code Builder} with the given {@code context}. The @@ -416,32 +400,35 @@ public class KeyGeneratorSpec implements AlgorithmParameterSpec { } /** - * Sets the user authenticators which protect access to this key. The key can only be used - * iff the user has authenticated to at least one of these user authenticators. + * Sets whether user authentication is required to use this key. * * <p>By default, the key can be used without user authentication. * - * @param userAuthenticators user authenticators or empty list if this key can be accessed - * without user authentication. + * <p>When user authentication is required, the user authorizes the use of the key by + * authenticating to this Android device using a subset of their secure lock screen + * credentials. Different authentication methods are used depending on whether the every + * use of the key must be authenticated (as specified by + * {@link #setUserAuthenticationValidityDurationSeconds(int)}). + * <a href="{@docRoot}training/articles/keystore.html#UserAuthentication">More + * information</a>. * * @see #setUserAuthenticationValidityDurationSeconds(int) */ - public Builder setUserAuthenticators( - @KeyStoreKeyProperties.UserAuthenticatorEnum int userAuthenticators) { - mUserAuthenticators = userAuthenticators; + public Builder setUserAuthenticationRequired(boolean required) { + mUserAuthenticationRequired = required; return this; } /** - * Sets the duration of time (seconds) for which this key can be used after the user - * successfully authenticates to one of the associated user authenticators. + * Sets the duration of time (seconds) for which this key can be used after the user is + * successfully authenticated. This has effect only if user authentication is required. * * <p>By default, the user needs to authenticate for every use of the key. * * @param seconds duration in seconds or {@code 0} if the user needs to authenticate for * every use of the key. * - * @see #setUserAuthenticators(int) + * @see #setUserAuthenticationRequired(boolean) */ public Builder setUserAuthenticationValidityDurationSeconds(int seconds) { mUserAuthenticationValidityDurationSeconds = seconds; @@ -449,20 +436,6 @@ 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) - */ - 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. @@ -479,9 +452,8 @@ public class KeyGeneratorSpec implements AlgorithmParameterSpec { mEncryptionPaddings, mBlockModes, mRandomizedEncryptionRequired, - mUserAuthenticators, - mUserAuthenticationValidityDurationSeconds, - mInvalidatedOnNewFingerprintEnrolled); + mUserAuthenticationRequired, + mUserAuthenticationValidityDurationSeconds); } } } diff --git a/keystore/java/android/security/KeyPairGeneratorSpec.java b/keystore/java/android/security/KeyPairGeneratorSpec.java index 5e5cf37c3e3b..d6d37897eee4 100644 --- a/keystore/java/android/security/KeyPairGeneratorSpec.java +++ b/keystore/java/android/security/KeyPairGeneratorSpec.java @@ -95,12 +95,10 @@ public final class KeyPairGeneratorSpec implements AlgorithmParameterSpec { private final boolean mRandomizedEncryptionRequired; - private final @KeyStoreKeyProperties.UserAuthenticatorEnum int mUserAuthenticators; + private final boolean mUserAuthenticationRequired; private final int mUserAuthenticationValidityDurationSeconds; - private final boolean mInvalidatedOnNewFingerprintEnrolled; - /** * Parameter specification for the "{@code AndroidKeyPairGenerator}" * instance of the {@link java.security.KeyPairGenerator} API. The @@ -145,9 +143,8 @@ public final class KeyPairGeneratorSpec implements AlgorithmParameterSpec { String[] signaturePaddings, String[] blockModes, boolean randomizedEncryptionRequired, - @KeyStoreKeyProperties.UserAuthenticatorEnum int userAuthenticators, - int userAuthenticationValidityDurationSeconds, - boolean invalidatedOnNewFingerprintEnrolled) { + boolean userAuthenticationRequired, + int userAuthenticationValidityDurationSeconds) { if (context == null) { throw new IllegalArgumentException("context == null"); } else if (TextUtils.isEmpty(keyStoreAlias)) { @@ -195,9 +192,8 @@ public final class KeyPairGeneratorSpec implements AlgorithmParameterSpec { mSignaturePaddings = ArrayUtils.cloneIfNotEmpty(ArrayUtils.nullToEmpty(signaturePaddings)); mBlockModes = ArrayUtils.cloneIfNotEmpty(ArrayUtils.nullToEmpty(blockModes)); mRandomizedEncryptionRequired = randomizedEncryptionRequired; - mUserAuthenticators = userAuthenticators; + mUserAuthenticationRequired = userAuthenticationRequired; mUserAuthenticationValidityDurationSeconds = userAuthenticationValidityDurationSeconds; - mInvalidatedOnNewFingerprintEnrolled = invalidatedOnNewFingerprintEnrolled; } /** @@ -227,9 +223,8 @@ public final class KeyPairGeneratorSpec implements AlgorithmParameterSpec { null, // signature paddings null, // block modes false, // randomized encryption required - 0, // user authenticators - -1, // user authentication validity duration (seconds) - false // invalidate on new fingerprint enrolled + false, // user authentication required + -1 // user authentication validity duration (seconds) ); } @@ -396,44 +391,34 @@ public final class KeyPairGeneratorSpec implements AlgorithmParameterSpec { } /** - * Gets the set of user authenticators which protect access to the private key. The key can only - * be used iff the user has authenticated to at least one of these user authenticators. + * Returns {@code true} if user authentication is required for this key to be used. * * <p>This restriction applies only to private key operations. Public key operations are not * restricted. * - * @return user authenticators or {@code 0} if the key can be used without user authentication. + * @see #getUserAuthenticationValidityDurationSeconds() */ - public @KeyStoreKeyProperties.UserAuthenticatorEnum int getUserAuthenticators() { - return mUserAuthenticators; + public boolean isUserAuthenticationRequired() { + return mUserAuthenticationRequired; } /** * Gets the duration of time (seconds) for which the private key can be used after the user - * successfully authenticates to one of the associated user authenticators. + * is successfully authenticated. * * <p>This restriction applies only to private key operations. Public key operations are not * restricted. * * @return duration in seconds or {@code -1} if not restricted. {@code 0} means authentication * is required for every use of the key. + * + * @see #isUserAuthenticationRequired() */ public int getUserAuthenticationValidityDurationSeconds() { return mUserAuthenticationValidityDurationSeconds; } /** - * 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() - */ - 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} @@ -493,12 +478,10 @@ public final class KeyPairGeneratorSpec implements AlgorithmParameterSpec { private boolean mRandomizedEncryptionRequired = true; - private @KeyStoreKeyProperties.UserAuthenticatorEnum int mUserAuthenticators; + private boolean mUserAuthenticationRequired; 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 @@ -774,28 +757,31 @@ public final class KeyPairGeneratorSpec implements AlgorithmParameterSpec { } /** - * Sets the user authenticators which protect access to this key. The key can only be used - * iff the user has authenticated to at least one of these user authenticators. + * Sets whether user authentication is required to use this key. * * <p>By default, the key can be used without user authentication. * + * <p>When user authentication is required, the user authorizes the use of the key by + * authenticating to this Android device using a subset of their secure lock screen + * credentials. Different authentication methods are used depending on whether the every + * use of the key must be authenticated (as specified by + * {@link #setUserAuthenticationValidityDurationSeconds(int)}). + * <a href="{@docRoot}training/articles/keystore.html#UserAuthentication">More + * information</a>. + * * <p>This restriction applies only to private key operations. Public key operations are not * restricted. * - * @param userAuthenticators user authenticators or {@code 0} if this key can be accessed - * without user authentication. - * * @see #setUserAuthenticationValidityDurationSeconds(int) */ - public Builder setUserAuthenticators( - @KeyStoreKeyProperties.UserAuthenticatorEnum int userAuthenticators) { - mUserAuthenticators = userAuthenticators; + public Builder setUserAuthenticationRequired(boolean required) { + mUserAuthenticationRequired = required; return this; } /** - * Sets the duration of time (seconds) for which this key can be used after the user - * successfully authenticates to one of the associated user authenticators. + * Sets the duration of time (seconds) for which this key can be used after the user is + * successfully authenticated. This has effect only if user authentication is required. * * <p>By default, the user needs to authenticate for every use of the key. * @@ -805,7 +791,7 @@ public final class KeyPairGeneratorSpec implements AlgorithmParameterSpec { * @param seconds duration in seconds or {@code 0} if the user needs to authenticate for * every use of the key. * - * @see #setUserAuthenticators(int) + * @see #setUserAuthenticationRequired(boolean) */ public Builder setUserAuthenticationValidityDurationSeconds(int seconds) { mUserAuthenticationValidityDurationSeconds = seconds; @@ -813,20 +799,6 @@ 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) - */ - public Builder setInvalidatedOnNewFingerprintEnrolled(boolean invalidated) { - mInvalidatedOnNewFingerprintEnrolled = invalidated; - return this; - } - - /** * Builds the instance of the {@code KeyPairGeneratorSpec}. * * @throws IllegalArgumentException if a required field is missing @@ -852,9 +824,8 @@ public final class KeyPairGeneratorSpec implements AlgorithmParameterSpec { mSignaturePaddings, mBlockModes, mRandomizedEncryptionRequired, - mUserAuthenticators, - mUserAuthenticationValidityDurationSeconds, - mInvalidatedOnNewFingerprintEnrolled); + mUserAuthenticationRequired, + mUserAuthenticationValidityDurationSeconds); } } } diff --git a/keystore/java/android/security/KeyStoreKeyGeneratorSpi.java b/keystore/java/android/security/KeyStoreKeyGeneratorSpi.java index 293c4c9427f2..20f6042d658c 100644 --- a/keystore/java/android/security/KeyStoreKeyGeneratorSpi.java +++ b/keystore/java/android/security/KeyStoreKeyGeneratorSpi.java @@ -161,27 +161,10 @@ public abstract class KeyStoreKeyGeneratorSpi extends KeyGeneratorSpi { KeymasterDefs.KM_TAG_PADDING, KeymasterUtils.getKeymasterPaddingsFromJcaEncryptionPaddings( spec.getEncryptionPaddings())); - if (spec.getUserAuthenticators() == 0) { - args.addBoolean(KeymasterDefs.KM_TAG_NO_AUTH_REQUIRED); - } else { - args.addInt(KeymasterDefs.KM_TAG_USER_AUTH_TYPE, - KeyStoreKeyProperties.UserAuthenticator.allToKeymaster( - spec.getUserAuthenticators())); - long secureUserId = GateKeeper.getSecureUserId(); - if (secureUserId == 0) { - throw new IllegalStateException("Secure lock screen must be enabled" - + " to generate keys requiring user authentication"); - } - args.addLong(KeymasterDefs.KM_TAG_USER_SECURE_ID, secureUserId); - } - 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()); - } + KeymasterUtils.addUserAuthArgs(args, + spec.getContext(), + spec.isUserAuthenticationRequired(), + spec.getUserAuthenticationValidityDurationSeconds()); args.addDate(KeymasterDefs.KM_TAG_ACTIVE_DATETIME, (spec.getKeyValidityStart() != null) ? spec.getKeyValidityStart() : new Date(0)); diff --git a/keystore/java/android/security/KeyStoreKeyProperties.java b/keystore/java/android/security/KeyStoreKeyProperties.java index 206103f44908..b85ec531f245 100644 --- a/keystore/java/android/security/KeyStoreKeyProperties.java +++ b/keystore/java/android/security/KeyStoreKeyProperties.java @@ -122,101 +122,6 @@ public abstract class KeyStoreKeyProperties { } @Retention(RetentionPolicy.SOURCE) - @IntDef(flag = true, - value = {UserAuthenticator.LOCK_SCREEN, UserAuthenticator.FINGERPRINT_READER}) - public @interface UserAuthenticatorEnum {} - - /** - * User authenticators which can be used to restrict/protect access to keys. - */ - public static abstract class UserAuthenticator { - private UserAuthenticator() {} - - /** Lock screen. */ - public static final int LOCK_SCREEN = 1 << 0; - - /** Fingerprint reader/sensor. */ - public static final int FINGERPRINT_READER = 1 << 1; - - /** - * @hide - */ - public static int toKeymaster(@UserAuthenticatorEnum int userAuthenticator) { - 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); - } - } - - /** - * @hide - */ - public static @UserAuthenticatorEnum int fromKeymaster(int userAuthenticator) { - 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); - } - } - - /** - * @hide - */ - public static int allToKeymaster(@UserAuthenticatorEnum int userAuthenticators) { - int result = 0; - int userAuthenticator = 1; - while (userAuthenticators != 0) { - if ((userAuthenticators & 1) != 0) { - result |= toKeymaster(userAuthenticator); - } - userAuthenticators >>>= 1; - userAuthenticator <<= 1; - } - return result; - } - - /** - * @hide - */ - public static @UserAuthenticatorEnum int allFromKeymaster(int userAuthenticators) { - @UserAuthenticatorEnum int result = 0; - int userAuthenticator = 1; - while (userAuthenticators != 0) { - if ((userAuthenticators & 1) != 0) { - result |= fromKeymaster(userAuthenticator); - } - userAuthenticators >>>= 1; - userAuthenticator <<= 1; - } - return result; - } - - /** - * @hide - */ - public static String toString(@UserAuthenticatorEnum int userAuthenticator) { - switch (userAuthenticator) { - case LOCK_SCREEN: - return "LOCK_SCREEN"; - case FINGERPRINT_READER: - return "FINGERPRINT_READER"; - default: - throw new IllegalArgumentException( - "Unknown user authenticator: " + userAuthenticator); - } - } - } - - @Retention(RetentionPolicy.SOURCE) @IntDef({Origin.GENERATED, Origin.IMPORTED, Origin.UNKNOWN}) public @interface OriginEnum {} diff --git a/keystore/java/android/security/KeyStoreKeySpec.java b/keystore/java/android/security/KeyStoreKeySpec.java index a89e4dd0f5b1..96d58d824011 100644 --- a/keystore/java/android/security/KeyStoreKeySpec.java +++ b/keystore/java/android/security/KeyStoreKeySpec.java @@ -36,10 +36,9 @@ public class KeyStoreKeySpec implements KeySpec { private final String[] mSignaturePaddings; private final String[] mDigests; private final String[] mBlockModes; - private final @KeyStoreKeyProperties.UserAuthenticatorEnum int mUserAuthenticators; - private final @KeyStoreKeyProperties.UserAuthenticatorEnum int mTeeEnforcedUserAuthenticators; + private final boolean mUserAuthenticationRequired; private final int mUserAuthenticationValidityDurationSeconds; - private final boolean mInvalidatedOnNewFingerprintEnrolled; + private final boolean mUserAuthenticationRequirementTeeEnforced; /** * @hide @@ -56,10 +55,9 @@ public class KeyStoreKeySpec implements KeySpec { String[] signaturePaddings, String[] digests, String[] blockModes, - @KeyStoreKeyProperties.UserAuthenticatorEnum int userAuthenticators, - @KeyStoreKeyProperties.UserAuthenticatorEnum int teeEnforcedUserAuthenticators, + boolean userAuthenticationRequired, int userAuthenticationValidityDurationSeconds, - boolean invalidatedOnNewFingerprintEnrolled) { + boolean userAuthenticationRequirementTeeEnforced) { mKeystoreAlias = keystoreKeyAlias; mTeeBacked = teeBacked; mOrigin = origin; @@ -74,10 +72,9 @@ public class KeyStoreKeySpec implements KeySpec { ArrayUtils.cloneIfNotEmpty(ArrayUtils.nullToEmpty(signaturePaddings)); mDigests = ArrayUtils.cloneIfNotEmpty(ArrayUtils.nullToEmpty(digests)); mBlockModes = ArrayUtils.cloneIfNotEmpty(ArrayUtils.nullToEmpty(blockModes)); - mUserAuthenticators = userAuthenticators; - mTeeEnforcedUserAuthenticators = teeEnforcedUserAuthenticators; + mUserAuthenticationRequired = userAuthenticationRequired; mUserAuthenticationValidityDurationSeconds = userAuthenticationValidityDurationSeconds; - mInvalidatedOnNewFingerprintEnrolled = invalidatedOnNewFingerprintEnrolled; + mUserAuthenticationRequirementTeeEnforced = userAuthenticationRequirementTeeEnforced; } /** @@ -172,43 +169,34 @@ public class KeyStoreKeySpec implements KeySpec { } /** - * Gets the set of user authenticators which protect access to the key. The key can only be used - * iff the user has authenticated to at least one of these user authenticators. + * Returns {@code true} if user authentication is required for this key to be used. * - * @return user authenticators or {@code 0} if the key can be used without user authentication. + * @see #getUserAuthenticationValidityDurationSeconds() */ - public @KeyStoreKeyProperties.UserAuthenticatorEnum int getUserAuthenticators() { - return mUserAuthenticators; + public boolean isUserAuthenticationRequired() { + return mUserAuthenticationRequired; } /** - * Gets the set of user authenticators for which the TEE enforces access restrictions for this - * key. This is a subset of the user authentications returned by - * {@link #getUserAuthenticators()}. - */ - public @KeyStoreKeyProperties.UserAuthenticatorEnum int getTeeEnforcedUserAuthenticators() { - return mTeeEnforcedUserAuthenticators; - } - - /** - * Gets the duration of time (seconds) for which the key can be used after the user - * successfully authenticates to one of the associated user authenticators. + * Gets the duration of time (seconds) for which this key can be used after the user is + * successfully authenticated. * * @return duration in seconds or {@code -1} if not restricted. {@code 0} means authentication * is required for every use of the key. + * + * @see #isUserAuthenticationRequired() */ 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. + * Returns {@code true} if the requirement that this key can only be used if the user has been + * authenticated if enforced by the TEE. * - * @see #getUserAuthenticators() + * @see #isUserAuthenticationRequired() */ - public boolean isInvalidatedOnNewFingerprintEnrolled() { - return mInvalidatedOnNewFingerprintEnrolled; + public boolean isUserAuthenticationRequirementTeeEnforced() { + return mUserAuthenticationRequirementTeeEnforced; } } diff --git a/keystore/java/android/security/KeyStoreParameter.java b/keystore/java/android/security/KeyStoreParameter.java index c24b74f42e20..b4747e937040 100644 --- a/keystore/java/android/security/KeyStoreParameter.java +++ b/keystore/java/android/security/KeyStoreParameter.java @@ -39,7 +39,8 @@ import javax.crypto.Cipher; * {@code KeyStore}. */ public final class KeyStoreParameter implements ProtectionParameter { - private int mFlags; + private final Context mContext; + private final int mFlags; private final Date mKeyValidityStart; private final Date mKeyValidityForOriginationEnd; private final Date mKeyValidityForConsumptionEnd; @@ -49,11 +50,12 @@ public final class KeyStoreParameter implements ProtectionParameter { private final String[] mDigests; private final String[] mBlockModes; private final boolean mRandomizedEncryptionRequired; - private final @KeyStoreKeyProperties.UserAuthenticatorEnum int mUserAuthenticators; + private final boolean mUserAuthenticationRequired; private final int mUserAuthenticationValidityDurationSeconds; - private final boolean mInvalidatedOnNewFingerprintEnrolled; - private KeyStoreParameter(int flags, + private KeyStoreParameter( + Context context, + int flags, Date keyValidityStart, Date keyValidityForOriginationEnd, Date keyValidityForConsumptionEnd, @@ -63,15 +65,17 @@ public final class KeyStoreParameter implements ProtectionParameter { String[] digests, String[] blockModes, boolean randomizedEncryptionRequired, - @KeyStoreKeyProperties.UserAuthenticatorEnum int userAuthenticators, - int userAuthenticationValidityDurationSeconds, - boolean invalidatedOnNewFingerprintEnrolled) { - if ((userAuthenticationValidityDurationSeconds < 0) + boolean userAuthenticationRequired, + int userAuthenticationValidityDurationSeconds) { + if (context == null) { + throw new IllegalArgumentException("context == null"); + } else if ((userAuthenticationValidityDurationSeconds < 0) && (userAuthenticationValidityDurationSeconds != -1)) { throw new IllegalArgumentException( "userAuthenticationValidityDurationSeconds must not be negative"); } + mContext = context; mFlags = flags; mKeyValidityStart = keyValidityStart; mKeyValidityForOriginationEnd = keyValidityForOriginationEnd; @@ -84,9 +88,15 @@ public final class KeyStoreParameter implements ProtectionParameter { mDigests = ArrayUtils.cloneIfNotEmpty(digests); mBlockModes = ArrayUtils.cloneIfNotEmpty(ArrayUtils.nullToEmpty(blockModes)); mRandomizedEncryptionRequired = randomizedEncryptionRequired; - mUserAuthenticators = userAuthenticators; + mUserAuthenticationRequired = userAuthenticationRequired; mUserAuthenticationValidityDurationSeconds = userAuthenticationValidityDurationSeconds; - mInvalidatedOnNewFingerprintEnrolled = invalidatedOnNewFingerprintEnrolled; + } + + /** + * Gets the Android context used for operations with this instance. + */ + public Context getContext() { + return mContext; } /** @@ -198,18 +208,17 @@ public final class KeyStoreParameter implements ProtectionParameter { } /** - * Gets the set of user authenticators which protect access to this key. The key can only be - * used iff the user has authenticated to at least one of these user authenticators. + * Returns {@code true} if user authentication is required for this key to be used. * - * @return user authenticators or {@code 0} if the key can be used without user authentication. + * @see #getUserAuthenticationValidityDurationSeconds() */ - public @KeyStoreKeyProperties.UserAuthenticatorEnum int getUserAuthenticators() { - return mUserAuthenticators; + public boolean isUserAuthenticationRequired() { + return mUserAuthenticationRequired; } /** - * Gets the duration of time (seconds) for which this key can be used after the user - * successfully authenticates to one of the associated user authenticators. + * Gets the duration of time (seconds) for which this key can be used after the user is + * successfully authenticated. * * @return duration in seconds or {@code -1} if not restricted. {@code 0} means authentication * is required for every use of the key. @@ -219,17 +228,6 @@ 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() - */ - public boolean isInvalidatedOnNewFingerprintEnrolled() { - return mInvalidatedOnNewFingerprintEnrolled; - } - - /** * Builder class for {@link KeyStoreParameter} objects. * <p> * This will build protection parameters for use with the @@ -247,6 +245,7 @@ public final class KeyStoreParameter implements ProtectionParameter { * </pre> */ public final static class Builder { + private final Context mContext; private int mFlags; private Date mKeyValidityStart; private Date mKeyValidityForOriginationEnd; @@ -257,9 +256,8 @@ public final class KeyStoreParameter implements ProtectionParameter { private String[] mDigests; private String[] mBlockModes; private boolean mRandomizedEncryptionRequired = true; - private @KeyStoreKeyProperties.UserAuthenticatorEnum int mUserAuthenticators; + private boolean mUserAuthenticationRequired; private int mUserAuthenticationValidityDurationSeconds = -1; - private boolean mInvalidatedOnNewFingerprintEnrolled; /** * Creates a new instance of the {@code Builder} with the given @@ -271,8 +269,7 @@ public final class KeyStoreParameter implements ProtectionParameter { if (context == null) { throw new NullPointerException("context == null"); } - - // Context is currently not used, but will be in the future. + mContext = context; } /** @@ -440,32 +437,35 @@ public final class KeyStoreParameter implements ProtectionParameter { } /** - * Sets the user authenticators which protect access to this key. The key can only be used - * iff the user has authenticated to at least one of these user authenticators. + * Sets whether user authentication is required to use this key. * * <p>By default, the key can be used without user authentication. * - * @param userAuthenticators user authenticators or {@code 0} if this key can be accessed - * without user authentication. + * <p>When user authentication is required, the user authorizes the use of the key by + * authenticating to this Android device using a subset of their secure lock screen + * credentials. Different authentication methods are used depending on whether the every + * use of the key must be authenticated (as specified by + * {@link #setUserAuthenticationValidityDurationSeconds(int)}). + * <a href="{@docRoot}training/articles/keystore.html#UserAuthentication">More + * information</a>. * * @see #setUserAuthenticationValidityDurationSeconds(int) */ - public Builder setUserAuthenticators( - @KeyStoreKeyProperties.UserAuthenticatorEnum int userAuthenticators) { - mUserAuthenticators = userAuthenticators; + public Builder setUserAuthenticationRequired(boolean required) { + mUserAuthenticationRequired = required; return this; } /** - * Sets the duration of time (seconds) for which this key can be used after the user - * successfully authenticates to one of the associated user authenticators. + * Sets the duration of time (seconds) for which this key can be used after the user is + * successfully authenticated. This has effect only if user authentication is required. * * <p>By default, the user needs to authenticate for every use of the key. * * @param seconds duration in seconds or {@code 0} if the user needs to authenticate for * every use of the key. * - * @see #setUserAuthenticators(int) + * @see #setUserAuthenticationRequired(boolean) */ public Builder setUserAuthenticationValidityDurationSeconds(int seconds) { mUserAuthenticationValidityDurationSeconds = seconds; @@ -473,27 +473,15 @@ 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) - */ - public Builder setInvalidatedOnNewFingerprintEnrolled(boolean invalidated) { - mInvalidatedOnNewFingerprintEnrolled = invalidated; - return this; - } - - /** * Builds the instance of the {@code KeyStoreParameter}. * * @throws IllegalArgumentException if a required field is missing * @return built instance of {@code KeyStoreParameter} */ public KeyStoreParameter build() { - return new KeyStoreParameter(mFlags, + return new KeyStoreParameter( + mContext, + mFlags, mKeyValidityStart, mKeyValidityForOriginationEnd, mKeyValidityForConsumptionEnd, @@ -503,9 +491,8 @@ public final class KeyStoreParameter implements ProtectionParameter { mDigests, mBlockModes, mRandomizedEncryptionRequired, - mUserAuthenticators, - mUserAuthenticationValidityDurationSeconds, - mInvalidatedOnNewFingerprintEnrolled); + mUserAuthenticationRequired, + mUserAuthenticationValidityDurationSeconds); } } } diff --git a/keystore/java/android/security/KeyStoreSecretKeyFactorySpi.java b/keystore/java/android/security/KeyStoreSecretKeyFactorySpi.java index 4be0638ca1a1..bfe09e3e1b73 100644 --- a/keystore/java/android/security/KeyStoreSecretKeyFactorySpi.java +++ b/keystore/java/android/security/KeyStoreSecretKeyFactorySpi.java @@ -81,8 +81,8 @@ public class KeyStoreSecretKeyFactorySpi extends SecretKeyFactorySpi { String[] encryptionPaddings; String[] digests; String[] blockModes; - @KeyStoreKeyProperties.UserAuthenticatorEnum int userAuthenticators; - @KeyStoreKeyProperties.UserAuthenticatorEnum int teeEnforcedUserAuthenticators; + int keymasterSwEnforcedUserAuthenticators; + int keymasterHwEnforcedUserAuthenticators; try { if (keyCharacteristics.hwEnforced.containsTag(KeymasterDefs.KM_TAG_ORIGIN)) { teeBacked = true; @@ -122,21 +122,10 @@ public class KeyStoreSecretKeyFactorySpi extends SecretKeyFactorySpi { keyCharacteristics.getInts(KeymasterDefs.KM_TAG_DIGEST)); blockModes = KeymasterUtils.getJcaBlockModesFromKeymasterBlockModes( keyCharacteristics.getInts(KeymasterDefs.KM_TAG_BLOCK_MODE)); - - @KeyStoreKeyProperties.UserAuthenticatorEnum - int swEnforcedKeymasterUserAuthenticators = + keymasterSwEnforcedUserAuthenticators = keyCharacteristics.swEnforced.getInt(KeymasterDefs.KM_TAG_USER_AUTH_TYPE, 0); - @KeyStoreKeyProperties.UserAuthenticatorEnum - int hwEnforcedKeymasterUserAuthenticators = + keymasterHwEnforcedUserAuthenticators = keyCharacteristics.hwEnforced.getInt(KeymasterDefs.KM_TAG_USER_AUTH_TYPE, 0); - @KeyStoreKeyProperties.UserAuthenticatorEnum - int keymasterUserAuthenticators = - swEnforcedKeymasterUserAuthenticators | hwEnforcedKeymasterUserAuthenticators; - userAuthenticators = KeyStoreKeyProperties.UserAuthenticator.allFromKeymaster( - keymasterUserAuthenticators); - teeEnforcedUserAuthenticators = - KeyStoreKeyProperties.UserAuthenticator.allFromKeymaster( - hwEnforcedKeymasterUserAuthenticators); } catch (IllegalArgumentException e) { throw new InvalidKeySpecException("Unsupported key characteristic", e); } @@ -157,11 +146,13 @@ public class KeyStoreSecretKeyFactorySpi extends SecretKeyFactorySpi { && (keyValidityForConsumptionEnd.getTime() == Long.MAX_VALUE)) { keyValidityForConsumptionEnd = null; } + boolean userAuthenticationRequired = + !keyCharacteristics.getBoolean(KeymasterDefs.KM_TAG_NO_AUTH_REQUIRED); 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; + boolean userAuthenticationRequirementEnforcedInTee = (userAuthenticationRequired) + && (keymasterHwEnforcedUserAuthenticators != 0) + && (keymasterSwEnforcedUserAuthenticators == 0); return new KeyStoreKeySpec(entryAlias, teeBacked, @@ -175,10 +166,9 @@ public class KeyStoreSecretKeyFactorySpi extends SecretKeyFactorySpi { EmptyArray.STRING, // no signature paddings -- this is symmetric crypto digests, blockModes, - userAuthenticators, - teeEnforcedUserAuthenticators, + userAuthenticationRequired, userAuthenticationValidityDurationSeconds, - invalidatedOnNewFingerprintEnrolled); + userAuthenticationRequirementEnforcedInTee); } @Override diff --git a/keystore/java/android/security/KeymasterUtils.java b/keystore/java/android/security/KeymasterUtils.java index 67f75c26b451..7bf5475ab16d 100644 --- a/keystore/java/android/security/KeymasterUtils.java +++ b/keystore/java/android/security/KeymasterUtils.java @@ -16,7 +16,14 @@ package android.security; +import android.content.Context; +import android.hardware.fingerprint.FingerprintManager; +import android.os.RemoteException; +import android.os.ServiceManager; +import android.os.UserHandle; +import android.security.keymaster.KeymasterArguments; import android.security.keymaster.KeymasterDefs; +import android.service.gatekeeper.IGateKeeperService; import libcore.util.EmptyArray; @@ -339,4 +346,72 @@ public abstract class KeymasterUtils { } return result; } + + private static long getRootSid() { + IGateKeeperService gatekeeperService = IGateKeeperService.Stub.asInterface( + ServiceManager.getService("android.service.gatekeeper.IGateKeeperService")); + if (gatekeeperService == null) { + throw new IllegalStateException("Gatekeeper service not available"); + } + + try { + return gatekeeperService.getSecureUserId(UserHandle.myUserId()); + } catch (RemoteException e) { + throw new IllegalStateException("Failed to obtain root SID"); + } + } + + /** + * Adds keymaster arguments to express the key's authorization policy supported by user + * authentication. + * + * @param userAuthenticationRequired whether user authentication is required to authorize the + * use of the key. + * @param userAuthenticationValidityDurationSeconds duration of time (seconds) for which user + * authentication is valid as authorization for using the key or {@code -1} if every + * use of the key needs authorization. + */ + public static void addUserAuthArgs(KeymasterArguments args, + Context context, + boolean userAuthenticationRequired, + int userAuthenticationValidityDurationSeconds) { + if (!userAuthenticationRequired) { + args.addBoolean(KeymasterDefs.KM_TAG_NO_AUTH_REQUIRED); + return; + } + + if (userAuthenticationValidityDurationSeconds == -1) { + // Every use of this key needs to be authorized by the user. This currently means + // fingerprint-only auth. + FingerprintManager fingerprintManager = + context.getSystemService(FingerprintManager.class); + if ((fingerprintManager == null) || (!fingerprintManager.isHardwareDetected())) { + throw new IllegalStateException( + "This device does not support keys which require authentication for every" + + " use -- this requires fingerprint authentication which is not" + + " available on this device"); + } + long fingerprintOnlySid = fingerprintManager.getAuthenticatorId(); + if (fingerprintOnlySid == 0) { + throw new IllegalStateException( + "At least one fingerprint must be enrolled to create keys requiring user" + + " authentication for every use"); + } + args.addLong(KeymasterDefs.KM_TAG_USER_SECURE_ID, fingerprintOnlySid); + args.addInt(KeymasterDefs.KM_TAG_USER_AUTH_TYPE, KeymasterDefs.HW_AUTH_FINGERPRINT); + } else { + // The key is authorized for use for the specified amount of time after the user has + // authenticated. Whatever unlocks the secure lock screen should authorize this key. + long rootSid = getRootSid(); + if (rootSid == 0) { + throw new IllegalStateException("Secure lock screen must be enabled" + + " to create keys requiring user authentication"); + } + args.addLong(KeymasterDefs.KM_TAG_USER_SECURE_ID, rootSid); + args.addInt(KeymasterDefs.KM_TAG_USER_AUTH_TYPE, + KeymasterDefs.HW_AUTH_PASSWORD | KeymasterDefs.HW_AUTH_FINGERPRINT); + args.addInt(KeymasterDefs.KM_TAG_AUTH_TIMEOUT, + userAuthenticationValidityDurationSeconds); + } + } } |