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 org.junit.Assert.assertThrows; 21 22 import com.google.crypto.tink.InsecureSecretKeyAccess; 23 import com.google.crypto.tink.internal.KeyTester; 24 import com.google.crypto.tink.mac.HmacKey; 25 import com.google.crypto.tink.mac.HmacParameters; 26 import com.google.crypto.tink.util.SecretBytes; 27 import java.security.GeneralSecurityException; 28 import java.util.Optional; 29 import org.junit.Test; 30 import org.junit.runner.RunWith; 31 import org.junit.runners.JUnit4; 32 33 @RunWith(JUnit4.class) 34 public final class JwtHmacKeyTest { 35 @Test buildSimpleVariantCheckProperties()36 public void buildSimpleVariantCheckProperties() throws Exception { 37 JwtHmacParameters parameters = 38 JwtHmacParameters.builder() 39 .setKeySizeBytes(16) 40 .setAlgorithm(JwtHmacParameters.Algorithm.HS256) 41 .setKidStrategy(JwtHmacParameters.KidStrategy.IGNORED) 42 .build(); 43 SecretBytes keyBytes = SecretBytes.randomBytes(16); 44 JwtHmacKey key = JwtHmacKey.builder().setParameters(parameters).setKeyBytes(keyBytes).build(); 45 assertThat(key.getParameters()).isEqualTo(parameters); 46 assertThat(key.getKeyBytes()).isEqualTo(keyBytes); 47 assertThat(key.getKid()).isEqualTo(Optional.empty()); 48 } 49 50 @Test buildWithoutKeyBytes_throws()51 public void buildWithoutKeyBytes_throws() throws Exception { 52 JwtHmacParameters parameters = 53 JwtHmacParameters.builder() 54 .setKeySizeBytes(16) 55 .setAlgorithm(JwtHmacParameters.Algorithm.HS256) 56 .setKidStrategy(JwtHmacParameters.KidStrategy.IGNORED) 57 .build(); 58 JwtHmacKey.Builder builder = JwtHmacKey.builder().setParameters(parameters); 59 assertThrows(GeneralSecurityException.class, builder::build); 60 } 61 62 @Test build_kidStrategyIgnored_WithCustomKid_throws()63 public void build_kidStrategyIgnored_WithCustomKid_throws() throws Exception { 64 JwtHmacParameters parameters = 65 JwtHmacParameters.builder() 66 .setKeySizeBytes(16) 67 .setAlgorithm(JwtHmacParameters.Algorithm.HS256) 68 .setKidStrategy(JwtHmacParameters.KidStrategy.IGNORED) 69 .build(); 70 SecretBytes keyBytes = SecretBytes.randomBytes(16); 71 JwtHmacKey.Builder builder = 72 JwtHmacKey.builder() 73 .setParameters(parameters) 74 .setCustomKid("customKid") 75 .setKeyBytes(keyBytes); 76 assertThrows(GeneralSecurityException.class, builder::build); 77 } 78 79 @Test build_kidStrategyIgnored_withIdRequirement_throws()80 public void build_kidStrategyIgnored_withIdRequirement_throws() throws Exception { 81 JwtHmacParameters parameters = 82 JwtHmacParameters.builder() 83 .setKeySizeBytes(16) 84 .setAlgorithm(JwtHmacParameters.Algorithm.HS256) 85 .setKidStrategy(JwtHmacParameters.KidStrategy.IGNORED) 86 .build(); 87 SecretBytes keyBytes = SecretBytes.randomBytes(16); 88 JwtHmacKey.Builder builder = 89 JwtHmacKey.builder().setParameters(parameters).setIdRequirement(120).setKeyBytes(keyBytes); 90 assertThrows(GeneralSecurityException.class, builder::build); 91 } 92 93 @Test build_kidStrategyCustom()94 public void build_kidStrategyCustom() throws Exception { 95 JwtHmacParameters parameters = 96 JwtHmacParameters.builder() 97 .setKeySizeBytes(16) 98 .setAlgorithm(JwtHmacParameters.Algorithm.HS384) 99 .setKidStrategy(JwtHmacParameters.KidStrategy.CUSTOM) 100 .build(); 101 SecretBytes keyBytes = SecretBytes.randomBytes(16); 102 JwtHmacKey key = 103 JwtHmacKey.builder() 104 .setParameters(parameters) 105 .setKeyBytes(keyBytes) 106 .setCustomKid("CustomKid") 107 .build(); 108 assertThat(key.getParameters()).isEqualTo(parameters); 109 assertThat(key.getKeyBytes()).isEqualTo(keyBytes); 110 assertThat(key.getKid()).isEqualTo(Optional.of("CustomKid")); 111 } 112 113 @Test build_kidStrategyCustom_differentAlgorithmAndKeyId_works()114 public void build_kidStrategyCustom_differentAlgorithmAndKeyId_works() throws Exception { 115 JwtHmacParameters parameters = 116 JwtHmacParameters.builder() 117 .setKeySizeBytes(16) 118 .setAlgorithm(JwtHmacParameters.Algorithm.HS256) 119 .setKidStrategy(JwtHmacParameters.KidStrategy.CUSTOM) 120 .build(); 121 SecretBytes keyBytes = SecretBytes.randomBytes(16); 122 JwtHmacKey key = 123 JwtHmacKey.builder() 124 .setParameters(parameters) 125 .setKeyBytes(keyBytes) 126 .setCustomKid("myCustomTestKid") 127 .build(); 128 assertThat(key.getParameters()).isEqualTo(parameters); 129 assertThat(key.getKeyBytes()).isEqualTo(keyBytes); 130 assertThat(key.getKid()).isEqualTo(Optional.of("myCustomTestKid")); 131 } 132 133 @Test build_kidStrategyCustom_doNotSetCustomKid_throws()134 public void build_kidStrategyCustom_doNotSetCustomKid_throws() throws Exception { 135 JwtHmacParameters parameters = 136 JwtHmacParameters.builder() 137 .setKeySizeBytes(16) 138 .setAlgorithm(JwtHmacParameters.Algorithm.HS256) 139 .setKidStrategy(JwtHmacParameters.KidStrategy.CUSTOM) 140 .build(); 141 SecretBytes keyBytes = SecretBytes.randomBytes(16); 142 JwtHmacKey.Builder builder = 143 JwtHmacKey.builder().setParameters(parameters).setKeyBytes(keyBytes); 144 assertThrows(GeneralSecurityException.class, builder::build); 145 } 146 147 @Test build_kidStrategyCustom_setIdRequirement_throws()148 public void build_kidStrategyCustom_setIdRequirement_throws() throws Exception { 149 JwtHmacParameters parameters = 150 JwtHmacParameters.builder() 151 .setKeySizeBytes(16) 152 .setAlgorithm(JwtHmacParameters.Algorithm.HS256) 153 .setKidStrategy(JwtHmacParameters.KidStrategy.CUSTOM) 154 .build(); 155 SecretBytes keyBytes = SecretBytes.randomBytes(16); 156 JwtHmacKey.Builder builder = 157 JwtHmacKey.builder() 158 .setParameters(parameters) 159 .setCustomKid("myCustomTestKid") 160 .setKeyBytes(keyBytes) 161 .setIdRequirement(2930); 162 assertThrows(GeneralSecurityException.class, builder::build); 163 } 164 165 @Test build_kidStrategyBase64_works()166 public void build_kidStrategyBase64_works() throws Exception { 167 JwtHmacParameters parameters = 168 JwtHmacParameters.builder() 169 .setKeySizeBytes(16) 170 .setAlgorithm(JwtHmacParameters.Algorithm.HS384) 171 .setKidStrategy(JwtHmacParameters.KidStrategy.BASE64_ENCODED_KEY_ID) 172 .build(); 173 SecretBytes keyBytes = SecretBytes.randomBytes(16); 174 JwtHmacKey key = 175 JwtHmacKey.builder() 176 .setParameters(parameters) 177 .setKeyBytes(keyBytes) 178 .setIdRequirement(0x1ac6a944) 179 .build(); 180 assertThat(key.getParameters()).isEqualTo(parameters); 181 assertThat(key.getKeyBytes()).isEqualTo(keyBytes); 182 assertThat(key.getIdRequirementOrNull()).isEqualTo(0x1ac6a944); 183 // See JwtFormatTest.getKidFromTinkOutputPrefixType_success 184 assertThat(key.getKid()).isEqualTo(Optional.of("GsapRA")); 185 } 186 187 @Test build_kidStrategyBase64_setCustomKeyId_throws()188 public void build_kidStrategyBase64_setCustomKeyId_throws() throws Exception { 189 JwtHmacParameters parameters = 190 JwtHmacParameters.builder() 191 .setKeySizeBytes(16) 192 .setAlgorithm(JwtHmacParameters.Algorithm.HS384) 193 .setKidStrategy(JwtHmacParameters.KidStrategy.BASE64_ENCODED_KEY_ID) 194 .build(); 195 SecretBytes keyBytes = SecretBytes.randomBytes(16); 196 JwtHmacKey.Builder builder = 197 JwtHmacKey.builder() 198 .setParameters(parameters) 199 .setKeyBytes(keyBytes) 200 .setIdRequirement(0x89abcdef) 201 .setCustomKid("customKeyId"); 202 assertThrows(GeneralSecurityException.class, builder::build); 203 } 204 205 @Test build_kidStrategyBase64_omitIdRequirement_throws()206 public void build_kidStrategyBase64_omitIdRequirement_throws() throws Exception { 207 JwtHmacParameters parameters = 208 JwtHmacParameters.builder() 209 .setKeySizeBytes(16) 210 .setAlgorithm(JwtHmacParameters.Algorithm.HS384) 211 .setKidStrategy(JwtHmacParameters.KidStrategy.BASE64_ENCODED_KEY_ID) 212 .build(); 213 SecretBytes keyBytes = SecretBytes.randomBytes(16); 214 JwtHmacKey.Builder builder = 215 JwtHmacKey.builder().setParameters(parameters).setKeyBytes(keyBytes); 216 assertThrows(GeneralSecurityException.class, builder::build); 217 } 218 219 @Test testEqualities()220 public void testEqualities() throws Exception { 221 SecretBytes keyBytes16 = SecretBytes.randomBytes(16); 222 SecretBytes keyBytes16Copy = 223 SecretBytes.copyFrom( 224 keyBytes16.toByteArray(InsecureSecretKeyAccess.get()), InsecureSecretKeyAccess.get()); 225 SecretBytes keyBytes16B = SecretBytes.randomBytes(16); 226 SecretBytes keyBytes32 = SecretBytes.randomBytes(32); 227 228 JwtHmacParameters parametersIgnoredKidStrategy = 229 JwtHmacParameters.builder() 230 .setKeySizeBytes(16) 231 .setAlgorithm(JwtHmacParameters.Algorithm.HS256) 232 .setKidStrategy(JwtHmacParameters.KidStrategy.IGNORED) 233 .build(); 234 JwtHmacParameters parametersIgnoredKidStrategyCopy = 235 JwtHmacParameters.builder() 236 .setKeySizeBytes(16) 237 .setAlgorithm(JwtHmacParameters.Algorithm.HS256) 238 .setKidStrategy(JwtHmacParameters.KidStrategy.IGNORED) 239 .build(); 240 JwtHmacParameters parametersHS384 = 241 JwtHmacParameters.builder() 242 .setKeySizeBytes(16) 243 .setAlgorithm(JwtHmacParameters.Algorithm.HS384) 244 .setKidStrategy(JwtHmacParameters.KidStrategy.IGNORED) 245 .build(); 246 JwtHmacParameters parametersHS512 = 247 JwtHmacParameters.builder() 248 .setKeySizeBytes(16) 249 .setAlgorithm(JwtHmacParameters.Algorithm.HS512) 250 .setKidStrategy(JwtHmacParameters.KidStrategy.IGNORED) 251 .build(); 252 JwtHmacParameters parametersKeySize32 = 253 JwtHmacParameters.builder() 254 .setKeySizeBytes(32) 255 .setAlgorithm(JwtHmacParameters.Algorithm.HS256) 256 .setKidStrategy(JwtHmacParameters.KidStrategy.IGNORED) 257 .build(); 258 JwtHmacParameters parametersKidStrategyCustom = 259 JwtHmacParameters.builder() 260 .setKeySizeBytes(16) 261 .setAlgorithm(JwtHmacParameters.Algorithm.HS256) 262 .setKidStrategy(JwtHmacParameters.KidStrategy.CUSTOM) 263 .build(); 264 JwtHmacParameters parametersKidStrategyBase64 = 265 JwtHmacParameters.builder() 266 .setKeySizeBytes(16) 267 .setAlgorithm(JwtHmacParameters.Algorithm.HS256) 268 .setKidStrategy(JwtHmacParameters.KidStrategy.BASE64_ENCODED_KEY_ID) 269 .build(); 270 new KeyTester() 271 .addEqualityGroup( 272 "StrategyKidIgnored", 273 JwtHmacKey.builder() 274 .setParameters(parametersIgnoredKidStrategy) 275 .setKeyBytes(keyBytes16) 276 .build(), 277 // the same key built twice must be equal 278 JwtHmacKey.builder() 279 .setParameters(parametersIgnoredKidStrategy) 280 .setKeyBytes(keyBytes16) 281 .build(), 282 // the same key built with a copy of key bytes and parameters must be equal 283 JwtHmacKey.builder() 284 .setParameters(parametersIgnoredKidStrategyCopy) 285 .setKeyBytes(keyBytes16Copy) 286 .build()) 287 .addEqualityGroup( 288 "keyBytes16B", 289 JwtHmacKey.builder() 290 .setParameters(parametersIgnoredKidStrategy) 291 .setKeyBytes(keyBytes16B) 292 .build()) 293 .addEqualityGroup( 294 "parametersHS384", 295 JwtHmacKey.builder().setParameters(parametersHS384).setKeyBytes(keyBytes16).build()) 296 .addEqualityGroup( 297 "parametersHS512", 298 JwtHmacKey.builder().setParameters(parametersHS512).setKeyBytes(keyBytes16).build()) 299 .addEqualityGroup( 300 "parameters32BytesKey", 301 JwtHmacKey.builder().setParameters(parametersKeySize32).setKeyBytes(keyBytes32).build()) 302 .addEqualityGroup( 303 "custom Kid 1", 304 JwtHmacKey.builder() 305 .setParameters(parametersKidStrategyCustom) 306 .setKeyBytes(keyBytes16) 307 .setCustomKid("myCustomKid1") 308 .build()) 309 .addEqualityGroup( 310 "custom Kid 2", 311 JwtHmacKey.builder() 312 .setParameters(parametersKidStrategyCustom) 313 .setKeyBytes(keyBytes16) 314 .setCustomKid("myCustomKid2") 315 .build()) 316 .addEqualityGroup( 317 "base64Id101", 318 JwtHmacKey.builder() 319 .setParameters(parametersKidStrategyBase64) 320 .setKeyBytes(keyBytes16) 321 .setIdRequirement(101) 322 .build()) 323 .addEqualityGroup( 324 "base64Id102", 325 JwtHmacKey.builder() 326 .setParameters(parametersKidStrategyBase64) 327 .setKeyBytes(keyBytes16) 328 .setIdRequirement(102) 329 .build()) 330 .doTests(); 331 } 332 333 @Test testDifferentKeyTypesEquality_fails()334 public void testDifferentKeyTypesEquality_fails() throws Exception { 335 JwtHmacParameters parameters = 336 JwtHmacParameters.builder() 337 .setKeySizeBytes(16) 338 .setAlgorithm(JwtHmacParameters.Algorithm.HS256) 339 .setKidStrategy(JwtHmacParameters.KidStrategy.IGNORED) 340 .build(); 341 SecretBytes keyBytes = SecretBytes.randomBytes(16); 342 JwtHmacKey key = JwtHmacKey.builder().setParameters(parameters).setKeyBytes(keyBytes).build(); 343 344 HmacParameters hmacParameters = 345 HmacParameters.builder() 346 .setKeySizeBytes(16) 347 .setTagSizeBytes(10) 348 .setHashType(HmacParameters.HashType.SHA256) 349 .setVariant(HmacParameters.Variant.NO_PREFIX) 350 .build(); 351 HmacKey hmacKey = HmacKey.builder().setParameters(hmacParameters).setKeyBytes(keyBytes).build(); 352 353 assertThat(key.equalsKey(hmacKey)).isFalse(); 354 } 355 } 356