From f04face41e5cbe45e221aff9f4c6a8d785d95020 Mon Sep 17 00:00:00 2001 From: Justin Richer Date: Mon, 19 Oct 2015 14:16:40 -0400 Subject: [PATCH] updated to nimbus 4.3, check JCE policy and algorithm availability before running unit tests, closes #938 --- openid-connect-common/pom.xml | 4 ++ ...aultJWTEncryptionAndDecryptionService.java | 34 ++++++++-- ...aultJWTEncryptionAndDecryptionService.java | 62 +++++++++++++++---- pom.xml | 14 +++-- 4 files changed, 91 insertions(+), 23 deletions(-) diff --git a/openid-connect-common/pom.xml b/openid-connect-common/pom.xml index 95976ad02..070f0001c 100644 --- a/openid-connect-common/pom.xml +++ b/openid-connect-common/pom.xml @@ -82,6 +82,10 @@ com.fasterxml.jackson.core jackson-annotations + + org.bouncycastle + bcprov-jdk15on + jar diff --git a/openid-connect-common/src/main/java/org/mitre/jwt/encryption/service/impl/DefaultJWTEncryptionAndDecryptionService.java b/openid-connect-common/src/main/java/org/mitre/jwt/encryption/service/impl/DefaultJWTEncryptionAndDecryptionService.java index e2d7ca023..f9d08b74a 100644 --- a/openid-connect-common/src/main/java/org/mitre/jwt/encryption/service/impl/DefaultJWTEncryptionAndDecryptionService.java +++ b/openid-connect-common/src/main/java/org/mitre/jwt/encryption/service/impl/DefaultJWTEncryptionAndDecryptionService.java @@ -40,8 +40,13 @@ import com.nimbusds.jose.JWEEncrypter; import com.nimbusds.jose.JWEObject; import com.nimbusds.jose.crypto.DirectDecrypter; import com.nimbusds.jose.crypto.DirectEncrypter; +import com.nimbusds.jose.crypto.ECDHDecrypter; +import com.nimbusds.jose.crypto.ECDHEncrypter; import com.nimbusds.jose.crypto.RSADecrypter; import com.nimbusds.jose.crypto.RSAEncrypter; +import com.nimbusds.jose.crypto.bc.BouncyCastleProviderSingleton; +import com.nimbusds.jose.jca.JCAContext; +import com.nimbusds.jose.jwk.ECKey; import com.nimbusds.jose.jwk.JWK; import com.nimbusds.jose.jwk.OctetSequenceKey; import com.nimbusds.jose.jwk.RSAKey; @@ -223,23 +228,40 @@ public class DefaultJWTEncryptionAndDecryptionService implements JWTEncryptionAn if (jwk instanceof RSAKey) { // build RSA encrypters and decrypters - RSAEncrypter encrypter = new RSAEncrypter(((RSAKey) jwk).toRSAPublicKey()); // there should always at least be the public key + RSAEncrypter encrypter = new RSAEncrypter((RSAKey) jwk); // there should always at least be the public key + encrypter.getJCAContext().setProvider(BouncyCastleProviderSingleton.getInstance()); encrypters.put(id, encrypter); if (jwk.isPrivate()) { // we can decrypt! - RSADecrypter decrypter = new RSADecrypter(((RSAKey) jwk).toRSAPrivateKey()); + RSADecrypter decrypter = new RSADecrypter((RSAKey) jwk); + decrypter.getJCAContext().setProvider(BouncyCastleProviderSingleton.getInstance()); decrypters.put(id, decrypter); } else { logger.warn("No private key for key #" + jwk.getKeyID()); } - - // TODO: add support for EC keys + } else if (jwk instanceof ECKey) { + + // build EC Encrypters and decrypters + + ECDHEncrypter encrypter = new ECDHEncrypter((ECKey) jwk); + encrypter.getJCAContext().setProvider(BouncyCastleProviderSingleton.getInstance()); + encrypters.put(id, encrypter); + + if (jwk.isPrivate()) { // we can decrypt too + ECDHDecrypter decrypter = new ECDHDecrypter((ECKey) jwk); + decrypter.getJCAContext().setProvider(BouncyCastleProviderSingleton.getInstance()); + decrypters.put(id, decrypter); + } else { + logger.warn("No private key for key # " + jwk.getKeyID()); + } } else if (jwk instanceof OctetSequenceKey) { // build symmetric encrypters and decrypters - DirectEncrypter encrypter = new DirectEncrypter(((OctetSequenceKey) jwk).toByteArray()); - DirectDecrypter decrypter = new DirectDecrypter(((OctetSequenceKey) jwk).toByteArray()); + DirectEncrypter encrypter = new DirectEncrypter((OctetSequenceKey) jwk); + encrypter.getJCAContext().setProvider(BouncyCastleProviderSingleton.getInstance()); + DirectDecrypter decrypter = new DirectDecrypter((OctetSequenceKey) jwk); + decrypter.getJCAContext().setProvider(BouncyCastleProviderSingleton.getInstance()); encrypters.put(id, encrypter); decrypters.put(id, decrypter); diff --git a/openid-connect-common/src/test/java/org/mitre/jwt/encryption/service/impl/TestDefaultJWTEncryptionAndDecryptionService.java b/openid-connect-common/src/test/java/org/mitre/jwt/encryption/service/impl/TestDefaultJWTEncryptionAndDecryptionService.java index 75e4875cf..807f5f759 100644 --- a/openid-connect-common/src/test/java/org/mitre/jwt/encryption/service/impl/TestDefaultJWTEncryptionAndDecryptionService.java +++ b/openid-connect-common/src/test/java/org/mitre/jwt/encryption/service/impl/TestDefaultJWTEncryptionAndDecryptionService.java @@ -23,9 +23,16 @@ import java.util.LinkedList; import java.util.List; import java.util.Map; +import javax.crypto.Cipher; + +import org.junit.Assume; import org.junit.Before; +import org.junit.Rule; import org.junit.Test; +import org.junit.rules.ExpectedException; import org.mitre.jose.keystore.JWKSetKeyStore; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import com.google.common.collect.ImmutableMap; import com.nimbusds.jose.EncryptionMethod; @@ -33,6 +40,7 @@ import com.nimbusds.jose.JOSEException; import com.nimbusds.jose.JWEAlgorithm; import com.nimbusds.jose.JWEHeader; import com.nimbusds.jose.JWEObject; +import com.nimbusds.jose.jca.JCASupport; import com.nimbusds.jose.jwk.JWK; import com.nimbusds.jose.jwk.JWKSet; import com.nimbusds.jose.jwk.KeyUse; @@ -57,14 +65,19 @@ import static org.junit.Assert.assertTrue; */ public class TestDefaultJWTEncryptionAndDecryptionService { + + private static Logger logger = LoggerFactory.getLogger(TestDefaultJWTEncryptionAndDecryptionService.class); private String plainText = "The true sign of intelligence is not knowledge but imagination."; private String issuer = "www.example.net"; private String subject = "example_user"; private JWTClaimsSet claimsSet = null; + + @Rule + public ExpectedException exception = ExpectedException.none(); - // Example data taken from Mike Jones's draft-ietf-jose-json-web-encryption-14 appendix examples + // Example data taken from rfc7516 appendix A private String compactSerializedJwe = "eyJhbGciOiJSU0EtT0FFUCIsImVuYyI6IkEyNTZHQ00ifQ." + "OKOawDo13gRp2ojaHV7LFpZcgV7T6DVZKTyKOMTYUmKoTCVJRgckCL9kiMT03JGe" + "ipsEdY3mx_etLbbWSrFr05kLzcSr4qKAq7YN7e9jwQRb23nfa6c9d-StnImGyFDb" + @@ -167,9 +180,13 @@ public class TestDefaultJWTEncryptionAndDecryptionService { } - //@Test - public void decrypt_RSA() throws ParseException { + @Test + public void decrypt_RSA() throws ParseException, NoSuchAlgorithmException { + Assume.assumeTrue(JCASupport.isSupported(JWEAlgorithm.RSA_OAEP) // check for algorithm support + && JCASupport.isSupported(EncryptionMethod.A256GCM) + && Cipher.getMaxAllowedKeyLength("RC5") >= 256); // check for unlimited crypto strength + service.setDefaultDecryptionKeyId(RSAkid); service.setDefaultEncryptionKeyId(RSAkid); @@ -184,9 +201,13 @@ public class TestDefaultJWTEncryptionAndDecryptionService { } - //@Test - public void encryptThenDecrypt_RSA() throws ParseException { + @Test + public void encryptThenDecrypt_RSA() throws ParseException, NoSuchAlgorithmException { + Assume.assumeTrue(JCASupport.isSupported(JWEAlgorithm.RSA_OAEP) // check for algorithm support + && JCASupport.isSupported(EncryptionMethod.A256GCM) + && Cipher.getMaxAllowedKeyLength("RC5") >= 256); // check for unlimited crypto strength + service.setDefaultDecryptionKeyId(RSAkid); service.setDefaultEncryptionKeyId(RSAkid); @@ -212,9 +233,13 @@ public class TestDefaultJWTEncryptionAndDecryptionService { // The same as encryptThenDecrypt_RSA() but relies on the key from the map - //@Test - public void encryptThenDecrypt_nullID() throws ParseException { - + @Test + public void encryptThenDecrypt_nullID() throws ParseException, NoSuchAlgorithmException { + + Assume.assumeTrue(JCASupport.isSupported(JWEAlgorithm.RSA_OAEP) // check for algorithm support + && JCASupport.isSupported(EncryptionMethod.A256GCM) + && Cipher.getMaxAllowedKeyLength("RC5") >= 256); // check for unlimited crypto strength + service.setDefaultDecryptionKeyId(null); service.setDefaultEncryptionKeyId(null); @@ -239,9 +264,15 @@ public class TestDefaultJWTEncryptionAndDecryptionService { } - @Test(expected=IllegalStateException.class) - public void encrypt_nullID_oneKey() { + @Test + public void encrypt_nullID_oneKey() throws NoSuchAlgorithmException { + Assume.assumeTrue(JCASupport.isSupported(JWEAlgorithm.RSA_OAEP) // check for algorithm support + && JCASupport.isSupported(EncryptionMethod.A256GCM) + && Cipher.getMaxAllowedKeyLength("RC5") >= 256); // check for unlimited crypto strength + + exception.expect(IllegalStateException.class); + service_2.setDefaultEncryptionKeyId(null); assertEquals(null, service_2.getDefaultEncryptionKeyId()); @@ -254,9 +285,16 @@ public class TestDefaultJWTEncryptionAndDecryptionService { } - @Test(expected=IllegalStateException.class) - public void decrypt_nullID() throws ParseException { + @Test + public void decrypt_nullID() throws ParseException, NoSuchAlgorithmException { + Assume.assumeTrue(JCASupport.isSupported(JWEAlgorithm.RSA_OAEP) // check for algorithm support + && JCASupport.isSupported(EncryptionMethod.A256GCM) + && Cipher.getMaxAllowedKeyLength("RC5") >= 256); // check for unlimited crypto strength + + + exception.expect(IllegalStateException.class); + service_2.setDefaultEncryptionKeyId(RSAkid); service_2.setDefaultDecryptionKeyId(null); diff --git a/pom.xml b/pom.xml index 8e2ebe909..b3856f198 100644 --- a/pom.xml +++ b/pom.xml @@ -335,6 +335,11 @@ javax.persistence 2.1.0 + + com.zaxxer + HikariCP + 2.4.1 + @@ -470,13 +475,12 @@ com.nimbusds nimbus-jose-jwt - 4.2 + 4.3 - - com.zaxxer - HikariCP - 2.4.1 + org.bouncycastle + bcprov-jdk15on + [1.52,]