// Copyright 2023 Google LLC
//
// 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 com.google.crypto.tink.aead;

import static com.google.common.truth.Truth.assertThat;
import static com.google.crypto.tink.internal.testing.Asserts.assertEqualWhenValueParsed;
import static org.junit.Assert.assertThrows;

import com.google.crypto.tink.Key;
import com.google.crypto.tink.Parameters;
import com.google.crypto.tink.aead.internal.AesGcmSivProtoSerialization;
import com.google.crypto.tink.internal.MutableSerializationRegistry;
import com.google.crypto.tink.internal.ProtoKeySerialization;
import com.google.crypto.tink.internal.ProtoParametersSerialization;
import com.google.crypto.tink.mac.MacConfig;
import com.google.crypto.tink.proto.AesCmacKeyFormat;
import com.google.crypto.tink.proto.AesCmacParams;
import com.google.crypto.tink.proto.AesCtrHmacAeadKeyFormat;
import com.google.crypto.tink.proto.AesCtrKeyFormat;
import com.google.crypto.tink.proto.AesCtrParams;
import com.google.crypto.tink.proto.AesEaxKeyFormat;
import com.google.crypto.tink.proto.AesEaxParams;
import com.google.crypto.tink.proto.AesGcmKeyFormat;
import com.google.crypto.tink.proto.AesGcmSivKeyFormat;
import com.google.crypto.tink.proto.HashType;
import com.google.crypto.tink.proto.HmacKeyFormat;
import com.google.crypto.tink.proto.HmacParams;
import com.google.crypto.tink.proto.KeyData.KeyMaterialType;
import com.google.crypto.tink.proto.KeyTemplate;
import com.google.crypto.tink.proto.KmsEnvelopeAeadKey;
import com.google.crypto.tink.proto.KmsEnvelopeAeadKeyFormat;
import com.google.crypto.tink.proto.OutputPrefixType;
import java.security.GeneralSecurityException;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;

@RunWith(JUnit4.class)
public final class LegacyKmsEnvelopeAeadProtoSerializationTest {
  private static final AeadParameters CHACHA20POLY1305_PARAMETERS =
      ChaCha20Poly1305Parameters.create(ChaCha20Poly1305Parameters.Variant.NO_PREFIX);

  private static final KeyTemplate CHACHA20POLY1305_RAW_TEMPLATE =
      KeyTemplate.newBuilder()
          .setTypeUrl("type.googleapis.com/google.crypto.tink.ChaCha20Poly1305Key")
          .setOutputPrefixType(OutputPrefixType.RAW)
          .build();

  private static final String TYPE_URL =
      "type.googleapis.com/google.crypto.tink.KmsEnvelopeAeadKey";

  private static final MutableSerializationRegistry registry = new MutableSerializationRegistry();

  @BeforeClass
  public static void setUp() throws Exception {
    MacConfig.register();
    AeadConfig.register();
    LegacyKmsEnvelopeAeadProtoSerialization.register(registry);
    // Also register the AesGcmSivProtoSerialization if we don't have conscrypt.
    // We anyhow only want to parse and serialize.
    AesGcmSivProtoSerialization.register();
  }

  @Test
  public void registerTwice() throws Exception {
    MutableSerializationRegistry registry = new MutableSerializationRegistry();
    LegacyKmsAeadProtoSerialization.register(registry);
    LegacyKmsAeadProtoSerialization.register(registry);
  }

  @Test
  public void serializeParseParameters_aesGcm_works() throws Exception {
    LegacyKmsEnvelopeAeadParameters parameters =
        LegacyKmsEnvelopeAeadParameters.builder()
            .setKekUri("someOtherKeyUri")
            .setDekParsingStrategy(
                LegacyKmsEnvelopeAeadParameters.DekParsingStrategy.ASSUME_AES_GCM)
            .setDekParametersForNewKeys(
                AesGcmParameters.builder()
                    .setIvSizeBytes(12)
                    .setKeySizeBytes(16)
                    .setTagSizeBytes(16)
                    .setVariant(AesGcmParameters.Variant.NO_PREFIX)
                    .build())
            .build();

    ProtoParametersSerialization serialization =
        ProtoParametersSerialization.create(
            TYPE_URL,
            OutputPrefixType.RAW,
            KmsEnvelopeAeadKeyFormat.newBuilder()
                .setKekUri("someOtherKeyUri")
                .setDekTemplate(
                    KeyTemplate.newBuilder()
                        .setTypeUrl("type.googleapis.com/google.crypto.tink.AesGcmKey")
                        .setValue(
                            AesGcmKeyFormat.newBuilder().setKeySize(16).build().toByteString())
                        .setOutputPrefixType(OutputPrefixType.RAW)
                        .build())
                .build());

    ProtoParametersSerialization serialized =
        registry.serializeParameters(parameters, ProtoParametersSerialization.class);
    assertEqualWhenValueParsed(KmsEnvelopeAeadKeyFormat.parser(), serialized, serialization);

    Parameters parsed = registry.parseParameters(serialization);
    assertThat(parsed).isEqualTo(parameters);
  }

  @Test
  public void serializeParseParameters_xChaCha20Poly1305_works() throws Exception {
    LegacyKmsEnvelopeAeadParameters parameters =
        LegacyKmsEnvelopeAeadParameters.builder()
            .setKekUri("someOtherKeyUriForAnXChaChaKey")
            .setDekParsingStrategy(
                LegacyKmsEnvelopeAeadParameters.DekParsingStrategy.ASSUME_XCHACHA20POLY1305)
            .setDekParametersForNewKeys(XChaCha20Poly1305Parameters.create())
            .build();

    ProtoParametersSerialization serialization =
        ProtoParametersSerialization.create(
            TYPE_URL,
            OutputPrefixType.RAW,
            KmsEnvelopeAeadKeyFormat.newBuilder()
                .setKekUri("someOtherKeyUriForAnXChaChaKey")
                .setDekTemplate(
                    KeyTemplate.newBuilder()
                        .setTypeUrl("type.googleapis.com/google.crypto.tink.XChaCha20Poly1305Key")
                        .setOutputPrefixType(OutputPrefixType.RAW)
                        .build())
                .build());

    ProtoParametersSerialization serialized =
        registry.serializeParameters(parameters, ProtoParametersSerialization.class);
    assertEqualWhenValueParsed(KmsEnvelopeAeadKeyFormat.parser(), serialized, serialization);

    Parameters parsed = registry.parseParameters(serialization);
    assertThat(parsed).isEqualTo(parameters);
  }

  @Test
  public void serializeParseParameters_chaCha20Poly1305_works() throws Exception {
    LegacyKmsEnvelopeAeadParameters parameters =
        LegacyKmsEnvelopeAeadParameters.builder()
            .setKekUri("someArbitrarykeyUri723")
            .setDekParsingStrategy(
                LegacyKmsEnvelopeAeadParameters.DekParsingStrategy.ASSUME_CHACHA20POLY1305)
            .setDekParametersForNewKeys(CHACHA20POLY1305_PARAMETERS)
            .build();

    ProtoParametersSerialization serialization =
        ProtoParametersSerialization.create(
            TYPE_URL,
            OutputPrefixType.RAW,
            KmsEnvelopeAeadKeyFormat.newBuilder()
                .setKekUri("someArbitrarykeyUri723")
                .setDekTemplate(CHACHA20POLY1305_RAW_TEMPLATE)
                .build());

    ProtoParametersSerialization serialized =
        registry.serializeParameters(parameters, ProtoParametersSerialization.class);
    assertEqualWhenValueParsed(KmsEnvelopeAeadKeyFormat.parser(), serialized, serialization);

    Parameters parsed = registry.parseParameters(serialization);
    assertThat(parsed).isEqualTo(parameters);
  }

  @Test
  public void serializeParseParameters_aesCtrHmac_works() throws Exception {
    LegacyKmsEnvelopeAeadParameters parameters =
        LegacyKmsEnvelopeAeadParameters.builder()
            .setKekUri("someEaxOtherKeyUri")
            .setDekParsingStrategy(
                LegacyKmsEnvelopeAeadParameters.DekParsingStrategy.ASSUME_AES_CTR_HMAC)
            .setDekParametersForNewKeys(
                AesCtrHmacAeadParameters.builder()
                    .setAesKeySizeBytes(16)
                    .setHmacKeySizeBytes(32)
                    .setTagSizeBytes(32)
                    .setIvSizeBytes(16)
                    .setHashType(AesCtrHmacAeadParameters.HashType.SHA256)
                    .setVariant(AesCtrHmacAeadParameters.Variant.NO_PREFIX)
                    .build())
            .build();

    AesCtrKeyFormat aesCtrKeyFormat =
        AesCtrKeyFormat.newBuilder()
            .setParams(AesCtrParams.newBuilder().setIvSize(16).build())
            .setKeySize(16)
            .build();
    HmacKeyFormat hmacKeyFormat =
        HmacKeyFormat.newBuilder()
            .setParams(HmacParams.newBuilder().setHash(HashType.SHA256).setTagSize(32).build())
            .setKeySize(32)
            .build();
    AesCtrHmacAeadKeyFormat format =
        AesCtrHmacAeadKeyFormat.newBuilder()
            .setAesCtrKeyFormat(aesCtrKeyFormat)
            .setHmacKeyFormat(hmacKeyFormat)
            .build();

    ProtoParametersSerialization serialization =
        ProtoParametersSerialization.create(
            TYPE_URL,
            OutputPrefixType.RAW,
            KmsEnvelopeAeadKeyFormat.newBuilder()
                .setKekUri("someEaxOtherKeyUri")
                .setDekTemplate(
                    KeyTemplate.newBuilder()
                        .setTypeUrl("type.googleapis.com/google.crypto.tink.AesCtrHmacAeadKey")
                        .setOutputPrefixType(OutputPrefixType.RAW)
                        .setValue(format.toByteString())
                        .build())
                .build());
    Parameters parsed = registry.parseParameters(serialization);
    assertThat(parsed).isEqualTo(parameters);

    ProtoParametersSerialization serialized =
        registry.serializeParameters(parameters, ProtoParametersSerialization.class);
    assertEqualWhenValueParsed(KmsEnvelopeAeadKeyFormat.parser(), serialized, serialization);
  }

  @Test
  public void serializeParseParameters_aesEax_works() throws Exception {
    LegacyKmsEnvelopeAeadParameters parameters =
        LegacyKmsEnvelopeAeadParameters.builder()
            .setKekUri("someEaxOtherKeyUri")
            .setDekParsingStrategy(
                LegacyKmsEnvelopeAeadParameters.DekParsingStrategy.ASSUME_AES_EAX)
            .setDekParametersForNewKeys(
                AesEaxParameters.builder()
                    .setIvSizeBytes(12)
                    .setKeySizeBytes(16)
                    .setTagSizeBytes(16)
                    .setVariant(AesEaxParameters.Variant.NO_PREFIX)
                    .build())
            .build();

    ProtoParametersSerialization serialization =
        ProtoParametersSerialization.create(
            TYPE_URL,
            OutputPrefixType.RAW,
            KmsEnvelopeAeadKeyFormat.newBuilder()
                .setKekUri("someEaxOtherKeyUri")
                .setDekTemplate(
                    KeyTemplate.newBuilder()
                        .setTypeUrl("type.googleapis.com/google.crypto.tink.AesEaxKey")
                        .setValue(
                            AesEaxKeyFormat.newBuilder()
                                .setKeySize(16)
                                .setParams(AesEaxParams.newBuilder().setIvSize(12))
                                .build()
                                .toByteString())
                        .setOutputPrefixType(OutputPrefixType.RAW)
                        .build())
                .build());

    ProtoParametersSerialization serialized =
        registry.serializeParameters(parameters, ProtoParametersSerialization.class);
    assertEqualWhenValueParsed(KmsEnvelopeAeadKeyFormat.parser(), serialized, serialization);

    Parameters parsed = registry.parseParameters(serialization);
    assertThat(parsed).isEqualTo(parameters);
  }

  @Test
  public void serializeParseParameters_aesGcmSiv_works() throws Exception {
    LegacyKmsEnvelopeAeadParameters parameters =
        LegacyKmsEnvelopeAeadParameters.builder()
            .setKekUri("someEaxOtherKeyUri")
            .setDekParsingStrategy(
                LegacyKmsEnvelopeAeadParameters.DekParsingStrategy.ASSUME_AES_GCM_SIV)
            .setDekParametersForNewKeys(
                AesGcmSivParameters.builder()
                    .setKeySizeBytes(16)
                    .setVariant(AesGcmSivParameters.Variant.NO_PREFIX)
                    .build())
            .build();

    ProtoParametersSerialization serialization =
        ProtoParametersSerialization.create(
            TYPE_URL,
            OutputPrefixType.RAW,
            KmsEnvelopeAeadKeyFormat.newBuilder()
                .setKekUri("someEaxOtherKeyUri")
                .setDekTemplate(
                    KeyTemplate.newBuilder()
                        .setTypeUrl("type.googleapis.com/google.crypto.tink.AesGcmSivKey")
                        .setValue(
                            AesGcmSivKeyFormat.newBuilder().setKeySize(16).build().toByteString())
                        .setOutputPrefixType(OutputPrefixType.RAW)
                        .build())
                .build());

    ProtoParametersSerialization serialized =
        registry.serializeParameters(parameters, ProtoParametersSerialization.class);
    assertEqualWhenValueParsed(KmsEnvelopeAeadKeyFormat.parser(), serialized, serialization);

    Parameters parsed = registry.parseParameters(serialization);
    assertThat(parsed).isEqualTo(parameters);
  }

  @Test
  public void serializeParseParameters_withTinkPrefix_works() throws Exception {
    LegacyKmsEnvelopeAeadParameters parameters =
        LegacyKmsEnvelopeAeadParameters.builder()
            .setVariant(LegacyKmsEnvelopeAeadParameters.Variant.TINK)
            .setKekUri("kekUri")
            .setDekParsingStrategy(
                LegacyKmsEnvelopeAeadParameters.DekParsingStrategy.ASSUME_AES_GCM)
            .setDekParametersForNewKeys(
                AesGcmParameters.builder()
                    .setIvSizeBytes(12)
                    .setKeySizeBytes(16)
                    .setTagSizeBytes(16)
                    .setVariant(AesGcmParameters.Variant.NO_PREFIX)
                    .build())
            .build();

    ProtoParametersSerialization serialization =
        ProtoParametersSerialization.create(
            TYPE_URL,
            OutputPrefixType.TINK,
            KmsEnvelopeAeadKeyFormat.newBuilder()
                .setKekUri("kekUri")
                .setDekTemplate(
                    KeyTemplate.newBuilder()
                        .setTypeUrl("type.googleapis.com/google.crypto.tink.AesGcmKey")
                        .setValue(
                            AesGcmKeyFormat.newBuilder().setKeySize(16).build().toByteString())
                        .setOutputPrefixType(OutputPrefixType.RAW)
                        .build())
                .build());

    ProtoParametersSerialization serialized =
        registry.serializeParameters(parameters, ProtoParametersSerialization.class);
    assertEqualWhenValueParsed(KmsEnvelopeAeadKeyFormat.parser(), serialized, serialization);

    Parameters parsed = registry.parseParameters(serialization);
    assertThat(parsed).isEqualTo(parameters);
  }

  @Test
  public void parseParameters_macTypeUrl_throws() throws Exception {
    ProtoParametersSerialization serialization =
        ProtoParametersSerialization.create(
            TYPE_URL,
            OutputPrefixType.RAW,
            KmsEnvelopeAeadKeyFormat.newBuilder()
                .setKekUri("someEaxOtherKeyUri")
                .setDekTemplate(
                    KeyTemplate.newBuilder()
                        .setTypeUrl("type.googleapis.com/google.crypto.tink.AesCmacParams")
                        .setValue(
                            AesCmacKeyFormat.newBuilder()
                                .setKeySize(32)
                                .setParams(AesCmacParams.newBuilder().setTagSize(16).build())
                                .build()
                                .toByteString())
                        .setOutputPrefixType(OutputPrefixType.RAW)
                        .build())
                .build());

    GeneralSecurityException thrown =
        assertThrows(GeneralSecurityException.class, () -> registry.parseParameters(serialization));
    // Check the message to ensure that the exception is not thrown when parsing the key template
    // but instead when computing the DekParsingStrategy from the class.
    assertThat(thrown).hasMessageThat().contains("Unsupported DEK parameters when");
  }

  /**
   * Tests that when parsing, the OutputPrefixType of the template in DekKeyTemplate is ignored and
   * RAW is used instead.
   */
  @Test
  public void parseParameters_dekOutputPrefixUnknown_isIgnored() throws Exception {
    LegacyKmsEnvelopeAeadParameters parameters =
        LegacyKmsEnvelopeAeadParameters.builder()
            .setKekUri("someEaxOtherKeyUri")
            .setDekParsingStrategy(
                LegacyKmsEnvelopeAeadParameters.DekParsingStrategy.ASSUME_XCHACHA20POLY1305)
            .setDekParametersForNewKeys(XChaCha20Poly1305Parameters.create())
            .build();

    ProtoParametersSerialization serialization =
        ProtoParametersSerialization.create(
            TYPE_URL,
            OutputPrefixType.RAW,
            KmsEnvelopeAeadKeyFormat.newBuilder()
                .setKekUri("someEaxOtherKeyUri")
                .setDekTemplate(
                    KeyTemplate.newBuilder()
                        .setTypeUrl("type.googleapis.com/google.crypto.tink.XChaCha20Poly1305Key")
                        .setOutputPrefixType(OutputPrefixType.UNKNOWN_PREFIX)
                        .build())
                .build());

    Parameters parsed = registry.parseParameters(serialization);
    assertThat(parsed).isEqualTo(parameters);
  }

  /**
   * Tests that when parsing, the OutputPrefixType of the template in DekKeyTemplate is ignored and
   * RAW is used instead.
   */
  @Test
  public void parseParameters_dekOutputPrefixTink_isIgnored() throws Exception {
    LegacyKmsEnvelopeAeadParameters parameters =
        LegacyKmsEnvelopeAeadParameters.builder()
            .setKekUri("someEaxOtherKeyUri")
            .setDekParsingStrategy(
                LegacyKmsEnvelopeAeadParameters.DekParsingStrategy.ASSUME_XCHACHA20POLY1305)
            .setDekParametersForNewKeys(XChaCha20Poly1305Parameters.create())
            .build();

    ProtoParametersSerialization serialization =
        ProtoParametersSerialization.create(
            TYPE_URL,
            OutputPrefixType.RAW,
            KmsEnvelopeAeadKeyFormat.newBuilder()
                .setKekUri("someEaxOtherKeyUri")
                .setDekTemplate(
                    KeyTemplate.newBuilder()
                        .setTypeUrl("type.googleapis.com/google.crypto.tink.XChaCha20Poly1305Key")
                        .setOutputPrefixType(OutputPrefixType.TINK)
                        .build())
                .build());

    Parameters parsed = registry.parseParameters(serialization);
    assertThat(parsed).isEqualTo(parameters);
  }

  @Test
  public void serializeParseKey_works() throws Exception {
    LegacyKmsEnvelopeAeadParameters parameters =
        LegacyKmsEnvelopeAeadParameters.builder()
            .setKekUri("someKeyUriForKeyTests")
            .setDekParsingStrategy(
                LegacyKmsEnvelopeAeadParameters.DekParsingStrategy.ASSUME_XCHACHA20POLY1305)
            .setDekParametersForNewKeys(XChaCha20Poly1305Parameters.create())
            .build();
    LegacyKmsEnvelopeAeadKey key = LegacyKmsEnvelopeAeadKey.create(parameters);

    KmsEnvelopeAeadKeyFormat format =
        KmsEnvelopeAeadKeyFormat.newBuilder()
            .setKekUri("someKeyUriForKeyTests")
            .setDekTemplate(
                KeyTemplate.newBuilder()
                    .setTypeUrl("type.googleapis.com/google.crypto.tink.XChaCha20Poly1305Key")
                    .setOutputPrefixType(OutputPrefixType.RAW))
            .build();

    ProtoKeySerialization serialization =
        ProtoKeySerialization.create(
            TYPE_URL,
            KmsEnvelopeAeadKey.newBuilder().setParams(format).build().toByteString(),
            KeyMaterialType.REMOTE,
            OutputPrefixType.RAW,
            /* idRequirement= */ null);

    ProtoKeySerialization serialized =
        registry.serializeKey(key, ProtoKeySerialization.class, /* access= */ null);
    assertEqualWhenValueParsed(KmsEnvelopeAeadKey.parser(), serialized, serialization);

    Key parsed = registry.parseKey(serialization, /* access= */ null);
    assertThat(parsed.equalsKey(key)).isTrue();
  }

  @Test
  public void serializeParseKeyWithTinkPrefix_works() throws Exception {
    LegacyKmsEnvelopeAeadParameters parameters =
        LegacyKmsEnvelopeAeadParameters.builder()
            .setVariant(LegacyKmsEnvelopeAeadParameters.Variant.TINK)
            .setKekUri("someKeyUriForKeyTests")
            .setDekParsingStrategy(
                LegacyKmsEnvelopeAeadParameters.DekParsingStrategy.ASSUME_XCHACHA20POLY1305)
            .setDekParametersForNewKeys(XChaCha20Poly1305Parameters.create())
            .build();
    LegacyKmsEnvelopeAeadKey key =
        LegacyKmsEnvelopeAeadKey.create(parameters, /* idRequirement= */ 0x11223344);

    KmsEnvelopeAeadKeyFormat format =
        KmsEnvelopeAeadKeyFormat.newBuilder()
            .setKekUri("someKeyUriForKeyTests")
            .setDekTemplate(
                KeyTemplate.newBuilder()
                    .setTypeUrl("type.googleapis.com/google.crypto.tink.XChaCha20Poly1305Key")
                    .setOutputPrefixType(OutputPrefixType.RAW))
            .build();

    ProtoKeySerialization serialization =
        ProtoKeySerialization.create(
            TYPE_URL,
            KmsEnvelopeAeadKey.newBuilder().setParams(format).build().toByteString(),
            KeyMaterialType.REMOTE,
            OutputPrefixType.TINK,
            /* idRequirement= */ 0x11223344);

    ProtoKeySerialization serialized =
        registry.serializeKey(key, ProtoKeySerialization.class, /* access= */ null);
    assertEqualWhenValueParsed(KmsEnvelopeAeadKey.parser(), serialized, serialization);

    Key parsed = registry.parseKey(serialization, /* access= */ null);
    assertThat(parsed.equalsKey(key)).isTrue();
  }

  @Test
  public void parseKey_wrongVersion_throws() throws Exception {
    KmsEnvelopeAeadKeyFormat format =
        KmsEnvelopeAeadKeyFormat.newBuilder()
            .setKekUri("someKeyUriForKeyTests")
            .setDekTemplate(
                KeyTemplate.newBuilder()
                    .setTypeUrl("type.googleapis.com/google.crypto.tink.XChaCha20Poly1305Key")
                    .setOutputPrefixType(OutputPrefixType.RAW))
            .build();

    ProtoKeySerialization serialization =
        ProtoKeySerialization.create(
            TYPE_URL,
            KmsEnvelopeAeadKey.newBuilder().setVersion(1).setParams(format).build().toByteString(),
            KeyMaterialType.REMOTE,
            OutputPrefixType.RAW,
            /* idRequirement= */ null);

    assertThrows(
        GeneralSecurityException.class, () -> registry.parseKey(serialization, /* access= */ null));
  }

  @Test
  public void parseKey_invalidOutputPrefixType_throws() throws Exception {
    KmsEnvelopeAeadKeyFormat format =
        KmsEnvelopeAeadKeyFormat.newBuilder()
            .setKekUri("someKeyUriForKeyTests")
            .setDekTemplate(
                KeyTemplate.newBuilder()
                    .setTypeUrl("type.googleapis.com/google.crypto.tink.XChaCha20Poly1305Key")
                    .setOutputPrefixType(OutputPrefixType.RAW))
            .build();

    ProtoKeySerialization serialization =
        ProtoKeySerialization.create(
            TYPE_URL,
            KmsEnvelopeAeadKey.newBuilder().setParams(format).build().toByteString(),
            KeyMaterialType.REMOTE,
            OutputPrefixType.LEGACY,
            /* idRequirement= */ 123);

    assertThrows(
        GeneralSecurityException.class, () -> registry.parseKey(serialization, /* access= */ null));
  }
}
