Add "Unlocked device required" parameter to keys
Add a keymaster parameter for keys that should be inaccessible when the device screen is locked. "Locked" here is a state where the device can be used or accessed without any further trust factor such as a PIN, password, fingerprint, or trusted face or voice. This parameter is added to the Java keystore interface for key creation and import, as well as enums specified by and for the native keystore process. Test: CTS tests in I8a5affd1eaed176756175158e3057e44934fffed Bug: 67752510 Change-Id: I314b848f6971d1849a7a6347d52e41d9604639ae
This commit is contained in:
@@ -38445,6 +38445,7 @@ package android.security.keystore {
|
||||
method public boolean isRandomizedEncryptionRequired();
|
||||
method public boolean isStrongBoxBacked();
|
||||
method public boolean isTrustedUserPresenceRequired();
|
||||
method public boolean isUnlockedDeviceRequired();
|
||||
method public boolean isUserAuthenticationRequired();
|
||||
method public boolean isUserAuthenticationValidWhileOnBody();
|
||||
method public boolean isUserConfirmationRequired();
|
||||
@@ -38472,6 +38473,7 @@ package android.security.keystore {
|
||||
method public android.security.keystore.KeyGenParameterSpec.Builder setRandomizedEncryptionRequired(boolean);
|
||||
method public android.security.keystore.KeyGenParameterSpec.Builder setSignaturePaddings(java.lang.String...);
|
||||
method public android.security.keystore.KeyGenParameterSpec.Builder setTrustedUserPresenceRequired(boolean);
|
||||
method public android.security.keystore.KeyGenParameterSpec.Builder setUnlockedDeviceRequired(boolean);
|
||||
method public android.security.keystore.KeyGenParameterSpec.Builder setUserAuthenticationRequired(boolean);
|
||||
method public android.security.keystore.KeyGenParameterSpec.Builder setUserAuthenticationValidWhileOnBody(boolean);
|
||||
method public android.security.keystore.KeyGenParameterSpec.Builder setUserAuthenticationValidityDurationSeconds(int);
|
||||
@@ -38563,6 +38565,8 @@ package android.security.keystore {
|
||||
method public boolean isDigestsSpecified();
|
||||
method public boolean isInvalidatedByBiometricEnrollment();
|
||||
method public boolean isRandomizedEncryptionRequired();
|
||||
method public boolean isTrustedUserPresenceRequired();
|
||||
method public boolean isUnlockedDeviceRequired();
|
||||
method public boolean isUserAuthenticationRequired();
|
||||
method public boolean isUserAuthenticationValidWhileOnBody();
|
||||
method public boolean isUserConfirmationRequired();
|
||||
@@ -38581,6 +38585,8 @@ package android.security.keystore {
|
||||
method public android.security.keystore.KeyProtection.Builder setKeyValidityStart(java.util.Date);
|
||||
method public android.security.keystore.KeyProtection.Builder setRandomizedEncryptionRequired(boolean);
|
||||
method public android.security.keystore.KeyProtection.Builder setSignaturePaddings(java.lang.String...);
|
||||
method public android.security.keystore.KeyProtection.Builder setTrustedUserPresenceRequired(boolean);
|
||||
method public android.security.keystore.KeyProtection.Builder setUnlockedDeviceRequired(boolean);
|
||||
method public android.security.keystore.KeyProtection.Builder setUserAuthenticationRequired(boolean);
|
||||
method public android.security.keystore.KeyProtection.Builder setUserAuthenticationValidWhileOnBody(boolean);
|
||||
method public android.security.keystore.KeyProtection.Builder setUserAuthenticationValidityDurationSeconds(int);
|
||||
|
||||
@@ -75,6 +75,7 @@ public final class KeymasterDefs {
|
||||
public static final int KM_TAG_ALLOW_WHILE_ON_BODY = KM_BOOL | 506;
|
||||
public static final int KM_TAG_TRUSTED_USER_PRESENCE_REQUIRED = KM_BOOL | 507;
|
||||
public static final int KM_TAG_TRUSTED_CONFIRMATION_REQUIRED = KM_BOOL | 508;
|
||||
public static final int KM_TAG_UNLOCKED_DEVICE_REQUIRED = KM_BOOL | 509;
|
||||
|
||||
public static final int KM_TAG_ALL_APPLICATIONS = KM_BOOL | 600;
|
||||
public static final int KM_TAG_APPLICATION_ID = KM_BYTES | 601;
|
||||
@@ -216,6 +217,7 @@ public final class KeymasterDefs {
|
||||
public static final int KM_ERROR_MISSING_MIN_MAC_LENGTH = -58;
|
||||
public static final int KM_ERROR_UNSUPPORTED_MIN_MAC_LENGTH = -59;
|
||||
public static final int KM_ERROR_CANNOT_ATTEST_IDS = -66;
|
||||
public static final int KM_ERROR_DEVICE_LOCKED = -72;
|
||||
public static final int KM_ERROR_UNIMPLEMENTED = -100;
|
||||
public static final int KM_ERROR_VERSION_MISMATCH = -101;
|
||||
public static final int KM_ERROR_UNKNOWN_ERROR = -1000;
|
||||
@@ -262,6 +264,7 @@ public final class KeymasterDefs {
|
||||
sErrorCodeToString.put(KM_ERROR_INVALID_MAC_LENGTH,
|
||||
"Invalid MAC or authentication tag length");
|
||||
sErrorCodeToString.put(KM_ERROR_CANNOT_ATTEST_IDS, "Unable to attest device ids");
|
||||
sErrorCodeToString.put(KM_ERROR_DEVICE_LOCKED, "Device locked");
|
||||
sErrorCodeToString.put(KM_ERROR_UNIMPLEMENTED, "Not implemented");
|
||||
sErrorCodeToString.put(KM_ERROR_UNKNOWN_ERROR, "Unknown error");
|
||||
}
|
||||
|
||||
@@ -545,7 +545,9 @@ public class KeyStore {
|
||||
try {
|
||||
args = args != null ? args : new KeymasterArguments();
|
||||
entropy = entropy != null ? entropy : new byte[0];
|
||||
return mBinder.begin(getToken(), alias, purpose, pruneable, args, entropy, uid);
|
||||
OperationResult res = mBinder.begin(getToken(), alias, purpose, pruneable, args, entropy, uid);
|
||||
// This result is -26 (KEY_USER_NOT_AUTHENTICATED) but why??
|
||||
return res;
|
||||
} catch (RemoteException e) {
|
||||
Log.w(TAG, "Cannot connect to keystore", e);
|
||||
return null;
|
||||
@@ -563,7 +565,8 @@ public class KeyStore {
|
||||
try {
|
||||
arguments = arguments != null ? arguments : new KeymasterArguments();
|
||||
input = input != null ? input : new byte[0];
|
||||
return mBinder.update(token, arguments, input);
|
||||
OperationResult res = mBinder.update(token, arguments, input);
|
||||
return res;
|
||||
} catch (RemoteException e) {
|
||||
Log.w(TAG, "Cannot connect to keystore", e);
|
||||
return null;
|
||||
@@ -618,9 +621,9 @@ public class KeyStore {
|
||||
* @return {@code KeyStore.NO_ERROR} on success, otherwise an error value corresponding to
|
||||
* a {@code KeymasterDefs.KM_ERROR_} value or {@code KeyStore} ResponseCode.
|
||||
*/
|
||||
public int addAuthToken(byte[] authToken) {
|
||||
public int addAuthToken(byte[] authToken, int userId) {
|
||||
try {
|
||||
return mBinder.addAuthToken(authToken);
|
||||
return mBinder.addAuthToken(authToken, userId);
|
||||
} catch (RemoteException e) {
|
||||
Log.w(TAG, "Cannot connect to keystore", e);
|
||||
return SYSTEM_ERROR;
|
||||
@@ -832,14 +835,14 @@ public class KeyStore {
|
||||
public InvalidKeyException getInvalidKeyException(
|
||||
String keystoreKeyAlias, int uid, KeyStoreException e) {
|
||||
switch (e.getErrorCode()) {
|
||||
case LOCKED:
|
||||
case LOCKED: // 2
|
||||
return new UserNotAuthenticatedException();
|
||||
case KeymasterDefs.KM_ERROR_KEY_EXPIRED:
|
||||
case KeymasterDefs.KM_ERROR_KEY_EXPIRED: // -25
|
||||
return new KeyExpiredException();
|
||||
case KeymasterDefs.KM_ERROR_KEY_NOT_YET_VALID:
|
||||
case KeymasterDefs.KM_ERROR_KEY_NOT_YET_VALID: // -2
|
||||
return new KeyNotYetValidException();
|
||||
case KeymasterDefs.KM_ERROR_KEY_USER_NOT_AUTHENTICATED:
|
||||
case OP_AUTH_NEEDED:
|
||||
case KeymasterDefs.KM_ERROR_KEY_USER_NOT_AUTHENTICATED: // -26
|
||||
case OP_AUTH_NEEDED: // 15
|
||||
{
|
||||
// We now need to determine whether the key/operation can become usable if user
|
||||
// authentication is performed, or whether it can never become usable again.
|
||||
@@ -879,7 +882,7 @@ public class KeyStore {
|
||||
// None of the key's SIDs can ever be authenticated
|
||||
return new KeyPermanentlyInvalidatedException();
|
||||
}
|
||||
case UNINITIALIZED:
|
||||
case UNINITIALIZED: // 3
|
||||
return new KeyPermanentlyInvalidatedException();
|
||||
default:
|
||||
return new InvalidKeyException("Keystore operation failed", e);
|
||||
|
||||
@@ -243,13 +243,7 @@ public abstract class AndroidKeyStoreKeyGeneratorSpi extends KeyGeneratorSpi {
|
||||
// Check that user authentication related parameters are acceptable. This method
|
||||
// will throw an IllegalStateException if there are issues (e.g., secure lock screen
|
||||
// not set up).
|
||||
KeymasterUtils.addUserAuthArgs(new KeymasterArguments(),
|
||||
spec.isUserAuthenticationRequired(),
|
||||
spec.getUserAuthenticationValidityDurationSeconds(),
|
||||
spec.isUserAuthenticationValidWhileOnBody(),
|
||||
spec.isInvalidatedByBiometricEnrollment(),
|
||||
GateKeeper.INVALID_SECURE_USER_ID /* boundToSpecificSecureUserId */,
|
||||
spec.isUserConfirmationRequired());
|
||||
KeymasterUtils.addUserAuthArgs(new KeymasterArguments(), spec);
|
||||
} catch (IllegalStateException | IllegalArgumentException e) {
|
||||
throw new InvalidAlgorithmParameterException(e);
|
||||
}
|
||||
@@ -285,16 +279,7 @@ public abstract class AndroidKeyStoreKeyGeneratorSpi extends KeyGeneratorSpi {
|
||||
args.addEnums(KeymasterDefs.KM_TAG_BLOCK_MODE, mKeymasterBlockModes);
|
||||
args.addEnums(KeymasterDefs.KM_TAG_PADDING, mKeymasterPaddings);
|
||||
args.addEnums(KeymasterDefs.KM_TAG_DIGEST, mKeymasterDigests);
|
||||
KeymasterUtils.addUserAuthArgs(args,
|
||||
spec.isUserAuthenticationRequired(),
|
||||
spec.getUserAuthenticationValidityDurationSeconds(),
|
||||
spec.isUserAuthenticationValidWhileOnBody(),
|
||||
spec.isInvalidatedByBiometricEnrollment(),
|
||||
GateKeeper.INVALID_SECURE_USER_ID /* boundToSpecificSecureUserId */,
|
||||
spec.isUserConfirmationRequired());
|
||||
if (spec.isTrustedUserPresenceRequired()) {
|
||||
args.addBoolean(KeymasterDefs.KM_TAG_TRUSTED_USER_PRESENCE_REQUIRED);
|
||||
}
|
||||
KeymasterUtils.addUserAuthArgs(args, spec);
|
||||
KeymasterUtils.addMinMacLengthAuthorizationIfNecessary(
|
||||
args,
|
||||
mKeymasterAlgorithm,
|
||||
|
||||
@@ -344,13 +344,7 @@ public abstract class AndroidKeyStoreKeyPairGeneratorSpi extends KeyPairGenerato
|
||||
// Check that user authentication related parameters are acceptable. This method
|
||||
// will throw an IllegalStateException if there are issues (e.g., secure lock screen
|
||||
// not set up).
|
||||
KeymasterUtils.addUserAuthArgs(new KeymasterArguments(),
|
||||
mSpec.isUserAuthenticationRequired(),
|
||||
mSpec.getUserAuthenticationValidityDurationSeconds(),
|
||||
mSpec.isUserAuthenticationValidWhileOnBody(),
|
||||
mSpec.isInvalidatedByBiometricEnrollment(),
|
||||
GateKeeper.INVALID_SECURE_USER_ID /* boundToSpecificSecureUserId */,
|
||||
mSpec.isUserConfirmationRequired());
|
||||
KeymasterUtils.addUserAuthArgs(new KeymasterArguments(), mSpec);
|
||||
} catch (IllegalArgumentException | IllegalStateException e) {
|
||||
throw new InvalidAlgorithmParameterException(e);
|
||||
}
|
||||
@@ -541,13 +535,7 @@ public abstract class AndroidKeyStoreKeyPairGeneratorSpi extends KeyPairGenerato
|
||||
args.addEnums(KeymasterDefs.KM_TAG_PADDING, mKeymasterSignaturePaddings);
|
||||
args.addEnums(KeymasterDefs.KM_TAG_DIGEST, mKeymasterDigests);
|
||||
|
||||
KeymasterUtils.addUserAuthArgs(args,
|
||||
mSpec.isUserAuthenticationRequired(),
|
||||
mSpec.getUserAuthenticationValidityDurationSeconds(),
|
||||
mSpec.isUserAuthenticationValidWhileOnBody(),
|
||||
mSpec.isInvalidatedByBiometricEnrollment(),
|
||||
GateKeeper.INVALID_SECURE_USER_ID /* boundToSpecificSecureUserId */,
|
||||
mSpec.isUserConfirmationRequired());
|
||||
KeymasterUtils.addUserAuthArgs(args, mSpec);
|
||||
args.addDateIfNotNull(KeymasterDefs.KM_TAG_ACTIVE_DATETIME, mSpec.getKeyValidityStart());
|
||||
args.addDateIfNotNull(KeymasterDefs.KM_TAG_ORIGINATION_EXPIRE_DATETIME,
|
||||
mSpec.getKeyValidityForOriginationEnd());
|
||||
|
||||
@@ -497,13 +497,7 @@ public class AndroidKeyStoreSpi extends KeyStoreSpi {
|
||||
importArgs.addEnums(KeymasterDefs.KM_TAG_PADDING, keymasterEncryptionPaddings);
|
||||
importArgs.addEnums(KeymasterDefs.KM_TAG_PADDING,
|
||||
KeyProperties.SignaturePadding.allToKeymaster(spec.getSignaturePaddings()));
|
||||
KeymasterUtils.addUserAuthArgs(importArgs,
|
||||
spec.isUserAuthenticationRequired(),
|
||||
spec.getUserAuthenticationValidityDurationSeconds(),
|
||||
spec.isUserAuthenticationValidWhileOnBody(),
|
||||
spec.isInvalidatedByBiometricEnrollment(),
|
||||
spec.getBoundToSpecificSecureUserId(),
|
||||
spec.isUserConfirmationRequired());
|
||||
KeymasterUtils.addUserAuthArgs(importArgs, spec);
|
||||
importArgs.addDateIfNotNull(KeymasterDefs.KM_TAG_ACTIVE_DATETIME,
|
||||
spec.getKeyValidityStart());
|
||||
importArgs.addDateIfNotNull(KeymasterDefs.KM_TAG_ORIGINATION_EXPIRE_DATETIME,
|
||||
@@ -700,13 +694,7 @@ public class AndroidKeyStoreSpi extends KeyStoreSpi {
|
||||
int[] keymasterPaddings = KeyProperties.EncryptionPadding.allToKeymaster(
|
||||
params.getEncryptionPaddings());
|
||||
args.addEnums(KeymasterDefs.KM_TAG_PADDING, keymasterPaddings);
|
||||
KeymasterUtils.addUserAuthArgs(args,
|
||||
params.isUserAuthenticationRequired(),
|
||||
params.getUserAuthenticationValidityDurationSeconds(),
|
||||
params.isUserAuthenticationValidWhileOnBody(),
|
||||
params.isInvalidatedByBiometricEnrollment(),
|
||||
params.getBoundToSpecificSecureUserId(),
|
||||
params.isUserConfirmationRequired());
|
||||
KeymasterUtils.addUserAuthArgs(args, params);
|
||||
KeymasterUtils.addMinMacLengthAuthorizationIfNecessary(
|
||||
args,
|
||||
keymasterAlgorithm,
|
||||
|
||||
@@ -21,6 +21,7 @@ import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.app.KeyguardManager;
|
||||
import android.hardware.fingerprint.FingerprintManager;
|
||||
import android.security.GateKeeper;
|
||||
import android.security.KeyStore;
|
||||
import android.text.TextUtils;
|
||||
|
||||
@@ -232,7 +233,7 @@ import javax.security.auth.x500.X500Principal;
|
||||
* key = (SecretKey) keyStore.getKey("key2", null);
|
||||
* }</pre>
|
||||
*/
|
||||
public final class KeyGenParameterSpec implements AlgorithmParameterSpec {
|
||||
public final class KeyGenParameterSpec implements AlgorithmParameterSpec, UserAuthArgs {
|
||||
|
||||
private static final X500Principal DEFAULT_CERT_SUBJECT = new X500Principal("CN=fake");
|
||||
private static final BigInteger DEFAULT_CERT_SERIAL_NUMBER = new BigInteger("1");
|
||||
@@ -265,6 +266,7 @@ public final class KeyGenParameterSpec implements AlgorithmParameterSpec {
|
||||
private final boolean mInvalidatedByBiometricEnrollment;
|
||||
private final boolean mIsStrongBoxBacked;
|
||||
private final boolean mUserConfirmationRequired;
|
||||
private final boolean mUnlockedDeviceRequired;
|
||||
|
||||
/**
|
||||
* @hide should be built with Builder
|
||||
@@ -295,7 +297,8 @@ public final class KeyGenParameterSpec implements AlgorithmParameterSpec {
|
||||
boolean userAuthenticationValidWhileOnBody,
|
||||
boolean invalidatedByBiometricEnrollment,
|
||||
boolean isStrongBoxBacked,
|
||||
boolean userConfirmationRequired) {
|
||||
boolean userConfirmationRequired,
|
||||
boolean unlockedDeviceRequired) {
|
||||
if (TextUtils.isEmpty(keyStoreAlias)) {
|
||||
throw new IllegalArgumentException("keyStoreAlias must not be empty");
|
||||
}
|
||||
@@ -344,6 +347,7 @@ public final class KeyGenParameterSpec implements AlgorithmParameterSpec {
|
||||
mInvalidatedByBiometricEnrollment = invalidatedByBiometricEnrollment;
|
||||
mIsStrongBoxBacked = isStrongBoxBacked;
|
||||
mUserConfirmationRequired = userConfirmationRequired;
|
||||
mUnlockedDeviceRequired = unlockedDeviceRequired;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -668,6 +672,22 @@ public final class KeyGenParameterSpec implements AlgorithmParameterSpec {
|
||||
return mIsStrongBoxBacked;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns {@code true} if the key cannot be used unless the device screen is unlocked.
|
||||
*
|
||||
* @see Builder#SetUnlockedDeviceRequired(boolean)
|
||||
*/
|
||||
public boolean isUnlockedDeviceRequired() {
|
||||
return mUnlockedDeviceRequired;
|
||||
}
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
public long getBoundToSpecificSecureUserId() {
|
||||
return GateKeeper.INVALID_SECURE_USER_ID;
|
||||
}
|
||||
|
||||
/**
|
||||
* Builder of {@link KeyGenParameterSpec} instances.
|
||||
*/
|
||||
@@ -699,6 +719,7 @@ public final class KeyGenParameterSpec implements AlgorithmParameterSpec {
|
||||
private boolean mInvalidatedByBiometricEnrollment = true;
|
||||
private boolean mIsStrongBoxBacked = false;
|
||||
private boolean mUserConfirmationRequired;
|
||||
private boolean mUnlockedDeviceRequired = false;
|
||||
|
||||
/**
|
||||
* Creates a new instance of the {@code Builder}.
|
||||
@@ -1266,6 +1287,18 @@ public final class KeyGenParameterSpec implements AlgorithmParameterSpec {
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets whether the keystore requires the screen to be unlocked before allowing decryption
|
||||
* using this key. If this is set to {@code true}, any attempt to decrypt using this key
|
||||
* while the screen is locked will fail. A locked device requires a PIN, password,
|
||||
* fingerprint, or other trusted factor to access.
|
||||
*/
|
||||
@NonNull
|
||||
public Builder setUnlockedDeviceRequired(boolean unlockedDeviceRequired) {
|
||||
mUnlockedDeviceRequired = unlockedDeviceRequired;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds an instance of {@code KeyGenParameterSpec}.
|
||||
*/
|
||||
@@ -1297,7 +1330,8 @@ public final class KeyGenParameterSpec implements AlgorithmParameterSpec {
|
||||
mUserAuthenticationValidWhileOnBody,
|
||||
mInvalidatedByBiometricEnrollment,
|
||||
mIsStrongBoxBacked,
|
||||
mUserConfirmationRequired);
|
||||
mUserConfirmationRequired,
|
||||
mUnlockedDeviceRequired);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -212,7 +212,7 @@ import javax.crypto.Mac;
|
||||
* ...
|
||||
* }</pre>
|
||||
*/
|
||||
public final class KeyProtection implements ProtectionParameter {
|
||||
public final class KeyProtection implements ProtectionParameter, UserAuthArgs {
|
||||
private final Date mKeyValidityStart;
|
||||
private final Date mKeyValidityForOriginationEnd;
|
||||
private final Date mKeyValidityForConsumptionEnd;
|
||||
@@ -229,6 +229,8 @@ public final class KeyProtection implements ProtectionParameter {
|
||||
private final long mBoundToSecureUserId;
|
||||
private final boolean mCriticalToDeviceEncryption;
|
||||
private final boolean mUserConfirmationRequired;
|
||||
private final boolean mTrustedUserPresenceRequired;
|
||||
private final boolean mUnlockedDeviceRequired;
|
||||
|
||||
private KeyProtection(
|
||||
Date keyValidityStart,
|
||||
@@ -242,11 +244,13 @@ public final class KeyProtection implements ProtectionParameter {
|
||||
boolean randomizedEncryptionRequired,
|
||||
boolean userAuthenticationRequired,
|
||||
int userAuthenticationValidityDurationSeconds,
|
||||
boolean trustedUserPresenceRequired,
|
||||
boolean userAuthenticationValidWhileOnBody,
|
||||
boolean invalidatedByBiometricEnrollment,
|
||||
long boundToSecureUserId,
|
||||
boolean criticalToDeviceEncryption,
|
||||
boolean userConfirmationRequired) {
|
||||
boolean userConfirmationRequired,
|
||||
boolean unlockedDeviceRequired) {
|
||||
mKeyValidityStart = Utils.cloneIfNotNull(keyValidityStart);
|
||||
mKeyValidityForOriginationEnd = Utils.cloneIfNotNull(keyValidityForOriginationEnd);
|
||||
mKeyValidityForConsumptionEnd = Utils.cloneIfNotNull(keyValidityForConsumptionEnd);
|
||||
@@ -265,6 +269,8 @@ public final class KeyProtection implements ProtectionParameter {
|
||||
mBoundToSecureUserId = boundToSecureUserId;
|
||||
mCriticalToDeviceEncryption = criticalToDeviceEncryption;
|
||||
mUserConfirmationRequired = userConfirmationRequired;
|
||||
mTrustedUserPresenceRequired = trustedUserPresenceRequired;
|
||||
mUnlockedDeviceRequired = unlockedDeviceRequired;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -436,6 +442,14 @@ public final class KeyProtection implements ProtectionParameter {
|
||||
return mUserAuthenticationValidityDurationSeconds;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns {@code true} if the key is authorized to be used only if a test of user presence has
|
||||
* been performed between the {@code Signature.initSign()} and {@code Signature.sign()} calls.
|
||||
*/
|
||||
public boolean isTrustedUserPresenceRequired() {
|
||||
return mTrustedUserPresenceRequired;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns {@code true} if the key will be de-authorized when the device is removed from the
|
||||
* user's body. This option has no effect on keys that don't have an authentication validity
|
||||
@@ -493,6 +507,15 @@ public final class KeyProtection implements ProtectionParameter {
|
||||
return mCriticalToDeviceEncryption;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns {@code true} if the key cannot be used unless the device screen is unlocked.
|
||||
*
|
||||
* @see Builder#SetRequireDeviceUnlocked(boolean)
|
||||
*/
|
||||
public boolean isUnlockedDeviceRequired() {
|
||||
return mUnlockedDeviceRequired;
|
||||
}
|
||||
|
||||
/**
|
||||
* Builder of {@link KeyProtection} instances.
|
||||
*/
|
||||
@@ -512,6 +535,9 @@ public final class KeyProtection implements ProtectionParameter {
|
||||
private boolean mUserAuthenticationValidWhileOnBody;
|
||||
private boolean mInvalidatedByBiometricEnrollment = true;
|
||||
private boolean mUserConfirmationRequired;
|
||||
private boolean mTrustedUserPresenceRequired = false;
|
||||
private boolean mUnlockedDeviceRequired = false;
|
||||
|
||||
private long mBoundToSecureUserId = GateKeeper.INVALID_SECURE_USER_ID;
|
||||
private boolean mCriticalToDeviceEncryption = false;
|
||||
|
||||
@@ -810,6 +836,16 @@ public final class KeyProtection implements ProtectionParameter {
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets whether a test of user presence is required to be performed between the
|
||||
* {@code Signature.initSign()} and {@code Signature.sign()} method calls.
|
||||
*/
|
||||
@NonNull
|
||||
public Builder setTrustedUserPresenceRequired(boolean required) {
|
||||
mTrustedUserPresenceRequired = required;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets whether the key will remain authorized only until the device is removed from the
|
||||
* user's body up to the limit of the authentication validity period (see
|
||||
@@ -891,6 +927,18 @@ public final class KeyProtection implements ProtectionParameter {
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets whether the keystore requires the screen to be unlocked before allowing decryption
|
||||
* using this key. If this is set to {@code true}, any attempt to decrypt using this key
|
||||
* while the screen is locked will fail. A locked device requires a PIN, password,
|
||||
* fingerprint, or other trusted factor to access.
|
||||
*/
|
||||
@NonNull
|
||||
public Builder setUnlockedDeviceRequired(boolean unlockedDeviceRequired) {
|
||||
mUnlockedDeviceRequired = unlockedDeviceRequired;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds an instance of {@link KeyProtection}.
|
||||
*
|
||||
@@ -910,11 +958,13 @@ public final class KeyProtection implements ProtectionParameter {
|
||||
mRandomizedEncryptionRequired,
|
||||
mUserAuthenticationRequired,
|
||||
mUserAuthenticationValidityDurationSeconds,
|
||||
mTrustedUserPresenceRequired,
|
||||
mUserAuthenticationValidWhileOnBody,
|
||||
mInvalidatedByBiometricEnrollment,
|
||||
mBoundToSecureUserId,
|
||||
mCriticalToDeviceEncryption,
|
||||
mUserConfirmationRequired);
|
||||
mUserConfirmationRequired,
|
||||
mUnlockedDeviceRequired);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@ package android.security.keystore;
|
||||
|
||||
import android.util.Log;
|
||||
import android.hardware.fingerprint.FingerprintManager;
|
||||
import android.os.UserHandle;
|
||||
import android.security.GateKeeper;
|
||||
import android.security.KeyStore;
|
||||
import android.security.keymaster.KeymasterArguments;
|
||||
@@ -101,22 +102,27 @@ public abstract class KeymasterUtils {
|
||||
* require user authentication.
|
||||
*/
|
||||
public static void addUserAuthArgs(KeymasterArguments args,
|
||||
boolean userAuthenticationRequired,
|
||||
int userAuthenticationValidityDurationSeconds,
|
||||
boolean userAuthenticationValidWhileOnBody,
|
||||
boolean invalidatedByBiometricEnrollment,
|
||||
long boundToSpecificSecureUserId,
|
||||
boolean userConfirmationRequired) {
|
||||
if (userConfirmationRequired) {
|
||||
UserAuthArgs spec) {
|
||||
if (spec.isTrustedUserPresenceRequired()) {
|
||||
args.addBoolean(KeymasterDefs.KM_TAG_TRUSTED_USER_PRESENCE_REQUIRED);
|
||||
}
|
||||
|
||||
if (spec.isUserConfirmationRequired()) {
|
||||
args.addBoolean(KeymasterDefs.KM_TAG_TRUSTED_CONFIRMATION_REQUIRED);
|
||||
}
|
||||
|
||||
if (!userAuthenticationRequired) {
|
||||
if (spec.isUnlockedDeviceRequired()) {
|
||||
args.addBoolean(KeymasterDefs.KM_TAG_UNLOCKED_DEVICE_REQUIRED);
|
||||
// Once keymaster is properly ignoring this tag, it should be added to every auth list
|
||||
args.addUnsignedInt(KeymasterDefs.KM_TAG_USER_ID, UserHandle.getCallingUserId());
|
||||
}
|
||||
|
||||
if (!spec.isUserAuthenticationRequired()) {
|
||||
args.addBoolean(KeymasterDefs.KM_TAG_NO_AUTH_REQUIRED);
|
||||
return;
|
||||
}
|
||||
|
||||
if (userAuthenticationValidityDurationSeconds == -1) {
|
||||
if (spec.getUserAuthenticationValidityDurationSeconds() == -1) {
|
||||
// Every use of this key needs to be authorized by the user. This currently means
|
||||
// fingerprint-only auth.
|
||||
FingerprintManager fingerprintManager =
|
||||
@@ -132,9 +138,9 @@ public abstract class KeymasterUtils {
|
||||
}
|
||||
|
||||
long sid;
|
||||
if (boundToSpecificSecureUserId != GateKeeper.INVALID_SECURE_USER_ID) {
|
||||
sid = boundToSpecificSecureUserId;
|
||||
} else if (invalidatedByBiometricEnrollment) {
|
||||
if (spec.getBoundToSpecificSecureUserId() != GateKeeper.INVALID_SECURE_USER_ID) {
|
||||
sid = spec.getBoundToSpecificSecureUserId();
|
||||
} else if (spec.isInvalidatedByBiometricEnrollment()) {
|
||||
// The fingerprint-only SID will change on fingerprint enrollment or removal of all,
|
||||
// enrolled fingerprints, invalidating the key.
|
||||
sid = fingerprintOnlySid;
|
||||
@@ -147,14 +153,14 @@ public abstract class KeymasterUtils {
|
||||
args.addUnsignedLong(
|
||||
KeymasterDefs.KM_TAG_USER_SECURE_ID, KeymasterArguments.toUint64(sid));
|
||||
args.addEnum(KeymasterDefs.KM_TAG_USER_AUTH_TYPE, KeymasterDefs.HW_AUTH_FINGERPRINT);
|
||||
if (userAuthenticationValidWhileOnBody) {
|
||||
if (spec.isUserAuthenticationValidWhileOnBody()) {
|
||||
throw new ProviderException("Key validity extension while device is on-body is not "
|
||||
+ "supported for keys requiring fingerprint authentication");
|
||||
}
|
||||
} else {
|
||||
long sid;
|
||||
if (boundToSpecificSecureUserId != GateKeeper.INVALID_SECURE_USER_ID) {
|
||||
sid = boundToSpecificSecureUserId;
|
||||
if (spec.getBoundToSpecificSecureUserId() != GateKeeper.INVALID_SECURE_USER_ID) {
|
||||
sid = spec.getBoundToSpecificSecureUserId();
|
||||
} 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.
|
||||
@@ -165,8 +171,8 @@ public abstract class KeymasterUtils {
|
||||
args.addEnum(KeymasterDefs.KM_TAG_USER_AUTH_TYPE,
|
||||
KeymasterDefs.HW_AUTH_PASSWORD | KeymasterDefs.HW_AUTH_FINGERPRINT);
|
||||
args.addUnsignedInt(KeymasterDefs.KM_TAG_AUTH_TIMEOUT,
|
||||
userAuthenticationValidityDurationSeconds);
|
||||
if (userAuthenticationValidWhileOnBody) {
|
||||
spec.getUserAuthenticationValidityDurationSeconds());
|
||||
if (spec.isUserAuthenticationValidWhileOnBody()) {
|
||||
args.addBoolean(KeymasterDefs.KM_TAG_ALLOW_WHILE_ON_BODY);
|
||||
}
|
||||
}
|
||||
|
||||
38
keystore/java/android/security/keystore/UserAuthArgs.java
Normal file
38
keystore/java/android/security/keystore/UserAuthArgs.java
Normal file
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Copyright (C) 2017 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.keystore;
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*
|
||||
* This is an interface to encapsulate the user authentication arguments that
|
||||
* are passed to KeymasterUtils.addUserAuthArgs. Classes that represent
|
||||
* authorization characteristics for new or imported keys can implement this
|
||||
* interface to be passed to that method.
|
||||
*/
|
||||
public interface UserAuthArgs {
|
||||
|
||||
boolean isUserAuthenticationRequired();
|
||||
int getUserAuthenticationValidityDurationSeconds();
|
||||
boolean isUserAuthenticationValidWhileOnBody();
|
||||
boolean isInvalidatedByBiometricEnrollment();
|
||||
boolean isTrustedUserPresenceRequired();
|
||||
boolean isUnlockedDeviceRequired();
|
||||
boolean isUserConfirmationRequired();
|
||||
long getBoundToSpecificSecureUserId();
|
||||
|
||||
}
|
||||
@@ -421,7 +421,7 @@ public class FingerprintService extends SystemService implements IHwBinder.Death
|
||||
byteToken[i] = token.get(i);
|
||||
}
|
||||
// Send to Keystore
|
||||
KeyStore.getInstance().addAuthToken(byteToken);
|
||||
KeyStore.getInstance().addAuthToken(byteToken, mCurrentUserId);
|
||||
}
|
||||
if (client != null && client.onAuthenticated(fingerId, groupId)) {
|
||||
removeClient(client);
|
||||
|
||||
@@ -19,6 +19,8 @@ package com.android.server.policy.keyguard;
|
||||
import android.app.ActivityManager;
|
||||
import android.content.Context;
|
||||
import android.os.RemoteException;
|
||||
import android.os.ServiceManager;
|
||||
import android.security.IKeystoreService;
|
||||
import android.util.Slog;
|
||||
|
||||
import com.android.internal.policy.IKeyguardService;
|
||||
@@ -51,11 +53,16 @@ public class KeyguardStateMonitor extends IKeyguardStateCallback.Stub {
|
||||
private final LockPatternUtils mLockPatternUtils;
|
||||
private final StateCallback mCallback;
|
||||
|
||||
IKeystoreService mKeystoreService;
|
||||
|
||||
public KeyguardStateMonitor(Context context, IKeyguardService service, StateCallback callback) {
|
||||
mLockPatternUtils = new LockPatternUtils(context);
|
||||
mCurrentUserId = ActivityManager.getCurrentUser();
|
||||
mCallback = callback;
|
||||
|
||||
mKeystoreService = IKeystoreService.Stub.asInterface(ServiceManager
|
||||
.getService("android.security.keystore"));
|
||||
|
||||
try {
|
||||
service.addStateMonitorCallback(this);
|
||||
} catch (RemoteException e) {
|
||||
@@ -86,6 +93,12 @@ public class KeyguardStateMonitor extends IKeyguardStateCallback.Stub {
|
||||
@Override // Binder interface
|
||||
public void onShowingStateChanged(boolean showing) {
|
||||
mIsShowing = showing;
|
||||
|
||||
if (showing) try {
|
||||
mKeystoreService.lock(mCurrentUserId); // as long as this doesn't recur...
|
||||
} catch (RemoteException e) {
|
||||
Slog.e(TAG, "Error locking keystore", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override // Binder interface
|
||||
|
||||
Reference in New Issue
Block a user