Add key accessing functions to KeysetHandle.

We add a static inner class KeysetHandle.Entry as well as methods
 * getPrimary()
 * size()
 * getAt(i)

These return the size of the keyset, as well as corresponding entries.

In entries, users can query "getKey()", "getStatus()", "getId()", as well as "isPrimary()".

Note: these functions should never throw, but currently Tink accepts keysets without primary and with invalid status objects. In these cases, we may throw.

The function getKey will, in the future, return a Key object which can be used to query information about the key (including key material). However, currently it only returns an internal object (LegacyProtoKey).

PiperOrigin-RevId: 455359595
Change-Id: I4595d3b98755ae0dce630ddb8eb2c32b121c6b5d
diff --git a/src/main/java/com/google/crypto/tink/BUILD.bazel b/src/main/java/com/google/crypto/tink/BUILD.bazel
index 47a21d8..254e4c5 100644
--- a/src/main/java/com/google/crypto/tink/BUILD.bazel
+++ b/src/main/java/com/google/crypto/tink/BUILD.bazel
@@ -528,6 +528,9 @@
     ],
     deps = [
         ":aead",
+        ":insecure_secret_key_access",
+        ":key",
+        ":key_status",
         ":key_template",
         ":keyset_reader",
         ":keyset_writer",
@@ -535,7 +538,11 @@
         ":registry",
         ":util",
         "//proto:tink_java_proto",
+        "//src/main/java/com/google/crypto/tink/annotations:alpha",
         "//src/main/java/com/google/crypto/tink/internal:key_status_type_proto_converter",
+        "//src/main/java/com/google/crypto/tink/internal:legacy_proto_key",
+        "//src/main/java/com/google/crypto/tink/internal:mutable_serialization_registry",
+        "//src/main/java/com/google/crypto/tink/internal:proto_key_serialization",
         "//src/main/java/com/google/crypto/tink/internal:util",
         "//src/main/java/com/google/crypto/tink/tinkkey:key_access",
         "//src/main/java/com/google/crypto/tink/tinkkey:key_handle",
@@ -544,6 +551,7 @@
         "//src/main/java/com/google/crypto/tink/tinkkey/internal:proto_key",
         "@com_google_protobuf//:protobuf_javalite",
         "@maven//:com_google_code_findbugs_jsr305",
+        "@maven//:com_google_errorprone_error_prone_annotations",
     ],
 )
 
@@ -555,6 +563,9 @@
     ],
     deps = [
         ":aead-android",
+        ":insecure_secret_key_access-android",
+        ":key-android",
+        ":key_status-android",
         ":key_template-android",
         ":keyset_reader-android",
         ":keyset_writer-android",
@@ -562,7 +573,11 @@
         ":registry-android",
         ":util-android",
         "//proto:tink_java_proto_lite",
+        "//src/main/java/com/google/crypto/tink/annotations:alpha-android",
         "//src/main/java/com/google/crypto/tink/internal:key_status_type_proto_converter-android",
+        "//src/main/java/com/google/crypto/tink/internal:legacy_proto_key-android",
+        "//src/main/java/com/google/crypto/tink/internal:mutable_serialization_registry-android",
+        "//src/main/java/com/google/crypto/tink/internal:proto_key_serialization-android",
         "//src/main/java/com/google/crypto/tink/internal:util-android",
         "//src/main/java/com/google/crypto/tink/tinkkey:key_access-android",
         "//src/main/java/com/google/crypto/tink/tinkkey:key_handle-android",
@@ -571,6 +586,7 @@
         "//src/main/java/com/google/crypto/tink/tinkkey/internal:proto_key-android",
         "@com_google_protobuf//:protobuf_javalite",
         "@maven//:com_google_code_findbugs_jsr305",
+        "@maven//:com_google_errorprone_error_prone_annotations",
     ],
 )
 
diff --git a/src/main/java/com/google/crypto/tink/KeysetHandle.java b/src/main/java/com/google/crypto/tink/KeysetHandle.java
index 95d2fce..ba50f00 100644
--- a/src/main/java/com/google/crypto/tink/KeysetHandle.java
+++ b/src/main/java/com/google/crypto/tink/KeysetHandle.java
@@ -16,15 +16,21 @@
 
 package com.google.crypto.tink;
 
+import com.google.crypto.tink.annotations.Alpha;
+import com.google.crypto.tink.internal.LegacyProtoKey;
+import com.google.crypto.tink.internal.MutableSerializationRegistry;
+import com.google.crypto.tink.internal.ProtoKeySerialization;
 import com.google.crypto.tink.proto.EncryptedKeyset;
 import com.google.crypto.tink.proto.KeyData;
 import com.google.crypto.tink.proto.KeyStatusType;
 import com.google.crypto.tink.proto.Keyset;
 import com.google.crypto.tink.proto.KeysetInfo;
+import com.google.crypto.tink.proto.OutputPrefixType;
 import com.google.crypto.tink.tinkkey.KeyAccess;
 import com.google.crypto.tink.tinkkey.KeyHandle;
 import com.google.crypto.tink.tinkkey.internal.InternalKeyHandle;
 import com.google.crypto.tink.tinkkey.internal.ProtoKey;
+import com.google.errorprone.annotations.Immutable;
 import com.google.protobuf.ByteString;
 import com.google.protobuf.ExtensionRegistryLite;
 import com.google.protobuf.InvalidProtocolBufferException;
@@ -33,6 +39,7 @@
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
+import javax.annotation.Nullable;
 
 /**
  * A KeysetHandle provides abstracted access to {@link Keyset}, to limit the exposure of actual
@@ -45,6 +52,113 @@
  * @since 1.0.0
  */
 public final class KeysetHandle {
+  /**
+   * Represents a single entry in a keyset.
+   *
+   * <p>An entry in a keyset consists of a key, its ID, and the {@link KeyStatus}. In addition,
+   * there is one key marked as a primary.
+   *
+   * <p>The ID should be considered unique (though currently Tink still accepts keysets with
+   * repeated IDs). The {@code KeyStatus} tells Tink whether the key should still be used or not.
+   * There should always be exactly one key which is marked as a primary, however, at the moment
+   * Tink still accepts keysets which have none. This will be changed in the future.
+   */
+  @Alpha
+  @Immutable
+  public static final class Entry {
+    private Entry(Key key, KeyStatus keyStatus, int id, boolean isPrimary) {
+      this.key = key;
+      this.keyStatus = keyStatus;
+      this.id = id;
+      this.isPrimary = isPrimary;
+    }
+
+    private final Key key;
+    private final KeyStatus keyStatus;
+    private final int id;
+    private final boolean isPrimary;
+    /**
+     * May return an internal class {@link com.google.crypto.tink.internal.LegacyProtoKey} in case
+     * there is no implementation of the corresponding key class yet.
+     */
+    public Key getKey() {
+      return key;
+    }
+
+    public KeyStatus getStatus() {
+      return keyStatus;
+    }
+
+    public int getId() {
+      return id;
+    }
+    /**
+     * Guaranteed to be true in exactly one entry.
+     *
+     * <p>Note: currently this may be false for all entries, since it is possible that keysets are
+     * parsed without a primary. In the future, such keysets will be rejected when the keyset is
+     * parsed.
+     */
+    public boolean isPrimary() {
+      return isPrimary;
+    }
+  }
+
+  private static KeyStatus parseStatus(KeyStatusType in) throws GeneralSecurityException {
+    switch (in) {
+      case ENABLED:
+        return KeyStatus.ENABLED;
+      case DISABLED:
+        return KeyStatus.DISABLED;
+      case DESTROYED:
+        return KeyStatus.DESTROYED;
+      default:
+        throw new GeneralSecurityException("Unknown key status");
+    }
+  }
+
+  private KeysetHandle.Entry entryByIndex(int i) {
+    Keyset.Key protoKey = keyset.getKey(i);
+    int id = protoKey.getKeyId();
+
+    @Nullable
+    Integer idRequirement = protoKey.getOutputPrefixType() == OutputPrefixType.RAW ? null : id;
+    ProtoKeySerialization protoKeySerialization;
+    try {
+      protoKeySerialization =
+          ProtoKeySerialization.create(
+              protoKey.getKeyData().getTypeUrl(),
+              protoKey.getKeyData().getValue(),
+              protoKey.getKeyData().getKeyMaterialType(),
+              protoKey.getOutputPrefixType(),
+              idRequirement);
+    } catch (GeneralSecurityException e) {
+      // Cannot happen -- this only happens if the idRequirement doesn't match OutputPrefixType
+      throw new IllegalStateException("Creating a protokey serialization failed", e);
+    }
+    Key key;
+    try {
+      key =
+          MutableSerializationRegistry.globalInstance()
+              .parseKey(protoKeySerialization, InsecureSecretKeyAccess.get());
+    } catch (GeneralSecurityException e) {
+      try {
+        key = new LegacyProtoKey(protoKeySerialization, InsecureSecretKeyAccess.get());
+      } catch (GeneralSecurityException e2) {
+        // Cannot happen -- this only throws if we have no access.
+        throw new IllegalStateException("Creating a LegacyProtoKey failed", e2);
+      }
+    }
+    KeyStatus status;
+    try {
+      status = parseStatus(protoKey.getStatus());
+    } catch (GeneralSecurityException e) {
+      // Possible if a status is wrongly set
+      throw new IllegalStateException("Parsing a status failed", e);
+    }
+    return new KeysetHandle.Entry(key, status, id, id == keyset.getPrimaryKeyId());
+  }
+
   private final Keyset keyset;
 
   private KeysetHandle(Keyset keyset) {
@@ -60,11 +174,54 @@
     return new KeysetHandle(keyset);
   }
 
-  /** @return the actual keyset data. */
+  /**
+   * @return the actual keyset data.
+   */
   Keyset getKeyset() {
     return keyset;
   }
 
+  /**
+   * Returns the unique entry where isPrimary() = true and getStatus() = ENABLED.
+   *
+   * <p>Note: currently this may throw IllegalStateException, since it is possible that keysets are
+   * parsed without a primary. In the future, such keysets will be rejected when the keyset is
+   * parsed.
+   */
+  public KeysetHandle.Entry getPrimary() {
+    for (int i = 0; i < keyset.getKeyCount(); ++i) {
+      if (keyset.getKey(i).getKeyId() == keyset.getPrimaryKeyId()) {
+        Entry result = entryByIndex(i);
+        if (result.getStatus() != KeyStatus.ENABLED) {
+          throw new IllegalStateException("Keyset has primary which isn't enabled");
+        }
+        return result;
+      }
+    }
+    throw new IllegalStateException("Keyset has no primary");
+  }
+
+  /** Returns the size of this keyset. */
+  public int size() {
+    return keyset.getKeyCount();
+  }
+
+  /**
+   * Returns the entry at index i. The order is preserved and depends on the order at which the
+   * entries were inserted when the KeysetHandle was built.
+   *
+   * <p>Currently, this may throw "IllegalStateException" in case the status entry of the Key in the
+   * keyset was wrongly set. In the future, Tink will throw at parsing time in this case.
+   *
+   * @throws IndexOutOfBoundsException if i < 0 or i >= size();
+   */
+  public KeysetHandle.Entry getAt(int i) {
+    if (i < 0 || i >= size()) {
+      throw new IndexOutOfBoundsException("Invalid index " + i + " for keyset of size " + size());
+    }
+    return entryByIndex(i);
+  }
+
   /** Returns the keyset data as a list of {@link KeyHandle}s. */
   public List<KeyHandle> getKeys() {
     ArrayList<KeyHandle> result = new ArrayList<>();
diff --git a/src/test/java/com/google/crypto/tink/BUILD.bazel b/src/test/java/com/google/crypto/tink/BUILD.bazel
index c3d37d1..1c27792 100644
--- a/src/test/java/com/google/crypto/tink/BUILD.bazel
+++ b/src/test/java/com/google/crypto/tink/BUILD.bazel
@@ -281,6 +281,9 @@
         "//src/main/java/com/google/crypto/tink:binary_keyset_writer",
         "//src/main/java/com/google/crypto/tink:cleartext_keyset_handle",
         "//src/main/java/com/google/crypto/tink:config",
+        "//src/main/java/com/google/crypto/tink:key",
+        "//src/main/java/com/google/crypto/tink:key_format",
+        "//src/main/java/com/google/crypto/tink:key_status",
         "//src/main/java/com/google/crypto/tink:key_template",
         "//src/main/java/com/google/crypto/tink:key_templates",
         "//src/main/java/com/google/crypto/tink:keyset_reader",
@@ -292,9 +295,14 @@
         "//src/main/java/com/google/crypto/tink:public_key_verify",
         "//src/main/java/com/google/crypto/tink:registry",
         "//src/main/java/com/google/crypto/tink:registry_cluster",
+        "//src/main/java/com/google/crypto/tink:secret_key_access",
         "//src/main/java/com/google/crypto/tink/aead:aes_eax_key_manager",
         "//src/main/java/com/google/crypto/tink/config:tink_config",
+        "//src/main/java/com/google/crypto/tink/internal:key_parser",
         "//src/main/java/com/google/crypto/tink/internal:key_status_type_proto_converter",
+        "//src/main/java/com/google/crypto/tink/internal:legacy_proto_key",
+        "//src/main/java/com/google/crypto/tink/internal:mutable_serialization_registry",
+        "//src/main/java/com/google/crypto/tink/internal:proto_key_serialization",
         "//src/main/java/com/google/crypto/tink/signature:public_key_sign_factory",
         "//src/main/java/com/google/crypto/tink/signature:public_key_verify_factory",
         "//src/main/java/com/google/crypto/tink/signature:signature_config",
@@ -306,7 +314,10 @@
         "//src/main/java/com/google/crypto/tink/tinkkey:key_handle",
         "//src/main/java/com/google/crypto/tink/tinkkey:secret_key_access",
         "//src/main/java/com/google/crypto/tink/tinkkey/internal:proto_key",
+        "//src/main/java/com/google/crypto/tink/util:bytes",
         "@com_google_protobuf//:protobuf_javalite",
+        "@maven//:com_google_code_findbugs_jsr305",
+        "@maven//:com_google_errorprone_error_prone_annotations",
         "@maven//:com_google_truth_truth",
         "@maven//:junit_junit",
     ],
diff --git a/src/test/java/com/google/crypto/tink/KeysetHandleTest.java b/src/test/java/com/google/crypto/tink/KeysetHandleTest.java
index 0708292..11b45a6 100644
--- a/src/test/java/com/google/crypto/tink/KeysetHandleTest.java
+++ b/src/test/java/com/google/crypto/tink/KeysetHandleTest.java
@@ -23,7 +23,11 @@
 import com.google.common.truth.Expect;
 import com.google.crypto.tink.aead.AesEaxKeyManager;
 import com.google.crypto.tink.config.TinkConfig;
+import com.google.crypto.tink.internal.KeyParser;
 import com.google.crypto.tink.internal.KeyStatusTypeProtoConverter;
+import com.google.crypto.tink.internal.LegacyProtoKey;
+import com.google.crypto.tink.internal.MutableSerializationRegistry;
+import com.google.crypto.tink.internal.ProtoKeySerialization;
 import com.google.crypto.tink.proto.AesEaxKey;
 import com.google.crypto.tink.proto.AesEaxKeyFormat;
 import com.google.crypto.tink.proto.EcdsaPrivateKey;
@@ -42,6 +46,9 @@
 import com.google.crypto.tink.tinkkey.KeyHandle;
 import com.google.crypto.tink.tinkkey.SecretKeyAccess;
 import com.google.crypto.tink.tinkkey.internal.ProtoKey;
+import com.google.crypto.tink.util.Bytes;
+import com.google.errorprone.annotations.Immutable;
+import com.google.protobuf.ByteString;
 import com.google.protobuf.ExtensionRegistryLite;
 import java.io.ByteArrayInputStream;
 import java.io.ByteArrayOutputStream;
@@ -51,6 +58,7 @@
 import java.util.Set;
 import java.util.TreeSet;
 import java.util.stream.Collectors;
+import javax.annotation.Nullable;
 import org.junit.BeforeClass;
 import org.junit.Rule;
 import org.junit.Test;
@@ -515,4 +523,209 @@
 
     assertThrows(GeneralSecurityException.class, ksh::primaryKey);
   }
+
+  @Test
+  public void testGetAt_singleKey_works() throws Exception {
+    Keyset keyset =
+        TestUtil.createKeyset(
+            TestUtil.createKey(
+                TestUtil.createHmacKeyData("01234567890123456".getBytes(UTF_8), 16),
+                42,
+                KeyStatusType.ENABLED,
+                OutputPrefixType.TINK));
+    KeysetHandle handle = KeysetHandle.fromKeyset(keyset);
+    assertThat(handle.size()).isEqualTo(1);
+    KeysetHandle.Entry entry = handle.getAt(0);
+    assertThat(entry.getId()).isEqualTo(42);
+    assertThat(entry.getStatus()).isEqualTo(KeyStatus.ENABLED);
+    assertThat(entry.isPrimary()).isTrue();
+    assertThat(entry.getKey().getClass()).isEqualTo(LegacyProtoKey.class);
+  }
+
+  @Test
+  public void testGetAt_multipleKeys_works() throws Exception {
+    Keyset.Key key1 =
+        TestUtil.createKey(
+            TestUtil.createHmacKeyData("01234567890123456".getBytes(UTF_8), 16),
+            42,
+            KeyStatusType.DISABLED,
+            OutputPrefixType.TINK);
+    Keyset.Key key2 =
+        TestUtil.createKey(
+            TestUtil.createHmacKeyData("abcdefghijklmnopq".getBytes(UTF_8), 32),
+            44,
+            KeyStatusType.ENABLED,
+            OutputPrefixType.CRUNCHY);
+    Keyset.Key key3 =
+        TestUtil.createKey(
+            TestUtil.createHmacKeyData("ABCDEFGHIJKLMNOPQ".getBytes(UTF_8), 32),
+            46,
+            KeyStatusType.DESTROYED,
+            OutputPrefixType.TINK);
+    Keyset keyset = TestUtil.createKeyset(key1, key2, key3);
+    KeysetHandle handle =
+        KeysetHandle.fromKeyset(Keyset.newBuilder(keyset).setPrimaryKeyId(44).build());
+
+    assertThat(handle.size()).isEqualTo(3);
+    assertThat(handle.getAt(0).getId()).isEqualTo(42);
+    assertThat(handle.getAt(0).getStatus()).isEqualTo(KeyStatus.DISABLED);
+    assertThat(handle.getAt(0).isPrimary()).isFalse();
+
+    assertThat(handle.getAt(1).getId()).isEqualTo(44);
+    assertThat(handle.getAt(1).getStatus()).isEqualTo(KeyStatus.ENABLED);
+    assertThat(handle.getAt(1).isPrimary()).isTrue();
+
+    assertThat(handle.getAt(2).getId()).isEqualTo(46);
+    assertThat(handle.getAt(2).getStatus()).isEqualTo(KeyStatus.DESTROYED);
+    assertThat(handle.getAt(2).isPrimary()).isFalse();
+  }
+
+  @Test
+  public void testPrimary_multipleKeys_works() throws Exception {
+    Keyset.Key key1 =
+        TestUtil.createKey(
+            TestUtil.createHmacKeyData("01234567890123456".getBytes(UTF_8), 16),
+            42,
+            KeyStatusType.ENABLED,
+            OutputPrefixType.TINK);
+    Keyset.Key key2 =
+        TestUtil.createKey(
+            TestUtil.createHmacKeyData("abcdefghijklmnopq".getBytes(UTF_8), 32),
+            44,
+            KeyStatusType.ENABLED,
+            OutputPrefixType.CRUNCHY);
+    Keyset.Key key3 =
+        TestUtil.createKey(
+            TestUtil.createHmacKeyData("ABCDEFGHIJKLMNOPQ".getBytes(UTF_8), 32),
+            46,
+            KeyStatusType.ENABLED,
+            OutputPrefixType.TINK);
+    Keyset keyset = TestUtil.createKeyset(key1, key2, key3);
+    KeysetHandle handle =
+        KeysetHandle.fromKeyset(Keyset.newBuilder(keyset).setPrimaryKeyId(44).build());
+    KeysetHandle.Entry primary = handle.getPrimary();
+    assertThat(primary.getId()).isEqualTo(44);
+    assertThat(primary.getStatus()).isEqualTo(KeyStatus.ENABLED);
+    assertThat(primary.isPrimary()).isTrue();
+  }
+
+  @Test
+  public void testGetPrimary_noPrimary_throws() throws Exception {
+    Keyset.Key key1 =
+        TestUtil.createKey(
+            TestUtil.createHmacKeyData("01234567890123456".getBytes(UTF_8), 16),
+            42,
+            KeyStatusType.ENABLED,
+            OutputPrefixType.TINK);
+    Keyset keyset = TestUtil.createKeyset(key1);
+    KeysetHandle handle =
+        KeysetHandle.fromKeyset(Keyset.newBuilder(keyset).setPrimaryKeyId(77).build());
+
+    assertThrows(IllegalStateException.class, handle::getPrimary);
+  }
+
+  @Test
+  public void testGetPrimary_disabledPrimary_throws() throws Exception {
+    Keyset.Key key1 =
+        TestUtil.createKey(
+            TestUtil.createHmacKeyData("01234567890123456".getBytes(UTF_8), 16),
+            42,
+            KeyStatusType.DISABLED,
+            OutputPrefixType.TINK);
+    Keyset keyset = TestUtil.createKeyset(key1);
+    KeysetHandle handle =
+        KeysetHandle.fromKeyset(Keyset.newBuilder(keyset).setPrimaryKeyId(16).build());
+
+    assertThrows(IllegalStateException.class, handle::getPrimary);
+  }
+
+  @Test
+  public void testGetAt_indexOutOfBounds_throws() throws Exception {
+    Keyset.Key key1 =
+        TestUtil.createKey(
+            TestUtil.createHmacKeyData("01234567890123456".getBytes(UTF_8), 16),
+            42,
+            KeyStatusType.ENABLED,
+            OutputPrefixType.TINK);
+    KeysetHandle handle = KeysetHandle.fromKeyset(TestUtil.createKeyset(key1));
+
+    assertThrows(IndexOutOfBoundsException.class, () -> handle.getAt(-1));
+    assertThrows(IndexOutOfBoundsException.class, () -> handle.getAt(1));
+  }
+
+  @Test
+  public void testGetAt_wrongStatus_throws() throws Exception {
+    Keyset.Key key1 =
+        TestUtil.createKey(
+            TestUtil.createHmacKeyData("01234567890123456".getBytes(UTF_8), 16),
+            42,
+            KeyStatusType.UNKNOWN_STATUS,
+            OutputPrefixType.TINK);
+    KeysetHandle handle = KeysetHandle.fromKeyset(TestUtil.createKeyset(key1));
+
+    assertThrows(IllegalStateException.class, () -> handle.getAt(0));
+  }
+
+  @Immutable
+  private static final class TestKey extends Key {
+    private final ByteString keymaterial;
+
+    public TestKey(ByteString keymaterial) {
+      this.keymaterial = keymaterial;
+    }
+
+    @Override
+    public KeyFormat getKeyFormat() {
+      throw new UnsupportedOperationException("Not needed in test");
+    }
+
+    @Override
+    @Nullable
+    public Integer getIdRequirementOrNull() {
+      throw new UnsupportedOperationException("Not needed in test");
+    }
+
+    @Override
+    public boolean equalsKey(Key other) {
+      throw new UnsupportedOperationException("Not needed in test");
+    }
+
+    public ByteString getKeyMaterial() {
+      return keymaterial;
+    }
+  }
+
+  private static TestKey parseTestKey(
+      ProtoKeySerialization serialization,
+      @Nullable com.google.crypto.tink.SecretKeyAccess access) {
+    return new TestKey(serialization.getValue());
+  }
+
+  /**
+   * Tests that key parsing via the serialization registry works as expected.
+   *
+   * <p>NOTE: This adds a parser to the MutableSerializationRegistry, which no other test uses.
+   */
+  @Test
+  public void testKeysAreParsed() throws Exception {
+    ByteString value = ByteString.copyFromUtf8("some value");
+    // NOTE: This adds a parser to the MutableSerializationRegistry, which no other test uses.
+    MutableSerializationRegistry.globalInstance()
+        .registerKeyParser(
+            KeyParser.create(
+                KeysetHandleTest::parseTestKey,
+                Bytes.copyFrom("testKeyTypeUrl".getBytes(UTF_8)),
+                ProtoKeySerialization.class));
+    Keyset keyset =
+        Keyset.newBuilder()
+            .setPrimaryKeyId(1)
+            .addKey(
+                Keyset.Key.newBuilder()
+                    .setKeyId(1)
+                    .setStatus(KeyStatusType.ENABLED)
+                    .setKeyData(KeyData.newBuilder().setTypeUrl("testKeyTypeUrl").setValue(value)))
+            .build();
+    KeysetHandle handle = KeysetHandle.fromKeyset(keyset);
+    assertThat(((TestKey) handle.getPrimary().getKey()).getKeyMaterial()).isEqualTo(value);
+  }
 }