1 // Copyright 2023 Google LLC 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 // 15 //////////////////////////////////////////////////////////////////////////////// 16 17 package com.google.crypto.tink.internal; 18 19 import static com.google.common.truth.Truth.assertThat; 20 import static org.junit.Assert.assertThrows; 21 22 import com.google.crypto.tink.InsecureSecretKeyAccess; 23 import com.google.crypto.tink.Key; 24 import com.google.crypto.tink.Parameters; 25 import com.google.crypto.tink.proto.KeyData; 26 import com.google.crypto.tink.proto.KeyData.KeyMaterialType; 27 import com.google.crypto.tink.util.SecretBytes; 28 import com.google.errorprone.annotations.Immutable; 29 import com.google.protobuf.ByteString; 30 import java.security.GeneralSecurityException; 31 import javax.annotation.Nullable; 32 import org.junit.Test; 33 import org.junit.runner.RunWith; 34 import org.junit.runners.JUnit4; 35 36 /** Unit tests for {@link InternalConfiguration}. */ 37 @RunWith(JUnit4.class) 38 public class InternalConfigurationTest { 39 // Test classes which we can populate PrimitiveRegistry instances with. 40 @Immutable 41 private static final class TestKey1 extends Key { 42 @Override getParameters()43 public Parameters getParameters() { 44 throw new UnsupportedOperationException("Not needed in test"); 45 } 46 47 @Override 48 @Nullable getIdRequirementOrNull()49 public Integer getIdRequirementOrNull() { 50 return null; 51 } 52 53 @Override equalsKey(Key other)54 public boolean equalsKey(Key other) { 55 throw new UnsupportedOperationException("Not needed in test"); 56 } 57 } 58 59 @Immutable 60 private static final class TestKey2 extends Key { 61 @Override getParameters()62 public Parameters getParameters() { 63 throw new UnsupportedOperationException("Not needed in test"); 64 } 65 66 @Override 67 @Nullable getIdRequirementOrNull()68 public Integer getIdRequirementOrNull() { 69 throw new UnsupportedOperationException("Not needed in test"); 70 } 71 72 @Override equalsKey(Key other)73 public boolean equalsKey(Key other) { 74 throw new UnsupportedOperationException("Not needed in test"); 75 } 76 } 77 78 @Immutable 79 private static final class TestPrimitiveA { 80 81 private final Key key; 82 TestPrimitiveA()83 public TestPrimitiveA() { 84 this.key = null; 85 } 86 TestPrimitiveA(Key key)87 public TestPrimitiveA(Key key) { 88 this.key = key; 89 } 90 getKey()91 public Key getKey() { 92 return key; 93 } 94 } 95 96 @Immutable 97 private static final class TestPrimitiveB { TestPrimitiveB()98 public TestPrimitiveB() {} 99 } 100 101 @Immutable 102 private static final class TestWrapperA 103 implements PrimitiveWrapper<TestPrimitiveA, TestPrimitiveA> { 104 105 @Override wrap(final PrimitiveSet<TestPrimitiveA> primitives)106 public TestPrimitiveA wrap(final PrimitiveSet<TestPrimitiveA> primitives) { 107 return new TestPrimitiveA(); 108 } 109 110 @Override getPrimitiveClass()111 public Class<TestPrimitiveA> getPrimitiveClass() { 112 return TestPrimitiveA.class; 113 } 114 115 @Override getInputPrimitiveClass()116 public Class<TestPrimitiveA> getInputPrimitiveClass() { 117 return TestPrimitiveA.class; 118 } 119 } 120 121 @Immutable 122 private static final class TestWrapperB 123 implements PrimitiveWrapper<TestPrimitiveB, TestPrimitiveB> { 124 125 @Override wrap(final PrimitiveSet<TestPrimitiveB> primitives)126 public TestPrimitiveB wrap(final PrimitiveSet<TestPrimitiveB> primitives) { 127 return new TestPrimitiveB(); 128 } 129 130 @Override getPrimitiveClass()131 public Class<TestPrimitiveB> getPrimitiveClass() { 132 return TestPrimitiveB.class; 133 } 134 135 @Override getInputPrimitiveClass()136 public Class<TestPrimitiveB> getInputPrimitiveClass() { 137 return TestPrimitiveB.class; 138 } 139 } 140 getPrimitiveAKey1(TestKey1 key)141 private static TestPrimitiveA getPrimitiveAKey1(TestKey1 key) { 142 return new TestPrimitiveA(key); 143 } 144 getPrimitiveAKey2(TestKey2 key)145 private static TestPrimitiveA getPrimitiveAKey2(TestKey2 key) { 146 return new TestPrimitiveA(key); 147 } 148 getPrimitiveBKey1(TestKey1 key)149 private static TestPrimitiveB getPrimitiveBKey1(TestKey1 key) { 150 return new TestPrimitiveB(); 151 } 152 getPrimitiveBKey2(TestKey2 key)153 private static TestPrimitiveB getPrimitiveBKey2(TestKey2 key) { 154 return new TestPrimitiveB(); 155 } 156 157 @Test getLegacyPrimitive_throws()158 public void getLegacyPrimitive_throws() throws Exception { 159 PrimitiveRegistry registry = 160 PrimitiveRegistry.builder() 161 .registerPrimitiveConstructor( 162 PrimitiveConstructor.create( 163 InternalConfigurationTest::getPrimitiveAKey1, 164 TestKey1.class, 165 TestPrimitiveA.class)) 166 .build(); 167 InternalConfiguration configuration = 168 InternalConfiguration.createFromPrimitiveRegistry(registry); 169 170 assertThrows( 171 UnsupportedOperationException.class, 172 () -> 173 configuration.getLegacyPrimitive( 174 KeyData.newBuilder() 175 .setValue( 176 ByteString.copyFrom( 177 SecretBytes.randomBytes(32).toByteArray(InsecureSecretKeyAccess.get()))) 178 .setTypeUrl("type.googleapis.com/google.crypto.tink.HmacKey") 179 .setKeyMaterialType(KeyMaterialType.SYMMETRIC) 180 .build(), 181 TestPrimitiveA.class)); 182 } 183 184 @Test getPrimitive_works()185 public void getPrimitive_works() throws Exception { 186 PrimitiveRegistry registry = 187 PrimitiveRegistry.builder() 188 .registerPrimitiveConstructor( 189 PrimitiveConstructor.create( 190 InternalConfigurationTest::getPrimitiveAKey1, 191 TestKey1.class, 192 TestPrimitiveA.class)) 193 .build(); 194 InternalConfiguration configuration = 195 InternalConfiguration.createFromPrimitiveRegistry(registry); 196 TestKey1 key = new TestKey1(); 197 198 TestPrimitiveA primitive = configuration.getPrimitive(key, TestPrimitiveA.class); 199 200 assertThat(primitive.getKey()).isEqualTo(key); 201 } 202 203 @Test wrap_works()204 public void wrap_works() throws Exception { 205 PrimitiveRegistry registry = 206 PrimitiveRegistry.builder().registerPrimitiveWrapper(new TestWrapperA()).build(); 207 InternalConfiguration configuration = 208 InternalConfiguration.createFromPrimitiveRegistry(registry); 209 210 // Check that the type is as expected. 211 TestPrimitiveA unused = configuration.wrap( 212 PrimitiveSet.newBuilder(TestPrimitiveA.class).build(), TestPrimitiveA.class); 213 } 214 215 @Test getInputPrimitiveClass_works()216 public void getInputPrimitiveClass_works() throws Exception { 217 PrimitiveRegistry registry = 218 PrimitiveRegistry.builder().registerPrimitiveWrapper(new TestWrapperA()).build(); 219 InternalConfiguration configuration = 220 InternalConfiguration.createFromPrimitiveRegistry(registry); 221 222 assertThat(configuration.getInputPrimitiveClass(TestPrimitiveA.class)) 223 .isEqualTo(TestPrimitiveA.class); 224 } 225 226 @Test getPrimitive_dispatchWorks()227 public void getPrimitive_dispatchWorks() throws Exception { 228 PrimitiveRegistry registry = 229 PrimitiveRegistry.builder() 230 .registerPrimitiveConstructor( 231 PrimitiveConstructor.create( 232 InternalConfigurationTest::getPrimitiveAKey1, 233 TestKey1.class, 234 TestPrimitiveA.class)) 235 .registerPrimitiveConstructor( 236 PrimitiveConstructor.create( 237 InternalConfigurationTest::getPrimitiveAKey2, 238 TestKey2.class, 239 TestPrimitiveA.class)) 240 .registerPrimitiveConstructor( 241 PrimitiveConstructor.create( 242 InternalConfigurationTest::getPrimitiveBKey1, 243 TestKey1.class, 244 TestPrimitiveB.class)) 245 .build(); 246 InternalConfiguration configuration = 247 InternalConfiguration.createFromPrimitiveRegistry(registry); 248 TestKey1 key1 = new TestKey1(); 249 TestKey2 key2 = new TestKey2(); 250 251 TestPrimitiveA primitiveAKey1 = configuration.getPrimitive(key1, TestPrimitiveA.class); 252 TestPrimitiveA primitiveAKey2 = configuration.getPrimitive(key2, TestPrimitiveA.class); 253 254 assertThat(primitiveAKey1.getKey()).isEqualTo(key1); 255 assertThat(primitiveAKey2.getKey()).isEqualTo(key2); 256 // Check that the resulting primitive is of the expected type. 257 TestPrimitiveB unused = configuration.getPrimitive(key1, TestPrimitiveB.class); 258 } 259 260 @Test wrap_dispatchWorks()261 public void wrap_dispatchWorks() throws Exception { 262 PrimitiveRegistry registry = 263 PrimitiveRegistry.builder() 264 .registerPrimitiveWrapper(new TestWrapperA()) 265 .registerPrimitiveWrapper(new TestWrapperB()) 266 .build(); 267 InternalConfiguration configuration = 268 InternalConfiguration.createFromPrimitiveRegistry(registry); 269 270 // Check that the wrapped primitives are of the expected types. 271 TestPrimitiveA unusedA = configuration.wrap( 272 PrimitiveSet.newBuilder(TestPrimitiveA.class).build(), TestPrimitiveA.class); 273 TestPrimitiveB unusedB = configuration.wrap( 274 PrimitiveSet.newBuilder(TestPrimitiveB.class).build(), TestPrimitiveB.class); 275 } 276 277 @Test getInputPrimitiveClass_dispatchWorks()278 public void getInputPrimitiveClass_dispatchWorks() throws Exception { 279 PrimitiveRegistry registry = 280 PrimitiveRegistry.builder() 281 .registerPrimitiveWrapper(new TestWrapperA()) 282 .registerPrimitiveWrapper(new TestWrapperB()) 283 .build(); 284 InternalConfiguration configuration = 285 InternalConfiguration.createFromPrimitiveRegistry(registry); 286 287 assertThat(configuration.getInputPrimitiveClass(TestPrimitiveA.class)) 288 .isEqualTo(TestPrimitiveA.class); 289 assertThat(configuration.getInputPrimitiveClass(TestPrimitiveB.class)) 290 .isEqualTo(TestPrimitiveB.class); 291 } 292 293 @Test getPrimitive_unregisteredKeyTypeThrows()294 public void getPrimitive_unregisteredKeyTypeThrows() throws Exception { 295 PrimitiveRegistry registry = 296 PrimitiveRegistry.builder() 297 .registerPrimitiveConstructor( 298 PrimitiveConstructor.create( 299 InternalConfigurationTest::getPrimitiveAKey1, 300 TestKey1.class, 301 TestPrimitiveA.class)) 302 .build(); 303 InternalConfiguration configuration = 304 InternalConfiguration.createFromPrimitiveRegistry(registry); 305 TestKey2 wrongClassKey = new TestKey2(); 306 307 assertThrows( 308 GeneralSecurityException.class, 309 () -> configuration.getPrimitive(wrongClassKey, TestPrimitiveA.class)); 310 } 311 312 @Test getPrimitive_unregisteredPrimitiveClassThrows()313 public void getPrimitive_unregisteredPrimitiveClassThrows() throws Exception { 314 PrimitiveRegistry registry = 315 PrimitiveRegistry.builder() 316 .registerPrimitiveConstructor( 317 PrimitiveConstructor.create( 318 InternalConfigurationTest::getPrimitiveAKey1, 319 TestKey1.class, 320 TestPrimitiveA.class)) 321 .build(); 322 InternalConfiguration configuration = 323 InternalConfiguration.createFromPrimitiveRegistry(registry); 324 TestKey1 correctClassKey = new TestKey1(); 325 326 assertThrows( 327 GeneralSecurityException.class, 328 () -> configuration.getPrimitive(correctClassKey, TestPrimitiveB.class)); 329 } 330 331 @Test getPrimitive_wrongPrimitiveKeyClassCombinationThrows()332 public void getPrimitive_wrongPrimitiveKeyClassCombinationThrows() throws Exception { 333 PrimitiveRegistry registry = 334 PrimitiveRegistry.builder() 335 .registerPrimitiveConstructor( 336 PrimitiveConstructor.create( 337 InternalConfigurationTest::getPrimitiveAKey1, 338 TestKey1.class, 339 TestPrimitiveA.class)) 340 .registerPrimitiveConstructor( 341 PrimitiveConstructor.create( 342 InternalConfigurationTest::getPrimitiveBKey2, 343 TestKey2.class, 344 TestPrimitiveB.class)) 345 .build(); 346 InternalConfiguration configuration = 347 InternalConfiguration.createFromPrimitiveRegistry(registry); 348 349 assertThrows( 350 GeneralSecurityException.class, 351 () -> configuration.getPrimitive(new TestKey1(), TestPrimitiveB.class)); 352 assertThrows( 353 GeneralSecurityException.class, 354 () -> configuration.getPrimitive(new TestKey2(), TestPrimitiveA.class)); 355 } 356 357 @Test wrap_wrongInputPrimitiveClassThrows()358 public void wrap_wrongInputPrimitiveClassThrows() throws Exception { 359 PrimitiveRegistry registry = 360 PrimitiveRegistry.builder().registerPrimitiveWrapper(new TestWrapperA()).build(); 361 InternalConfiguration configuration = 362 InternalConfiguration.createFromPrimitiveRegistry(registry); 363 364 assertThrows( 365 GeneralSecurityException.class, 366 () -> 367 configuration.wrap( 368 PrimitiveSet.newBuilder(TestPrimitiveB.class).build(), TestPrimitiveA.class)); 369 } 370 371 @Test wrap_unregisteredWrapperClassThrows()372 public void wrap_unregisteredWrapperClassThrows() throws Exception { 373 PrimitiveRegistry registry = 374 PrimitiveRegistry.builder().registerPrimitiveWrapper(new TestWrapperA()).build(); 375 InternalConfiguration configuration = 376 InternalConfiguration.createFromPrimitiveRegistry(registry); 377 378 assertThrows( 379 GeneralSecurityException.class, 380 () -> 381 configuration.wrap( 382 PrimitiveSet.newBuilder(TestPrimitiveA.class).build(), TestPrimitiveB.class)); 383 } 384 385 @Test getInputPrimitiveClass_unregisteredWrapperClassThrows()386 public void getInputPrimitiveClass_unregisteredWrapperClassThrows() throws Exception { 387 PrimitiveRegistry registry = 388 PrimitiveRegistry.builder().registerPrimitiveWrapper(new TestWrapperA()).build(); 389 InternalConfiguration configuration = 390 InternalConfiguration.createFromPrimitiveRegistry(registry); 391 392 assertThrows( 393 GeneralSecurityException.class, 394 () -> configuration.getInputPrimitiveClass(TestPrimitiveB.class)); 395 } 396 397 @Test emptyRegistry_throws()398 public void emptyRegistry_throws() { 399 PrimitiveRegistry registry = PrimitiveRegistry.builder().build(); 400 InternalConfiguration configuration = 401 InternalConfiguration.createFromPrimitiveRegistry(registry); 402 403 assertThrows( 404 GeneralSecurityException.class, 405 () -> configuration.getPrimitive(new TestKey1(), TestPrimitiveA.class)); 406 assertThrows( 407 GeneralSecurityException.class, 408 () -> configuration.getInputPrimitiveClass(TestPrimitiveA.class)); 409 assertThrows( 410 GeneralSecurityException.class, 411 () -> 412 configuration.wrap( 413 PrimitiveSet.newBuilder(TestPrimitiveA.class).build(), TestPrimitiveA.class)); 414 } 415 } 416