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.jwt; 18 19 import static com.google.common.truth.Truth.assertThat; 20 import static com.google.crypto.tink.internal.testing.Asserts.assertEqualWhenValueParsed; 21 import static org.junit.Assert.assertThrows; 22 23 import com.google.crypto.tink.InsecureSecretKeyAccess; 24 import com.google.crypto.tink.Key; 25 import com.google.crypto.tink.Parameters; 26 import com.google.crypto.tink.internal.MutableSerializationRegistry; 27 import com.google.crypto.tink.internal.ProtoKeySerialization; 28 import com.google.crypto.tink.internal.ProtoParametersSerialization; 29 import com.google.crypto.tink.proto.JwtHmacAlgorithm; 30 import com.google.crypto.tink.proto.JwtHmacKey.CustomKid; 31 import com.google.crypto.tink.proto.KeyData.KeyMaterialType; 32 import com.google.crypto.tink.proto.OutputPrefixType; 33 import com.google.crypto.tink.util.SecretBytes; 34 import com.google.protobuf.ByteString; 35 import java.security.GeneralSecurityException; 36 import org.junit.BeforeClass; 37 import org.junit.Test; 38 import org.junit.experimental.theories.Theories; 39 import org.junit.runner.RunWith; 40 41 /** Test for JwtHmacProtoSerialization. */ 42 @RunWith(Theories.class) 43 public final class JwtHmacProtoSerializationTest { 44 private static final String TYPE_URL = "type.googleapis.com/google.crypto.tink.JwtHmacKey"; 45 46 private static final SecretBytes KEY_BYTES_42 = SecretBytes.randomBytes(42); 47 private static final ByteString KEY_BYTES_42_AS_BYTE_STRING = 48 ByteString.copyFrom(KEY_BYTES_42.toByteArray(InsecureSecretKeyAccess.get())); 49 50 private static final MutableSerializationRegistry registry = new MutableSerializationRegistry(); 51 52 @BeforeClass setUp()53 public static void setUp() throws Exception { 54 JwtHmacProtoSerialization.register(registry); 55 } 56 57 // PARAMETERS PARSING ========================================================= PARAMETERS PARSING 58 @Test serializeParseParameters_kidStrategyIsIgnored_works()59 public void serializeParseParameters_kidStrategyIsIgnored_works() throws Exception { 60 JwtHmacParameters parameters = 61 JwtHmacParameters.builder() 62 .setKeySizeBytes(19) 63 .setAlgorithm(JwtHmacParameters.Algorithm.HS256) 64 .setKidStrategy(JwtHmacParameters.KidStrategy.IGNORED) 65 .build(); 66 ProtoParametersSerialization serialization = 67 ProtoParametersSerialization.create( 68 TYPE_URL, 69 OutputPrefixType.RAW, 70 com.google.crypto.tink.proto.JwtHmacKeyFormat.newBuilder() 71 .setVersion(0) 72 .setAlgorithm(JwtHmacAlgorithm.HS256) 73 .setKeySize(19) 74 .build()); 75 76 ProtoParametersSerialization serialized = 77 registry.serializeParameters(parameters, ProtoParametersSerialization.class); 78 assertEqualWhenValueParsed( 79 com.google.crypto.tink.proto.JwtHmacKeyFormat.parser(), serialized, serialization); 80 81 Parameters parsed = registry.parseParameters(serialization); 82 assertThat(parsed).isEqualTo(parameters); 83 } 84 85 @Test serializeParseParameters_kidStrategyIsIgnored_differentKeySize_works()86 public void serializeParseParameters_kidStrategyIsIgnored_differentKeySize_works() 87 throws Exception { 88 JwtHmacParameters parameters = 89 JwtHmacParameters.builder() 90 .setKeySizeBytes(21) 91 .setAlgorithm(JwtHmacParameters.Algorithm.HS256) 92 .setKidStrategy(JwtHmacParameters.KidStrategy.IGNORED) 93 .build(); 94 ProtoParametersSerialization serialization = 95 ProtoParametersSerialization.create( 96 TYPE_URL, 97 OutputPrefixType.RAW, 98 com.google.crypto.tink.proto.JwtHmacKeyFormat.newBuilder() 99 .setVersion(0) 100 .setAlgorithm(JwtHmacAlgorithm.HS256) 101 .setKeySize(21) 102 .build()); 103 104 ProtoParametersSerialization serialized = 105 registry.serializeParameters(parameters, ProtoParametersSerialization.class); 106 assertEqualWhenValueParsed( 107 com.google.crypto.tink.proto.JwtHmacKeyFormat.parser(), serialized, serialization); 108 109 Parameters parsed = registry.parseParameters(serialization); 110 assertThat(parsed).isEqualTo(parameters); 111 } 112 113 @Test serializeParseParameters_kidStrategyIsIgnored_differentAlgorithm_works()114 public void serializeParseParameters_kidStrategyIsIgnored_differentAlgorithm_works() 115 throws Exception { 116 JwtHmacParameters parameters = 117 JwtHmacParameters.builder() 118 .setKeySizeBytes(19) 119 .setAlgorithm(JwtHmacParameters.Algorithm.HS512) 120 .setKidStrategy(JwtHmacParameters.KidStrategy.IGNORED) 121 .build(); 122 ProtoParametersSerialization serialization = 123 ProtoParametersSerialization.create( 124 TYPE_URL, 125 OutputPrefixType.RAW, 126 com.google.crypto.tink.proto.JwtHmacKeyFormat.newBuilder() 127 .setVersion(0) 128 .setAlgorithm(JwtHmacAlgorithm.HS512) 129 .setKeySize(19) 130 .build()); 131 132 ProtoParametersSerialization serialized = 133 registry.serializeParameters(parameters, ProtoParametersSerialization.class); 134 assertEqualWhenValueParsed( 135 com.google.crypto.tink.proto.JwtHmacKeyFormat.parser(), serialized, serialization); 136 137 Parameters parsed = registry.parseParameters(serialization); 138 assertThat(parsed).isEqualTo(parameters); 139 } 140 141 @Test serializeParseParameters_kidStrategyBase64_works()142 public void serializeParseParameters_kidStrategyBase64_works() throws Exception { 143 JwtHmacParameters parameters = 144 JwtHmacParameters.builder() 145 .setKeySizeBytes(19) 146 .setAlgorithm(JwtHmacParameters.Algorithm.HS256) 147 .setKidStrategy(JwtHmacParameters.KidStrategy.BASE64_ENCODED_KEY_ID) 148 .build(); 149 ProtoParametersSerialization serialization = 150 ProtoParametersSerialization.create( 151 TYPE_URL, 152 OutputPrefixType.TINK, 153 com.google.crypto.tink.proto.JwtHmacKeyFormat.newBuilder() 154 .setVersion(0) 155 .setAlgorithm(JwtHmacAlgorithm.HS256) 156 .setKeySize(19) 157 .build()); 158 159 ProtoParametersSerialization serialized = 160 registry.serializeParameters(parameters, ProtoParametersSerialization.class); 161 assertEqualWhenValueParsed( 162 com.google.crypto.tink.proto.JwtHmacKeyFormat.parser(), serialized, serialization); 163 164 Parameters parsed = registry.parseParameters(serialization); 165 assertThat(parsed).isEqualTo(parameters); 166 } 167 168 // INVALID PARAMETERS SERIALIZATIONS =========================== INVALID PARAMETERS SERIALIZATIONS 169 @Test serializeParameters_kidStrategyCustom_cannotBeSerialized_throws()170 public void serializeParameters_kidStrategyCustom_cannotBeSerialized_throws() throws Exception { 171 JwtHmacParameters parameters = 172 JwtHmacParameters.builder() 173 .setKeySizeBytes(19) 174 .setAlgorithm(JwtHmacParameters.Algorithm.HS256) 175 .setKidStrategy(JwtHmacParameters.KidStrategy.CUSTOM) 176 .build(); 177 assertThrows( 178 GeneralSecurityException.class, 179 () -> registry.serializeParameters(parameters, ProtoParametersSerialization.class)); 180 } 181 182 @Test parseParameters_crunchy_cannotBeParsed_throws()183 public void parseParameters_crunchy_cannotBeParsed_throws() throws Exception { 184 ProtoParametersSerialization serialization = 185 ProtoParametersSerialization.create( 186 TYPE_URL, 187 OutputPrefixType.CRUNCHY, 188 com.google.crypto.tink.proto.JwtHmacKeyFormat.newBuilder() 189 .setVersion(0) 190 .setAlgorithm(JwtHmacAlgorithm.HS256) 191 .setKeySize(19) 192 .build()); 193 assertThrows(GeneralSecurityException.class, () -> registry.parseParameters(serialization)); 194 } 195 196 // KEYS PARSING ===================================================================== KEYS PARSING 197 @Test serializeParseKey_kidStrategyIsIgnored_works()198 public void serializeParseKey_kidStrategyIsIgnored_works() throws Exception { 199 JwtHmacParameters parameters = 200 JwtHmacParameters.builder() 201 .setKeySizeBytes(42) 202 .setAlgorithm(JwtHmacParameters.Algorithm.HS256) 203 .setKidStrategy(JwtHmacParameters.KidStrategy.IGNORED) 204 .build(); 205 JwtHmacKey key = 206 JwtHmacKey.builder().setParameters(parameters).setKeyBytes(KEY_BYTES_42).build(); 207 208 com.google.crypto.tink.proto.JwtHmacKey protoKey = 209 com.google.crypto.tink.proto.JwtHmacKey.newBuilder() 210 .setVersion(0) 211 .setAlgorithm(JwtHmacAlgorithm.HS256) 212 .setKeyValue(KEY_BYTES_42_AS_BYTE_STRING) 213 .build(); 214 ProtoKeySerialization serialization = 215 ProtoKeySerialization.create( 216 "type.googleapis.com/google.crypto.tink.JwtHmacKey", 217 protoKey.toByteString(), 218 KeyMaterialType.SYMMETRIC, 219 OutputPrefixType.RAW, 220 /* idRequirement= */ null); 221 222 ProtoKeySerialization serialized = 223 registry.serializeKey(key, ProtoKeySerialization.class, InsecureSecretKeyAccess.get()); 224 assertEqualWhenValueParsed( 225 com.google.crypto.tink.proto.JwtHmacKey.parser(), serialized, serialization); 226 227 Key parsed = registry.parseKey(serialization, InsecureSecretKeyAccess.get()); 228 assertThat(parsed.equalsKey(key)).isTrue(); 229 } 230 231 @Test serializeParseKey_kidStrategyIsIgnored_differentAlgorithm_works()232 public void serializeParseKey_kidStrategyIsIgnored_differentAlgorithm_works() throws Exception { 233 JwtHmacParameters parameters = 234 JwtHmacParameters.builder() 235 .setKeySizeBytes(42) 236 .setAlgorithm(JwtHmacParameters.Algorithm.HS384) 237 .setKidStrategy(JwtHmacParameters.KidStrategy.IGNORED) 238 .build(); 239 JwtHmacKey key = 240 JwtHmacKey.builder().setParameters(parameters).setKeyBytes(KEY_BYTES_42).build(); 241 242 com.google.crypto.tink.proto.JwtHmacKey protoKey = 243 com.google.crypto.tink.proto.JwtHmacKey.newBuilder() 244 .setVersion(0) 245 .setAlgorithm(JwtHmacAlgorithm.HS384) 246 .setKeyValue(KEY_BYTES_42_AS_BYTE_STRING) 247 .build(); 248 ProtoKeySerialization serialization = 249 ProtoKeySerialization.create( 250 "type.googleapis.com/google.crypto.tink.JwtHmacKey", 251 protoKey.toByteString(), 252 KeyMaterialType.SYMMETRIC, 253 OutputPrefixType.RAW, 254 /* idRequirement= */ null); 255 256 ProtoKeySerialization serialized = 257 registry.serializeKey(key, ProtoKeySerialization.class, InsecureSecretKeyAccess.get()); 258 assertEqualWhenValueParsed( 259 com.google.crypto.tink.proto.JwtHmacKey.parser(), serialized, serialization); 260 261 Key parsed = registry.parseKey(serialization, InsecureSecretKeyAccess.get()); 262 assertThat(parsed.equalsKey(key)).isTrue(); 263 } 264 265 @Test serializeParseKey_kidStrategyIsCustom_works()266 public void serializeParseKey_kidStrategyIsCustom_works() throws Exception { 267 JwtHmacParameters parameters = 268 JwtHmacParameters.builder() 269 .setKeySizeBytes(42) 270 .setAlgorithm(JwtHmacParameters.Algorithm.HS512) 271 .setKidStrategy(JwtHmacParameters.KidStrategy.CUSTOM) 272 .build(); 273 JwtHmacKey key = 274 JwtHmacKey.builder() 275 .setParameters(parameters) 276 .setKeyBytes(KEY_BYTES_42) 277 .setCustomKid("customKidForThisTest") 278 .build(); 279 280 com.google.crypto.tink.proto.JwtHmacKey protoKey = 281 com.google.crypto.tink.proto.JwtHmacKey.newBuilder() 282 .setVersion(0) 283 .setAlgorithm(JwtHmacAlgorithm.HS512) 284 .setKeyValue(KEY_BYTES_42_AS_BYTE_STRING) 285 .setCustomKid(CustomKid.newBuilder().setValue("customKidForThisTest")) 286 .build(); 287 ProtoKeySerialization serialization = 288 ProtoKeySerialization.create( 289 "type.googleapis.com/google.crypto.tink.JwtHmacKey", 290 protoKey.toByteString(), 291 KeyMaterialType.SYMMETRIC, 292 OutputPrefixType.RAW, 293 /* idRequirement= */ null); 294 295 ProtoKeySerialization serialized = 296 registry.serializeKey(key, ProtoKeySerialization.class, InsecureSecretKeyAccess.get()); 297 assertEqualWhenValueParsed( 298 com.google.crypto.tink.proto.JwtHmacKey.parser(), serialized, serialization); 299 300 Key parsed = registry.parseKey(serialization, InsecureSecretKeyAccess.get()); 301 assertThat(parsed.equalsKey(key)).isTrue(); 302 } 303 304 @Test serializeParseKey_kidStrategyIsCustom_differentAlgorithm_works()305 public void serializeParseKey_kidStrategyIsCustom_differentAlgorithm_works() throws Exception { 306 JwtHmacParameters parameters = 307 JwtHmacParameters.builder() 308 .setKeySizeBytes(42) 309 .setAlgorithm(JwtHmacParameters.Algorithm.HS384) 310 .setKidStrategy(JwtHmacParameters.KidStrategy.CUSTOM) 311 .build(); 312 JwtHmacKey key = 313 JwtHmacKey.builder() 314 .setParameters(parameters) 315 .setKeyBytes(KEY_BYTES_42) 316 .setCustomKid("customKidForThisTest") 317 .build(); 318 319 com.google.crypto.tink.proto.JwtHmacKey protoKey = 320 com.google.crypto.tink.proto.JwtHmacKey.newBuilder() 321 .setVersion(0) 322 .setAlgorithm(JwtHmacAlgorithm.HS384) 323 .setKeyValue(KEY_BYTES_42_AS_BYTE_STRING) 324 .setCustomKid(CustomKid.newBuilder().setValue("customKidForThisTest")) 325 .build(); 326 ProtoKeySerialization serialization = 327 ProtoKeySerialization.create( 328 "type.googleapis.com/google.crypto.tink.JwtHmacKey", 329 protoKey.toByteString(), 330 KeyMaterialType.SYMMETRIC, 331 OutputPrefixType.RAW, 332 /* idRequirement= */ null); 333 334 ProtoKeySerialization serialized = 335 registry.serializeKey(key, ProtoKeySerialization.class, InsecureSecretKeyAccess.get()); 336 assertEqualWhenValueParsed( 337 com.google.crypto.tink.proto.JwtHmacKey.parser(), serialized, serialization); 338 339 Key parsed = registry.parseKey(serialization, InsecureSecretKeyAccess.get()); 340 assertThat(parsed.equalsKey(key)).isTrue(); 341 } 342 343 @Test serializeParseKey_kidStrategyIsBase64_works()344 public void serializeParseKey_kidStrategyIsBase64_works() throws Exception { 345 JwtHmacParameters parameters = 346 JwtHmacParameters.builder() 347 .setKeySizeBytes(42) 348 .setAlgorithm(JwtHmacParameters.Algorithm.HS384) 349 .setKidStrategy(JwtHmacParameters.KidStrategy.BASE64_ENCODED_KEY_ID) 350 .build(); 351 JwtHmacKey key = 352 JwtHmacKey.builder() 353 .setParameters(parameters) 354 .setKeyBytes(KEY_BYTES_42) 355 .setIdRequirement(10203) 356 .build(); 357 358 com.google.crypto.tink.proto.JwtHmacKey protoKey = 359 com.google.crypto.tink.proto.JwtHmacKey.newBuilder() 360 .setVersion(0) 361 .setAlgorithm(JwtHmacAlgorithm.HS384) 362 .setKeyValue(KEY_BYTES_42_AS_BYTE_STRING) 363 .build(); 364 ProtoKeySerialization serialization = 365 ProtoKeySerialization.create( 366 "type.googleapis.com/google.crypto.tink.JwtHmacKey", 367 protoKey.toByteString(), 368 KeyMaterialType.SYMMETRIC, 369 OutputPrefixType.TINK, 370 /* idRequirement= */ 10203); 371 372 ProtoKeySerialization serialized = 373 registry.serializeKey(key, ProtoKeySerialization.class, InsecureSecretKeyAccess.get()); 374 assertEqualWhenValueParsed( 375 com.google.crypto.tink.proto.JwtHmacKey.parser(), serialized, serialization); 376 377 Key parsed = registry.parseKey(serialization, InsecureSecretKeyAccess.get()); 378 assertThat(parsed.equalsKey(key)).isTrue(); 379 } 380 381 // INVALID KEYS SERIALIZATIONS ======================================= INVALID KEYS SERIALIZATIONS 382 @Test serializeKey_wrongVersion_throws()383 public void serializeKey_wrongVersion_throws() throws Exception { 384 com.google.crypto.tink.proto.JwtHmacKey protoKey = 385 com.google.crypto.tink.proto.JwtHmacKey.newBuilder() 386 .setVersion(1) 387 .setAlgorithm(JwtHmacAlgorithm.HS384) 388 .setKeyValue(KEY_BYTES_42_AS_BYTE_STRING) 389 .build(); 390 ProtoKeySerialization serialization = 391 ProtoKeySerialization.create( 392 "type.googleapis.com/google.crypto.tink.JwtHmacKey", 393 protoKey.toByteString(), 394 KeyMaterialType.SYMMETRIC, 395 OutputPrefixType.TINK, 396 /* idRequirement= */ 10203); 397 398 assertThrows( 399 GeneralSecurityException.class, 400 () -> registry.parseKey(serialization, InsecureSecretKeyAccess.get())); 401 } 402 403 @Test serializeKey_unknownAlgorithm_throws()404 public void serializeKey_unknownAlgorithm_throws() throws Exception { 405 com.google.crypto.tink.proto.JwtHmacKey protoKey = 406 com.google.crypto.tink.proto.JwtHmacKey.newBuilder() 407 .setVersion(0) 408 .setAlgorithm(JwtHmacAlgorithm.HS_UNKNOWN) 409 .setKeyValue(KEY_BYTES_42_AS_BYTE_STRING) 410 .build(); 411 ProtoKeySerialization serialization = 412 ProtoKeySerialization.create( 413 "type.googleapis.com/google.crypto.tink.JwtHmacKey", 414 protoKey.toByteString(), 415 KeyMaterialType.SYMMETRIC, 416 OutputPrefixType.TINK, 417 /* idRequirement= */ 10203); 418 419 assertThrows( 420 GeneralSecurityException.class, 421 () -> registry.parseKey(serialization, InsecureSecretKeyAccess.get())); 422 } 423 424 @Test serializeKey_tinkKeyWithCustomSet_throws()425 public void serializeKey_tinkKeyWithCustomSet_throws() throws Exception { 426 com.google.crypto.tink.proto.JwtHmacKey protoKey = 427 com.google.crypto.tink.proto.JwtHmacKey.newBuilder() 428 .setVersion(0) 429 .setAlgorithm(JwtHmacAlgorithm.HS256) 430 .setKeyValue(KEY_BYTES_42_AS_BYTE_STRING) 431 .setCustomKid(CustomKid.newBuilder().setValue("customKidForThisTest")) 432 .build(); 433 ProtoKeySerialization serialization = 434 ProtoKeySerialization.create( 435 "type.googleapis.com/google.crypto.tink.JwtHmacKey", 436 protoKey.toByteString(), 437 KeyMaterialType.SYMMETRIC, 438 OutputPrefixType.TINK, 439 /* idRequirement= */ 10203); 440 441 assertThrows( 442 GeneralSecurityException.class, 443 () -> registry.parseKey(serialization, InsecureSecretKeyAccess.get())); 444 } 445 } 446