Merge changes from topic "limited_use_keys"
* changes: Add limited use keys related API into Keystore 2.0 SPI. Limited use key: feature flags.
This commit is contained in:
@@ -12134,6 +12134,8 @@ package android.content.pm {
|
|||||||
field public static final String FEATURE_INPUT_METHODS = "android.software.input_methods";
|
field public static final String FEATURE_INPUT_METHODS = "android.software.input_methods";
|
||||||
field public static final String FEATURE_IPSEC_TUNNELS = "android.software.ipsec_tunnels";
|
field public static final String FEATURE_IPSEC_TUNNELS = "android.software.ipsec_tunnels";
|
||||||
field public static final String FEATURE_IRIS = "android.hardware.biometrics.iris";
|
field public static final String FEATURE_IRIS = "android.hardware.biometrics.iris";
|
||||||
|
field public static final String FEATURE_KEYSTORE_LIMITED_USE_KEY = "android.hardware.keystore.limited_use_key";
|
||||||
|
field public static final String FEATURE_KEYSTORE_SINGLE_USE_KEY = "android.hardware.keystore.single_use_key";
|
||||||
field public static final String FEATURE_LEANBACK = "android.software.leanback";
|
field public static final String FEATURE_LEANBACK = "android.software.leanback";
|
||||||
field public static final String FEATURE_LEANBACK_ONLY = "android.software.leanback_only";
|
field public static final String FEATURE_LEANBACK_ONLY = "android.software.leanback_only";
|
||||||
field public static final String FEATURE_LIVE_TV = "android.software.live_tv";
|
field public static final String FEATURE_LIVE_TV = "android.software.live_tv";
|
||||||
@@ -36205,6 +36207,7 @@ package android.security.keystore {
|
|||||||
method @Nullable public java.util.Date getKeyValidityForOriginationEnd();
|
method @Nullable public java.util.Date getKeyValidityForOriginationEnd();
|
||||||
method @Nullable public java.util.Date getKeyValidityStart();
|
method @Nullable public java.util.Date getKeyValidityStart();
|
||||||
method @NonNull public String getKeystoreAlias();
|
method @NonNull public String getKeystoreAlias();
|
||||||
|
method public int getMaxUsageCount();
|
||||||
method public int getPurposes();
|
method public int getPurposes();
|
||||||
method @NonNull public String[] getSignaturePaddings();
|
method @NonNull public String[] getSignaturePaddings();
|
||||||
method public int getUserAuthenticationType();
|
method public int getUserAuthenticationType();
|
||||||
@@ -36241,6 +36244,7 @@ package android.security.keystore {
|
|||||||
method @NonNull public android.security.keystore.KeyGenParameterSpec.Builder setKeyValidityForConsumptionEnd(java.util.Date);
|
method @NonNull public android.security.keystore.KeyGenParameterSpec.Builder setKeyValidityForConsumptionEnd(java.util.Date);
|
||||||
method @NonNull public android.security.keystore.KeyGenParameterSpec.Builder setKeyValidityForOriginationEnd(java.util.Date);
|
method @NonNull public android.security.keystore.KeyGenParameterSpec.Builder setKeyValidityForOriginationEnd(java.util.Date);
|
||||||
method @NonNull public android.security.keystore.KeyGenParameterSpec.Builder setKeyValidityStart(java.util.Date);
|
method @NonNull public android.security.keystore.KeyGenParameterSpec.Builder setKeyValidityStart(java.util.Date);
|
||||||
|
method @NonNull public android.security.keystore.KeyGenParameterSpec.Builder setMaxUsageCount(int);
|
||||||
method @NonNull public android.security.keystore.KeyGenParameterSpec.Builder setRandomizedEncryptionRequired(boolean);
|
method @NonNull public android.security.keystore.KeyGenParameterSpec.Builder setRandomizedEncryptionRequired(boolean);
|
||||||
method @NonNull public android.security.keystore.KeyGenParameterSpec.Builder setSignaturePaddings(java.lang.String...);
|
method @NonNull public android.security.keystore.KeyGenParameterSpec.Builder setSignaturePaddings(java.lang.String...);
|
||||||
method @NonNull public android.security.keystore.KeyGenParameterSpec.Builder setUnlockedDeviceRequired(boolean);
|
method @NonNull public android.security.keystore.KeyGenParameterSpec.Builder setUnlockedDeviceRequired(boolean);
|
||||||
@@ -36263,6 +36267,7 @@ package android.security.keystore {
|
|||||||
method public String getKeystoreAlias();
|
method public String getKeystoreAlias();
|
||||||
method public int getOrigin();
|
method public int getOrigin();
|
||||||
method public int getPurposes();
|
method public int getPurposes();
|
||||||
|
method public int getRemainingUsageCount();
|
||||||
method public int getSecurityLevel();
|
method public int getSecurityLevel();
|
||||||
method @NonNull public String[] getSignaturePaddings();
|
method @NonNull public String[] getSignaturePaddings();
|
||||||
method public int getUserAuthenticationType();
|
method public int getUserAuthenticationType();
|
||||||
@@ -36332,6 +36337,7 @@ package android.security.keystore {
|
|||||||
field public static final int SECURITY_LEVEL_UNKNOWN_SECURE = -1; // 0xffffffff
|
field public static final int SECURITY_LEVEL_UNKNOWN_SECURE = -1; // 0xffffffff
|
||||||
field public static final String SIGNATURE_PADDING_RSA_PKCS1 = "PKCS1";
|
field public static final String SIGNATURE_PADDING_RSA_PKCS1 = "PKCS1";
|
||||||
field public static final String SIGNATURE_PADDING_RSA_PSS = "PSS";
|
field public static final String SIGNATURE_PADDING_RSA_PSS = "PSS";
|
||||||
|
field public static final int UNRESTRICTED_USAGE_COUNT = -1; // 0xffffffff
|
||||||
}
|
}
|
||||||
|
|
||||||
public final class KeyProtection implements java.security.KeyStore.ProtectionParameter {
|
public final class KeyProtection implements java.security.KeyStore.ProtectionParameter {
|
||||||
@@ -36341,6 +36347,7 @@ package android.security.keystore {
|
|||||||
method @Nullable public java.util.Date getKeyValidityForConsumptionEnd();
|
method @Nullable public java.util.Date getKeyValidityForConsumptionEnd();
|
||||||
method @Nullable public java.util.Date getKeyValidityForOriginationEnd();
|
method @Nullable public java.util.Date getKeyValidityForOriginationEnd();
|
||||||
method @Nullable public java.util.Date getKeyValidityStart();
|
method @Nullable public java.util.Date getKeyValidityStart();
|
||||||
|
method public int getMaxUsageCount();
|
||||||
method public int getPurposes();
|
method public int getPurposes();
|
||||||
method @NonNull public String[] getSignaturePaddings();
|
method @NonNull public String[] getSignaturePaddings();
|
||||||
method public int getUserAuthenticationType();
|
method public int getUserAuthenticationType();
|
||||||
@@ -36366,6 +36373,7 @@ package android.security.keystore {
|
|||||||
method @NonNull public android.security.keystore.KeyProtection.Builder setKeyValidityForConsumptionEnd(java.util.Date);
|
method @NonNull public android.security.keystore.KeyProtection.Builder setKeyValidityForConsumptionEnd(java.util.Date);
|
||||||
method @NonNull public android.security.keystore.KeyProtection.Builder setKeyValidityForOriginationEnd(java.util.Date);
|
method @NonNull public android.security.keystore.KeyProtection.Builder setKeyValidityForOriginationEnd(java.util.Date);
|
||||||
method @NonNull public android.security.keystore.KeyProtection.Builder setKeyValidityStart(java.util.Date);
|
method @NonNull public android.security.keystore.KeyProtection.Builder setKeyValidityStart(java.util.Date);
|
||||||
|
method @NonNull public android.security.keystore.KeyProtection.Builder setMaxUsageCount(int);
|
||||||
method @NonNull public android.security.keystore.KeyProtection.Builder setRandomizedEncryptionRequired(boolean);
|
method @NonNull public android.security.keystore.KeyProtection.Builder setRandomizedEncryptionRequired(boolean);
|
||||||
method @NonNull public android.security.keystore.KeyProtection.Builder setSignaturePaddings(java.lang.String...);
|
method @NonNull public android.security.keystore.KeyProtection.Builder setSignaturePaddings(java.lang.String...);
|
||||||
method @NonNull public android.security.keystore.KeyProtection.Builder setUnlockedDeviceRequired(boolean);
|
method @NonNull public android.security.keystore.KeyProtection.Builder setUnlockedDeviceRequired(boolean);
|
||||||
|
|||||||
@@ -3224,6 +3224,24 @@ public abstract class PackageManager {
|
|||||||
@SdkConstant(SdkConstantType.FEATURE)
|
@SdkConstant(SdkConstantType.FEATURE)
|
||||||
public static final String FEATURE_APP_ENUMERATION = "android.software.app_enumeration";
|
public static final String FEATURE_APP_ENUMERATION = "android.software.app_enumeration";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Feature for {@link #getSystemAvailableFeatures} and {@link #hasSystemFeature}: The device has
|
||||||
|
* a Keystore implementation that can only enforce limited use key in hardware with max usage
|
||||||
|
* count equals to 1.
|
||||||
|
*/
|
||||||
|
@SdkConstant(SdkConstantType.FEATURE)
|
||||||
|
public static final String FEATURE_KEYSTORE_SINGLE_USE_KEY =
|
||||||
|
"android.hardware.keystore.single_use_key";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Feature for {@link #getSystemAvailableFeatures} and {@link #hasSystemFeature}: The device has
|
||||||
|
* a Keystore implementation that can enforce limited use key in hardware with any max usage
|
||||||
|
* count (including count equals to 1).
|
||||||
|
*/
|
||||||
|
@SdkConstant(SdkConstantType.FEATURE)
|
||||||
|
public static final String FEATURE_KEYSTORE_LIMITED_USE_KEY =
|
||||||
|
"android.hardware.keystore.limited_use_key";
|
||||||
|
|
||||||
/** @hide */
|
/** @hide */
|
||||||
public static final boolean APP_ENUMERATION_ENABLED_BY_DEFAULT = true;
|
public static final boolean APP_ENUMERATION_ENABLED_BY_DEFAULT = true;
|
||||||
|
|
||||||
|
|||||||
@@ -80,6 +80,7 @@ public final class KeymasterDefs {
|
|||||||
public static final int KM_TAG_MIN_SECONDS_BETWEEN_OPS =
|
public static final int KM_TAG_MIN_SECONDS_BETWEEN_OPS =
|
||||||
Tag.MIN_SECONDS_BETWEEN_OPS; // KM_UINT | 403;
|
Tag.MIN_SECONDS_BETWEEN_OPS; // KM_UINT | 403;
|
||||||
public static final int KM_TAG_MAX_USES_PER_BOOT = Tag.MAX_USES_PER_BOOT; // KM_UINT | 404;
|
public static final int KM_TAG_MAX_USES_PER_BOOT = Tag.MAX_USES_PER_BOOT; // KM_UINT | 404;
|
||||||
|
public static final int KM_TAG_USAGE_COUNT_LIMIT = Tag.USAGE_COUNT_LIMIT; // KM_UINT | 405;
|
||||||
|
|
||||||
public static final int KM_TAG_USER_ID = Tag.USER_ID; // KM_UINT | 501;
|
public static final int KM_TAG_USER_ID = Tag.USER_ID; // KM_UINT | 501;
|
||||||
public static final int KM_TAG_USER_SECURE_ID = Tag.USER_SECURE_ID; // KM_ULONG_REP | 502;
|
public static final int KM_TAG_USER_SECURE_ID = Tag.USER_SECURE_ID; // KM_ULONG_REP | 502;
|
||||||
|
|||||||
@@ -215,7 +215,8 @@ public class AndroidKeyStoreSecretKeyFactorySpi extends SecretKeyFactorySpi {
|
|||||||
// Keystore 1.0 does not tell us the exact security level of the key
|
// Keystore 1.0 does not tell us the exact security level of the key
|
||||||
// so we report an unknown but secure security level.
|
// so we report an unknown but secure security level.
|
||||||
insideSecureHardware ? KeyProperties.SECURITY_LEVEL_UNKNOWN_SECURE
|
insideSecureHardware ? KeyProperties.SECURITY_LEVEL_UNKNOWN_SECURE
|
||||||
: KeyProperties.SECURITY_LEVEL_SOFTWARE);
|
: KeyProperties.SECURITY_LEVEL_SOFTWARE,
|
||||||
|
KeyProperties.UNRESTRICTED_USAGE_COUNT);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static BigInteger getGateKeeperSecureUserId() throws ProviderException {
|
private static BigInteger getGateKeeperSecureUserId() throws ProviderException {
|
||||||
|
|||||||
@@ -274,6 +274,7 @@ public final class KeyGenParameterSpec implements AlgorithmParameterSpec, UserAu
|
|||||||
private final boolean mUserConfirmationRequired;
|
private final boolean mUserConfirmationRequired;
|
||||||
private final boolean mUnlockedDeviceRequired;
|
private final boolean mUnlockedDeviceRequired;
|
||||||
private final boolean mCriticalToDeviceEncryption;
|
private final boolean mCriticalToDeviceEncryption;
|
||||||
|
private final int mMaxUsageCount;
|
||||||
/*
|
/*
|
||||||
* ***NOTE***: All new fields MUST also be added to the following:
|
* ***NOTE***: All new fields MUST also be added to the following:
|
||||||
* ParcelableKeyGenParameterSpec class.
|
* ParcelableKeyGenParameterSpec class.
|
||||||
@@ -313,7 +314,8 @@ public final class KeyGenParameterSpec implements AlgorithmParameterSpec, UserAu
|
|||||||
boolean isStrongBoxBacked,
|
boolean isStrongBoxBacked,
|
||||||
boolean userConfirmationRequired,
|
boolean userConfirmationRequired,
|
||||||
boolean unlockedDeviceRequired,
|
boolean unlockedDeviceRequired,
|
||||||
boolean criticalToDeviceEncryption) {
|
boolean criticalToDeviceEncryption,
|
||||||
|
int maxUsageCount) {
|
||||||
if (TextUtils.isEmpty(keyStoreAlias)) {
|
if (TextUtils.isEmpty(keyStoreAlias)) {
|
||||||
throw new IllegalArgumentException("keyStoreAlias must not be empty");
|
throw new IllegalArgumentException("keyStoreAlias must not be empty");
|
||||||
}
|
}
|
||||||
@@ -366,6 +368,7 @@ public final class KeyGenParameterSpec implements AlgorithmParameterSpec, UserAu
|
|||||||
mUserConfirmationRequired = userConfirmationRequired;
|
mUserConfirmationRequired = userConfirmationRequired;
|
||||||
mUnlockedDeviceRequired = unlockedDeviceRequired;
|
mUnlockedDeviceRequired = unlockedDeviceRequired;
|
||||||
mCriticalToDeviceEncryption = criticalToDeviceEncryption;
|
mCriticalToDeviceEncryption = criticalToDeviceEncryption;
|
||||||
|
mMaxUsageCount = maxUsageCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -782,7 +785,7 @@ public final class KeyGenParameterSpec implements AlgorithmParameterSpec, UserAu
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return whether this key is critical to the device encryption flow.
|
* Returns whether this key is critical to the device encryption flow.
|
||||||
*
|
*
|
||||||
* @see android.security.KeyStore#FLAG_CRITICAL_TO_DEVICE_ENCRYPTION
|
* @see android.security.KeyStore#FLAG_CRITICAL_TO_DEVICE_ENCRYPTION
|
||||||
* @hide
|
* @hide
|
||||||
@@ -791,6 +794,17 @@ public final class KeyGenParameterSpec implements AlgorithmParameterSpec, UserAu
|
|||||||
return mCriticalToDeviceEncryption;
|
return mCriticalToDeviceEncryption;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the maximum number of times the limited use key is allowed to be used or
|
||||||
|
* {@link KeyProperties#UNRESTRICTED_USAGE_COUNT} if there’s no restriction on the number of
|
||||||
|
* times the key can be used.
|
||||||
|
*
|
||||||
|
* @see Builder#setMaxUsageCount(int)
|
||||||
|
*/
|
||||||
|
public int getMaxUsageCount() {
|
||||||
|
return mMaxUsageCount;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Builder of {@link KeyGenParameterSpec} instances.
|
* Builder of {@link KeyGenParameterSpec} instances.
|
||||||
*/
|
*/
|
||||||
@@ -827,6 +841,7 @@ public final class KeyGenParameterSpec implements AlgorithmParameterSpec, UserAu
|
|||||||
private boolean mUserConfirmationRequired;
|
private boolean mUserConfirmationRequired;
|
||||||
private boolean mUnlockedDeviceRequired = false;
|
private boolean mUnlockedDeviceRequired = false;
|
||||||
private boolean mCriticalToDeviceEncryption = false;
|
private boolean mCriticalToDeviceEncryption = false;
|
||||||
|
private int mMaxUsageCount = KeyProperties.UNRESTRICTED_USAGE_COUNT;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new instance of the {@code Builder}.
|
* Creates a new instance of the {@code Builder}.
|
||||||
@@ -894,6 +909,7 @@ public final class KeyGenParameterSpec implements AlgorithmParameterSpec, UserAu
|
|||||||
mUserConfirmationRequired = sourceSpec.isUserConfirmationRequired();
|
mUserConfirmationRequired = sourceSpec.isUserConfirmationRequired();
|
||||||
mUnlockedDeviceRequired = sourceSpec.isUnlockedDeviceRequired();
|
mUnlockedDeviceRequired = sourceSpec.isUnlockedDeviceRequired();
|
||||||
mCriticalToDeviceEncryption = sourceSpec.isCriticalToDeviceEncryption();
|
mCriticalToDeviceEncryption = sourceSpec.isCriticalToDeviceEncryption();
|
||||||
|
mMaxUsageCount = sourceSpec.getMaxUsageCount();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1552,6 +1568,47 @@ public final class KeyGenParameterSpec implements AlgorithmParameterSpec, UserAu
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the maximum number of times the key is allowed to be used. After every use of the
|
||||||
|
* key, the use counter will decrease. This authorization applies only to secret key and
|
||||||
|
* private key operations. Public key operations are not restricted. For example, after
|
||||||
|
* successfully encrypting and decrypting data using methods such as
|
||||||
|
* {@link Cipher#doFinal()}, the use counter of the secret key will decrease. After
|
||||||
|
* successfully signing data using methods such as {@link Signature#sign()}, the use
|
||||||
|
* counter of the private key will decrease.
|
||||||
|
*
|
||||||
|
* When the use counter is depleted, the key will be marked for deletion by Android
|
||||||
|
* Keystore and any subsequent attempt to use the key will throw
|
||||||
|
* {@link KeyPermanentlyInvalidatedException}. There is no key to be loaded from the
|
||||||
|
* Android Keystore once the exhausted key is permanently deleted, as if the key never
|
||||||
|
* existed before.
|
||||||
|
*
|
||||||
|
* <p>By default, there is no restriction on the usage of key.
|
||||||
|
*
|
||||||
|
* <p>Some secure hardware may not support this feature at all, in which case it will
|
||||||
|
* be enforced in software, some secure hardware may support it but only with
|
||||||
|
* maxUsageCount = 1, and some secure hardware may support it with larger value
|
||||||
|
* of maxUsageCount.
|
||||||
|
*
|
||||||
|
* <p>The PackageManger feature flags:
|
||||||
|
* {@link android.content.pm.PackageManager#FEATURE_KEYSTORE_SINGLE_USE_KEY} and
|
||||||
|
* {@link android.content.pm.PackageManager#FEATURE_KEYSTORE_LIMITED_USE_KEY} can be used
|
||||||
|
* to check whether the secure hardware cannot enforce this feature, can only enforce it
|
||||||
|
* with maxUsageCount = 1, or can enforce it with larger value of maxUsageCount.
|
||||||
|
*
|
||||||
|
* @param maxUsageCount maximum number of times the key is allowed to be used or
|
||||||
|
* {@link KeyProperties#UNRESTRICTED_USAGE_COUNT} if there is no restriction on the
|
||||||
|
* usage.
|
||||||
|
*/
|
||||||
|
@NonNull
|
||||||
|
public Builder setMaxUsageCount(int maxUsageCount) {
|
||||||
|
if (maxUsageCount == KeyProperties.UNRESTRICTED_USAGE_COUNT || maxUsageCount > 0) {
|
||||||
|
mMaxUsageCount = maxUsageCount;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
throw new IllegalArgumentException("maxUsageCount is not valid");
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Builds an instance of {@code KeyGenParameterSpec}.
|
* Builds an instance of {@code KeyGenParameterSpec}.
|
||||||
*/
|
*/
|
||||||
@@ -1587,7 +1644,8 @@ public final class KeyGenParameterSpec implements AlgorithmParameterSpec, UserAu
|
|||||||
mIsStrongBoxBacked,
|
mIsStrongBoxBacked,
|
||||||
mUserConfirmationRequired,
|
mUserConfirmationRequired,
|
||||||
mUnlockedDeviceRequired,
|
mUnlockedDeviceRequired,
|
||||||
mCriticalToDeviceEncryption);
|
mCriticalToDeviceEncryption,
|
||||||
|
mMaxUsageCount);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -85,6 +85,7 @@ public class KeyInfo implements KeySpec {
|
|||||||
private final boolean mInvalidatedByBiometricEnrollment;
|
private final boolean mInvalidatedByBiometricEnrollment;
|
||||||
private final boolean mUserConfirmationRequired;
|
private final boolean mUserConfirmationRequired;
|
||||||
private final @KeyProperties.SecurityLevelEnum int mSecurityLevel;
|
private final @KeyProperties.SecurityLevelEnum int mSecurityLevel;
|
||||||
|
private final int mRemainingUsageCount;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @hide
|
* @hide
|
||||||
@@ -109,7 +110,8 @@ public class KeyInfo implements KeySpec {
|
|||||||
boolean trustedUserPresenceRequired,
|
boolean trustedUserPresenceRequired,
|
||||||
boolean invalidatedByBiometricEnrollment,
|
boolean invalidatedByBiometricEnrollment,
|
||||||
boolean userConfirmationRequired,
|
boolean userConfirmationRequired,
|
||||||
@KeyProperties.SecurityLevelEnum int securityLevel) {
|
@KeyProperties.SecurityLevelEnum int securityLevel,
|
||||||
|
int remainingUsageCount) {
|
||||||
mKeystoreAlias = keystoreKeyAlias;
|
mKeystoreAlias = keystoreKeyAlias;
|
||||||
mInsideSecureHardware = insideSecureHardware;
|
mInsideSecureHardware = insideSecureHardware;
|
||||||
mOrigin = origin;
|
mOrigin = origin;
|
||||||
@@ -134,6 +136,7 @@ public class KeyInfo implements KeySpec {
|
|||||||
mInvalidatedByBiometricEnrollment = invalidatedByBiometricEnrollment;
|
mInvalidatedByBiometricEnrollment = invalidatedByBiometricEnrollment;
|
||||||
mUserConfirmationRequired = userConfirmationRequired;
|
mUserConfirmationRequired = userConfirmationRequired;
|
||||||
mSecurityLevel = securityLevel;
|
mSecurityLevel = securityLevel;
|
||||||
|
mRemainingUsageCount = remainingUsageCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -374,4 +377,15 @@ public class KeyInfo implements KeySpec {
|
|||||||
public @KeyProperties.SecurityLevelEnum int getSecurityLevel() {
|
public @KeyProperties.SecurityLevelEnum int getSecurityLevel() {
|
||||||
return mSecurityLevel;
|
return mSecurityLevel;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the remaining number of times the key is allowed to be used or
|
||||||
|
* {@link KeyProperties#UNRESTRICTED_USAGE_COUNT} if there's no restriction on the number of
|
||||||
|
* times the key can be used. Note that this gives a best effort count and need not be
|
||||||
|
* accurate (as there might be usages happening in parallel and the count maintained here need
|
||||||
|
* not be in sync with the usage).
|
||||||
|
*/
|
||||||
|
public int getRemainingUsageCount() {
|
||||||
|
return mRemainingUsageCount;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -907,4 +907,9 @@ public abstract class KeyProperties {
|
|||||||
+ uid);
|
+ uid);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This value indicates that there is no restriction on the number of times the key can be used.
|
||||||
|
*/
|
||||||
|
public static final int UNRESTRICTED_USAGE_COUNT = -1;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -235,6 +235,7 @@ public final class KeyProtection implements ProtectionParameter, UserAuthArgs {
|
|||||||
private final boolean mUserConfirmationRequired;
|
private final boolean mUserConfirmationRequired;
|
||||||
private final boolean mUnlockedDeviceRequired;
|
private final boolean mUnlockedDeviceRequired;
|
||||||
private final boolean mIsStrongBoxBacked;
|
private final boolean mIsStrongBoxBacked;
|
||||||
|
private final int mMaxUsageCount;
|
||||||
|
|
||||||
private KeyProtection(
|
private KeyProtection(
|
||||||
Date keyValidityStart,
|
Date keyValidityStart,
|
||||||
@@ -256,7 +257,8 @@ public final class KeyProtection implements ProtectionParameter, UserAuthArgs {
|
|||||||
boolean criticalToDeviceEncryption,
|
boolean criticalToDeviceEncryption,
|
||||||
boolean userConfirmationRequired,
|
boolean userConfirmationRequired,
|
||||||
boolean unlockedDeviceRequired,
|
boolean unlockedDeviceRequired,
|
||||||
boolean isStrongBoxBacked) {
|
boolean isStrongBoxBacked,
|
||||||
|
int maxUsageCount) {
|
||||||
mKeyValidityStart = Utils.cloneIfNotNull(keyValidityStart);
|
mKeyValidityStart = Utils.cloneIfNotNull(keyValidityStart);
|
||||||
mKeyValidityForOriginationEnd = Utils.cloneIfNotNull(keyValidityForOriginationEnd);
|
mKeyValidityForOriginationEnd = Utils.cloneIfNotNull(keyValidityForOriginationEnd);
|
||||||
mKeyValidityForConsumptionEnd = Utils.cloneIfNotNull(keyValidityForConsumptionEnd);
|
mKeyValidityForConsumptionEnd = Utils.cloneIfNotNull(keyValidityForConsumptionEnd);
|
||||||
@@ -279,6 +281,7 @@ public final class KeyProtection implements ProtectionParameter, UserAuthArgs {
|
|||||||
mUserConfirmationRequired = userConfirmationRequired;
|
mUserConfirmationRequired = userConfirmationRequired;
|
||||||
mUnlockedDeviceRequired = unlockedDeviceRequired;
|
mUnlockedDeviceRequired = unlockedDeviceRequired;
|
||||||
mIsStrongBoxBacked = isStrongBoxBacked;
|
mIsStrongBoxBacked = isStrongBoxBacked;
|
||||||
|
mMaxUsageCount = maxUsageCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -547,6 +550,17 @@ public final class KeyProtection implements ProtectionParameter, UserAuthArgs {
|
|||||||
return mIsStrongBoxBacked;
|
return mIsStrongBoxBacked;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the maximum number of times the limited use key is allowed to be used or
|
||||||
|
* {@link KeyProperties#UNRESTRICTED_USAGE_COUNT} if there’s no restriction on the number of
|
||||||
|
* times the key can be used.
|
||||||
|
*
|
||||||
|
* @see Builder#setMaxUsageCount(int)
|
||||||
|
*/
|
||||||
|
public int getMaxUsageCount() {
|
||||||
|
return mMaxUsageCount;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Builder of {@link KeyProtection} instances.
|
* Builder of {@link KeyProtection} instances.
|
||||||
*/
|
*/
|
||||||
@@ -574,6 +588,7 @@ public final class KeyProtection implements ProtectionParameter, UserAuthArgs {
|
|||||||
private long mBoundToSecureUserId = GateKeeper.INVALID_SECURE_USER_ID;
|
private long mBoundToSecureUserId = GateKeeper.INVALID_SECURE_USER_ID;
|
||||||
private boolean mCriticalToDeviceEncryption = false;
|
private boolean mCriticalToDeviceEncryption = false;
|
||||||
private boolean mIsStrongBoxBacked = false;
|
private boolean mIsStrongBoxBacked = false;
|
||||||
|
private int mMaxUsageCount = KeyProperties.UNRESTRICTED_USAGE_COUNT;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new instance of the {@code Builder}.
|
* Creates a new instance of the {@code Builder}.
|
||||||
@@ -1039,6 +1054,47 @@ public final class KeyProtection implements ProtectionParameter, UserAuthArgs {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the maximum number of times the key is allowed to be used. After every use of the
|
||||||
|
* key, the use counter will decrease. This authorization applies only to secret key and
|
||||||
|
* private key operations. Public key operations are not restricted. For example, after
|
||||||
|
* successfully encrypting and decrypting data using methods such as
|
||||||
|
* {@link Cipher#doFinal()}, the use counter of the secret key will decrease. After
|
||||||
|
* successfully signing data using methods such as {@link Signature#sign()}, the use
|
||||||
|
* counter of the private key will decrease.
|
||||||
|
*
|
||||||
|
* When the use counter is depleted, the key will be marked for deletion by Android
|
||||||
|
* Keystore and any subsequent attempt to use the key will throw
|
||||||
|
* {@link KeyPermanentlyInvalidatedException}. There is no key to be loaded from the
|
||||||
|
* Android Keystore once the exhausted key is permanently deleted, as if the key never
|
||||||
|
* existed before.
|
||||||
|
*
|
||||||
|
* <p>By default, there is no restriction on the usage of key.
|
||||||
|
*
|
||||||
|
* <p>Some secure hardware may not support this feature at all, in which case it will
|
||||||
|
* be enforced in software, some secure hardware may support it but only with
|
||||||
|
* maxUsageCount = 1, and some secure hardware may support it with larger value
|
||||||
|
* of maxUsageCount.
|
||||||
|
*
|
||||||
|
* <p>The PackageManger feature flags:
|
||||||
|
* {@link android.content.pm.PackageManager#FEATURE_KEYSTORE_SINGLE_USE_KEY} and
|
||||||
|
* {@link android.content.pm.PackageManager#FEATURE_KEYSTORE_LIMITED_USE_KEY} can be used
|
||||||
|
* to check whether the secure hardware cannot enforce this feature, can only enforce it
|
||||||
|
* with maxUsageCount = 1, or can enforce it with larger value of maxUsageCount.
|
||||||
|
*
|
||||||
|
* @param maxUsageCount maximum number of times the key is allowed to be used or
|
||||||
|
* {@link KeyProperties#UNRESTRICTED_USAGE_COUNT} if there is no restriction on the
|
||||||
|
* usage.
|
||||||
|
*/
|
||||||
|
@NonNull
|
||||||
|
public Builder setMaxUsageCount(int maxUsageCount) {
|
||||||
|
if (maxUsageCount == KeyProperties.UNRESTRICTED_USAGE_COUNT || maxUsageCount > 0) {
|
||||||
|
mMaxUsageCount = maxUsageCount;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
throw new IllegalArgumentException("maxUsageCount is not valid");
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Builds an instance of {@link KeyProtection}.
|
* Builds an instance of {@link KeyProtection}.
|
||||||
*
|
*
|
||||||
@@ -1066,7 +1122,8 @@ public final class KeyProtection implements ProtectionParameter, UserAuthArgs {
|
|||||||
mCriticalToDeviceEncryption,
|
mCriticalToDeviceEncryption,
|
||||||
mUserConfirmationRequired,
|
mUserConfirmationRequired,
|
||||||
mUnlockedDeviceRequired,
|
mUnlockedDeviceRequired,
|
||||||
mIsStrongBoxBacked);
|
mIsStrongBoxBacked,
|
||||||
|
mMaxUsageCount);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -108,6 +108,7 @@ public final class ParcelableKeyGenParameterSpec implements Parcelable {
|
|||||||
out.writeBoolean(mSpec.isUserConfirmationRequired());
|
out.writeBoolean(mSpec.isUserConfirmationRequired());
|
||||||
out.writeBoolean(mSpec.isUnlockedDeviceRequired());
|
out.writeBoolean(mSpec.isUnlockedDeviceRequired());
|
||||||
out.writeBoolean(mSpec.isCriticalToDeviceEncryption());
|
out.writeBoolean(mSpec.isCriticalToDeviceEncryption());
|
||||||
|
out.writeInt(mSpec.getMaxUsageCount());
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Date readDateOrNull(Parcel in) {
|
private static Date readDateOrNull(Parcel in) {
|
||||||
@@ -166,6 +167,7 @@ public final class ParcelableKeyGenParameterSpec implements Parcelable {
|
|||||||
final boolean userConfirmationRequired = in.readBoolean();
|
final boolean userConfirmationRequired = in.readBoolean();
|
||||||
final boolean unlockedDeviceRequired = in.readBoolean();
|
final boolean unlockedDeviceRequired = in.readBoolean();
|
||||||
final boolean criticalToDeviceEncryption = in.readBoolean();
|
final boolean criticalToDeviceEncryption = in.readBoolean();
|
||||||
|
final int maxUsageCount = in.readInt();
|
||||||
// The KeyGenParameterSpec is intentionally not constructed using a Builder here:
|
// The KeyGenParameterSpec is intentionally not constructed using a Builder here:
|
||||||
// The intention is for this class to break if new parameters are added to the
|
// The intention is for this class to break if new parameters are added to the
|
||||||
// KeyGenParameterSpec constructor (whereas using a builder would silently drop them).
|
// KeyGenParameterSpec constructor (whereas using a builder would silently drop them).
|
||||||
@@ -199,7 +201,8 @@ public final class ParcelableKeyGenParameterSpec implements Parcelable {
|
|||||||
isStrongBoxBacked,
|
isStrongBoxBacked,
|
||||||
userConfirmationRequired,
|
userConfirmationRequired,
|
||||||
unlockedDeviceRequired,
|
unlockedDeviceRequired,
|
||||||
criticalToDeviceEncryption);
|
criticalToDeviceEncryption,
|
||||||
|
maxUsageCount);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static final @android.annotation.NonNull Creator<ParcelableKeyGenParameterSpec> CREATOR = new Creator<ParcelableKeyGenParameterSpec>() {
|
public static final @android.annotation.NonNull Creator<ParcelableKeyGenParameterSpec> CREATOR = new Creator<ParcelableKeyGenParameterSpec>() {
|
||||||
|
|||||||
@@ -366,6 +366,13 @@ public abstract class AndroidKeyStoreKeyGeneratorSpi extends KeyGeneratorSpi {
|
|||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (spec.getMaxUsageCount() != KeyProperties.UNRESTRICTED_USAGE_COUNT) {
|
||||||
|
params.add(KeyStore2ParameterUtils.makeInt(
|
||||||
|
KeymasterDefs.KM_TAG_USAGE_COUNT_LIMIT,
|
||||||
|
spec.getMaxUsageCount()
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
byte[] additionalEntropy =
|
byte[] additionalEntropy =
|
||||||
KeyStoreCryptoOperationUtils.getRandomBytesToMixIntoKeystoreRng(
|
KeyStoreCryptoOperationUtils.getRandomBytesToMixIntoKeystoreRng(
|
||||||
mRng, (mKeySizeBits + 7) / 8);
|
mRng, (mKeySizeBits + 7) / 8);
|
||||||
|
|||||||
@@ -586,6 +586,13 @@ public abstract class AndroidKeyStoreKeyPairGeneratorSpi extends KeyPairGenerato
|
|||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (mSpec.getMaxUsageCount() != KeyProperties.UNRESTRICTED_USAGE_COUNT) {
|
||||||
|
params.add(KeyStore2ParameterUtils.makeInt(
|
||||||
|
KeymasterDefs.KM_TAG_USAGE_COUNT_LIMIT,
|
||||||
|
mSpec.getMaxUsageCount()
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
addAlgorithmSpecificParameters(params);
|
addAlgorithmSpecificParameters(params);
|
||||||
|
|
||||||
if (mSpec.isUniqueIdIncluded()) {
|
if (mSpec.isUniqueIdIncluded()) {
|
||||||
|
|||||||
@@ -95,6 +95,7 @@ public class AndroidKeyStoreSecretKeyFactorySpi extends SecretKeyFactorySpi {
|
|||||||
boolean userAuthenticationValidWhileOnBody = false;
|
boolean userAuthenticationValidWhileOnBody = false;
|
||||||
boolean trustedUserPresenceRequired = false;
|
boolean trustedUserPresenceRequired = false;
|
||||||
boolean trustedUserConfirmationRequired = false;
|
boolean trustedUserConfirmationRequired = false;
|
||||||
|
int remainingUsageCount = KeyProperties.UNRESTRICTED_USAGE_COUNT;
|
||||||
try {
|
try {
|
||||||
for (Authorization a : key.getAuthorizations()) {
|
for (Authorization a : key.getAuthorizations()) {
|
||||||
switch (a.keyParameter.tag) {
|
switch (a.keyParameter.tag) {
|
||||||
@@ -195,6 +196,16 @@ public class AndroidKeyStoreSecretKeyFactorySpi extends SecretKeyFactorySpi {
|
|||||||
trustedUserConfirmationRequired =
|
trustedUserConfirmationRequired =
|
||||||
KeyStore2ParameterUtils.isSecureHardware(a.securityLevel);
|
KeyStore2ParameterUtils.isSecureHardware(a.securityLevel);
|
||||||
break;
|
break;
|
||||||
|
case KeymasterDefs.KM_TAG_USAGE_COUNT_LIMIT:
|
||||||
|
long remainingUsageCountUnsigned =
|
||||||
|
KeyStore2ParameterUtils.getUnsignedInt(a);
|
||||||
|
if (remainingUsageCountUnsigned > Integer.MAX_VALUE) {
|
||||||
|
throw new ProviderException(
|
||||||
|
"Usage count of limited use key too long: "
|
||||||
|
+ remainingUsageCountUnsigned);
|
||||||
|
}
|
||||||
|
remainingUsageCount = (int) remainingUsageCountUnsigned;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (IllegalArgumentException e) {
|
} catch (IllegalArgumentException e) {
|
||||||
@@ -247,7 +258,8 @@ public class AndroidKeyStoreSecretKeyFactorySpi extends SecretKeyFactorySpi {
|
|||||||
trustedUserPresenceRequired,
|
trustedUserPresenceRequired,
|
||||||
invalidatedByBiometricEnrollment,
|
invalidatedByBiometricEnrollment,
|
||||||
trustedUserConfirmationRequired,
|
trustedUserConfirmationRequired,
|
||||||
securityLevel);
|
securityLevel,
|
||||||
|
remainingUsageCount);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static BigInteger getGateKeeperSecureUserId() throws ProviderException {
|
private static BigInteger getGateKeeperSecureUserId() throws ProviderException {
|
||||||
|
|||||||
@@ -535,6 +535,12 @@ public class AndroidKeyStoreSpi extends KeyStoreSpi {
|
|||||||
spec.getKeyValidityForConsumptionEnd()
|
spec.getKeyValidityForConsumptionEnd()
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
if (spec.getMaxUsageCount() != KeyProperties.UNRESTRICTED_USAGE_COUNT) {
|
||||||
|
importArgs.add(KeyStore2ParameterUtils.makeInt(
|
||||||
|
KeymasterDefs.KM_TAG_USAGE_COUNT_LIMIT,
|
||||||
|
spec.getMaxUsageCount()
|
||||||
|
));
|
||||||
|
}
|
||||||
} catch (IllegalArgumentException | IllegalStateException e) {
|
} catch (IllegalArgumentException | IllegalStateException e) {
|
||||||
throw new KeyStoreException(e);
|
throw new KeyStoreException(e);
|
||||||
}
|
}
|
||||||
@@ -772,6 +778,12 @@ public class AndroidKeyStoreSpi extends KeyStoreSpi {
|
|||||||
params.getKeyValidityForConsumptionEnd()
|
params.getKeyValidityForConsumptionEnd()
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
if (params.getMaxUsageCount() != KeyProperties.UNRESTRICTED_USAGE_COUNT) {
|
||||||
|
importArgs.add(KeyStore2ParameterUtils.makeInt(
|
||||||
|
KeymasterDefs.KM_TAG_USAGE_COUNT_LIMIT,
|
||||||
|
params.getMaxUsageCount()
|
||||||
|
));
|
||||||
|
}
|
||||||
} catch (IllegalArgumentException | IllegalStateException e) {
|
} catch (IllegalArgumentException | IllegalStateException e) {
|
||||||
throw new KeyStoreException(e);
|
throw new KeyStoreException(e);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user