diff --git a/CHANGES b/CHANGES index 398fb9f..1f002f1 100644 --- a/CHANGES +++ b/CHANGES @@ -1,5 +1,9 @@ FusionAuth JWT Changes +Changes in 3.5.0 + + * Initial support for RSA Probabilistic Signature Schema (RSASSA-PSS) algorithms PS256, PS384 and PS512. + Changes in 3.4.1 * Modify JSONWebKeyBuilder.build when taking a PEM to prefer a certificate over a public key to ensure we get the x5t in the output. diff --git a/fusionauth-jwt.ipr b/fusionauth-jwt.ipr index 7cbe16f..8f2827a 100644 --- a/fusionauth-jwt.ipr +++ b/fusionauth-jwt.ipr @@ -617,8 +617,10 @@ + aand jwks rsassa + secp diff --git a/src/main/java/io/fusionauth/jwt/rsa/RSAPSSSigner.java b/src/main/java/io/fusionauth/jwt/rsa/RSAPSSSigner.java index e1cb526..86f1033 100644 --- a/src/main/java/io/fusionauth/jwt/rsa/RSAPSSSigner.java +++ b/src/main/java/io/fusionauth/jwt/rsa/RSAPSSSigner.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016-2020, FusionAuth, All Rights Reserved + * Copyright (c) 2020, FusionAuth, All Rights Reserved * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/src/main/java/io/fusionauth/jwt/rsa/RSAPSAVerifier.java b/src/main/java/io/fusionauth/jwt/rsa/RSAPSSVerifier.java similarity index 86% rename from src/main/java/io/fusionauth/jwt/rsa/RSAPSAVerifier.java rename to src/main/java/io/fusionauth/jwt/rsa/RSAPSSVerifier.java index 9d6deb2..0e07260 100644 --- a/src/main/java/io/fusionauth/jwt/rsa/RSAPSAVerifier.java +++ b/src/main/java/io/fusionauth/jwt/rsa/RSAPSSVerifier.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016-2020, FusionAuth, All Rights Reserved + * Copyright (c) 2020, FusionAuth, All Rights Reserved * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -44,12 +44,12 @@ * * @author Daniel DeGroff */ -public class RSAPSAVerifier implements Verifier { +public class RSAPSSVerifier implements Verifier { private final RSAPublicKey publicKey; private final CryptoProvider cryptoProvider; - private RSAPSAVerifier(RSAPublicKey publicKey, CryptoProvider cryptoProvider) { + private RSAPSSVerifier(RSAPublicKey publicKey, CryptoProvider cryptoProvider) { Objects.requireNonNull(publicKey); Objects.requireNonNull(cryptoProvider); @@ -58,7 +58,7 @@ private RSAPSAVerifier(RSAPublicKey publicKey, CryptoProvider cryptoProvider) { assertValidKeyLength(); } - private RSAPSAVerifier(String publicKey, CryptoProvider cryptoProvider) { + private RSAPSSVerifier(String publicKey, CryptoProvider cryptoProvider) { Objects.requireNonNull(publicKey); Objects.requireNonNull(cryptoProvider); @@ -78,7 +78,7 @@ private RSAPSAVerifier(String publicKey, CryptoProvider cryptoProvider) { * @param publicKey The RSA public key object. * @return a new instance of the RSA verifier. */ - public static RSAPSAVerifier newVerifier(RSAPublicKey publicKey) { + public static RSAPSSVerifier newVerifier(RSAPublicKey publicKey) { return newVerifier(publicKey, new DefaultCryptoProvider()); } @@ -89,9 +89,9 @@ public static RSAPSAVerifier newVerifier(RSAPublicKey publicKey) { * @param cryptoProvider The crypto provider used to get the RSA signature Algorithm. * @return a new instance of the RSA verifier. */ - public static RSAPSAVerifier newVerifier(RSAPublicKey publicKey, CryptoProvider cryptoProvider) { + public static RSAPSSVerifier newVerifier(RSAPublicKey publicKey, CryptoProvider cryptoProvider) { Objects.requireNonNull(publicKey); - return new RSAPSAVerifier(publicKey, cryptoProvider); + return new RSAPSSVerifier(publicKey, cryptoProvider); } /** @@ -100,7 +100,7 @@ public static RSAPSAVerifier newVerifier(RSAPublicKey publicKey, CryptoProvider * @param publicKey The RSA public key PEM. * @return a new instance of the RSA verifier. */ - public static RSAPSAVerifier newVerifier(String publicKey) { + public static RSAPSSVerifier newVerifier(String publicKey) { return newVerifier(publicKey, new DefaultCryptoProvider()); } @@ -111,9 +111,9 @@ public static RSAPSAVerifier newVerifier(String publicKey) { * @param cryptoProvider The crypto provider used to get the RSA signature Algorithm. * @return a new instance of the RSA verifier. */ - public static RSAPSAVerifier newVerifier(String publicKey, CryptoProvider cryptoProvider) { + public static RSAPSSVerifier newVerifier(String publicKey, CryptoProvider cryptoProvider) { Objects.requireNonNull(publicKey); - return new RSAPSAVerifier(publicKey, cryptoProvider); + return new RSAPSSVerifier(publicKey, cryptoProvider); } /** @@ -122,7 +122,7 @@ public static RSAPSAVerifier newVerifier(String publicKey, CryptoProvider crypto * @param path The path to the RSA public key PEM. * @return a new instance of the RSA verifier. */ - public static RSAPSAVerifier newVerifier(Path path) { + public static RSAPSSVerifier newVerifier(Path path) { return newVerifier(path, new DefaultCryptoProvider()); } @@ -133,11 +133,11 @@ public static RSAPSAVerifier newVerifier(Path path) { * @param cryptoProvider The crypto provider used to get the RSA signature Algorithm. * @return a new instance of the RSA verifier. */ - public static RSAPSAVerifier newVerifier(Path path, CryptoProvider cryptoProvider) { + public static RSAPSSVerifier newVerifier(Path path, CryptoProvider cryptoProvider) { Objects.requireNonNull(path); try { - return new RSAPSAVerifier(new String(Files.readAllBytes(path)), cryptoProvider); + return new RSAPSSVerifier(new String(Files.readAllBytes(path)), cryptoProvider); } catch (IOException e) { throw new JWTVerifierException("Unable to read the file from path [" + path.toAbsolutePath().toString() + "]", e); } @@ -149,9 +149,9 @@ public static RSAPSAVerifier newVerifier(Path path, CryptoProvider cryptoProvide * @param bytes The bytes of the RSA public key PEM. * @return a new instance of the RSA verifier. */ - public static RSAPSAVerifier newVerifier(byte[] bytes) { + public static RSAPSSVerifier newVerifier(byte[] bytes) { Objects.requireNonNull(bytes); - return new RSAPSAVerifier((new String(bytes)), new DefaultCryptoProvider()); + return new RSAPSSVerifier((new String(bytes)), new DefaultCryptoProvider()); } @Override diff --git a/src/test/java/io/fusionauth/jwt/JWTTest.java b/src/test/java/io/fusionauth/jwt/JWTTest.java index 042f824..1cf75be 100644 --- a/src/test/java/io/fusionauth/jwt/JWTTest.java +++ b/src/test/java/io/fusionauth/jwt/JWTTest.java @@ -21,7 +21,7 @@ import io.fusionauth.jwt.ec.ECVerifier; import io.fusionauth.jwt.hmac.HMACSigner; import io.fusionauth.jwt.hmac.HMACVerifier; -import io.fusionauth.jwt.rsa.RSAPSAVerifier; +import io.fusionauth.jwt.rsa.RSAPSSVerifier; import io.fusionauth.jwt.rsa.RSAPSSSigner; import io.fusionauth.jwt.rsa.RSASigner; import io.fusionauth.jwt.rsa.RSAVerifier; @@ -437,7 +437,7 @@ public void test_PS256() throws IOException { String encodedJWT = JWT.getEncoder().encode(jwt, signer); // Verify the JWT - Verifier verifier = RSAPSAVerifier.newVerifier(Paths.get("src/test/resources/rsa_public_key_2048.pem")); + Verifier verifier = RSAPSSVerifier.newVerifier(Paths.get("src/test/resources/rsa_public_key_2048.pem")); JWT actual = JWT.getDecoder().decode(encodedJWT, verifier); assertEquals(actual.subject, jwt.subject); @@ -453,7 +453,7 @@ public void test_PS384() throws IOException { String encodedJWT = JWT.getEncoder().encode(jwt, signer); // Verify the JWT - Verifier verifier = RSAPSAVerifier.newVerifier(Paths.get("src/test/resources/rsa_public_key_2048.pem")); + Verifier verifier = RSAPSSVerifier.newVerifier(Paths.get("src/test/resources/rsa_public_key_2048.pem")); JWT actual = JWT.getDecoder().decode(encodedJWT, verifier); assertEquals(actual.subject, jwt.subject); @@ -469,7 +469,7 @@ public void test_PS512() throws IOException { String encodedJWT = JWT.getEncoder().encode(jwt, signer); // Verify the JWT - Verifier verifier = RSAPSAVerifier.newVerifier(Paths.get("src/test/resources/rsa_public_key_3072.pem")); + Verifier verifier = RSAPSSVerifier.newVerifier(Paths.get("src/test/resources/rsa_public_key_3072.pem")); JWT actual = JWT.getDecoder().decode(encodedJWT, verifier); assertEquals(actual.subject, jwt.subject); diff --git a/src/test/java/io/fusionauth/jwt/RequiresAlgorithm.java b/src/test/java/io/fusionauth/jwt/RequiresAlgorithm.java index 82b57aa..3a55904 100644 --- a/src/test/java/io/fusionauth/jwt/RequiresAlgorithm.java +++ b/src/test/java/io/fusionauth/jwt/RequiresAlgorithm.java @@ -14,7 +14,6 @@ * language governing permissions and limitations under the License. */ - package io.fusionauth.jwt; import java.lang.annotation.Retention; @@ -22,6 +21,11 @@ import static java.lang.annotation.ElementType.METHOD; +/** + * Test marker annotation to indicate the test should be only be run when a particular algorithm is available. + * + * @author Daniel DeGroff + */ @Retention(java.lang.annotation.RetentionPolicy.RUNTIME) @Target({METHOD}) public @interface RequiresAlgorithm { diff --git a/src/test/java/io/fusionauth/jwt/TestNGAnnotationTransformer.java b/src/test/java/io/fusionauth/jwt/TestNGAnnotationTransformer.java index 6f40252..1d5a38b 100644 --- a/src/test/java/io/fusionauth/jwt/TestNGAnnotationTransformer.java +++ b/src/test/java/io/fusionauth/jwt/TestNGAnnotationTransformer.java @@ -23,6 +23,11 @@ import java.lang.reflect.Method; import java.security.Signature; +/** + * Test NG transformer used to disable tests at runtime. + * + * @author Daniel DeGroff + */ @SuppressWarnings("unused") public class TestNGAnnotationTransformer implements IAnnotationTransformer { private static boolean RSAProbabilisticSignatureSchemaAvailable; diff --git a/src/test/java/io/fusionauth/jwt/rsa/RSAPSASignerTest.java b/src/test/java/io/fusionauth/jwt/rsa/RSAPSSSignerTest.java similarity index 99% rename from src/test/java/io/fusionauth/jwt/rsa/RSAPSASignerTest.java rename to src/test/java/io/fusionauth/jwt/rsa/RSAPSSSignerTest.java index 9cd9f71..1f68e73 100644 --- a/src/test/java/io/fusionauth/jwt/rsa/RSAPSASignerTest.java +++ b/src/test/java/io/fusionauth/jwt/rsa/RSAPSSSignerTest.java @@ -26,7 +26,7 @@ /** * @author Daniel DeGroff */ -public class RSAPSASignerTest extends BaseTest { +public class RSAPSSSignerTest extends BaseTest { @Test public void test_private_pem_parsing() { // No kid diff --git a/src/test/java/io/fusionauth/jwt/rsa/RSAPSAVerifierTest.java b/src/test/java/io/fusionauth/jwt/rsa/RSAPSSVerifierTest.java similarity index 87% rename from src/test/java/io/fusionauth/jwt/rsa/RSAPSAVerifierTest.java rename to src/test/java/io/fusionauth/jwt/rsa/RSAPSSVerifierTest.java index 60deb33..22def8a 100644 --- a/src/test/java/io/fusionauth/jwt/rsa/RSAPSAVerifierTest.java +++ b/src/test/java/io/fusionauth/jwt/rsa/RSAPSSVerifierTest.java @@ -40,7 +40,7 @@ /** * @author Daniel DeGroff */ -public class RSAPSAVerifierTest extends BaseTest { +public class RSAPSSVerifierTest extends BaseTest { @Test public void test_public_pem_parsing() { Arrays.asList( @@ -51,13 +51,13 @@ public void test_public_pem_parsing() { "rsa_public_key_4096.pem") .forEach(fileName -> { // Take a String arg - assertRSAPSAVerifier(RSAPSAVerifier.newVerifier(getPath(fileName))); + assertRSAPSAVerifier(RSAPSSVerifier.newVerifier(getPath(fileName))); // Take a Path arg - assertRSAPSAVerifier(RSAPSAVerifier.newVerifier(readFile(fileName))); + assertRSAPSAVerifier(RSAPSSVerifier.newVerifier(readFile(fileName))); // Take a byte[] arg - assertRSAPSAVerifier(RSAPSAVerifier.newVerifier(readFile(fileName).getBytes(StandardCharsets.UTF_8))); + assertRSAPSAVerifier(RSAPSSVerifier.newVerifier(readFile(fileName).getBytes(StandardCharsets.UTF_8))); // Take a public key arg - assertRSAPSAVerifier(RSAPSAVerifier.newVerifier((RSAPublicKey) PEM.decode(readFile(fileName)).getPublicKey())); + assertRSAPSAVerifier(RSAPSSVerifier.newVerifier((RSAPublicKey) PEM.decode(readFile(fileName)).getPublicKey())); }); // Public key parsing also works with private keys since the public key is encoded in the private @@ -68,20 +68,20 @@ public void test_public_pem_parsing() { "rsa_private_key_4096.pem") .forEach((fileName -> { // Take a String arg - assertRSAPSAVerifier(RSAPSAVerifier.newVerifier(getPath(fileName))); + assertRSAPSAVerifier(RSAPSSVerifier.newVerifier(getPath(fileName))); // Take a Path arg - assertRSAPSAVerifier(RSAPSAVerifier.newVerifier(readFile(fileName))); + assertRSAPSAVerifier(RSAPSSVerifier.newVerifier(readFile(fileName))); // Take a byte[] arg - assertRSAPSAVerifier(RSAPSAVerifier.newVerifier(readFile(fileName).getBytes(StandardCharsets.UTF_8))); + assertRSAPSAVerifier(RSAPSSVerifier.newVerifier(readFile(fileName).getBytes(StandardCharsets.UTF_8))); // Take a public key arg - assertRSAPSAVerifier(RSAPSAVerifier.newVerifier((RSAPublicKey) PEM.decode(readFile(fileName)).getPublicKey())); + assertRSAPSAVerifier(RSAPSSVerifier.newVerifier((RSAPublicKey) PEM.decode(readFile(fileName)).getPublicKey())); })); } @Test public void test_rsa_1024_pem() { try { - RSAPSAVerifier.newVerifier(new String(Files.readAllBytes(Paths.get("src/test/resources/rsa_public_key_1024.pem")))); + RSAPSSVerifier.newVerifier(new String(Files.readAllBytes(Paths.get("src/test/resources/rsa_public_key_1024.pem")))); Assert.fail("Expected [InvalidKeyLengthException] exception"); } catch (InvalidKeyLengthException ignore) { } catch (Exception e) { @@ -104,7 +104,7 @@ public void control() { "-----END PUBLIC KEY-----"; - Verifier verifier = RSAPSAVerifier.newVerifier(publicKeyPEM); + Verifier verifier = RSAPSSVerifier.newVerifier(publicKeyPEM); JWT jwt = JWT.getDecoder().decode(encodedJWT, verifier); assertNotNull(jwt); assertEquals(jwt.subject, "1234567890");