blob: f2c7c1bf048f426ea1504fe14789796e0d07d8cd [file] [log] [blame]
// Copyright 2022 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.internal;
import static com.google.common.truth.Truth.assertThat;
import static java.nio.charset.StandardCharsets.UTF_8;
import com.google.crypto.tink.InsecureSecretKeyAccess;
import com.google.crypto.tink.Key;
import com.google.crypto.tink.Parameters;
import com.google.crypto.tink.SecretKeyAccess;
import com.google.crypto.tink.proto.KeyData.KeyMaterialType;
import com.google.crypto.tink.proto.OutputPrefixType;
import com.google.crypto.tink.proto.TestProto;
import com.google.crypto.tink.util.Bytes;
import com.google.errorprone.annotations.Immutable;
import com.google.protobuf.ByteString;
import java.security.GeneralSecurityException;
import javax.annotation.Nullable;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
/**
* Thread safety tests for {@link MutableSerializationRegistry}.
*
* <p>We repeat the main tests in SerializationRegistryTest. There really shouldn't be both classes,
* but currently this is what we need, and the other is what we should have.
*/
@RunWith(JUnit4.class)
public final class MutableSerializationRegistryTest {
private static final SecretKeyAccess ACCESS = InsecureSecretKeyAccess.get();
private static final Bytes A_1 = Bytes.copyFrom("0".getBytes(UTF_8));
private static final Bytes A_2 = Bytes.copyFrom("1".getBytes(UTF_8));
private static final Bytes B_1 = Bytes.copyFrom("1".getBytes(UTF_8));
private static final Bytes B_2 = Bytes.copyFrom("2".getBytes(UTF_8));
@Immutable
private static final class TestParameters1 extends Parameters {
@Override
public boolean hasIdRequirement() {
return false;
}
}
@Immutable
private static final class TestParameters2 extends Parameters {
@Override
public boolean hasIdRequirement() {
return false;
}
}
@Immutable
private static final class TestKey1 extends Key {
@Override
public Parameters getParameters() {
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");
}
}
@Immutable
private static final class TestKey2 extends Key {
@Override
public Parameters getParameters() {
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");
}
}
@Immutable
private static final class TestSerializationA implements Serialization {
public TestSerializationA(Bytes objectIdentifier) {
this.objectIdentifier = objectIdentifier;
}
private final Bytes objectIdentifier;
@Override
public Bytes getObjectIdentifier() {
return objectIdentifier;
}
}
@Immutable
private static final class TestSerializationB implements Serialization {
public TestSerializationB(Bytes objectIdentifier) {
this.objectIdentifier = objectIdentifier;
}
private final Bytes objectIdentifier;
@Override
public Bytes getObjectIdentifier() {
return objectIdentifier;
}
}
private static TestSerializationA serializeKey1ToA(TestKey1 key, @Nullable SecretKeyAccess access)
throws GeneralSecurityException {
SecretKeyAccess.requireAccess(access);
return new TestSerializationA(A_1);
}
private static TestSerializationA serializeKey2ToA(TestKey2 key, @Nullable SecretKeyAccess access)
throws GeneralSecurityException {
SecretKeyAccess.requireAccess(access);
return new TestSerializationA(A_2);
}
private static TestSerializationB serializeKey1ToB(TestKey1 key, @Nullable SecretKeyAccess access)
throws GeneralSecurityException {
SecretKeyAccess.requireAccess(access);
return new TestSerializationB(B_1);
}
private static TestSerializationB serializeKey2ToB(TestKey2 key, @Nullable SecretKeyAccess access)
throws GeneralSecurityException {
SecretKeyAccess.requireAccess(access);
return new TestSerializationB(B_2);
}
private static Key parseAToKey1(
TestSerializationA serialization, @Nullable SecretKeyAccess access)
throws GeneralSecurityException {
if (!A_1.equals(serialization.getObjectIdentifier())) {
throw new GeneralSecurityException("Wrong object identifier");
}
SecretKeyAccess.requireAccess(access);
return new TestKey1();
}
private static Key parseAToKey2(
TestSerializationA serialization, @Nullable SecretKeyAccess access)
throws GeneralSecurityException {
if (!A_2.equals(serialization.getObjectIdentifier())) {
throw new GeneralSecurityException("Wrong object identifier");
}
SecretKeyAccess.requireAccess(access);
return new TestKey2();
}
private static Key parseBToKey1(
TestSerializationB serialization, @Nullable SecretKeyAccess access)
throws GeneralSecurityException {
if (!B_1.equals(serialization.getObjectIdentifier())) {
throw new GeneralSecurityException("Wrong object identifier");
}
SecretKeyAccess.requireAccess(access);
return new TestKey1();
}
private static Key parseBToKey2(
TestSerializationB serialization, @Nullable SecretKeyAccess access)
throws GeneralSecurityException {
if (!B_2.equals(serialization.getObjectIdentifier())) {
throw new GeneralSecurityException("Wrong object identifier");
}
SecretKeyAccess.requireAccess(access);
return new TestKey2();
}
// ======================================================================= Key serialization tests
@Test
public void test_registerAllSerializers_checkDispatch() throws Exception {
MutableSerializationRegistry registry = new MutableSerializationRegistry();
registry.registerKeySerializer(
KeySerializer.create(
MutableSerializationRegistryTest::serializeKey1ToA,
TestKey1.class,
TestSerializationA.class));
registry.registerKeySerializer(
KeySerializer.create(
MutableSerializationRegistryTest::serializeKey1ToB,
TestKey1.class,
TestSerializationB.class));
registry.registerKeySerializer(
KeySerializer.create(
MutableSerializationRegistryTest::serializeKey2ToA,
TestKey2.class,
TestSerializationA.class));
registry.registerKeySerializer(
KeySerializer.create(
MutableSerializationRegistryTest::serializeKey2ToB,
TestKey2.class,
TestSerializationB.class));
assertThat(
registry
.serializeKey(new TestKey1(), TestSerializationA.class, ACCESS)
.getObjectIdentifier())
.isEqualTo(A_1);
assertThat(
registry
.serializeKey(new TestKey2(), TestSerializationA.class, ACCESS)
.getObjectIdentifier())
.isEqualTo(A_2);
assertThat(
registry
.serializeKey(new TestKey1(), TestSerializationB.class, ACCESS)
.getObjectIdentifier())
.isEqualTo(B_1);
assertThat(
registry
.serializeKey(new TestKey2(), TestSerializationB.class, ACCESS)
.getObjectIdentifier())
.isEqualTo(B_2);
}
@Test
public void test_registerAllParsers_checkDispatch() throws Exception {
MutableSerializationRegistry registry = new MutableSerializationRegistry();
registry.registerKeyParser(
KeyParser.create(
MutableSerializationRegistryTest::parseAToKey1, A_1, TestSerializationA.class));
registry.registerKeyParser(
KeyParser.create(
MutableSerializationRegistryTest::parseBToKey1, B_1, TestSerializationB.class));
registry.registerKeyParser(
KeyParser.create(
MutableSerializationRegistryTest::parseAToKey2, A_2, TestSerializationA.class));
registry.registerKeyParser(
KeyParser.create(
MutableSerializationRegistryTest::parseBToKey2, B_2, TestSerializationB.class));
assertThat(registry.parseKey(new TestSerializationA(A_1), ACCESS)).isInstanceOf(TestKey1.class);
assertThat(registry.parseKey(new TestSerializationA(A_2), ACCESS)).isInstanceOf(TestKey2.class);
assertThat(registry.parseKey(new TestSerializationB(B_1), ACCESS)).isInstanceOf(TestKey1.class);
assertThat(registry.parseKey(new TestSerializationB(B_2), ACCESS)).isInstanceOf(TestKey2.class);
}
// ================================================================================================
// PARAMETERS TESTS
// ================================================================================================
private static TestSerializationA serializeParameters1ToA(TestParameters1 parameters)
throws GeneralSecurityException {
return new TestSerializationA(A_1);
}
private static TestSerializationA serializeParameters2ToA(TestParameters2 parameters)
throws GeneralSecurityException {
return new TestSerializationA(A_2);
}
private static TestSerializationB serializeParameters1ToB(TestParameters1 parameters)
throws GeneralSecurityException {
return new TestSerializationB(B_1);
}
private static TestSerializationB serializeParameters2ToB(TestParameters2 parameters)
throws GeneralSecurityException {
return new TestSerializationB(B_2);
}
private static Parameters parseAToParameters1(TestSerializationA serialization)
throws GeneralSecurityException {
if (!A_1.equals(serialization.getObjectIdentifier())) {
throw new GeneralSecurityException("Wrong object identifier");
}
return new TestParameters1();
}
private static Parameters parseAToParameters2(TestSerializationA serialization)
throws GeneralSecurityException {
if (!A_2.equals(serialization.getObjectIdentifier())) {
throw new GeneralSecurityException("Wrong object identifier");
}
return new TestParameters2();
}
private static Parameters parseBToParameters1(TestSerializationB serialization)
throws GeneralSecurityException {
if (!B_1.equals(serialization.getObjectIdentifier())) {
throw new GeneralSecurityException("Wrong object identifier");
}
return new TestParameters1();
}
private static Parameters parseBToParameters2(TestSerializationB serialization)
throws GeneralSecurityException {
if (!B_2.equals(serialization.getObjectIdentifier())) {
throw new GeneralSecurityException("Wrong object identifier");
}
return new TestParameters2();
}
@Test
public void test_registerAllParametersSerializers_checkDispatch() throws Exception {
MutableSerializationRegistry registry = new MutableSerializationRegistry();
registry.registerParametersSerializer(
ParametersSerializer.create(
MutableSerializationRegistryTest::serializeParameters1ToA,
TestParameters1.class,
TestSerializationA.class));
registry.registerParametersSerializer(
ParametersSerializer.create(
MutableSerializationRegistryTest::serializeParameters1ToB,
TestParameters1.class,
TestSerializationB.class));
registry.registerParametersSerializer(
ParametersSerializer.create(
MutableSerializationRegistryTest::serializeParameters2ToA,
TestParameters2.class,
TestSerializationA.class));
registry.registerParametersSerializer(
ParametersSerializer.create(
MutableSerializationRegistryTest::serializeParameters2ToB,
TestParameters2.class,
TestSerializationB.class));
assertThat(
registry
.serializeParameters(new TestParameters1(), TestSerializationA.class)
.getObjectIdentifier())
.isEqualTo(A_1);
assertThat(
registry
.serializeParameters(new TestParameters2(), TestSerializationA.class)
.getObjectIdentifier())
.isEqualTo(A_2);
assertThat(
registry
.serializeParameters(new TestParameters1(), TestSerializationB.class)
.getObjectIdentifier())
.isEqualTo(B_1);
assertThat(
registry
.serializeParameters(new TestParameters2(), TestSerializationB.class)
.getObjectIdentifier())
.isEqualTo(B_2);
}
@Test
public void test_registerAllParametersParsers_checkDispatch() throws Exception {
MutableSerializationRegistry registry = new MutableSerializationRegistry();
registry.registerParametersParser(
ParametersParser.create(
MutableSerializationRegistryTest::parseAToParameters1, A_1, TestSerializationA.class));
registry.registerParametersParser(
ParametersParser.create(
MutableSerializationRegistryTest::parseBToParameters1, B_1, TestSerializationB.class));
registry.registerParametersParser(
ParametersParser.create(
MutableSerializationRegistryTest::parseAToParameters2, A_2, TestSerializationA.class));
registry.registerParametersParser(
ParametersParser.create(
MutableSerializationRegistryTest::parseBToParameters2, B_2, TestSerializationB.class));
assertThat(registry.parseParameters(new TestSerializationA(A_1)))
.isInstanceOf(TestParameters1.class);
assertThat(registry.parseParameters(new TestSerializationA(A_2)))
.isInstanceOf(TestParameters2.class);
assertThat(registry.parseParameters(new TestSerializationB(B_1)))
.isInstanceOf(TestParameters1.class);
assertThat(registry.parseParameters(new TestSerializationB(B_2)))
.isInstanceOf(TestParameters2.class);
}
@Test
public void test_parseParametersWithLegacyFallback_testFallback() throws Exception {
MutableSerializationRegistry registry = new MutableSerializationRegistry();
ProtoParametersSerialization protoParameters =
ProtoParametersSerialization.create(
"typeUrlForTesting73107", OutputPrefixType.TINK, TestProto.getDefaultInstance());
Parameters parameters = registry.parseParametersWithLegacyFallback(protoParameters);
assertThat(parameters).isInstanceOf(LegacyProtoParameters.class);
LegacyProtoParameters legacyProtoParameters = (LegacyProtoParameters) parameters;
assertThat(legacyProtoParameters.getSerialization().getKeyTemplate().getTypeUrl())
.isEqualTo("typeUrlForTesting73107");
}
private static TestParameters1 parseParameters(ProtoParametersSerialization serialization)
throws GeneralSecurityException {
return new TestParameters1();
}
@Test
public void test_parseParametersWithLegacyFallback_testRegistered() throws Exception {
MutableSerializationRegistry registry = new MutableSerializationRegistry();
registry.registerParametersParser(
ParametersParser.create(
MutableSerializationRegistryTest::parseParameters,
Util.toBytesFromPrintableAscii("typeUrlForTesting98178"),
ProtoParametersSerialization.class));
ProtoParametersSerialization protoParameters =
ProtoParametersSerialization.create(
"typeUrlForTesting98178", OutputPrefixType.TINK, TestProto.getDefaultInstance());
Parameters parameters = registry.parseParametersWithLegacyFallback(protoParameters);
assertThat(parameters).isInstanceOf(TestParameters1.class);
}
@Test
public void test_parseKeyWithLegacyFallback_testFallback() throws Exception {
MutableSerializationRegistry registry = new MutableSerializationRegistry();
ProtoKeySerialization protoKey =
ProtoKeySerialization.create(
"typeUrlForTesting21125",
ByteString.EMPTY,
KeyMaterialType.SYMMETRIC,
OutputPrefixType.RAW,
/* idRequirement= */ null);
Key key = registry.parseKeyWithLegacyFallback(protoKey, InsecureSecretKeyAccess.get());
assertThat(key).isInstanceOf(LegacyProtoKey.class);
LegacyProtoKey legacyProtoKey = (LegacyProtoKey) key;
assertThat(legacyProtoKey.getSerialization(InsecureSecretKeyAccess.get()).getTypeUrl())
.isEqualTo("typeUrlForTesting21125");
}
private static TestKey1 parseKey(
ProtoKeySerialization serialization, @Nullable SecretKeyAccess access)
throws GeneralSecurityException {
return new TestKey1();
}
@Test
public void test_parseKeyWithLegacyFallback_testRegistered() throws Exception {
MutableSerializationRegistry registry = new MutableSerializationRegistry();
registry.registerKeyParser(
KeyParser.create(
MutableSerializationRegistryTest::parseKey,
Util.toBytesFromPrintableAscii("typeUrlForTesting18412"),
ProtoKeySerialization.class));
ProtoKeySerialization protoKey =
ProtoKeySerialization.create(
"typeUrlForTesting18412",
ByteString.EMPTY,
KeyMaterialType.SYMMETRIC,
OutputPrefixType.RAW,
/* idRequirement= */ null);
Key key = registry.parseKeyWithLegacyFallback(protoKey, InsecureSecretKeyAccess.get());
assertThat(key).isInstanceOf(TestKey1.class);
}
}