1 // Copyright 2022 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; 18 19 import static com.google.common.truth.Truth.assertThat; 20 import static java.nio.charset.StandardCharsets.UTF_8; 21 import static org.junit.Assert.assertThrows; 22 23 import com.google.crypto.tink.internal.KeyParser; 24 import com.google.crypto.tink.internal.KeySerializer; 25 import com.google.crypto.tink.internal.MutablePrimitiveRegistry; 26 import com.google.crypto.tink.internal.MutableSerializationRegistry; 27 import com.google.crypto.tink.internal.PrimitiveConstructor; 28 import com.google.crypto.tink.internal.PrimitiveSet; 29 import com.google.crypto.tink.internal.PrimitiveSet.Entry; 30 import com.google.crypto.tink.internal.PrimitiveWrapper; 31 import com.google.crypto.tink.internal.ProtoKeySerialization; 32 import com.google.crypto.tink.mac.AesCmacKey; 33 import com.google.crypto.tink.mac.AesCmacParameters; 34 import com.google.crypto.tink.mac.AesCmacParameters.Variant; 35 import com.google.crypto.tink.mac.MacConfig; 36 import com.google.crypto.tink.proto.KeyData.KeyMaterialType; 37 import com.google.crypto.tink.proto.OutputPrefixType; 38 import com.google.crypto.tink.util.Bytes; 39 import com.google.crypto.tink.util.SecretBytes; 40 import com.google.protobuf.ByteString; 41 import java.security.GeneralSecurityException; 42 import java.util.List; 43 import javax.annotation.Nullable; 44 import org.junit.Test; 45 import org.junit.runner.RunWith; 46 import org.junit.runners.JUnit4; 47 48 /** 49 * Tests how {@link KeysetHandle} handles the situation when there is a {@link 50 * PrimitiveSet#fullPrimitive} registered. 51 */ 52 @RunWith(JUnit4.class) 53 public class KeysetHandleFullPrimitiveTest { 54 55 private static final PrimitiveConstructor<TestKey, SingleTestPrimitive> 56 TEST_PRIMITIVE_CONSTRUCTOR = 57 PrimitiveConstructor.create( 58 KeysetHandleFullPrimitiveTest::createTestPrimitive, 59 TestKey.class, 60 SingleTestPrimitive.class); 61 public static final KeySerializer<TestKey, ProtoKeySerialization> TEST_KEY_SERIALIZER = 62 KeySerializer.create( 63 KeysetHandleFullPrimitiveTest::serializeTestKey, 64 TestKey.class, 65 ProtoKeySerialization.class); 66 public static final KeyParser<ProtoKeySerialization> TEST_KEY_PARSER = 67 KeyParser.create( 68 KeysetHandleFullPrimitiveTest::parseTestKey, 69 Bytes.copyFrom("testKeyForFullPrimitiveUrl".getBytes(UTF_8)), 70 ProtoKeySerialization.class); 71 72 private static class SingleTestPrimitive {} 73 74 /** 75 * In combination with {@link KeysetHandleFullPrimitiveTest#TestWrapper}, this test primitive lets 76 * us check some assumptions about the {@link PrimitiveSet} which was created by the {@link 77 * KeysetHandle}. 78 */ 79 private static class WrappedTestPrimitive { 80 81 private final PrimitiveSet<SingleTestPrimitive> primitiveSet; 82 WrappedTestPrimitive(PrimitiveSet<SingleTestPrimitive> primitiveSet)83 WrappedTestPrimitive(PrimitiveSet<SingleTestPrimitive> primitiveSet) { 84 this.primitiveSet = primitiveSet; 85 } 86 getPrimitiveSet()87 PrimitiveSet<SingleTestPrimitive> getPrimitiveSet() { 88 return primitiveSet; 89 } 90 } 91 92 private static class TestWrapper 93 implements PrimitiveWrapper<SingleTestPrimitive, WrappedTestPrimitive> { 94 95 private static final TestWrapper WRAPPER = new TestWrapper(); 96 97 @Override wrap(PrimitiveSet<SingleTestPrimitive> primitiveSet)98 public WrappedTestPrimitive wrap(PrimitiveSet<SingleTestPrimitive> primitiveSet) 99 throws GeneralSecurityException { 100 return new WrappedTestPrimitive(primitiveSet); 101 } 102 103 @Override getPrimitiveClass()104 public Class<WrappedTestPrimitive> getPrimitiveClass() { 105 return WrappedTestPrimitive.class; 106 } 107 108 @Override getInputPrimitiveClass()109 public Class<SingleTestPrimitive> getInputPrimitiveClass() { 110 return SingleTestPrimitive.class; 111 } 112 register()113 public static void register() throws GeneralSecurityException { 114 MutablePrimitiveRegistry.globalInstance().registerPrimitiveWrapper(WRAPPER); 115 } 116 } 117 118 private static final class TestKey extends Key { 119 120 private final int id; 121 TestKey(int id)122 TestKey(int id) { 123 this.id = id; 124 } 125 126 @Override getParameters()127 public Parameters getParameters() { 128 throw new UnsupportedOperationException("Not needed in test"); 129 } 130 131 @Override getIdRequirementOrNull()132 public Integer getIdRequirementOrNull() { 133 return id; 134 } 135 136 @Override equalsKey(Key other)137 public boolean equalsKey(Key other) { 138 throw new UnsupportedOperationException("Not needed in test"); 139 } 140 getId()141 public int getId() { 142 return id; 143 } 144 } 145 serializeTestKey( TestKey key, @Nullable SecretKeyAccess access)146 private static ProtoKeySerialization serializeTestKey( 147 TestKey key, @Nullable SecretKeyAccess access) throws GeneralSecurityException { 148 return ProtoKeySerialization.create( 149 "testKeyForFullPrimitiveUrl", 150 ByteString.EMPTY, 151 KeyMaterialType.ASYMMETRIC_PUBLIC, 152 OutputPrefixType.TINK, 153 key.getId()); 154 } 155 parseTestKey( ProtoKeySerialization serialization, @Nullable SecretKeyAccess access)156 private static TestKey parseTestKey( 157 ProtoKeySerialization serialization, @Nullable SecretKeyAccess access) { 158 return new TestKey(serialization.getIdRequirementOrNull()); 159 } 160 createTestPrimitive(TestKey key)161 private static SingleTestPrimitive createTestPrimitive(TestKey key) 162 throws GeneralSecurityException { 163 return new SingleTestPrimitive(); 164 } 165 166 /** 167 * In combination with {@link KeysetHandleFullPrimitiveTest#MacTestWrapper}, this test primitive 168 * lets us check some assumptions about the {@link PrimitiveSet} which was created by the {@link 169 * KeysetHandle}. 170 */ 171 private static class WrappedMacTestPrimitive { 172 173 private final PrimitiveSet<Mac> primitiveSet; 174 WrappedMacTestPrimitive(PrimitiveSet<Mac> primitiveSet)175 WrappedMacTestPrimitive(PrimitiveSet<Mac> primitiveSet) { 176 this.primitiveSet = primitiveSet; 177 } 178 getPrimitiveSet()179 PrimitiveSet<Mac> getPrimitiveSet() { 180 return primitiveSet; 181 } 182 } 183 184 private static class MacTestWrapper implements PrimitiveWrapper<Mac, WrappedMacTestPrimitive> { 185 186 private static final MacTestWrapper WRAPPER = new MacTestWrapper(); 187 188 @Override wrap(PrimitiveSet<Mac> primitiveSet)189 public WrappedMacTestPrimitive wrap(PrimitiveSet<Mac> primitiveSet) 190 throws GeneralSecurityException { 191 return new WrappedMacTestPrimitive(primitiveSet); 192 } 193 194 @Override getPrimitiveClass()195 public Class<WrappedMacTestPrimitive> getPrimitiveClass() { 196 return WrappedMacTestPrimitive.class; 197 } 198 199 @Override getInputPrimitiveClass()200 public Class<Mac> getInputPrimitiveClass() { 201 return Mac.class; 202 } 203 register()204 public static void register() throws GeneralSecurityException { 205 MutablePrimitiveRegistry.globalInstance().registerPrimitiveWrapper(WRAPPER); 206 } 207 } 208 209 @Test getPrimitive_fullPrimitiveWithoutPrimitive_worksCorrectly()210 public void getPrimitive_fullPrimitiveWithoutPrimitive_worksCorrectly() throws Exception { 211 Registry.reset(); 212 MutableSerializationRegistry.globalInstance().registerKeySerializer(TEST_KEY_SERIALIZER); 213 MutableSerializationRegistry.globalInstance().registerKeyParser(TEST_KEY_PARSER); 214 MutablePrimitiveRegistry.globalInstance() 215 .registerPrimitiveConstructor(TEST_PRIMITIVE_CONSTRUCTOR); 216 TestWrapper.register(); 217 KeysetHandle keysetHandle = 218 KeysetHandle.newBuilder() 219 .addEntry( 220 KeysetHandle.importKey(new TestKey(1234)) 221 .setStatus(KeyStatus.ENABLED) 222 .withFixedId(1234) 223 .makePrimary()) 224 .addEntry( 225 KeysetHandle.importKey(new TestKey(1235)) 226 .setStatus(KeyStatus.ENABLED) 227 .withFixedId(1235)) 228 .addEntry( 229 KeysetHandle.importKey(new TestKey(1236)) 230 .setStatus(KeyStatus.ENABLED) 231 .withFixedId(1236)) 232 .addEntry( 233 KeysetHandle.importKey(new TestKey(1237)) 234 .setStatus(KeyStatus.ENABLED) 235 .withFixedId(1237)) 236 .build(); 237 238 WrappedTestPrimitive primitive = 239 keysetHandle.getPrimitive(RegistryConfiguration.get(), WrappedTestPrimitive.class); 240 241 for (List<Entry<SingleTestPrimitive>> list : primitive.getPrimitiveSet().getAll()) { 242 for (PrimitiveSet.Entry<SingleTestPrimitive> entry : list) { 243 assertThat(entry.getFullPrimitive()).isNotNull(); 244 } 245 } 246 } 247 248 @Test getPrimitive_noFullPrimitiveNoPrimitive_throws()249 public void getPrimitive_noFullPrimitiveNoPrimitive_throws() throws Exception { 250 Registry.reset(); 251 MutableSerializationRegistry.globalInstance().registerKeySerializer(TEST_KEY_SERIALIZER); 252 MutableSerializationRegistry.globalInstance().registerKeyParser(TEST_KEY_PARSER); 253 KeysetHandle keysetHandle = 254 KeysetHandle.newBuilder() 255 .addEntry( 256 KeysetHandle.importKey(new TestKey(1234)) 257 .setStatus(KeyStatus.ENABLED) 258 .withFixedId(1234) 259 .makePrimary()) 260 .addEntry( 261 KeysetHandle.importKey(new TestKey(1235)) 262 .setStatus(KeyStatus.ENABLED) 263 .withFixedId(1235)) 264 .addEntry( 265 KeysetHandle.importKey(new TestKey(1236)) 266 .setStatus(KeyStatus.ENABLED) 267 .withFixedId(1236)) 268 .addEntry( 269 KeysetHandle.importKey(new TestKey(1237)) 270 .setStatus(KeyStatus.ENABLED) 271 .withFixedId(1237)) 272 .build(); 273 274 assertThrows( 275 GeneralSecurityException.class, 276 () -> keysetHandle.getPrimitive(RegistryConfiguration.get(), WrappedTestPrimitive.class)); 277 } 278 279 @Test getPrimitive_fullPrimitiveWithPrimitive_worksCorrectly()280 public void getPrimitive_fullPrimitiveWithPrimitive_worksCorrectly() throws Exception { 281 Registry.reset(); 282 MacTestWrapper.register(); 283 MacConfig.register(); 284 AesCmacParameters parameters = 285 AesCmacParameters.builder() 286 .setKeySizeBytes(32) 287 .setTagSizeBytes(10) 288 .setVariant(Variant.TINK) 289 .build(); 290 KeysetHandle keysetHandle = 291 KeysetHandle.newBuilder() 292 .addEntry( 293 KeysetHandle.importKey( 294 AesCmacKey.builder() 295 .setParameters(parameters) 296 .setAesKeyBytes(SecretBytes.randomBytes(32)) 297 .setIdRequirement(1234) 298 .build()) 299 .setStatus(KeyStatus.ENABLED) 300 .withFixedId(1234) 301 .makePrimary()) 302 .addEntry( 303 KeysetHandle.importKey( 304 AesCmacKey.builder() 305 .setParameters(parameters) 306 .setAesKeyBytes(SecretBytes.randomBytes(32)) 307 .setIdRequirement(1235) 308 .build()) 309 .setStatus(KeyStatus.ENABLED) 310 .withFixedId(1235)) 311 .addEntry( 312 KeysetHandle.importKey( 313 AesCmacKey.builder() 314 .setParameters(parameters) 315 .setAesKeyBytes(SecretBytes.randomBytes(32)) 316 .setIdRequirement(1236) 317 .build()) 318 .setStatus(KeyStatus.ENABLED) 319 .withFixedId(1236)) 320 .addEntry( 321 KeysetHandle.importKey( 322 AesCmacKey.builder() 323 .setParameters(parameters) 324 .setAesKeyBytes(SecretBytes.randomBytes(32)) 325 .setIdRequirement(1237) 326 .build()) 327 .setStatus(KeyStatus.ENABLED) 328 .withFixedId(1237)) 329 .build(); 330 331 WrappedMacTestPrimitive primitive = 332 keysetHandle.getPrimitive(RegistryConfiguration.get(), WrappedMacTestPrimitive.class); 333 334 for (List<Entry<Mac>> list : primitive.getPrimitiveSet().getAll()) { 335 for (PrimitiveSet.Entry<Mac> entry : list) { 336 assertThat(entry.getFullPrimitive()).isNotNull(); 337 } 338 } 339 } 340 } 341