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 java.math.BigInteger; 23 import java.security.GeneralSecurityException; 24 import org.junit.Test; 25 import org.junit.experimental.theories.DataPoints; 26 import org.junit.experimental.theories.FromDataPoints; 27 import org.junit.experimental.theories.Theories; 28 import org.junit.experimental.theories.Theory; 29 import org.junit.runner.RunWith; 30 31 @RunWith(Theories.class) 32 public final class JwtRsaSsaPkcs1ParametersTest { 33 34 @DataPoints("algorithms") 35 public static final JwtRsaSsaPkcs1Parameters.Algorithm[] ALGORITHMS = 36 new JwtRsaSsaPkcs1Parameters.Algorithm[] { 37 JwtRsaSsaPkcs1Parameters.Algorithm.RS256, 38 JwtRsaSsaPkcs1Parameters.Algorithm.RS384, 39 JwtRsaSsaPkcs1Parameters.Algorithm.RS512 40 }; 41 42 @Theory buildParametersAndGetProperties_hasExpectedValues( @romDataPoints"algorithms") JwtRsaSsaPkcs1Parameters.Algorithm algorithm)43 public void buildParametersAndGetProperties_hasExpectedValues( 44 @FromDataPoints("algorithms") JwtRsaSsaPkcs1Parameters.Algorithm algorithm) throws Exception { 45 JwtRsaSsaPkcs1Parameters parameters = 46 JwtRsaSsaPkcs1Parameters.builder() 47 .setModulusSizeBits(2048) 48 .setPublicExponent(JwtRsaSsaPkcs1Parameters.F4) 49 .setAlgorithm(algorithm) 50 .setKidStrategy(JwtRsaSsaPkcs1Parameters.KidStrategy.IGNORED) 51 .build(); 52 assertThat(parameters.getModulusSizeBits()).isEqualTo(2048); 53 assertThat(parameters.getPublicExponent()).isEqualTo(JwtRsaSsaPkcs1Parameters.F4); 54 assertThat(parameters.getKidStrategy()).isEqualTo(JwtRsaSsaPkcs1Parameters.KidStrategy.IGNORED); 55 assertThat(parameters.getAlgorithm()).isEqualTo(algorithm); 56 assertThat(parameters.hasIdRequirement()).isFalse(); 57 assertThat(parameters.allowKidAbsent()).isTrue(); 58 } 59 60 @Test buildParameters_kidCustom_succeds()61 public void buildParameters_kidCustom_succeds() throws Exception { 62 JwtRsaSsaPkcs1Parameters parameters = 63 JwtRsaSsaPkcs1Parameters.builder() 64 .setModulusSizeBits(2048) 65 .setPublicExponent(JwtRsaSsaPkcs1Parameters.F4) 66 .setAlgorithm(JwtRsaSsaPkcs1Parameters.Algorithm.RS256) 67 .setKidStrategy(JwtRsaSsaPkcs1Parameters.KidStrategy.CUSTOM) 68 .build(); 69 assertThat(parameters.getKidStrategy()).isEqualTo(JwtRsaSsaPkcs1Parameters.KidStrategy.CUSTOM); 70 assertThat(parameters.hasIdRequirement()).isFalse(); 71 assertThat(parameters.allowKidAbsent()).isTrue(); 72 } 73 74 @Test buildParameters_kidBase64_succeds()75 public void buildParameters_kidBase64_succeds() throws Exception { 76 JwtRsaSsaPkcs1Parameters parameters = 77 JwtRsaSsaPkcs1Parameters.builder() 78 .setModulusSizeBits(2048) 79 .setPublicExponent(JwtRsaSsaPkcs1Parameters.F4) 80 .setAlgorithm(JwtRsaSsaPkcs1Parameters.Algorithm.RS256) 81 .setKidStrategy(JwtRsaSsaPkcs1Parameters.KidStrategy.BASE64_ENCODED_KEY_ID) 82 .build(); 83 assertThat(parameters.getKidStrategy()) 84 .isEqualTo(JwtRsaSsaPkcs1Parameters.KidStrategy.BASE64_ENCODED_KEY_ID); 85 assertThat(parameters.hasIdRequirement()).isTrue(); 86 assertThat(parameters.allowKidAbsent()).isFalse(); 87 } 88 89 @Test buildParameters_withoutExponent_isF4()90 public void buildParameters_withoutExponent_isF4() throws Exception { 91 JwtRsaSsaPkcs1Parameters parameters = 92 JwtRsaSsaPkcs1Parameters.builder() 93 .setModulusSizeBits(2048) 94 .setAlgorithm(JwtRsaSsaPkcs1Parameters.Algorithm.RS256) 95 .setKidStrategy(JwtRsaSsaPkcs1Parameters.KidStrategy.IGNORED) 96 .build(); 97 assertThat(parameters.getPublicExponent()).isEqualTo(JwtRsaSsaPkcs1Parameters.F4); 98 } 99 100 @Test buildParameters_withLargeModulusSize_succeds()101 public void buildParameters_withLargeModulusSize_succeds() throws Exception { 102 JwtRsaSsaPkcs1Parameters parameters = 103 JwtRsaSsaPkcs1Parameters.builder() 104 .setModulusSizeBits(16789) 105 .setPublicExponent(JwtRsaSsaPkcs1Parameters.F4) 106 .setAlgorithm(JwtRsaSsaPkcs1Parameters.Algorithm.RS256) 107 .setKidStrategy(JwtRsaSsaPkcs1Parameters.KidStrategy.IGNORED) 108 .build(); 109 assertThat(parameters.getModulusSizeBits()).isEqualTo(16789); 110 } 111 112 @Test buildParameters_withTooSmallModulusSize_fails()113 public void buildParameters_withTooSmallModulusSize_fails() throws Exception { 114 assertThrows( 115 GeneralSecurityException.class, 116 () -> 117 JwtRsaSsaPkcs1Parameters.builder() 118 .setModulusSizeBits(2047) 119 .setPublicExponent(JwtRsaSsaPkcs1Parameters.F4) 120 .setAlgorithm(JwtRsaSsaPkcs1Parameters.Algorithm.RS256) 121 .setKidStrategy(JwtRsaSsaPkcs1Parameters.KidStrategy.IGNORED) 122 .build()); 123 } 124 125 @Test buildParameters_withValidNonF4PublicExponent_succeds()126 public void buildParameters_withValidNonF4PublicExponent_succeds() throws Exception { 127 JwtRsaSsaPkcs1Parameters parameters = 128 JwtRsaSsaPkcs1Parameters.builder() 129 .setModulusSizeBits(2048) 130 .setPublicExponent(BigInteger.valueOf(1234567)) 131 .setAlgorithm(JwtRsaSsaPkcs1Parameters.Algorithm.RS512) 132 .setKidStrategy(JwtRsaSsaPkcs1Parameters.KidStrategy.CUSTOM) 133 .build(); 134 assertThat(parameters.getPublicExponent()).isEqualTo(BigInteger.valueOf(1234567)); 135 } 136 137 @Test buildParameters_withSmallPublicExponent_fails()138 public void buildParameters_withSmallPublicExponent_fails() throws Exception { 139 assertThrows( 140 GeneralSecurityException.class, 141 () -> 142 JwtRsaSsaPkcs1Parameters.builder() 143 .setModulusSizeBits(2048) 144 .setPublicExponent(BigInteger.valueOf(3)) 145 .setAlgorithm(JwtRsaSsaPkcs1Parameters.Algorithm.RS256) 146 .setKidStrategy(JwtRsaSsaPkcs1Parameters.KidStrategy.IGNORED) 147 .build()); 148 } 149 150 @Test buildParameters_withEvenPublicExponent_fails()151 public void buildParameters_withEvenPublicExponent_fails() throws Exception { 152 assertThrows( 153 GeneralSecurityException.class, 154 () -> 155 JwtRsaSsaPkcs1Parameters.builder() 156 .setModulusSizeBits(2048) 157 .setPublicExponent(BigInteger.valueOf(1234568)) 158 .setAlgorithm(JwtRsaSsaPkcs1Parameters.Algorithm.RS256) 159 .setKidStrategy(JwtRsaSsaPkcs1Parameters.KidStrategy.IGNORED) 160 .build()); 161 } 162 163 // Public exponents larger than 2^256 are rejected. See: 164 // https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.186-4.pdf, B.3 165 @Test buildParameters_withTooLargePublicExponent_fails()166 public void buildParameters_withTooLargePublicExponent_fails() throws Exception { 167 BigInteger tooLargeE = BigInteger.valueOf(2).pow(256).add(BigInteger.ONE); 168 assertThat(tooLargeE.bitLength()).isEqualTo(257); 169 assertThrows( 170 GeneralSecurityException.class, 171 () -> 172 JwtRsaSsaPkcs1Parameters.builder() 173 .setModulusSizeBits(2048) 174 .setPublicExponent(tooLargeE) 175 .setAlgorithm(JwtRsaSsaPkcs1Parameters.Algorithm.RS256) 176 .setKidStrategy(JwtRsaSsaPkcs1Parameters.KidStrategy.IGNORED) 177 .build()); 178 } 179 180 @Test buildParameters_withoutSettingModulusSize_fails()181 public void buildParameters_withoutSettingModulusSize_fails() throws Exception { 182 assertThrows( 183 GeneralSecurityException.class, 184 () -> 185 JwtRsaSsaPkcs1Parameters.builder() 186 .setPublicExponent(JwtRsaSsaPkcs1Parameters.F4) 187 .setAlgorithm(JwtRsaSsaPkcs1Parameters.Algorithm.RS256) 188 .setKidStrategy(JwtRsaSsaPkcs1Parameters.KidStrategy.IGNORED) 189 .build()); 190 } 191 192 @Test buildParameters_withoutSettingAlgorithm_fails()193 public void buildParameters_withoutSettingAlgorithm_fails() throws Exception { 194 assertThrows( 195 GeneralSecurityException.class, 196 () -> 197 JwtRsaSsaPkcs1Parameters.builder() 198 .setModulusSizeBits(2048) 199 .setPublicExponent(JwtRsaSsaPkcs1Parameters.F4) 200 .setKidStrategy(JwtRsaSsaPkcs1Parameters.KidStrategy.IGNORED) 201 .build()); 202 } 203 204 @Test buildParameters_withoutSettingKidStrategy_fails()205 public void buildParameters_withoutSettingKidStrategy_fails() throws Exception { 206 assertThrows( 207 GeneralSecurityException.class, 208 () -> 209 JwtRsaSsaPkcs1Parameters.builder() 210 .setModulusSizeBits(2048) 211 .setPublicExponent(JwtRsaSsaPkcs1Parameters.F4) 212 .setAlgorithm(JwtRsaSsaPkcs1Parameters.Algorithm.RS256) 213 .build()); 214 } 215 216 @Test testEqualsAndEqualsHashCode_succeds()217 public void testEqualsAndEqualsHashCode_succeds() throws Exception { 218 JwtRsaSsaPkcs1Parameters parameters1 = 219 JwtRsaSsaPkcs1Parameters.builder() 220 .setModulusSizeBits(2048) 221 .setPublicExponent(JwtRsaSsaPkcs1Parameters.F4) 222 .setAlgorithm(JwtRsaSsaPkcs1Parameters.Algorithm.RS256) 223 .setKidStrategy(JwtRsaSsaPkcs1Parameters.KidStrategy.IGNORED) 224 .build(); 225 JwtRsaSsaPkcs1Parameters parameters2 = 226 JwtRsaSsaPkcs1Parameters.builder() 227 .setModulusSizeBits(2048) 228 .setPublicExponent(JwtRsaSsaPkcs1Parameters.F4) 229 .setAlgorithm(JwtRsaSsaPkcs1Parameters.Algorithm.RS256) 230 .setKidStrategy(JwtRsaSsaPkcs1Parameters.KidStrategy.IGNORED) 231 .build(); 232 assertThat(parameters1).isEqualTo(parameters2); 233 assertThat(parameters1.hashCode()).isEqualTo(parameters2.hashCode()); 234 } 235 236 @Test testEqualsHashCode_dependsOnModulusSize()237 public void testEqualsHashCode_dependsOnModulusSize() throws Exception { 238 JwtRsaSsaPkcs1Parameters parameters1 = 239 JwtRsaSsaPkcs1Parameters.builder() 240 .setModulusSizeBits(2048) 241 .setPublicExponent(JwtRsaSsaPkcs1Parameters.F4) 242 .setAlgorithm(JwtRsaSsaPkcs1Parameters.Algorithm.RS256) 243 .setKidStrategy(JwtRsaSsaPkcs1Parameters.KidStrategy.IGNORED) 244 .build(); 245 JwtRsaSsaPkcs1Parameters parameters2 = 246 JwtRsaSsaPkcs1Parameters.builder() 247 .setModulusSizeBits(2049) 248 .setPublicExponent(JwtRsaSsaPkcs1Parameters.F4) 249 .setAlgorithm(JwtRsaSsaPkcs1Parameters.Algorithm.RS256) 250 .setKidStrategy(JwtRsaSsaPkcs1Parameters.KidStrategy.IGNORED) 251 .build(); 252 assertThat(parameters1).isNotEqualTo(parameters2); 253 assertThat(parameters1.hashCode()).isNotEqualTo(parameters2.hashCode()); 254 } 255 256 @Test testEqualsHashCode_dependsOnPublicExponent()257 public void testEqualsHashCode_dependsOnPublicExponent() throws Exception { 258 JwtRsaSsaPkcs1Parameters parameters1 = 259 JwtRsaSsaPkcs1Parameters.builder() 260 .setModulusSizeBits(2048) 261 .setPublicExponent(JwtRsaSsaPkcs1Parameters.F4) 262 .setAlgorithm(JwtRsaSsaPkcs1Parameters.Algorithm.RS256) 263 .setKidStrategy(JwtRsaSsaPkcs1Parameters.KidStrategy.IGNORED) 264 .build(); 265 JwtRsaSsaPkcs1Parameters parameters2 = 266 JwtRsaSsaPkcs1Parameters.builder() 267 .setModulusSizeBits(2048) 268 .setPublicExponent(BigInteger.valueOf(65539)) 269 .setAlgorithm(JwtRsaSsaPkcs1Parameters.Algorithm.RS256) 270 .setKidStrategy(JwtRsaSsaPkcs1Parameters.KidStrategy.IGNORED) 271 .build(); 272 assertThat(parameters1).isNotEqualTo(parameters2); 273 assertThat(parameters1.hashCode()).isNotEqualTo(parameters2.hashCode()); 274 } 275 276 @Test testEqualsHashCode_dependsOnAlgorithm()277 public void testEqualsHashCode_dependsOnAlgorithm() throws Exception { 278 JwtRsaSsaPkcs1Parameters parameters1 = 279 JwtRsaSsaPkcs1Parameters.builder() 280 .setModulusSizeBits(2048) 281 .setPublicExponent(JwtRsaSsaPkcs1Parameters.F4) 282 .setAlgorithm(JwtRsaSsaPkcs1Parameters.Algorithm.RS256) 283 .setKidStrategy(JwtRsaSsaPkcs1Parameters.KidStrategy.IGNORED) 284 .build(); 285 JwtRsaSsaPkcs1Parameters parameters2 = 286 JwtRsaSsaPkcs1Parameters.builder() 287 .setModulusSizeBits(2048) 288 .setPublicExponent(JwtRsaSsaPkcs1Parameters.F4) 289 .setAlgorithm(JwtRsaSsaPkcs1Parameters.Algorithm.RS384) 290 .setKidStrategy(JwtRsaSsaPkcs1Parameters.KidStrategy.IGNORED) 291 .build(); 292 assertThat(parameters1).isNotEqualTo(parameters2); 293 assertThat(parameters1.hashCode()).isNotEqualTo(parameters2.hashCode()); 294 } 295 296 @Test testEqualsHashCode_dependsOnKidStrategy()297 public void testEqualsHashCode_dependsOnKidStrategy() throws Exception { 298 JwtRsaSsaPkcs1Parameters parameters1 = 299 JwtRsaSsaPkcs1Parameters.builder() 300 .setModulusSizeBits(2048) 301 .setPublicExponent(JwtRsaSsaPkcs1Parameters.F4) 302 .setAlgorithm(JwtRsaSsaPkcs1Parameters.Algorithm.RS256) 303 .setKidStrategy(JwtRsaSsaPkcs1Parameters.KidStrategy.IGNORED) 304 .build(); 305 JwtRsaSsaPkcs1Parameters parameters2 = 306 JwtRsaSsaPkcs1Parameters.builder() 307 .setModulusSizeBits(2048) 308 .setPublicExponent(JwtRsaSsaPkcs1Parameters.F4) 309 .setAlgorithm(JwtRsaSsaPkcs1Parameters.Algorithm.RS256) 310 .setKidStrategy(JwtRsaSsaPkcs1Parameters.KidStrategy.CUSTOM) 311 .build(); 312 assertThat(parameters1).isNotEqualTo(parameters2); 313 assertThat(parameters1.hashCode()).isNotEqualTo(parameters2.hashCode()); 314 } 315 } 316