/* * JBoss, Home of Professional Open Source. * Copyright 2012, Red Hat, Inc., and individual contributors * as indicated by the @author tags. See the copyright.txt file in the * distribution for a full listing of individual contributors. * * This is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this software; if not, write to the Free * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA, or see the FSF site: http://www.fsf.org. */ package org.picketlink.test.json.api; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; import static org.picketlink.json.JsonConstants.RSA; import static org.picketlink.json.JsonConstants.JWE.ALG_RSA1_5; import static org.picketlink.json.JsonConstants.JWE.ALG_RSA_OAEP; import static org.picketlink.json.JsonConstants.JWE.ALG_RSA_OAEP_256; import static org.picketlink.json.JsonConstants.JWE.ENC_A128CBC_HS256; import static org.picketlink.json.JsonConstants.JWE.ENC_A128GCM; import static org.picketlink.json.JsonConstants.JWE.ENC_A192CBC_HS384; import static org.picketlink.json.JsonConstants.JWE.ENC_A192GCM; import static org.picketlink.json.JsonConstants.JWE.ENC_A256CBC_HS512; import static org.picketlink.json.JsonConstants.JWE.ENC_A256GCM; import java.io.StringReader; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.security.KeyPair; import java.security.KeyPairGenerator; import java.security.NoSuchAlgorithmException; import java.security.interfaces.RSAPrivateKey; import java.security.interfaces.RSAPublicKey; import java.text.ParseException; import java.util.Map; import javax.json.Json; import javax.json.JsonArray; import javax.json.JsonObject; import javax.json.JsonValue; import org.junit.Before; import org.junit.Test; import org.picketlink.json.jose.JWE; import org.picketlink.json.jose.JWEBuilder; import org.picketlink.json.jose.JWK; import org.picketlink.json.jose.JWKBuilder; import org.picketlink.json.jose.JWKSet; import org.picketlink.json.jose.crypto.JWEDecrypter; import org.picketlink.json.jose.crypto.JWEEncrypter; import org.picketlink.json.util.JOSEUtil; /** * The Class JWEAPITestCase. * * @author Giriraj Sharma */ public class JWEAPITestCase { private JWKSet keySet; private KeyPair keyPair1; private KeyPair keyPair2; /** * On before. * * @throws Exception the exception */ @Before public void onBefore() throws Exception { this.keySet = new JWKSet(); KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA"); keyGen.initialize(2048); this.keyPair1 = keyGen.generateKeyPair(); registerPublicKey("1", (RSAPublicKey) this.keyPair1.getPublic()); this.keyPair2 = keyGen.generateKeyPair(); registerPublicKey("2", (RSAPublicKey) this.keyPair2.getPublic()); } /** * Register public key. * * @param kid the kid * @param publicKey the public key */ private void registerPublicKey(String kid, RSAPublicKey publicKey) { JWK rsaJWK = new JWKBuilder() .modulus(publicKey.getModulus()) .publicExponent(publicKey.getPublicExponent()) .keyIdentifier(kid) .keyType(RSA) .keyAlgorithm(publicKey.getAlgorithm()) .keyUse("sig") .build(); this.keySet.add(rsaJWK); } /** * Use JCE unlimited strength policy files. * * @see http://stackoverflow.com/questions/14156522/using-encryption-that-would-need-java-policy-files-in-openjre */ private void useJCEUnlimitedStrengthPolicyFiles() { try { Field gate = Class.forName("javax.crypto.JceSecurity").getDeclaredField("isRestricted"); gate.setAccessible(true); gate.setBoolean(null, false); Field allPerm = Class.forName("javax.crypto.CryptoAllPermission").getDeclaredField("INSTANCE"); allPerm.setAccessible(true); Object accessAllAreasCard = allPerm.get(null); final Constructor<?> constructor = Class.forName("javax.crypto.CryptoPermissions").getDeclaredConstructor(); constructor.setAccessible(true); Object coll = constructor.newInstance(); Method addPerm = Class.forName("javax.crypto.CryptoPermissions").getDeclaredMethod("add", java.security.Permission.class); addPerm.setAccessible(true); addPerm.invoke(coll, accessAllAreasCard); Field defaultPolicy = Class.forName("javax.crypto.JceSecurity").getDeclaredField("defaultPolicy"); defaultPolicy.setAccessible(true); defaultPolicy.set(null, coll); } catch (Exception ex) { ex.printStackTrace(System.err); } } /** * Test RSA JWE JSON. */ @Test public void testRSAJWEJSON() { JWE token = new JWEBuilder() .keys(this.keySet) .algorithm(ALG_RSA_OAEP) .encryptionAlgorithm(ENC_A256GCM, 256) .compressionAlgorithm("DEF") .type("jwt") .contentType("jwe") .X509CertificateChain("cert1", "cert2", "cert3") .keyIdentifier("1") .build(); String jsonString = token.toString(); JWK jwkKeyPair1 = this.keySet.get("1"); JWK jwkKeyPair2 = this.keySet.get("2"); assertJwEquals( "{\"keys\":[{\"n\":\"" + jwkKeyPair2.getModulus() + "\",\"e\":\"AQAB\",\"kid\":\"2\",\"kty\":\"RSA\",\"alg\":\"RSA\",\"use\":\"sig\"},{\"n\":\"" + jwkKeyPair1.getModulus() + "\",\"e\":\"AQAB\",\"kid\":\"1\",\"kty\":\"RSA\",\"alg\":\"RSA\",\"use\":\"sig\"}],\"alg\":\"RSA-OAEP\",\"enc\":\"A256GCM\",\"cek_bitlength\":256,\"zip\":\"DEF\",\"typ\":\"jwt\",\"cty\":\"jwe\",\"x5c\":[\"cert1\",\"cert2\",\"cert3\"],\"kid\":\"1\"}", jsonString); } /** * Test ALG_RSA1_5. * * @throws ParseException the parse exception */ @Test public void test_ALG_RSA1_5() throws ParseException { JWE jwe = new JWEBuilder() .algorithm(ALG_RSA1_5) .encryptionAlgorithm(ENC_A128GCM, 128) .compressionAlgorithm("DEF") .build(); String payLoad = "{\"alg\": \"ALG_RSA1_5\",\"enc\": \"ENC_A128GCM\",\"zip\": \"DEF\"}"; JWEEncrypter encrypter = new JWEEncrypter((RSAPublicKey) keyPair1.getPublic()); String encryptedPayload = encrypter.encrypt(jwe, payLoad.getBytes()); String[] cryptoPart = JOSEUtil.split(encryptedPayload); JWEDecrypter decrypter = new JWEDecrypter((RSAPrivateKey) keyPair1.getPrivate()); byte[] decryptedByteArray = decrypter.decrypt(jwe, cryptoPart[1], cryptoPart[2], cryptoPart[3], cryptoPart[4]); String decryptedPayload = new String(decryptedByteArray); assertEquals(payLoad, decryptedPayload); } /** * Test ALG_RSA_OAEP. * * @throws ParseException the parse exception */ @Test public void test_ALG_RSA_OAEP() throws ParseException { JWE jwe = new JWEBuilder() .algorithm(ALG_RSA_OAEP) .encryptionAlgorithm(ENC_A192GCM, 192) .compressionAlgorithm("DEF") .build(); String payLoad = "{\"alg\": \"ALG_RSA_OAEP\",\"enc\": \"ENC_A192GCM\",\"zip\": \"DEF\"}"; JWEEncrypter encrypter = new JWEEncrypter((RSAPublicKey) keyPair1.getPublic()); String encryptedPayload = encrypter.encrypt(jwe, payLoad.getBytes()); String[] cryptoPart = JOSEUtil.split(encryptedPayload); JWEDecrypter decrypter = new JWEDecrypter((RSAPrivateKey) keyPair1.getPrivate()); byte[] decryptedByteArray = decrypter.decrypt(jwe, cryptoPart[1], cryptoPart[2], cryptoPart[3], cryptoPart[4]); String decryptedPayload = new String(decryptedByteArray); assertEquals(payLoad, decryptedPayload); } /** * Test ALG_RSA_OAEP_256. * * @throws ParseException the parse exception */ @Test public void test_ALG_RSA_OAEP_256() throws ParseException { JWE jwe = new JWEBuilder() .algorithm(ALG_RSA_OAEP_256) .encryptionAlgorithm(ENC_A256GCM, 256) .compressionAlgorithm("DEF") .build(); String payLoad = "{\"alg\": \"ALG_RSA_OAEP_256\",\"enc\": \"ENC_A256GCM\",\"zip\": \"DEF\"}"; JWEEncrypter encrypter = new JWEEncrypter((RSAPublicKey) keyPair1.getPublic()); String encryptedPayload = encrypter.encrypt(jwe, payLoad.getBytes()); String[] cryptoPart = JOSEUtil.split(encryptedPayload); JWEDecrypter decrypter = new JWEDecrypter((RSAPrivateKey) keyPair1.getPrivate()); byte[] decryptedByteArray = decrypter.decrypt(jwe, cryptoPart[1], cryptoPart[2], cryptoPart[3], cryptoPart[4]); String decryptedPayload = new String(decryptedByteArray); assertEquals(payLoad, decryptedPayload); } /** * Test ALGRSA1_5_WITH_ENC_A128CBC_HS256. * * @throws ParseException the parse exception */ @Test public void test_ALGRSA1_5_WITH_ENC_A128CBC_HS256() throws ParseException { JWE jwe = new JWEBuilder() .algorithm(ALG_RSA1_5) .encryptionAlgorithm(ENC_A128CBC_HS256, 256) .compressionAlgorithm("DEF") .build(); String payLoad = "{\"alg\": \"ALG_RSA1_5\",\"enc\": \"ENC_A128CBC_HS256\",\"zip\": \"DEF\"}"; JWEEncrypter encrypter = new JWEEncrypter((RSAPublicKey) keyPair1.getPublic()); String encryptedPayload = encrypter.encrypt(jwe, payLoad.getBytes()); String[] cryptoPart = JOSEUtil.split(encryptedPayload); JWEDecrypter decrypter = new JWEDecrypter((RSAPrivateKey) keyPair1.getPrivate()); byte[] decryptedByteArray = decrypter.decrypt(jwe, cryptoPart[1], cryptoPart[2], cryptoPart[3], cryptoPart[4]); String decryptedPayload = new String(decryptedByteArray); assertEquals(payLoad, decryptedPayload); } /** * Test ALGRSA_OAEP_WITH_ENC_A192CBC_HS384. * * @throws ParseException the parse exception * @throws NoSuchAlgorithmException */ @Test public void test_ALGRSA_OAEP_WITH_ENC_A192CBC_HS384() throws ParseException, NoSuchAlgorithmException { JWE jwe = new JWEBuilder() .algorithm(ALG_RSA_OAEP) .encryptionAlgorithm(ENC_A192CBC_HS384, 384) .compressionAlgorithm("DEF") .build(); useJCEUnlimitedStrengthPolicyFiles(); String payLoad = "{\"alg\": \"ALG_RSA_OAEP\",\"enc\": \"ENC_A192CBC_HS384\",\"zip\": \"DEF\"}"; JWEEncrypter encrypter = new JWEEncrypter((RSAPublicKey) keyPair1.getPublic()); String encryptedPayload = encrypter.encrypt(jwe, payLoad.getBytes()); String[] cryptoPart = JOSEUtil.split(encryptedPayload); JWEDecrypter decrypter = new JWEDecrypter((RSAPrivateKey) keyPair1.getPrivate()); byte[] decryptedByteArray = decrypter.decrypt(jwe, cryptoPart[1], cryptoPart[2], cryptoPart[3], cryptoPart[4]); String decryptedPayload = new String(decryptedByteArray); assertEquals(payLoad, decryptedPayload); } /** * Test ALGRSA_OAEP256_WITH_ENC_A256CBC_HS512. * * @throws ParseException the parse exception */ @Test public void test_ALGRSA_OAEP256_WITH_ENC_A256CBC_HS512() throws ParseException { JWE jwe = new JWEBuilder() .algorithm(ALG_RSA_OAEP_256) .encryptionAlgorithm(ENC_A256CBC_HS512, 512) .compressionAlgorithm("DEF") .build(); String payLoad = "{\"alg\": \"ALG_RSA_OAEP_256\",\"enc\": \"ENC_A256CBC_HS512\",\"zip\": \"DEF\"}"; JWEEncrypter encrypter = new JWEEncrypter((RSAPublicKey) keyPair1.getPublic()); String encryptedPayload = encrypter.encrypt(jwe, payLoad.getBytes()); String[] cryptoPart = JOSEUtil.split(encryptedPayload); JWEDecrypter decrypter = new JWEDecrypter((RSAPrivateKey) keyPair1.getPrivate()); byte[] decryptedByteArray = decrypter.decrypt(jwe, cryptoPart[1], cryptoPart[2], cryptoPart[3], cryptoPart[4]); String decryptedPayload = new String(decryptedByteArray); assertEquals(payLoad, decryptedPayload); } /** * Test invalid private key. * * @throws ParseException the parse exception */ @Test(expected = RuntimeException.class) public void test_INVALID_PRIVATE_KEY() throws ParseException { JWE jwe = new JWEBuilder() .algorithm(ALG_RSA_OAEP_256) .encryptionAlgorithm(ENC_A256GCM, 256) .compressionAlgorithm("DEF") .build(); String payLoad = "{\"alg\": \"ALG_RSA_OAEP_256\",\"enc\": \"ENC_A256GCM\",\"zip\": \"DEF\"}"; JWEEncrypter encrypter = new JWEEncrypter((RSAPublicKey) keyPair1.getPublic()); String encryptedPayload = encrypter.encrypt(jwe, payLoad.getBytes()); String[] cryptoPart = JOSEUtil.split(encryptedPayload); JWEDecrypter decrypter = new JWEDecrypter((RSAPrivateKey) keyPair2.getPrivate()); byte[] decryptedByteArray = decrypter.decrypt(jwe, cryptoPart[1], cryptoPart[2], cryptoPart[3], cryptoPart[4]); String decryptedPayload = new String(decryptedByteArray); assertEquals(payLoad, decryptedPayload); } /** * Test invalid serialization. * * @throws ParseException the parse exception */ @Test(expected = ParseException.class) public void test_INVALID_SERIALIZATION_1() throws ParseException { JWE jwe = new JWEBuilder() .algorithm(ALG_RSA_OAEP_256) .encryptionAlgorithm(ENC_A256GCM, 256) .compressionAlgorithm("DEF") .build(); String payLoad = "{\"alg\": \"ALG_RSA_OAEP_256\",\"enc\": \"ENC_A256GCM\",\"zip\": \"DEF\"}"; JWEEncrypter encrypter = new JWEEncrypter((RSAPublicKey) keyPair1.getPublic()); String encryptedPayload = encrypter.encrypt(jwe, payLoad.getBytes()); encryptedPayload = encryptedPayload.substring(encryptedPayload.lastIndexOf('.')); String[] cryptoPart = JOSEUtil.split(encryptedPayload); JWEDecrypter decrypter = new JWEDecrypter((RSAPrivateKey) keyPair1.getPrivate()); byte[] decryptedByteArray = decrypter.decrypt(jwe, cryptoPart[1], cryptoPart[2], cryptoPart[3], cryptoPart[4]); String decryptedPayload = new String(decryptedByteArray); assertEquals(payLoad, decryptedPayload); } /** * Test invalid serialization. * * @throws ParseException the parse exception */ @Test(expected = ParseException.class) public void test_INVALID_SERIALIZATION_2() throws ParseException { JWE jwe = new JWEBuilder() .algorithm(ALG_RSA_OAEP_256) .encryptionAlgorithm(ENC_A256GCM, 256) .compressionAlgorithm("DEF") .build(); String payLoad = "{\"alg\": \"ALG_RSA_OAEP_256\",\"enc\": \"ENC_A256GCM\",\"zip\": \"DEF\"}"; JWEEncrypter encrypter = new JWEEncrypter((RSAPublicKey) keyPair1.getPublic()); String encryptedPayload = encrypter.encrypt(jwe, payLoad.getBytes()); encryptedPayload = encryptedPayload.concat(".invalidExtraPart"); String[] cryptoPart = JOSEUtil.split(encryptedPayload); JWEDecrypter decrypter = new JWEDecrypter((RSAPrivateKey) keyPair1.getPrivate()); byte[] decryptedByteArray = decrypter.decrypt(jwe, cryptoPart[1], cryptoPart[2], cryptoPart[3], cryptoPart[4]); String decryptedPayload = new String(decryptedByteArray); assertEquals(payLoad, decryptedPayload); } public static void assertJwEquals(String test, String expected) { JsonObject testObj = Json.createReader(new StringReader(test)).readObject(); JsonObject expectedObj = Json.createReader(new StringReader(expected)).readObject(); for (Map.Entry<String, JsonValue> entry : testObj.entrySet()) { assertFieldEquals(testObj, expectedObj, entry.getKey()); } for (Map.Entry<String, JsonValue> entry : expectedObj.entrySet()) { assertFieldEquals(testObj, expectedObj, entry.getKey()); } } private static void assertFieldEquals(JsonObject testObj, JsonObject expectedObj, String key){ assertEquals("field: " + key, testObj.containsKey(key), expectedObj.containsKey(key)); if ("keys".equals(key)) { JsonArray testKeys = testObj.getJsonArray(key); JsonArray expectedKeys = expectedObj.getJsonArray(key); for (JsonValue v : testKeys) { assertTrue("testKeys: " + v, expectedKeys.contains(v)); } for (JsonValue v : expectedKeys) { assertTrue("expectedKeys: " + v, testKeys.contains(v)); } } else { assertEquals("field: " + key, testObj.get(key), expectedObj.get(key)); } } }