summaryrefslogtreecommitdiff
path: root/identity
diff options
context:
space:
mode:
authorDavid Zeuthen <zeuthen@google.com>2022-11-14 15:17:07 -0500
committerDavid Zeuthen <zeuthen@google.com>2022-12-09 13:05:50 -0500
commitc505485c2dff2b91dd627b679a13ea2db55e12d3 (patch)
tree7dde9445bae32aeeae3975061bb08eb49956fe35 /identity
parent55f62fc1252f45803263d9d88a9fe7179d334172 (diff)
downloadbase-c505485c2dff2b91dd627b679a13ea2db55e12d3.tar.gz
identity: Add support for setting minimum validity period for AuthKey.
This change adds support for specifying that an AuthKey should be replaced if it's going to expire within a certain amount of time configurable by the application. This also adds a way for the application to learn about the expiration time of currently configured AuthKeys. Combined these two changes allow an application to get a perfect picture of which AuthKeys are available, when they expire, and allows the application to refresh AuthKeys well ahead of expiration dates. Also remove wrong comment that storeStaticAuthenticationDate() variant taking an expiration is only available in feature version 202101. It's available on all feature versions. Bug: 241912421 Test: atest VtsHalIdentityTargetTest Test: atest android.security.identity.cts Change-Id: Ib79da64abfa25b37ed73a37ce78fedd4ef7d1ece
Diffstat (limited to 'identity')
-rw-r--r--identity/java/android/security/identity/AuthenticationKeyMetadata.java53
-rw-r--r--identity/java/android/security/identity/CredstoreIdentityCredential.java36
-rw-r--r--identity/java/android/security/identity/IdentityCredential.java62
3 files changed, 143 insertions, 8 deletions
diff --git a/identity/java/android/security/identity/AuthenticationKeyMetadata.java b/identity/java/android/security/identity/AuthenticationKeyMetadata.java
new file mode 100644
index 000000000000..d4c28f8d459a
--- /dev/null
+++ b/identity/java/android/security/identity/AuthenticationKeyMetadata.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2019 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.identity;
+
+import android.annotation.IntRange;
+import android.annotation.NonNull;
+
+import java.time.Instant;
+
+/**
+ * Data about authentication keys.
+ */
+public class AuthenticationKeyMetadata {
+ private int mUsageCount;
+ private Instant mExpirationDate;
+
+ AuthenticationKeyMetadata(int usageCount, Instant expirationDate) {
+ mUsageCount = usageCount;
+ mExpirationDate = expirationDate;
+ }
+
+ /**
+ * Gets usage count for the authentication key.
+ *
+ * @return the usage count
+ */
+ public @IntRange(from = 0) int getUsageCount() {
+ return mUsageCount;
+ }
+
+ /**
+ * Gets expiration date for the authentication key.
+ *
+ * @return the expiration date of the authentication key.
+ */
+ public @NonNull Instant getExpirationDate() {
+ return mExpirationDate;
+ }
+}
diff --git a/identity/java/android/security/identity/CredstoreIdentityCredential.java b/identity/java/android/security/identity/CredstoreIdentityCredential.java
index 06953ba83289..449c7a706753 100644
--- a/identity/java/android/security/identity/CredstoreIdentityCredential.java
+++ b/identity/java/android/security/identity/CredstoreIdentityCredential.java
@@ -380,8 +380,14 @@ class CredstoreIdentityCredential extends IdentityCredential {
@Override
public void setAvailableAuthenticationKeys(int keyCount, int maxUsesPerKey) {
+ setAvailableAuthenticationKeys(keyCount, maxUsesPerKey, 0);
+ }
+
+ @Override
+ public void setAvailableAuthenticationKeys(int keyCount, int maxUsesPerKey,
+ long minValidTimeMillis) {
try {
- mBinder.setAvailableAuthenticationKeys(keyCount, maxUsesPerKey);
+ mBinder.setAvailableAuthenticationKeys(keyCount, maxUsesPerKey, minValidTimeMillis);
} catch (android.os.RemoteException e) {
throw new RuntimeException("Unexpected RemoteException ", e);
} catch (android.os.ServiceSpecificException e) {
@@ -481,6 +487,34 @@ class CredstoreIdentityCredential extends IdentityCredential {
}
@Override
+ public @NonNull List<AuthenticationKeyMetadata> getAuthenticationKeyMetadata() {
+ try {
+ int[] usageCount = mBinder.getAuthenticationDataUsageCount();
+ long[] expirationsMillis = mBinder.getAuthenticationDataExpirations();
+ if (usageCount.length != expirationsMillis.length) {
+ throw new IllegalStateException("Size og usageCount and expirationMillis differ");
+ }
+ List<AuthenticationKeyMetadata> mds = new ArrayList<>();
+ for (int n = 0; n < expirationsMillis.length; n++) {
+ AuthenticationKeyMetadata md = null;
+ long expirationMillis = expirationsMillis[n];
+ if (expirationMillis != Long.MAX_VALUE) {
+ md = new AuthenticationKeyMetadata(
+ usageCount[n],
+ Instant.ofEpochMilli(expirationMillis));
+ }
+ mds.add(md);
+ }
+ return mds;
+ } catch (android.os.RemoteException e) {
+ throw new IllegalStateException("Unexpected RemoteException ", e);
+ } catch (android.os.ServiceSpecificException e) {
+ throw new IllegalStateException("Unexpected ServiceSpecificException with code "
+ + e.errorCode, e);
+ }
+ }
+
+ @Override
public @NonNull byte[] proveOwnership(@NonNull byte[] challenge) {
try {
byte[] proofOfOwnership = mBinder.proveOwnership(challenge);
diff --git a/identity/java/android/security/identity/IdentityCredential.java b/identity/java/android/security/identity/IdentityCredential.java
index 3988c0c82b6e..2dd9778a6fe7 100644
--- a/identity/java/android/security/identity/IdentityCredential.java
+++ b/identity/java/android/security/identity/IdentityCredential.java
@@ -16,6 +16,7 @@
package android.security.identity;
+import android.annotation.IntRange;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -25,6 +26,7 @@ import java.security.PublicKey;
import java.security.cert.X509Certificate;
import java.time.Instant;
import java.util.Collection;
+import java.util.List;
import java.util.Map;
/**
@@ -297,7 +299,7 @@ public abstract class IdentityCredential {
* session transcripts.
* @throws NoAuthenticationKeyAvailableException if authentication keys were never
* provisioned, the method
- * {@link #setAvailableAuthenticationKeys(int, int)}
+ * {@link #setAvailableAuthenticationKeys(int, int, long)}
* was called with {@code keyCount} set to 0,
* the method
* {@link #setAllowUsingExhaustedKeys(boolean)}
@@ -331,19 +333,25 @@ public abstract class IdentityCredential {
* for which this method has not been called behave as though it had been called wit
* {@code keyCount} 0 and {@code maxUsesPerKey} 1.
*
+ * <p>The effect of this method is like calling
+ * {@link #setAvailableAuthenticationKeys(int, int, long)} with the last parameter is set to 0.
+ *
* @param keyCount The number of active, certified dynamic authentication keys the
* {@code IdentityCredential} will try to keep available. This value
* must be non-negative.
* @param maxUsesPerKey The maximum number of times each of the keys will be used before it's
* eligible for replacement. This value must be greater than zero.
+ * @deprecated Use {@link #setAvailableAuthenticationKeys(int, int, long)} instead.
*/
+ @Deprecated
public abstract void setAvailableAuthenticationKeys(int keyCount, int maxUsesPerKey);
/**
* Gets a collection of dynamic authentication keys that need certification.
*
* <p>When there aren't enough certified dynamic authentication keys, either because the key
- * count has been increased or because one or more keys have reached their usage count, this
+ * count has been increased or because one or more keys have reached their usage count or
+ * it if a key is too close to its expiration date, this
* method will generate replacement keys and certificates and return them for issuer
* certification. The issuer certificates and associated static authentication data must then
* be provided back to the Identity Credential using
@@ -401,11 +409,6 @@ public abstract class IdentityCredential {
* This should only be called for an authenticated key returned by
* {@link #getAuthKeysNeedingCertification()}.
*
- * <p>This is only implemented in feature version 202101 or later. If not implemented, the call
- * fails with {@link UnsupportedOperationException}. See
- * {@link android.content.pm.PackageManager#FEATURE_IDENTITY_CREDENTIAL_HARDWARE} for known
- * feature versions.
- *
* @param authenticationKey The dynamic authentication key for which certification and
* associated static
* authentication data is being provided.
@@ -427,7 +430,9 @@ public abstract class IdentityCredential {
* Get the number of times the dynamic authentication keys have been used.
*
* @return int array of dynamic authentication key usage counts.
+ * @deprecated Use {@link #getAuthenticationKeyMetadata()} instead.
*/
+ @Deprecated
public @NonNull abstract int[] getAuthenticationDataUsageCount();
/**
@@ -520,4 +525,47 @@ public abstract class IdentityCredential {
public @NonNull byte[] update(@NonNull PersonalizationData personalizationData) {
throw new UnsupportedOperationException();
}
+
+ /**
+ * Sets the number of dynamic authentication keys the {@code IdentityCredential} will maintain,
+ * the number of times each should be used, and the minimum amount of time it's valid for.
+ *
+ * <p>The Identity Credential system will select the least-used dynamic authentication key each
+ * time {@link #getEntries(byte[], Map, byte[], byte[])} is called. Identity Credentials
+ * for which this method has not been called behave as though it had been called wit
+ * {@code keyCount} 0, {@code maxUsesPerKey} 1, and {@code minValidTimeMillis} 0.
+ *
+ * <p>Applications can use {@link #getAuthenticationKeyMetadata()} to get a picture of the
+ * usage andtime left of each configured authentication key. This can be used to determine
+ * how urgent it is recertify new authentication keys via the
+ * {@link #getAuthKeysNeedingCertification()} method.
+ *
+ * @param keyCount The number of active, certified dynamic authentication keys the
+ * {@code IdentityCredential} will try to keep available. This value
+ * must be non-negative.
+ * @param maxUsesPerKey The maximum number of times each of the keys will be used before it's
+ * eligible for replacement. This value must be greater than zero.
+ * @param minValidTimeMillis If a key has less time left than this value it will be eliglible
+ * for replacement. This value must be non-negative.
+ */
+ public void setAvailableAuthenticationKeys(
+ @IntRange(from = 0) int keyCount,
+ @IntRange(from = 1) int maxUsesPerKey,
+ @IntRange(from = 0) long minValidTimeMillis) {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * Get information about dynamic authentication keys.
+ *
+ * <p>The returned list may have <code>null</code> values if certification for the dynamic
+ * authentication key is pending.
+ *
+ * <p>The list is always <code>keyCount</code> elements long.
+ *
+ * @return list of authentication key metadata objects.
+ */
+ public @NonNull List<AuthenticationKeyMetadata> getAuthenticationKeyMetadata() {
+ throw new UnsupportedOperationException();
+ }
}