From 83cc7a347f4775821ebeed04a2244b8b847be516 Mon Sep 17 00:00:00 2001 From: Alex Klyubin Date: Tue, 16 Jun 2015 10:44:11 -0700 Subject: Improve documentation for keys requiring user auth. Bug: 18088752 Change-Id: I24eeb33790a74d8d81d10fcdb1eb058d47144c44 --- docs/html/training/articles/keystore.jd | 59 ++++++----- .../security/keystore/KeyGenParameterSpec.java | 109 +++++++++++++++------ .../java/android/security/keystore/KeyInfo.java | 16 ++- .../KeyPermanentlyInvalidatedException.java | 13 +-- .../android/security/keystore/KeyProtection.java | 87 +++++++++++++--- 5 files changed, 209 insertions(+), 75 deletions(-) diff --git a/docs/html/training/articles/keystore.jd b/docs/html/training/articles/keystore.jd index fca958e..52cb13e 100644 --- a/docs/html/training/articles/keystore.jd +++ b/docs/html/training/articles/keystore.jd @@ -32,7 +32,7 @@ page.title=Android Keystore System keystore, they can be used for cryptographic operations with the key material 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. See + restricting keys to be used only in certain cryptographic modes. See Security Features section for more information.

The Keystore system is used by the {@link @@ -48,7 +48,8 @@ Android Keystore system protects key material from unauthorized use. Firstly, An mitigates unauthorized use of key material outside of the Android device by preventing extraction of the key material from application processes and from the Android device as a whole. Secondly, Android KeyStore mitigates unauthorized use of key material on the Android device by making apps -specify authorized uses of their keys and then enforcing these restrictions. +specify authorized uses of their keys and then enforcing these restrictions outside of the apps' +processes.

Extraction Prevention

@@ -78,14 +79,16 @@ Key material of Android Keystore keys is protected from extraction using two sec To mitigate unauthorized use of keys on the Android device, Android Keystore lets apps specify authorized uses of their keys when generating or importing the keys. Once a key is generated or imported, its authorizations can not be changed. Authorizations are then enforced by the Android -Keystore whenever the key is used. +Keystore whenever the key is used. This is an advanced security feature which is generally useful +only if your requirements are that a compromise of your application process after key +generation/import (but not before or during) cannot lead to unauthorized uses of the key.

Supported key use authorizations fall into the following categories:

\ No newline at end of file diff --git a/keystore/java/android/security/keystore/KeyGenParameterSpec.java b/keystore/java/android/security/keystore/KeyGenParameterSpec.java index 8d4bfcd..5775a87 100644 --- a/keystore/java/android/security/keystore/KeyGenParameterSpec.java +++ b/keystore/java/android/security/keystore/KeyGenParameterSpec.java @@ -19,16 +19,20 @@ package android.security.keystore; import android.annotation.IntRange; import android.annotation.NonNull; import android.annotation.Nullable; +import android.app.KeyguardManager; +import android.hardware.fingerprint.FingerprintManager; import android.text.TextUtils; import java.math.BigInteger; import java.security.KeyPairGenerator; +import java.security.Signature; import java.security.cert.Certificate; import java.security.spec.AlgorithmParameterSpec; import java.util.Date; import javax.crypto.Cipher; import javax.crypto.KeyGenerator; +import javax.crypto.Mac; import javax.security.auth.x500.X500Principal; /** @@ -62,10 +66,15 @@ import javax.security.auth.x500.X500Principal; *

NOTE: If a private key is not authorized to sign the self-signed certificate, then the * certificate will be created with an invalid signature which will not verify. Such a certificate * is still useful because it provides access to the public key. To generate a valid - * signature for the certificate the key needs to be authorized for - * {@link KeyProperties#PURPOSE_SIGN}, a suitable digest or {@link KeyProperties#DIGEST_NONE}, and - * {@link KeyProperties#SIGNATURE_PADDING_RSA_PKCS1} or - * {@link KeyProperties#ENCRYPTION_PADDING_NONE}. + * signature for the certificate the key needs to be authorized for all of the following: + *

* *

NOTE: The key material of the generated symmetric and private keys is not accessible. The key * material of the public keys is accessible. @@ -393,28 +402,32 @@ public final class KeyGenParameterSpec implements AlgorithmParameterSpec { } /** - * Returns {@code true} if user authentication is required for this key to be used. + * Returns {@code true} if the key is authorized to be used only if the user has been + * authenticated. * - *

This restriction applies only to private key operations. Public key operations are not - * restricted. + *

This authorization applies only to secret key and private key operations. Public key + * operations are not restricted. * * @see #getUserAuthenticationValidityDurationSeconds() + * @see Builder#setUserAuthenticationRequired(boolean) */ public boolean isUserAuthenticationRequired() { return mUserAuthenticationRequired; } /** - * Gets 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. + * Gets the duration of time (seconds) for which this key is authorized to be used after the + * user is successfully authenticated. This has effect only if user authentication is required + * (see {@link #isUserAuthenticationRequired()}). * - *

This restriction applies only to private key operations. Public key operations are not - * restricted. + *

This authorization applies only to secret key and private key operations. Public key + * operations are not restricted. * * @return duration in seconds or {@code -1} if authentication is required for every use of the - * key. + * key. * * @see #isUserAuthenticationRequired() + * @see Builder#setUserAuthenticationValidityDurationSeconds(int) */ public int getUserAuthenticationValidityDurationSeconds() { return mUserAuthenticationValidityDurationSeconds; @@ -738,22 +751,38 @@ public final class KeyGenParameterSpec implements AlgorithmParameterSpec { } /** - * Sets whether user authentication is required to use this key. + * Sets whether this key is authorized to be used only if the user has been authenticated. * - *

By default, the key can be used without user authentication. + *

By default, the key is authorized to be used regardless of whether the user has been + * authenticated. * - *

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)}). + *

When user authentication is required: + *

* - *

This restriction applies only to private key operations. Public key operations are not - * restricted. + *

This authorization applies only to secret key and private key operations. Public key + * operations are not restricted. * * @see #setUserAuthenticationValidityDurationSeconds(int) + * @see KeyguardManager#isDeviceSecure() + * @see FingerprintManager#hasEnrolledFingerprints() */ @NonNull public Builder setUserAuthenticationRequired(boolean required) { @@ -762,15 +791,39 @@ public final class KeyGenParameterSpec implements AlgorithmParameterSpec { } /** - * 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. - * - *

By default, the user needs to authenticate for every use of the key. - * - * @param seconds duration in seconds or {@code -1} if the user needs to authenticate for - * every use of the key. + * Sets the duration of time (seconds) for which this key is authorized to be used after the + * user is successfully authenticated. This has effect if the key requires user + * authentication for its use (see {@link #setUserAuthenticationRequired(boolean)}). + * + *

By default, if user authentication is required, it must take place for every use of + * the key. + * + *

Cryptographic operations involving keys which require user authentication to take + * place for every operation can only use fingerprint authentication. This is achieved by + * initializing a cryptographic operation ({@link Signature}, {@link Cipher}, {@link Mac}) + * with the key, wrapping it into a {@link FingerprintManager.CryptoObject}, invoking + * {@code FingerprintManager.authenticate} with {@code CryptoObject}, and proceeding with + * the cryptographic operation only if the authentication flow succeeds. + * + *

Cryptographic operations involving keys which are authorized to be used for a duration + * of time after a successful user authentication event can only use secure lock screen + * authentication. These cryptographic operations will throw + * {@link UserNotAuthenticatedException} during initialization if the user needs to be + * authenticated to proceed. This situation can be resolved by the user unlocking the secure + * lock screen of the Android or by going through the confirm credential flow initiated by + * {@link KeyguardManager#createConfirmDeviceCredentialIntent(CharSequence, CharSequence)}. + * Once resolved, initializing a new cryptographic operation using this key (or any other + * key which is authorized to be used for a fixed duration of time after user + * authentication) should succeed provided the user authentication flow completed + * successfully. + * + * @param seconds duration in seconds or {@code -1} if user authentication must take place + * for every use of the key. * * @see #setUserAuthenticationRequired(boolean) + * @see FingerprintManager + * @see FingerprintManager.CryptoObject + * @see KeyguardManager */ @NonNull public Builder setUserAuthenticationValidityDurationSeconds( diff --git a/keystore/java/android/security/keystore/KeyInfo.java b/keystore/java/android/security/keystore/KeyInfo.java index 03b4100..91a9a70 100644 --- a/keystore/java/android/security/keystore/KeyInfo.java +++ b/keystore/java/android/security/keystore/KeyInfo.java @@ -238,17 +238,27 @@ public class KeyInfo implements KeySpec { } /** - * Returns {@code true} if user authentication is required for this key to be used. + * Returns {@code true} if the key is authorized to be used only if the user has been + * authenticated. + * + *

This authorization applies only to secret key and private key operations. Public key + * operations are not restricted. * * @see #getUserAuthenticationValidityDurationSeconds() + * @see KeyGenParameterSpec.Builder#setUserAuthenticationRequired(boolean) + * @see KeyProtection.Builder#setUserAuthenticationRequired(boolean) */ public boolean isUserAuthenticationRequired() { return mUserAuthenticationRequired; } /** - * Gets 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. + * Gets the duration of time (seconds) for which this key is authorized to be used after the + * user is successfully authenticated. This has effect only if user authentication is required + * (see {@link #isUserAuthenticationRequired()}). + * + *

This authorization applies only to secret key and private key operations. Public key + * operations are not restricted. * * @return duration in seconds or {@code -1} if authentication is required for every use of the * key. diff --git a/keystore/java/android/security/keystore/KeyPermanentlyInvalidatedException.java b/keystore/java/android/security/keystore/KeyPermanentlyInvalidatedException.java index e320c9c..9e82fc0 100644 --- a/keystore/java/android/security/keystore/KeyPermanentlyInvalidatedException.java +++ b/keystore/java/android/security/keystore/KeyPermanentlyInvalidatedException.java @@ -21,12 +21,13 @@ import java.security.InvalidKeyException; /** * Indicates that the key can no longer be used because it has been permanently invalidated. * - *

This can currently occur only for keys that require user authentication. Such keys are - * permanently invalidated once the secure lock screen is disabled (i.e., reconfigured to None, - * Swipe or other mode which does not authenticate the user) or when the secure lock screen is - * forcibly reset (e.g., by Device Admin). Additionally, keys configured to require user - * authentication for every use of the key are also permanently invalidated once a new fingerprint - * is enrolled or once no more fingerprints are enrolled. + *

This only occurs for keys which are authorized to be used only if the user has been + * authenticated. Such keys are permanently and irreversibly invalidated once the secure lock screen + * is disabled (i.e., reconfigured to None, Swipe or other mode which does not authenticate the + * user) or when the secure lock screen is forcibly reset (e.g., by Device Admin). Additionally, + * keys configured to require user authentication to take place for every of the keys, are also + * permanently invalidated once a new fingerprint is enrolled or once no more fingerprints are + * enrolled. */ public class KeyPermanentlyInvalidatedException extends InvalidKeyException { diff --git a/keystore/java/android/security/keystore/KeyProtection.java b/keystore/java/android/security/keystore/KeyProtection.java index 1e0611c..cd46afa 100644 --- a/keystore/java/android/security/keystore/KeyProtection.java +++ b/keystore/java/android/security/keystore/KeyProtection.java @@ -19,13 +19,17 @@ package android.security.keystore; import android.annotation.IntRange; import android.annotation.NonNull; import android.annotation.Nullable; +import android.app.KeyguardManager; +import android.hardware.fingerprint.FingerprintManager; import java.security.Key; +import java.security.Signature; import java.security.KeyStore.ProtectionParameter; import java.security.cert.Certificate; import java.util.Date; import javax.crypto.Cipher; +import javax.crypto.Mac; /** * Specification of how a key or key pair is secured when imported into the @@ -257,22 +261,32 @@ public final class KeyProtection implements ProtectionParameter { } /** - * Returns {@code true} if user authentication is required for this key to be used. + * Returns {@code true} if the key is authorized to be used only if the user has been + * authenticated. + * + *

This authorization applies only to secret key and private key operations. Public key + * operations are not restricted. * * @see #getUserAuthenticationValidityDurationSeconds() + * @see Builder#setUserAuthenticationRequired(boolean) */ public boolean isUserAuthenticationRequired() { return mUserAuthenticationRequired; } /** - * Gets 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. + * Gets the duration of time (seconds) for which this key is authorized to be used after the + * user is successfully authenticated. This has effect only if user authentication is required + * (see {@link #isUserAuthenticationRequired()}). + * + *

This authorization applies only to secret key and private key operations. Public key + * operations are not restricted. * * @return duration in seconds or {@code -1} if authentication is required for every use of the * key. * * @see #isUserAuthenticationRequired() + * @see Builder#setUserAuthenticationValidityDurationSeconds(int) */ public int getUserAuthenticationValidityDurationSeconds() { return mUserAuthenticationValidityDurationSeconds; @@ -479,19 +493,38 @@ public final class KeyProtection implements ProtectionParameter { } /** - * Sets whether user authentication is required to use this key. + * Sets whether this key is authorized to be used only if the user has been authenticated. * - *

By default, the key can be used without user authentication. + *

By default, the key is authorized to be used regardless of whether the user has been + * authenticated. * - *

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)}). + *

When user authentication is required: + *

+ * + *

This authorization applies only to secret key and private key operations. Public key + * operations are not restricted. * * @see #setUserAuthenticationValidityDurationSeconds(int) + * @see KeyguardManager#isDeviceSecure() + * @see FingerprintManager#hasEnrolledFingerprints() */ @NonNull public Builder setUserAuthenticationRequired(boolean required) { @@ -500,15 +533,39 @@ public final class KeyProtection implements ProtectionParameter { } /** - * 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. + * Sets the duration of time (seconds) for which this key is authorized to be used after the + * user is successfully authenticated. This has effect if the key requires user + * authentication for its use (see {@link #setUserAuthenticationRequired(boolean)}). + * + *

By default, if user authentication is required, it must take place for every use of + * the key. + * + *

Cryptographic operations involving keys which require user authentication to take + * place for every operation can only use fingerprint authentication. This is achieved by + * initializing a cryptographic operation ({@link Signature}, {@link Cipher}, {@link Mac}) + * with the key, wrapping it into a {@link FingerprintManager.CryptoObject}, invoking + * {@code FingerprintManager.authenticate} with {@code CryptoObject}, and proceeding with + * the cryptographic operation only if the authentication flow succeeds. * - *

By default, the user needs to authenticate for every use of the key. + *

Cryptographic operations involving keys which are authorized to be used for a duration + * of time after a successful user authentication event can only use secure lock screen + * authentication. These cryptographic operations will throw + * {@link UserNotAuthenticatedException} during initialization if the user needs to be + * authenticated to proceed. This situation can be resolved by the user unlocking the secure + * lock screen of the Android or by going through the confirm credential flow initiated by + * {@link KeyguardManager#createConfirmDeviceCredentialIntent(CharSequence, CharSequence)}. + * Once resolved, initializing a new cryptographic operation using this key (or any other + * key which is authorized to be used for a fixed duration of time after user + * authentication) should succeed provided the user authentication flow completed + * successfully. * - * @param seconds duration in seconds or {@code -1} if the user needs to authenticate for - * every use of the key. + * @param seconds duration in seconds or {@code -1} if user authentication must take place + * for every use of the key. * * @see #setUserAuthenticationRequired(boolean) + * @see FingerprintManager + * @see FingerprintManager.CryptoObject + * @see KeyguardManager */ @NonNull public Builder setUserAuthenticationValidityDurationSeconds( -- cgit v1.1