diff options
author | ioannanedelcu <ioannanedelcu@google.com> | 2023-07-19 07:50:47 -0700 |
---|---|---|
committer | Copybara-Service <copybara-worker@google.com> | 2023-07-19 07:52:28 -0700 |
commit | 7ac3ceb9334b94bc8d327bd35f9b2c673211494e (patch) | |
tree | dd551b8efed6972e8ae92b396eacac4b08e7c6a9 | |
parent | 8db6a113331f062006e9a03d8561e3105753277b (diff) | |
download | tink-7ac3ceb9334b94bc8d327bd35f9b2c673211494e.tar.gz |
Add JwtRsaSsaPkcs1Parameters class in Java.
PiperOrigin-RevId: 549314771
5 files changed, 623 insertions, 0 deletions
diff --git a/java_src/BUILD.bazel b/java_src/BUILD.bazel index 27dd2b3dd..e8e3432ce 100644 --- a/java_src/BUILD.bazel +++ b/java_src/BUILD.bazel @@ -239,6 +239,7 @@ gen_maven_jar_rules( "//src/main/java/com/google/crypto/tink/jwt:jwt_public_key_verify", "//src/main/java/com/google/crypto/tink/jwt:jwt_public_key_verify_internal", "//src/main/java/com/google/crypto/tink/jwt:jwt_public_key_verify_wrapper", + "//src/main/java/com/google/crypto/tink/jwt:jwt_rsa_ssa_pkcs1_parameters", "//src/main/java/com/google/crypto/tink/jwt:jwt_rsa_ssa_pkcs1_sign_key_manager", "//src/main/java/com/google/crypto/tink/jwt:jwt_rsa_ssa_pkcs1_verify_key_manager", "//src/main/java/com/google/crypto/tink/jwt:jwt_rsa_ssa_pss_sign_key_manager", @@ -668,6 +669,7 @@ gen_maven_jar_rules( "//src/main/java/com/google/crypto/tink/jwt:jwt_public_key_verify-android", "//src/main/java/com/google/crypto/tink/jwt:jwt_public_key_verify_internal-android", "//src/main/java/com/google/crypto/tink/jwt:jwt_public_key_verify_wrapper-android", + "//src/main/java/com/google/crypto/tink/jwt:jwt_rsa_ssa_pkcs1_parameters-android", "//src/main/java/com/google/crypto/tink/jwt:jwt_rsa_ssa_pkcs1_sign_key_manager-android", "//src/main/java/com/google/crypto/tink/jwt:jwt_rsa_ssa_pkcs1_verify_key_manager-android", "//src/main/java/com/google/crypto/tink/jwt:jwt_rsa_ssa_pss_sign_key_manager-android", diff --git a/java_src/src/main/java/com/google/crypto/tink/jwt/BUILD.bazel b/java_src/src/main/java/com/google/crypto/tink/jwt/BUILD.bazel index 98c8cd132..5f205a5ee 100644 --- a/java_src/src/main/java/com/google/crypto/tink/jwt/BUILD.bazel +++ b/java_src/src/main/java/com/google/crypto/tink/jwt/BUILD.bazel @@ -1125,3 +1125,21 @@ java_library( "@maven//:com_google_protobuf_protobuf_java", ], ) + +android_library( + name = "jwt_rsa_ssa_pkcs1_parameters-android", + srcs = ["JwtRsaSsaPkcs1Parameters.java"], + deps = [ + ":jwt_signature_parameters-android", + "@maven//:com_google_errorprone_error_prone_annotations", + ], +) + +java_library( + name = "jwt_rsa_ssa_pkcs1_parameters", + srcs = ["JwtRsaSsaPkcs1Parameters.java"], + deps = [ + ":jwt_signature_parameters", + "@maven//:com_google_errorprone_error_prone_annotations", + ], +) diff --git a/java_src/src/main/java/com/google/crypto/tink/jwt/JwtRsaSsaPkcs1Parameters.java b/java_src/src/main/java/com/google/crypto/tink/jwt/JwtRsaSsaPkcs1Parameters.java new file mode 100644 index 000000000..9daa5f9c9 --- /dev/null +++ b/java_src/src/main/java/com/google/crypto/tink/jwt/JwtRsaSsaPkcs1Parameters.java @@ -0,0 +1,277 @@ +// Copyright 2023 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//////////////////////////////////////////////////////////////////////////////// + +package com.google.crypto.tink.jwt; + +import com.google.errorprone.annotations.CanIgnoreReturnValue; +import com.google.errorprone.annotations.Immutable; +import java.math.BigInteger; +import java.security.GeneralSecurityException; +import java.security.InvalidAlgorithmParameterException; +import java.util.Objects; +import java.util.Optional; + +/** + * Describes the parameters of a {@link JwtRsaSsaPkcs1PublicKey} and {@link + * JwtRsaSsaPkcs1PrivateKey}. + * + * <p>Standard: https://datatracker.ietf.org/doc/html/rfc7518 + */ +public final class JwtRsaSsaPkcs1Parameters extends JwtSignatureParameters { + /** Specifies how the "kid" header is handled. */ + @Immutable + public static final class KidStrategy { + /** + * The "kid" is the URL safe (RFC 4648 Section 5) base64-encoded big-endian key_id in the + * keyset. + * + * <p>In {@code PublicKeySign#signAndEncode} Tink always adds the KID. + * + * <p>In {@code PublicKeyVerify#verifyAndDecode} Tink checks that the kid is present and equal + * to this value. + * + * <p>This strategy is recommended by Tink. + */ + public static final KidStrategy BASE64_ENCODED_KEY_ID = + new KidStrategy("BASE64_ENCODED_KEY_ID"); + + /** + * The "kid" header is ignored. + * + * <p>In {@code PublicKeySign#signAndEncode} Tink does not write a "kid" header. + * + * <p>In {@code PublicKeyVerify#verifyAndDecode} Tink ignores the "kid" header. + */ + public static final KidStrategy IGNORED = new KidStrategy("IGNORED"); + + /** + * The "kid" is fixed. It can be obtained from {@code parameters.getCustomKid()}. + * + * <p>In {@code PublicKeySign#signAndEncode} Tink writes the "kid" header to the value given by + * {@code parameters.getCustomKid()}. + * + * <p>In {@code PublicKeyVerify#verifyAndDecode}, if the kid is present, it needs to match + * {@code parameters.getCustomKid()}. If the kid is absent, it will be accepted. + * + * <p>Note: Tink does not allow to randomly generate new {@link JwtRsaSsaPkcs1Key} objects from + * parameters objects with {@code KidStrategy} equals to {@code CUSTOM}. + */ + public static final KidStrategy CUSTOM = new KidStrategy("CUSTOM"); + + private final String name; + + private KidStrategy(String name) { + this.name = name; + } + + @Override + public String toString() { + return name; + } + } + + /** The algorithm to be used for the signature computation. */ + @Immutable + public static final class Algorithm { + /** RSASSAPKCS1 using SHA-256 */ + public static final Algorithm RS256 = new Algorithm("RS256"); + + /** RSASSAPKCS1 using SHA-384 */ + public static final Algorithm RS384 = new Algorithm("RS384"); + + /** RSASSAPKCS1 using SHA-512 */ + public static final Algorithm RS512 = new Algorithm("RS512"); + + private final String name; + + private Algorithm(String name) { + this.name = name; + } + + @Override + public String toString() { + return name; + } + + public String getStandardName() { + return name; + } + } + + public static final BigInteger F4 = BigInteger.valueOf(65537); + + /** Builds a new JwtRsaSsaPkcs1Parameters instance. */ + public static final class Builder { + Optional<Integer> modulusSizeBits = Optional.empty(); + Optional<BigInteger> publicExponent = Optional.of(F4); + Optional<KidStrategy> kidStrategy = Optional.empty(); + Optional<Algorithm> algorithm = Optional.empty(); + + private Builder() {} + + @CanIgnoreReturnValue + public Builder setModulusSizeBits(int modulusSizeBits) { + this.modulusSizeBits = Optional.of(modulusSizeBits); + return this; + } + + @CanIgnoreReturnValue + public Builder setPublicExponent(BigInteger e) { + this.publicExponent = Optional.of(e); + return this; + } + + @CanIgnoreReturnValue + public Builder setKidStrategy(KidStrategy kidStrategy) { + this.kidStrategy = Optional.of(kidStrategy); + return this; + } + + @CanIgnoreReturnValue + public Builder setAlgorithm(Algorithm algorithm) { + this.algorithm = Optional.of(algorithm); + return this; + } + + private static final BigInteger TWO = BigInteger.valueOf(2); + private static final BigInteger PUBLIC_EXPONENT_UPPER_BOUND = TWO.pow(256); + + private void validatePublicExponent(BigInteger publicExponent) + throws InvalidAlgorithmParameterException { + // We use the validation of the public exponent as defined in + // https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.186-4.pdf, B.3 + int c = publicExponent.compareTo(F4); + if (c == 0) { + // publicExponent is F4. + return; + } + if (c < 0) { + // publicExponent is smaller than F4. + throw new InvalidAlgorithmParameterException("Public exponent must be at least 65537."); + } + if (publicExponent.mod(TWO).equals(BigInteger.ZERO)) { + // publicExponent is even. This is invalid since it is not co-prime to p-1. + throw new InvalidAlgorithmParameterException("Invalid public exponent"); + } + if (publicExponent.compareTo(PUBLIC_EXPONENT_UPPER_BOUND) > 0) { + // publicExponent is larger than PUBLIC_EXPONENT_UPPER_BOUND. + throw new InvalidAlgorithmParameterException( + "Public exponent cannot be larger than 2^256."); + } + } + + public JwtRsaSsaPkcs1Parameters build() throws GeneralSecurityException { + if (!modulusSizeBits.isPresent()) { + throw new GeneralSecurityException("key size is not set"); + } + if (!publicExponent.isPresent()) { + throw new GeneralSecurityException("publicExponent is not set"); + } + if (!algorithm.isPresent()) { + throw new GeneralSecurityException("Algorithm must be set"); + } + if (!kidStrategy.isPresent()) { + throw new GeneralSecurityException("KidStrategy must be set"); + } + if (modulusSizeBits.get() < 2048) { + throw new InvalidAlgorithmParameterException( + String.format( + "Invalid modulus size in bits %d; must be at least 2048 bits", + modulusSizeBits.get())); + } + validatePublicExponent(publicExponent.get()); + return new JwtRsaSsaPkcs1Parameters( + modulusSizeBits.get(), publicExponent.get(), kidStrategy.get(), algorithm.get()); + } + } + + private final int modulusSizeBits; + private final BigInteger publicExponent; + private final KidStrategy kidStrategy; + private final Algorithm algorithm; + + private JwtRsaSsaPkcs1Parameters( + int modulusSizeBits, + BigInteger publicExponent, + KidStrategy kidStrategy, + Algorithm algorithm) { + this.modulusSizeBits = modulusSizeBits; + this.publicExponent = publicExponent; + this.kidStrategy = kidStrategy; + this.algorithm = algorithm; + } + + public static Builder builder() { + return new Builder(); + } + + public int getModulusSizeBits() { + return modulusSizeBits; + } + + public BigInteger getPublicExponent() { + return publicExponent; + } + + public KidStrategy getKidStrategy() { + return kidStrategy; + } + + public Algorithm getAlgorithm() { + return algorithm; + } + + @Override + public boolean allowKidAbsent() { + return kidStrategy.equals(KidStrategy.CUSTOM) || kidStrategy.equals(KidStrategy.IGNORED); + } + + @Override + public boolean equals(Object o) { + if (!(o instanceof JwtRsaSsaPkcs1Parameters)) { + return false; + } + JwtRsaSsaPkcs1Parameters that = (JwtRsaSsaPkcs1Parameters) o; + return that.getModulusSizeBits() == getModulusSizeBits() + && Objects.equals(that.getPublicExponent(), getPublicExponent()) + && that.kidStrategy.equals(kidStrategy) + && that.algorithm.equals(algorithm); + } + + @Override + public int hashCode() { + return Objects.hash( + JwtRsaSsaPkcs1Parameters.class, modulusSizeBits, publicExponent, kidStrategy, algorithm); + } + + @Override + public boolean hasIdRequirement() { + return kidStrategy.equals(KidStrategy.BASE64_ENCODED_KEY_ID); + } + + @Override + public String toString() { + return "JWT RSA SSA PKCS1 Parameters (kidStrategy: " + + kidStrategy + + ", algorithm " + + algorithm + + ", publicExponent: " + + publicExponent + + ", and " + + modulusSizeBits + + "-bit modulus)"; + } +} diff --git a/java_src/src/test/java/com/google/crypto/tink/jwt/BUILD.bazel b/java_src/src/test/java/com/google/crypto/tink/jwt/BUILD.bazel index b9176b827..6371ee03d 100644 --- a/java_src/src/test/java/com/google/crypto/tink/jwt/BUILD.bazel +++ b/java_src/src/test/java/com/google/crypto/tink/jwt/BUILD.bazel @@ -499,3 +499,14 @@ java_test( "@maven//:junit_junit", ], ) + +java_test( + name = "JwtRsaSsaPkcs1ParametersTest", + size = "small", + srcs = ["JwtRsaSsaPkcs1ParametersTest.java"], + deps = [ + "//src/main/java/com/google/crypto/tink/jwt:jwt_rsa_ssa_pkcs1_parameters", + "@maven//:com_google_truth_truth", + "@maven//:junit_junit", + ], +) diff --git a/java_src/src/test/java/com/google/crypto/tink/jwt/JwtRsaSsaPkcs1ParametersTest.java b/java_src/src/test/java/com/google/crypto/tink/jwt/JwtRsaSsaPkcs1ParametersTest.java new file mode 100644 index 000000000..8e0efbe2d --- /dev/null +++ b/java_src/src/test/java/com/google/crypto/tink/jwt/JwtRsaSsaPkcs1ParametersTest.java @@ -0,0 +1,315 @@ +// Copyright 2023 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//////////////////////////////////////////////////////////////////////////////// + +package com.google.crypto.tink.jwt; + +import static com.google.common.truth.Truth.assertThat; +import static org.junit.Assert.assertThrows; + +import java.math.BigInteger; +import java.security.GeneralSecurityException; +import org.junit.Test; +import org.junit.experimental.theories.DataPoints; +import org.junit.experimental.theories.FromDataPoints; +import org.junit.experimental.theories.Theories; +import org.junit.experimental.theories.Theory; +import org.junit.runner.RunWith; + +@RunWith(Theories.class) +public final class JwtRsaSsaPkcs1ParametersTest { + + @DataPoints("algorithms") + public static final JwtRsaSsaPkcs1Parameters.Algorithm[] ALGORITHMS = + new JwtRsaSsaPkcs1Parameters.Algorithm[] { + JwtRsaSsaPkcs1Parameters.Algorithm.RS256, + JwtRsaSsaPkcs1Parameters.Algorithm.RS384, + JwtRsaSsaPkcs1Parameters.Algorithm.RS512 + }; + + @Theory + public void buildParametersAndGetProperties_hasExpectedValues( + @FromDataPoints("algorithms") JwtRsaSsaPkcs1Parameters.Algorithm algorithm) throws Exception { + JwtRsaSsaPkcs1Parameters parameters = + JwtRsaSsaPkcs1Parameters.builder() + .setModulusSizeBits(2048) + .setPublicExponent(JwtRsaSsaPkcs1Parameters.F4) + .setAlgorithm(algorithm) + .setKidStrategy(JwtRsaSsaPkcs1Parameters.KidStrategy.IGNORED) + .build(); + assertThat(parameters.getModulusSizeBits()).isEqualTo(2048); + assertThat(parameters.getPublicExponent()).isEqualTo(JwtRsaSsaPkcs1Parameters.F4); + assertThat(parameters.getKidStrategy()).isEqualTo(JwtRsaSsaPkcs1Parameters.KidStrategy.IGNORED); + assertThat(parameters.getAlgorithm()).isEqualTo(algorithm); + assertThat(parameters.hasIdRequirement()).isFalse(); + assertThat(parameters.allowKidAbsent()).isTrue(); + } + + @Test + public void buildParameters_kidCustom_succeds() throws Exception { + JwtRsaSsaPkcs1Parameters parameters = + JwtRsaSsaPkcs1Parameters.builder() + .setModulusSizeBits(2048) + .setPublicExponent(JwtRsaSsaPkcs1Parameters.F4) + .setAlgorithm(JwtRsaSsaPkcs1Parameters.Algorithm.RS256) + .setKidStrategy(JwtRsaSsaPkcs1Parameters.KidStrategy.CUSTOM) + .build(); + assertThat(parameters.getKidStrategy()).isEqualTo(JwtRsaSsaPkcs1Parameters.KidStrategy.CUSTOM); + assertThat(parameters.hasIdRequirement()).isFalse(); + assertThat(parameters.allowKidAbsent()).isTrue(); + } + + @Test + public void buildParameters_kidBase64_succeds() throws Exception { + JwtRsaSsaPkcs1Parameters parameters = + JwtRsaSsaPkcs1Parameters.builder() + .setModulusSizeBits(2048) + .setPublicExponent(JwtRsaSsaPkcs1Parameters.F4) + .setAlgorithm(JwtRsaSsaPkcs1Parameters.Algorithm.RS256) + .setKidStrategy(JwtRsaSsaPkcs1Parameters.KidStrategy.BASE64_ENCODED_KEY_ID) + .build(); + assertThat(parameters.getKidStrategy()) + .isEqualTo(JwtRsaSsaPkcs1Parameters.KidStrategy.BASE64_ENCODED_KEY_ID); + assertThat(parameters.hasIdRequirement()).isTrue(); + assertThat(parameters.allowKidAbsent()).isFalse(); + } + + @Test + public void buildParameters_withoutExponent_isF4() throws Exception { + JwtRsaSsaPkcs1Parameters parameters = + JwtRsaSsaPkcs1Parameters.builder() + .setModulusSizeBits(2048) + .setAlgorithm(JwtRsaSsaPkcs1Parameters.Algorithm.RS256) + .setKidStrategy(JwtRsaSsaPkcs1Parameters.KidStrategy.IGNORED) + .build(); + assertThat(parameters.getPublicExponent()).isEqualTo(JwtRsaSsaPkcs1Parameters.F4); + } + + @Test + public void buildParameters_withLargeModulusSize_succeds() throws Exception { + JwtRsaSsaPkcs1Parameters parameters = + JwtRsaSsaPkcs1Parameters.builder() + .setModulusSizeBits(16789) + .setPublicExponent(JwtRsaSsaPkcs1Parameters.F4) + .setAlgorithm(JwtRsaSsaPkcs1Parameters.Algorithm.RS256) + .setKidStrategy(JwtRsaSsaPkcs1Parameters.KidStrategy.IGNORED) + .build(); + assertThat(parameters.getModulusSizeBits()).isEqualTo(16789); + } + + @Test + public void buildParameters_withTooSmallModulusSize_fails() throws Exception { + assertThrows( + GeneralSecurityException.class, + () -> + JwtRsaSsaPkcs1Parameters.builder() + .setModulusSizeBits(2047) + .setPublicExponent(JwtRsaSsaPkcs1Parameters.F4) + .setAlgorithm(JwtRsaSsaPkcs1Parameters.Algorithm.RS256) + .setKidStrategy(JwtRsaSsaPkcs1Parameters.KidStrategy.IGNORED) + .build()); + } + + @Test + public void buildParameters_withValidNonF4PublicExponent_succeds() throws Exception { + JwtRsaSsaPkcs1Parameters parameters = + JwtRsaSsaPkcs1Parameters.builder() + .setModulusSizeBits(2048) + .setPublicExponent(BigInteger.valueOf(1234567)) + .setAlgorithm(JwtRsaSsaPkcs1Parameters.Algorithm.RS512) + .setKidStrategy(JwtRsaSsaPkcs1Parameters.KidStrategy.CUSTOM) + .build(); + assertThat(parameters.getPublicExponent()).isEqualTo(BigInteger.valueOf(1234567)); + } + + @Test + public void buildParameters_withSmallPublicExponent_fails() throws Exception { + assertThrows( + GeneralSecurityException.class, + () -> + JwtRsaSsaPkcs1Parameters.builder() + .setModulusSizeBits(2048) + .setPublicExponent(BigInteger.valueOf(3)) + .setAlgorithm(JwtRsaSsaPkcs1Parameters.Algorithm.RS256) + .setKidStrategy(JwtRsaSsaPkcs1Parameters.KidStrategy.IGNORED) + .build()); + } + + @Test + public void buildParameters_withEvenPublicExponent_fails() throws Exception { + assertThrows( + GeneralSecurityException.class, + () -> + JwtRsaSsaPkcs1Parameters.builder() + .setModulusSizeBits(2048) + .setPublicExponent(BigInteger.valueOf(1234568)) + .setAlgorithm(JwtRsaSsaPkcs1Parameters.Algorithm.RS256) + .setKidStrategy(JwtRsaSsaPkcs1Parameters.KidStrategy.IGNORED) + .build()); + } + + // Public exponents larger than 2^256 are rejected. See: + // https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.186-4.pdf, B.3 + @Test + public void buildParameters_withTooLargePublicExponent_fails() throws Exception { + BigInteger tooLargeE = BigInteger.valueOf(2).pow(256).add(BigInteger.ONE); + assertThat(tooLargeE.bitLength()).isEqualTo(257); + assertThrows( + GeneralSecurityException.class, + () -> + JwtRsaSsaPkcs1Parameters.builder() + .setModulusSizeBits(2048) + .setPublicExponent(tooLargeE) + .setAlgorithm(JwtRsaSsaPkcs1Parameters.Algorithm.RS256) + .setKidStrategy(JwtRsaSsaPkcs1Parameters.KidStrategy.IGNORED) + .build()); + } + + @Test + public void buildParameters_withoutSettingModulusSize_fails() throws Exception { + assertThrows( + GeneralSecurityException.class, + () -> + JwtRsaSsaPkcs1Parameters.builder() + .setPublicExponent(JwtRsaSsaPkcs1Parameters.F4) + .setAlgorithm(JwtRsaSsaPkcs1Parameters.Algorithm.RS256) + .setKidStrategy(JwtRsaSsaPkcs1Parameters.KidStrategy.IGNORED) + .build()); + } + + @Test + public void buildParameters_withoutSettingAlgorithm_fails() throws Exception { + assertThrows( + GeneralSecurityException.class, + () -> + JwtRsaSsaPkcs1Parameters.builder() + .setModulusSizeBits(2048) + .setPublicExponent(JwtRsaSsaPkcs1Parameters.F4) + .setKidStrategy(JwtRsaSsaPkcs1Parameters.KidStrategy.IGNORED) + .build()); + } + + @Test + public void buildParameters_withoutSettingKidStrategy_fails() throws Exception { + assertThrows( + GeneralSecurityException.class, + () -> + JwtRsaSsaPkcs1Parameters.builder() + .setModulusSizeBits(2048) + .setPublicExponent(JwtRsaSsaPkcs1Parameters.F4) + .setAlgorithm(JwtRsaSsaPkcs1Parameters.Algorithm.RS256) + .build()); + } + + @Test + public void testEqualsAndEqualsHashCode_succeds() throws Exception { + JwtRsaSsaPkcs1Parameters parameters1 = + JwtRsaSsaPkcs1Parameters.builder() + .setModulusSizeBits(2048) + .setPublicExponent(JwtRsaSsaPkcs1Parameters.F4) + .setAlgorithm(JwtRsaSsaPkcs1Parameters.Algorithm.RS256) + .setKidStrategy(JwtRsaSsaPkcs1Parameters.KidStrategy.IGNORED) + .build(); + JwtRsaSsaPkcs1Parameters parameters2 = + JwtRsaSsaPkcs1Parameters.builder() + .setModulusSizeBits(2048) + .setPublicExponent(JwtRsaSsaPkcs1Parameters.F4) + .setAlgorithm(JwtRsaSsaPkcs1Parameters.Algorithm.RS256) + .setKidStrategy(JwtRsaSsaPkcs1Parameters.KidStrategy.IGNORED) + .build(); + assertThat(parameters1).isEqualTo(parameters2); + assertThat(parameters1.hashCode()).isEqualTo(parameters2.hashCode()); + } + + @Test + public void testEqualsHashCode_dependsOnModulusSize() throws Exception { + JwtRsaSsaPkcs1Parameters parameters1 = + JwtRsaSsaPkcs1Parameters.builder() + .setModulusSizeBits(2048) + .setPublicExponent(JwtRsaSsaPkcs1Parameters.F4) + .setAlgorithm(JwtRsaSsaPkcs1Parameters.Algorithm.RS256) + .setKidStrategy(JwtRsaSsaPkcs1Parameters.KidStrategy.IGNORED) + .build(); + JwtRsaSsaPkcs1Parameters parameters2 = + JwtRsaSsaPkcs1Parameters.builder() + .setModulusSizeBits(2049) + .setPublicExponent(JwtRsaSsaPkcs1Parameters.F4) + .setAlgorithm(JwtRsaSsaPkcs1Parameters.Algorithm.RS256) + .setKidStrategy(JwtRsaSsaPkcs1Parameters.KidStrategy.IGNORED) + .build(); + assertThat(parameters1).isNotEqualTo(parameters2); + assertThat(parameters1.hashCode()).isNotEqualTo(parameters2.hashCode()); + } + + @Test + public void testEqualsHashCode_dependsOnPublicExponent() throws Exception { + JwtRsaSsaPkcs1Parameters parameters1 = + JwtRsaSsaPkcs1Parameters.builder() + .setModulusSizeBits(2048) + .setPublicExponent(JwtRsaSsaPkcs1Parameters.F4) + .setAlgorithm(JwtRsaSsaPkcs1Parameters.Algorithm.RS256) + .setKidStrategy(JwtRsaSsaPkcs1Parameters.KidStrategy.IGNORED) + .build(); + JwtRsaSsaPkcs1Parameters parameters2 = + JwtRsaSsaPkcs1Parameters.builder() + .setModulusSizeBits(2048) + .setPublicExponent(BigInteger.valueOf(65539)) + .setAlgorithm(JwtRsaSsaPkcs1Parameters.Algorithm.RS256) + .setKidStrategy(JwtRsaSsaPkcs1Parameters.KidStrategy.IGNORED) + .build(); + assertThat(parameters1).isNotEqualTo(parameters2); + assertThat(parameters1.hashCode()).isNotEqualTo(parameters2.hashCode()); + } + + @Test + public void testEqualsHashCode_dependsOnAlgorithm() throws Exception { + JwtRsaSsaPkcs1Parameters parameters1 = + JwtRsaSsaPkcs1Parameters.builder() + .setModulusSizeBits(2048) + .setPublicExponent(JwtRsaSsaPkcs1Parameters.F4) + .setAlgorithm(JwtRsaSsaPkcs1Parameters.Algorithm.RS256) + .setKidStrategy(JwtRsaSsaPkcs1Parameters.KidStrategy.IGNORED) + .build(); + JwtRsaSsaPkcs1Parameters parameters2 = + JwtRsaSsaPkcs1Parameters.builder() + .setModulusSizeBits(2048) + .setPublicExponent(JwtRsaSsaPkcs1Parameters.F4) + .setAlgorithm(JwtRsaSsaPkcs1Parameters.Algorithm.RS384) + .setKidStrategy(JwtRsaSsaPkcs1Parameters.KidStrategy.IGNORED) + .build(); + assertThat(parameters1).isNotEqualTo(parameters2); + assertThat(parameters1.hashCode()).isNotEqualTo(parameters2.hashCode()); + } + + @Test + public void testEqualsHashCode_dependsOnKidStrategy() throws Exception { + JwtRsaSsaPkcs1Parameters parameters1 = + JwtRsaSsaPkcs1Parameters.builder() + .setModulusSizeBits(2048) + .setPublicExponent(JwtRsaSsaPkcs1Parameters.F4) + .setAlgorithm(JwtRsaSsaPkcs1Parameters.Algorithm.RS256) + .setKidStrategy(JwtRsaSsaPkcs1Parameters.KidStrategy.IGNORED) + .build(); + JwtRsaSsaPkcs1Parameters parameters2 = + JwtRsaSsaPkcs1Parameters.builder() + .setModulusSizeBits(2048) + .setPublicExponent(JwtRsaSsaPkcs1Parameters.F4) + .setAlgorithm(JwtRsaSsaPkcs1Parameters.Algorithm.RS256) + .setKidStrategy(JwtRsaSsaPkcs1Parameters.KidStrategy.CUSTOM) + .build(); + assertThat(parameters1).isNotEqualTo(parameters2); + assertThat(parameters1.hashCode()).isNotEqualTo(parameters2.hashCode()); + } +} |