Merge changes from topic "limited_use_keys" am: 892c82e0f2 am: 0e30e1e432

Original change: https://android-review.googlesource.com/c/platform/frameworks/base/+/1513132

MUST ONLY BE SUBMITTED BY AUTOMERGER

Change-Id: I47c55cba74b3fe9aacdeacd6fc13197dd57293f6
This commit is contained in:
Treehugger Robot
2021-02-03 18:02:12 +00:00
committed by Automerger Merge Worker
12 changed files with 192 additions and 9 deletions

View File

@@ -36207,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();
@@ -36243,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);
@@ -36265,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();
@@ -36334,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 {
@@ -36343,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();
@@ -36368,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);

View File

@@ -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;

View File

@@ -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 {

View File

@@ -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);
} }
} }
} }

View File

@@ -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;
}
} }

View File

@@ -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;
} }

View File

@@ -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);
} }
} }
} }

View File

@@ -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>() {

View File

@@ -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);

View File

@@ -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()) {

View File

@@ -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 {

View File

@@ -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);
} }