From 36716eb4709503f2ef370c6f67273440cd91d18c Mon Sep 17 00:00:00 2001 From: Brian Young Date: Fri, 23 Feb 2018 18:04:20 +0000 Subject: [PATCH] Add "Unlocked device required" key API This adds the API methods and values for keyguard-bound keys, but contains none of the actual functionality. Test: CTS tests in CtsKeystoreTestCases Bug: 67752510 Merged-In: Iccd7dafd77258d903d11353e02ba3ab956050c40 Change-Id: Iccd7dafd77258d903d11353e02ba3ab956050c40 (cherry picked from commit fd75c7232aebc8690f004de3486b3b9a44f3e0b0) --- .../android/security/keymaster/KeymasterDefs.java | 3 ++ keystore/java/android/security/KeyStore.java | 5 +-- .../security/keystore/KeyGenParameterSpec.java | 30 +++++++++++++++-- .../android/security/keystore/KeyProtection.java | 39 ++++++++++++++++++---- .../android/security/keystore/KeymasterUtils.java | 5 +-- .../policy/keyguard/KeyguardStateMonitor.java | 2 +- 6 files changed, 71 insertions(+), 13 deletions(-) diff --git a/core/java/android/security/keymaster/KeymasterDefs.java b/core/java/android/security/keymaster/KeymasterDefs.java index 1d1333504350..f4dcce1e7e58 100644 --- a/core/java/android/security/keymaster/KeymasterDefs.java +++ b/core/java/android/security/keymaster/KeymasterDefs.java @@ -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"); } diff --git a/keystore/java/android/security/KeyStore.java b/keystore/java/android/security/KeyStore.java index 1924bbe764c7..33ce582eda96 100644 --- a/keystore/java/android/security/KeyStore.java +++ b/keystore/java/android/security/KeyStore.java @@ -278,7 +278,7 @@ public class KeyStore { /** * Attempt to lock the keystore for {@code user}. * - * @param user Android user to lock. + * @param userId Android user to lock. * @return whether {@code user}'s keystore was locked. */ public boolean lock(int userId) { @@ -299,7 +299,7 @@ public class KeyStore { * This is required before keystore entries created with FLAG_ENCRYPTED can be accessed or * created. * - * @param user Android user ID to operate on + * @param userId Android user ID to operate on * @param password user's keystore password. Should be the most recent value passed to * {@link #onUserPasswordChanged} for the user. * @@ -545,6 +545,7 @@ public class KeyStore { try { args = args != null ? args : new KeymasterArguments(); entropy = entropy != null ? entropy : new byte[0]; + // TODO(67752510): Apply USER_ID tag return mBinder.begin(getToken(), alias, purpose, pruneable, args, entropy, uid); } catch (RemoteException e) { Log.w(TAG, "Cannot connect to keystore", e); diff --git a/keystore/java/android/security/keystore/KeyGenParameterSpec.java b/keystore/java/android/security/keystore/KeyGenParameterSpec.java index 4b9f3c803481..5d596cbbbc44 100644 --- a/keystore/java/android/security/keystore/KeyGenParameterSpec.java +++ b/keystore/java/android/security/keystore/KeyGenParameterSpec.java @@ -266,6 +266,7 @@ public final class KeyGenParameterSpec implements AlgorithmParameterSpec, UserAu private final boolean mInvalidatedByBiometricEnrollment; private final boolean mIsStrongBoxBacked; private final boolean mUserConfirmationRequired; + private final boolean mUnlockedDeviceRequired; /** * @hide should be built with Builder @@ -296,7 +297,8 @@ public final class KeyGenParameterSpec implements AlgorithmParameterSpec, UserAu boolean userAuthenticationValidWhileOnBody, boolean invalidatedByBiometricEnrollment, boolean isStrongBoxBacked, - boolean userConfirmationRequired) { + boolean userConfirmationRequired, + boolean unlockedDeviceRequired) { if (TextUtils.isEmpty(keyStoreAlias)) { throw new IllegalArgumentException("keyStoreAlias must not be empty"); } @@ -345,6 +347,7 @@ public final class KeyGenParameterSpec implements AlgorithmParameterSpec, UserAu mInvalidatedByBiometricEnrollment = invalidatedByBiometricEnrollment; mIsStrongBoxBacked = isStrongBoxBacked; mUserConfirmationRequired = userConfirmationRequired; + mUnlockedDeviceRequired = unlockedDeviceRequired; } /** @@ -670,6 +673,15 @@ public final class KeyGenParameterSpec implements AlgorithmParameterSpec, UserAu } /** + * @hide 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() { @@ -707,6 +719,7 @@ public final class KeyGenParameterSpec implements AlgorithmParameterSpec, UserAu private boolean mInvalidatedByBiometricEnrollment = true; private boolean mIsStrongBoxBacked = false; private boolean mUserConfirmationRequired; + private boolean mUnlockedDeviceRequired = false; /** * Creates a new instance of the {@code Builder}. @@ -1275,6 +1288,18 @@ public final class KeyGenParameterSpec implements AlgorithmParameterSpec, UserAu } /** + * @hide 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}. */ @NonNull @@ -1305,7 +1330,8 @@ public final class KeyGenParameterSpec implements AlgorithmParameterSpec, UserAu mUserAuthenticationValidWhileOnBody, mInvalidatedByBiometricEnrollment, mIsStrongBoxBacked, - mUserConfirmationRequired); + mUserConfirmationRequired, + mUnlockedDeviceRequired); } } } diff --git a/keystore/java/android/security/keystore/KeyProtection.java b/keystore/java/android/security/keystore/KeyProtection.java index 95eeec704847..cc7870ce1889 100644 --- a/keystore/java/android/security/keystore/KeyProtection.java +++ b/keystore/java/android/security/keystore/KeyProtection.java @@ -224,12 +224,13 @@ public final class KeyProtection implements ProtectionParameter, UserAuthArgs { private final boolean mRandomizedEncryptionRequired; private final boolean mUserAuthenticationRequired; private final int mUserAuthenticationValidityDurationSeconds; - private final boolean mTrustedUserPresenceRequred; + private final boolean mTrustedUserPresenceRequired; private final boolean mUserAuthenticationValidWhileOnBody; private final boolean mInvalidatedByBiometricEnrollment; private final long mBoundToSecureUserId; private final boolean mCriticalToDeviceEncryption; private final boolean mUserConfirmationRequired; + private final boolean mUnlockedDeviceRequired; private KeyProtection( Date keyValidityStart, @@ -243,12 +244,13 @@ public final class KeyProtection implements ProtectionParameter, UserAuthArgs { boolean randomizedEncryptionRequired, boolean userAuthenticationRequired, int userAuthenticationValidityDurationSeconds, - boolean trustedUserPresenceRequred, + 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); @@ -262,12 +264,13 @@ public final class KeyProtection implements ProtectionParameter, UserAuthArgs { mRandomizedEncryptionRequired = randomizedEncryptionRequired; mUserAuthenticationRequired = userAuthenticationRequired; mUserAuthenticationValidityDurationSeconds = userAuthenticationValidityDurationSeconds; - mTrustedUserPresenceRequred = trustedUserPresenceRequred; + mTrustedUserPresenceRequired = trustedUserPresenceRequired; mUserAuthenticationValidWhileOnBody = userAuthenticationValidWhileOnBody; mInvalidatedByBiometricEnrollment = invalidatedByBiometricEnrollment; mBoundToSecureUserId = boundToSecureUserId; mCriticalToDeviceEncryption = criticalToDeviceEncryption; mUserConfirmationRequired = userConfirmationRequired; + mUnlockedDeviceRequired = unlockedDeviceRequired; } /** @@ -444,7 +447,7 @@ public final class KeyProtection implements ProtectionParameter, UserAuthArgs { * been performed between the {@code Signature.initSign()} and {@code Signature.sign()} calls. */ public boolean isTrustedUserPresenceRequired() { - return mTrustedUserPresenceRequred; + return mTrustedUserPresenceRequired; } /** @@ -505,6 +508,15 @@ public final class KeyProtection implements ProtectionParameter, UserAuthArgs { } /** + * @hide Returns {@code true} if the key cannot be used unless the device screen is unlocked. + * + * @see Builder#setUnlockedDeviceRequired(boolean) + */ + public boolean isUnlockedDeviceRequired() { + return mUnlockedDeviceRequired; + } + + /** * Builder of {@link KeyProtection} instances. */ public final static class Builder { @@ -524,6 +536,8 @@ public final class KeyProtection implements ProtectionParameter, UserAuthArgs { private boolean mUserAuthenticationValidWhileOnBody; private boolean mInvalidatedByBiometricEnrollment = true; private boolean mUserConfirmationRequired; + private boolean mUnlockedDeviceRequired = false; + private long mBoundToSecureUserId = GateKeeper.INVALID_SECURE_USER_ID; private boolean mCriticalToDeviceEncryption = false; @@ -914,6 +928,18 @@ public final class KeyProtection implements ProtectionParameter, UserAuthArgs { } /** + * @hide 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}. * * @throws IllegalArgumentException if a required field is missing @@ -937,7 +963,8 @@ public final class KeyProtection implements ProtectionParameter, UserAuthArgs { mInvalidatedByBiometricEnrollment, mBoundToSecureUserId, mCriticalToDeviceEncryption, - mUserConfirmationRequired); + mUserConfirmationRequired, + mUnlockedDeviceRequired); } } } diff --git a/keystore/java/android/security/keystore/KeymasterUtils.java b/keystore/java/android/security/keystore/KeymasterUtils.java index 0ef08f237b4e..d194f0b9e4e9 100644 --- a/keystore/java/android/security/keystore/KeymasterUtils.java +++ b/keystore/java/android/security/keystore/KeymasterUtils.java @@ -101,8 +101,9 @@ public abstract class KeymasterUtils { * state (e.g., secure lock screen not set up) for generating or importing keys that * require user authentication. */ - public static void addUserAuthArgs(KeymasterArguments args, - UserAuthArgs spec) { + public static void addUserAuthArgs(KeymasterArguments args, UserAuthArgs spec) { + // TODO (67752510): Implement "unlocked device required" + if (spec.isUserConfirmationRequired()) { args.addBoolean(KeymasterDefs.KM_TAG_TRUSTED_CONFIRMATION_REQUIRED); } diff --git a/services/core/java/com/android/server/policy/keyguard/KeyguardStateMonitor.java b/services/core/java/com/android/server/policy/keyguard/KeyguardStateMonitor.java index 941cd4441e23..37e79e70d70a 100644 --- a/services/core/java/com/android/server/policy/keyguard/KeyguardStateMonitor.java +++ b/services/core/java/com/android/server/policy/keyguard/KeyguardStateMonitor.java @@ -130,4 +130,4 @@ public class KeyguardStateMonitor extends IKeyguardStateCallback.Stub { pw.println(prefix + "mTrusted=" + mTrusted); pw.println(prefix + "mCurrentUserId=" + mCurrentUserId); } -} \ No newline at end of file +} -- 2.11.0