From 5f80ebc89abaf7fba24a4d240d96566864e5f099 Mon Sep 17 00:00:00 2001 From: Mike Derryberry Date: Tue, 31 Jul 2012 08:42:44 -0400 Subject: [PATCH 1/4] changing encryption/decryption code to use enum classes rather than shady parsing techniques --- .../main/java/org/mitre/jwk/model/Rsa.java | 2 -- .../mitre/jwt/encryption/JweAlgorithms.java | 23 +++++++++++++++++++ 2 files changed, 23 insertions(+), 2 deletions(-) create mode 100644 openid-connect-common/src/main/java/org/mitre/jwt/encryption/JweAlgorithms.java diff --git a/openid-connect-common/src/main/java/org/mitre/jwk/model/Rsa.java b/openid-connect-common/src/main/java/org/mitre/jwk/model/Rsa.java index 6194c46be..9318d0a9f 100644 --- a/openid-connect-common/src/main/java/org/mitre/jwk/model/Rsa.java +++ b/openid-connect-common/src/main/java/org/mitre/jwk/model/Rsa.java @@ -19,8 +19,6 @@ public class Rsa extends AbstractJwk{ private String mod; private String exp; - JsonObject object = new JsonObject(); - public String getMod() { return mod; } diff --git a/openid-connect-common/src/main/java/org/mitre/jwt/encryption/JweAlgorithms.java b/openid-connect-common/src/main/java/org/mitre/jwt/encryption/JweAlgorithms.java new file mode 100644 index 000000000..79796865c --- /dev/null +++ b/openid-connect-common/src/main/java/org/mitre/jwt/encryption/JweAlgorithms.java @@ -0,0 +1,23 @@ +package org.mitre.jwt.encryption; + +public enum JweAlgorithms { + + //Key Derivation Function Values + CS256("256"), + CS384("384"), + CS512("512"), + //Encryption Method Values + A128GCM("GCM"), + A256GCM("GCM"), + A128CBC("CBC"), + A256CBC("CBC"); + + + + private final String value; + + JweAlgorithms(String value) { + this.value = value; + } + +} From 61c7231d9abf1febe1883be23b6f32c22ea3ca98 Mon Sep 17 00:00:00 2001 From: Mike Derryberry Date: Tue, 31 Jul 2012 09:25:02 -0400 Subject: [PATCH 2/4] updated encrypter and decrypter to use enum class rather than fragile parsing --- .../mitre/jwt/encryption/JweAlgorithms.java | 16 ++++++++++ .../jwt/encryption/impl/RsaDecrypter.java | 32 ++++--------------- .../jwt/encryption/impl/RsaEncrypter.java | 15 ++++----- .../impl/RsaEncrypterDecrypterTest.java | 5 ++- 4 files changed, 31 insertions(+), 37 deletions(-) diff --git a/openid-connect-common/src/main/java/org/mitre/jwt/encryption/JweAlgorithms.java b/openid-connect-common/src/main/java/org/mitre/jwt/encryption/JweAlgorithms.java index 79796865c..12135a1b4 100644 --- a/openid-connect-common/src/main/java/org/mitre/jwt/encryption/JweAlgorithms.java +++ b/openid-connect-common/src/main/java/org/mitre/jwt/encryption/JweAlgorithms.java @@ -1,5 +1,7 @@ package org.mitre.jwt.encryption; +import org.apache.commons.lang.StringUtils; + public enum JweAlgorithms { //Key Derivation Function Values @@ -19,5 +21,19 @@ public enum JweAlgorithms { JweAlgorithms(String value) { this.value = value; } + + public static String getByName(String name) { + for (JweAlgorithms correspondingType : JweAlgorithms.values()) { + if (correspondingType.toString().equals(name)) { + return correspondingType.value; + } + } + throw new IllegalArgumentException( + "JweAlgorithm name " + name + " does not have a corresponding JweAlgorithm: expected one of [" + StringUtils.join(JweAlgorithms.values(), ", ") + "]"); + } + + public String getValue() { + return value; + } } diff --git a/openid-connect-common/src/main/java/org/mitre/jwt/encryption/impl/RsaDecrypter.java b/openid-connect-common/src/main/java/org/mitre/jwt/encryption/impl/RsaDecrypter.java index eb9a99730..eebaa1731 100644 --- a/openid-connect-common/src/main/java/org/mitre/jwt/encryption/impl/RsaDecrypter.java +++ b/openid-connect-common/src/main/java/org/mitre/jwt/encryption/impl/RsaDecrypter.java @@ -15,7 +15,7 @@ import javax.crypto.spec.SecretKeySpec; import org.apache.commons.codec.binary.Base64; import org.mitre.jwe.model.Jwe; import org.mitre.jwt.encryption.AbstractJweDecrypter; -import org.mitre.jwt.signer.impl.HmacSigner; +import org.mitre.jwt.encryption.JweAlgorithms; public class RsaDecrypter extends AbstractJweDecrypter { @@ -33,35 +33,16 @@ public class RsaDecrypter extends AbstractJweDecrypter { //generation of cek and cik byte[] contentEncryptionKey = null; - byte[] contentIntegrityKey = null; //check what the key length is - String encMethod = jwe.getHeader().getKeyDerivationFunction(); - char[] array = encMethod.toCharArray(); - String keyBitLengthString = new String("" + array[2] + array[3] + array[4]); - int keyBitLength = Integer.parseInt(keyBitLengthString); + String kdf = jwe.getHeader().getKeyDerivationFunction(); + String keyLength = JweAlgorithms.getByName(kdf); + int keyBitLength = Integer.parseInt(keyLength); //generate cek and cik contentEncryptionKey = generateContentKey(jwe.getEncryptedKey(), keyBitLength, "Encryption".getBytes()); - contentIntegrityKey = generateContentKey(jwe.getEncryptedKey(), keyBitLength, "Integrity".getBytes()); //decrypt ciphertext to get claims jwe.setCiphertext(decryptCipherText(jwe, contentEncryptionKey)); - //generate signature for decrypted signature base in order to verify that decryption worked - /*String signature = null; - try { - HmacSigner hmacSigner = new HmacSigner(contentIntegrityKey); - signature = hmacSigner.generateSignature(jwe.getSignatureBase()); - } catch (NoSuchAlgorithmException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - - //verifys that the signature base was decrypted correctly - if(signature != jwe.getSignature()){ - throw new IllegalArgumentException("Didn't decrypt correctly. Decoded Sig and generated Sig do not match. " + - "Generated Signature is: " + signature + " while decoded sig is: " + jwe.getSignature()); - }*/ - } else { throw new IllegalArgumentException(jwe.getHeader().getEncryptionMethod() + " is not a valid decrypting algorithm"); } @@ -78,10 +59,9 @@ public class RsaDecrypter extends AbstractJweDecrypter { //TODO: should also check for A128GCM and A256GCM, but Cipher.getInstance() does not support the GCM mode. For now, don't use them if(encMethod.equals("A128CBC") || encMethod.equals("A256CBC")) { - String delims = "[8,6]+"; - String[] mode = encMethod.split(delims); + String mode = JweAlgorithms.getByName(encMethod); - Cipher cipher = Cipher.getInstance("AES/" + mode[1] + "/PKCS5Padding"); + Cipher cipher = Cipher.getInstance("AES/" + mode + "/PKCS5Padding"); cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(contentEncryptionKey, "AES"), new IvParameterSpec(iv)); byte[] clearText = cipher.doFinal(jwe.getCiphertext()); diff --git a/openid-connect-common/src/main/java/org/mitre/jwt/encryption/impl/RsaEncrypter.java b/openid-connect-common/src/main/java/org/mitre/jwt/encryption/impl/RsaEncrypter.java index 60f62d3b7..6cf8a4db7 100644 --- a/openid-connect-common/src/main/java/org/mitre/jwt/encryption/impl/RsaEncrypter.java +++ b/openid-connect-common/src/main/java/org/mitre/jwt/encryption/impl/RsaEncrypter.java @@ -17,6 +17,7 @@ import javax.crypto.spec.SecretKeySpec; import org.apache.commons.codec.binary.Base64; import org.mitre.jwe.model.Jwe; import org.mitre.jwt.encryption.AbstractJweEncrypter; +import org.mitre.jwt.encryption.JweAlgorithms; import org.mitre.jwt.signer.impl.HmacSigner; public class RsaEncrypter extends AbstractJweEncrypter { @@ -31,10 +32,9 @@ public class RsaEncrypter extends AbstractJweEncrypter { //generate random content master key //check what the key length is - String encMethod = jwe.getHeader().getKeyDerivationFunction(); - char[] array = encMethod.toCharArray(); - String keyBitLengthString = new String("" + array[2] + array[3] + array[4]); - int keyBitLength = Integer.parseInt(keyBitLengthString); + String kdf = jwe.getHeader().getKeyDerivationFunction(); + String keyLength = JweAlgorithms.getByName(kdf); + int keyBitLength = Integer.parseInt(keyLength); byte[] contentMasterKey = new byte[keyBitLength]; new Random().nextBytes(contentMasterKey); @@ -96,11 +96,10 @@ public class RsaEncrypter extends AbstractJweEncrypter { String encMethod = jwe.getHeader().getEncryptionMethod(); //TODO: should also check for A128GCM and A256GCM, but Cipher.getInstance() does not support the GCM mode. For now, don't use them if(encMethod.equals("A128CBC") || encMethod.equals("A256CBC")) { - // FIXME: this is fragile - String delims = "[8,6]+"; - String[] mode = encMethod.split(delims); - Cipher cipher = Cipher.getInstance("AES/" + mode[1] + "/PKCS5Padding"); + String mode = JweAlgorithms.getByName(encMethod); + + Cipher cipher = Cipher.getInstance("AES/" + mode + "/PKCS5Padding"); cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(contentEncryptionKey, "AES"), new IvParameterSpec(iv)); byte[] cipherText = cipher.doFinal(jwe.getCiphertext()); return cipherText; diff --git a/openid-connect-common/src/test/java/org/mitre/jwe/encryption/impl/RsaEncrypterDecrypterTest.java b/openid-connect-common/src/test/java/org/mitre/jwe/encryption/impl/RsaEncrypterDecrypterTest.java index 3f19fb1d1..8045516b5 100644 --- a/openid-connect-common/src/test/java/org/mitre/jwe/encryption/impl/RsaEncrypterDecrypterTest.java +++ b/openid-connect-common/src/test/java/org/mitre/jwe/encryption/impl/RsaEncrypterDecrypterTest.java @@ -20,7 +20,6 @@ import javax.crypto.Cipher; import javax.crypto.IllegalBlockSizeException; import javax.crypto.NoSuchPaddingException; -import org.easymock.internal.matchers.GreaterThan; import org.junit.After; import org.junit.Assume; import org.junit.Before; @@ -64,14 +63,14 @@ public class RsaEncrypterDecrypterTest { //read in header and plaintext from files JsonParser parser = new JsonParser(); JsonObject jweHeaderObject = parser.parse(new BufferedReader(new InputStreamReader(jweHeaderUrl.openStream()))).getAsJsonObject(); - //create jwe based on header and plaintext - Jwe jwe = new Jwe(new JweHeader(jweHeaderObject), null, jwePlaintextString.getBytes(), null); //generate key pair. this will be passed in from the user KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA"); keyGen.initialize(4096); KeyPair pair = keyGen.generateKeyPair(); PublicKey publicKey = pair.getPublic(); PrivateKey privateKey = pair.getPrivate(); + //create jwe based on header and plaintext + Jwe jwe = new Jwe(new JweHeader(jweHeaderObject), null, jwePlaintextString.getBytes(), null); //encrypt RsaEncrypter rsaEncrypter = new RsaEncrypter(); jwe = rsaEncrypter.encryptAndSign(jwe, publicKey); From 95dcb1047238d6c283ec2f4ccc74eb1f2aecd4ae Mon Sep 17 00:00:00 2001 From: Mike Derryberry Date: Tue, 31 Jul 2012 10:33:18 -0400 Subject: [PATCH 3/4] updated encrypter/decrypter to store keys as member variables rather than to pass them in --- .../mitre/jwt/encryption/JweDecrypter.java | 5 ++-- .../mitre/jwt/encryption/JweEncrypter.java | 5 ++-- .../jwt/encryption/impl/RsaDecrypter.java | 30 +++++++++++++++---- .../jwt/encryption/impl/RsaEncrypter.java | 30 +++++++++++++++---- .../java/org/mitre/jwt/model/ClaimSet.java | 12 ++++++++ .../main/java/org/mitre/jwt/model/Jwt.java | 9 ++---- .../impl/RsaEncrypterDecrypterTest.java | 8 +++-- 7 files changed, 75 insertions(+), 24 deletions(-) diff --git a/openid-connect-common/src/main/java/org/mitre/jwt/encryption/JweDecrypter.java b/openid-connect-common/src/main/java/org/mitre/jwt/encryption/JweDecrypter.java index ec28cdd48..807791922 100644 --- a/openid-connect-common/src/main/java/org/mitre/jwt/encryption/JweDecrypter.java +++ b/openid-connect-common/src/main/java/org/mitre/jwt/encryption/JweDecrypter.java @@ -2,7 +2,6 @@ package org.mitre.jwt.encryption; import java.security.InvalidAlgorithmParameterException; import java.security.InvalidKeyException; -import java.security.Key; import java.security.NoSuchAlgorithmException; import javax.crypto.BadPaddingException; @@ -13,11 +12,11 @@ import org.mitre.jwe.model.Jwe; public interface JweDecrypter { - public Jwe decrypt(String encryptedJwe, Key privateKey) throws InvalidKeyException, NoSuchAlgorithmException, NoSuchPaddingException, IllegalBlockSizeException, BadPaddingException, InvalidAlgorithmParameterException; + public Jwe decrypt(String encryptedJwe) throws InvalidKeyException, NoSuchAlgorithmException, NoSuchPaddingException, IllegalBlockSizeException, BadPaddingException, InvalidAlgorithmParameterException; public byte[] decryptCipherText(Jwe jwe, byte[] cek) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException, InvalidAlgorithmParameterException; - public byte[] decryptEncryptionKey(Jwe jwe, Key privateKey) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException, InvalidAlgorithmParameterException; + public byte[] decryptEncryptionKey(Jwe jwe) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException, InvalidAlgorithmParameterException; } diff --git a/openid-connect-common/src/main/java/org/mitre/jwt/encryption/JweEncrypter.java b/openid-connect-common/src/main/java/org/mitre/jwt/encryption/JweEncrypter.java index 0d80982e4..52c71ce03 100644 --- a/openid-connect-common/src/main/java/org/mitre/jwt/encryption/JweEncrypter.java +++ b/openid-connect-common/src/main/java/org/mitre/jwt/encryption/JweEncrypter.java @@ -3,7 +3,6 @@ package org.mitre.jwt.encryption; import java.io.IOException; import java.security.InvalidAlgorithmParameterException; import java.security.InvalidKeyException; -import java.security.Key; import java.security.NoSuchAlgorithmException; import java.security.spec.InvalidKeySpecException; @@ -19,11 +18,11 @@ import com.google.gson.JsonSyntaxException; public interface JweEncrypter { - public byte[] encryptKey(Jwe jwe, byte[] cmk, Key publicKey) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException; + public byte[] encryptKey(Jwe jwe, byte[] cmk) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException; public byte[] encryptClaims(Jwe jwe, byte[] cik) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException, InvalidAlgorithmParameterException, InvalidKeySpecException; - public Jwe encryptAndSign(Jwe jwe, Key publicKey) throws NoSuchAlgorithmException, JsonIOException, JsonSyntaxException, IOException, InvalidKeyException, NoSuchPaddingException, IllegalBlockSizeException, BadPaddingException, InvalidAlgorithmParameterException, InvalidKeySpecException; + public Jwe encryptAndSign(Jwe jwe) throws NoSuchAlgorithmException, JsonIOException, JsonSyntaxException, IOException, InvalidKeyException, NoSuchPaddingException, IllegalBlockSizeException, BadPaddingException, InvalidAlgorithmParameterException, InvalidKeySpecException; public byte[] generateContentKey(byte[] cmk, int keyDataLen, byte[] type) throws NoSuchAlgorithmException; diff --git a/openid-connect-common/src/main/java/org/mitre/jwt/encryption/impl/RsaDecrypter.java b/openid-connect-common/src/main/java/org/mitre/jwt/encryption/impl/RsaDecrypter.java index eebaa1731..0e8e73f26 100644 --- a/openid-connect-common/src/main/java/org/mitre/jwt/encryption/impl/RsaDecrypter.java +++ b/openid-connect-common/src/main/java/org/mitre/jwt/encryption/impl/RsaDecrypter.java @@ -2,8 +2,9 @@ package org.mitre.jwt.encryption.impl; import java.security.InvalidAlgorithmParameterException; import java.security.InvalidKeyException; -import java.security.Key; import java.security.NoSuchAlgorithmException; +import java.security.PrivateKey; +import java.security.PublicKey; import javax.crypto.BadPaddingException; import javax.crypto.Cipher; @@ -20,8 +21,11 @@ import org.mitre.jwt.encryption.JweAlgorithms; public class RsaDecrypter extends AbstractJweDecrypter { + private PublicKey publicKey; + private PrivateKey privateKey; + @Override - public Jwe decrypt(String encryptedJwe, Key privateKey) throws InvalidKeyException, NoSuchAlgorithmException, NoSuchPaddingException, IllegalBlockSizeException, BadPaddingException, InvalidAlgorithmParameterException { + public Jwe decrypt(String encryptedJwe) throws InvalidKeyException, NoSuchAlgorithmException, NoSuchPaddingException, IllegalBlockSizeException, BadPaddingException, InvalidAlgorithmParameterException { Jwe jwe = Jwe.parse(encryptedJwe); @@ -29,7 +33,7 @@ public class RsaDecrypter extends AbstractJweDecrypter { if(alg.equals("RSA1_5") || alg.equals("RSA-OAEP") || alg.equals("ECDH-ES") || alg.equals("A128KW") || alg.equals("A256KW")) { //decrypt to get cmk to be used for cek and cik - jwe.setEncryptedKey(decryptEncryptionKey(jwe, privateKey)); + jwe.setEncryptedKey(decryptEncryptionKey(jwe)); //generation of cek and cik byte[] contentEncryptionKey = null; @@ -75,11 +79,11 @@ public class RsaDecrypter extends AbstractJweDecrypter { } @Override - public byte[] decryptEncryptionKey(Jwe jwe, Key privateKey) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException { + public byte[] decryptEncryptionKey(Jwe jwe) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException { if(jwe.getHeader().getAlgorithm().equals("RSA1_5")){ Cipher cipher = Cipher.getInstance("RSA"); - cipher.init(Cipher.DECRYPT_MODE, privateKey); + cipher.init(Cipher.DECRYPT_MODE, getPrivateKey()); byte[] contentMasterKey = cipher.doFinal(jwe.getEncryptedKey()); return contentMasterKey; @@ -89,4 +93,20 @@ public class RsaDecrypter extends AbstractJweDecrypter { } + public PublicKey getPublicKey() { + return publicKey; + } + + public void setPublicKey(PublicKey publicKey) { + this.publicKey = publicKey; + } + + public PrivateKey getPrivateKey() { + return privateKey; + } + + public void setPrivateKey(PrivateKey privateKey) { + this.privateKey = privateKey; + } + } diff --git a/openid-connect-common/src/main/java/org/mitre/jwt/encryption/impl/RsaEncrypter.java b/openid-connect-common/src/main/java/org/mitre/jwt/encryption/impl/RsaEncrypter.java index 6cf8a4db7..baa1d5b4e 100644 --- a/openid-connect-common/src/main/java/org/mitre/jwt/encryption/impl/RsaEncrypter.java +++ b/openid-connect-common/src/main/java/org/mitre/jwt/encryption/impl/RsaEncrypter.java @@ -2,8 +2,9 @@ package org.mitre.jwt.encryption.impl; import java.security.InvalidAlgorithmParameterException; import java.security.InvalidKeyException; -import java.security.Key; import java.security.NoSuchAlgorithmException; +import java.security.PrivateKey; +import java.security.PublicKey; import java.security.spec.InvalidKeySpecException; import java.util.Random; @@ -21,8 +22,11 @@ import org.mitre.jwt.encryption.JweAlgorithms; import org.mitre.jwt.signer.impl.HmacSigner; public class RsaEncrypter extends AbstractJweEncrypter { + + private PublicKey publicKey; + private PrivateKey privateKey; - public Jwe encryptAndSign(Jwe jwe, Key publicKey) throws NoSuchAlgorithmException, InvalidKeyException, NoSuchPaddingException, IllegalBlockSizeException, BadPaddingException, InvalidAlgorithmParameterException, InvalidKeySpecException { + public Jwe encryptAndSign(Jwe jwe) throws NoSuchAlgorithmException, InvalidKeyException, NoSuchPaddingException, IllegalBlockSizeException, BadPaddingException, InvalidAlgorithmParameterException, InvalidKeySpecException { String alg = jwe.getHeader().getAlgorithm(); String integrityAlg = jwe.getHeader().getIntegrity(); @@ -48,7 +52,7 @@ public class RsaEncrypter extends AbstractJweEncrypter { //encrypt claims and cmk to get ciphertext and encrypted key jwe.setCiphertext(encryptClaims(jwe, contentEncryptionKey)); - jwe.setEncryptedKey(encryptKey(jwe, contentMasterKey, publicKey)); + jwe.setEncryptedKey(encryptKey(jwe, contentMasterKey)); //Signer must be hmac if(integrityAlg.equals("HS256") || integrityAlg.equals("HS384") || integrityAlg.equals("HS512")){ @@ -67,12 +71,12 @@ public class RsaEncrypter extends AbstractJweEncrypter { return jwe; } - public byte[] encryptKey(Jwe jwe, byte[] contentMasterKey, Key publicKey) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException { + public byte[] encryptKey(Jwe jwe, byte[] contentMasterKey) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException { if(jwe.getHeader().getAlgorithm().equals("RSA1_5")){ Cipher cipher = Cipher.getInstance("RSA"); - cipher.init(Cipher.ENCRYPT_MODE, publicKey); + cipher.init(Cipher.ENCRYPT_MODE, getPublicKey()); byte[] encryptedKey = cipher.doFinal(contentMasterKey); return encryptedKey; @@ -109,4 +113,20 @@ public class RsaEncrypter extends AbstractJweEncrypter { } } + + public PublicKey getPublicKey() { + return publicKey; + } + + public void setPublicKey(PublicKey publicKey) { + this.publicKey = publicKey; + } + + public PrivateKey getPrivateKey() { + return privateKey; + } + + public void setPrivateKey(PrivateKey privateKey) { + this.privateKey = privateKey; + } } diff --git a/openid-connect-common/src/main/java/org/mitre/jwt/model/ClaimSet.java b/openid-connect-common/src/main/java/org/mitre/jwt/model/ClaimSet.java index 513d78594..9db157700 100644 --- a/openid-connect-common/src/main/java/org/mitre/jwt/model/ClaimSet.java +++ b/openid-connect-common/src/main/java/org/mitre/jwt/model/ClaimSet.java @@ -37,6 +37,8 @@ import com.google.gson.JsonPrimitive; * */ public class ClaimSet { + + private String jsonString; // the LinkedHashMap preserves insertion order private Map claims = new LinkedHashMap(); @@ -94,6 +96,7 @@ public class ClaimSet { * Set an extension claim */ public void setClaim(String key, Object value) { + jsonString = null; claims.put(key, value); } @@ -101,6 +104,7 @@ public class ClaimSet { * Set a primitive claim */ public void setClaim(String key, JsonPrimitive prim) { + jsonString = null; if (prim == null) { // in case we get here with a primitive null claims.put(key, prim); @@ -111,6 +115,7 @@ public class ClaimSet { } else if (prim.isString()) { claims.put(key, prim.getAsString()); } + } /** @@ -203,4 +208,11 @@ public class ClaimSet { loadFromJsonObject(json); } + public String toString() { + if(jsonString == null) { + jsonString = this.getAsJsonObject().toString(); + } + return jsonString; + } + } diff --git a/openid-connect-common/src/main/java/org/mitre/jwt/model/Jwt.java b/openid-connect-common/src/main/java/org/mitre/jwt/model/Jwt.java index ca0474b88..e40e54823 100644 --- a/openid-connect-common/src/main/java/org/mitre/jwt/model/Jwt.java +++ b/openid-connect-common/src/main/java/org/mitre/jwt/model/Jwt.java @@ -22,7 +22,6 @@ import org.apache.commons.codec.binary.Base64; import com.google.common.base.Splitter; import com.google.common.base.Strings; import com.google.common.collect.Lists; -import com.google.gson.JsonObject; public class Jwt { @@ -124,11 +123,9 @@ public class Jwt { * The signature base of a JWT is the header in Base64, a period ".", and the claims in Base64. */ public String getSignatureBase() { - JsonObject h = header.getAsJsonObject(); - JsonObject c = claims.getAsJsonObject(); - - String h64 = new String(Base64.encodeBase64URLSafe(h.toString().getBytes())); - String c64 = new String(Base64.encodeBase64URLSafe(c.toString().getBytes())); + + String h64 = new String(Base64.encodeBase64URLSafe(header.toString().getBytes())); + String c64 = new String(Base64.encodeBase64URLSafe(claims.toString().getBytes())); return h64 + "." + c64; } diff --git a/openid-connect-common/src/test/java/org/mitre/jwe/encryption/impl/RsaEncrypterDecrypterTest.java b/openid-connect-common/src/test/java/org/mitre/jwe/encryption/impl/RsaEncrypterDecrypterTest.java index 8045516b5..f94b6e455 100644 --- a/openid-connect-common/src/test/java/org/mitre/jwe/encryption/impl/RsaEncrypterDecrypterTest.java +++ b/openid-connect-common/src/test/java/org/mitre/jwe/encryption/impl/RsaEncrypterDecrypterTest.java @@ -73,12 +73,16 @@ public class RsaEncrypterDecrypterTest { Jwe jwe = new Jwe(new JweHeader(jweHeaderObject), null, jwePlaintextString.getBytes(), null); //encrypt RsaEncrypter rsaEncrypter = new RsaEncrypter(); - jwe = rsaEncrypter.encryptAndSign(jwe, publicKey); + rsaEncrypter.setPublicKey(publicKey); + rsaEncrypter.setPrivateKey(privateKey); + jwe = rsaEncrypter.encryptAndSign(jwe); //decrypt RsaDecrypter rsaDecrypter = new RsaDecrypter(); + rsaDecrypter.setPublicKey(publicKey); + rsaDecrypter.setPrivateKey(privateKey); String encryptedJweString = jwe.toString(); - jwe = rsaDecrypter.decrypt(encryptedJweString, privateKey); + jwe = rsaDecrypter.decrypt(encryptedJweString); String jweDecryptedCleartext = new String(jwe.getCiphertext()); //test ALL THE THINGS From 3b2268c62278bf89aea95fe0064703e61872277b Mon Sep 17 00:00:00 2001 From: Mike Derryberry Date: Tue, 31 Jul 2012 11:19:10 -0400 Subject: [PATCH 4/4] updated jwtHeader typ to use an enum --- .../java/org/mitre/jwt/model/JwtHeader.java | 16 ++++- .../main/java/org/mitre/jwt/model/Type.java | 72 +++++++++++++++++++ .../src/test/java/org/mitre/jwt/JwtTest.java | 8 ++- 3 files changed, 92 insertions(+), 4 deletions(-) create mode 100644 openid-connect-common/src/main/java/org/mitre/jwt/model/Type.java diff --git a/openid-connect-common/src/main/java/org/mitre/jwt/model/JwtHeader.java b/openid-connect-common/src/main/java/org/mitre/jwt/model/JwtHeader.java index 26f56f7db..80969a199 100644 --- a/openid-connect-common/src/main/java/org/mitre/jwt/model/JwtHeader.java +++ b/openid-connect-common/src/main/java/org/mitre/jwt/model/JwtHeader.java @@ -15,6 +15,7 @@ ******************************************************************************/ package org.mitre.jwt.model; +import java.text.ParseException; import java.util.Map.Entry; import com.google.gson.JsonElement; @@ -59,7 +60,12 @@ public class JwtHeader extends ClaimSet { if (element.getValue().isJsonNull()) { pass.add(element.getKey(), element.getValue()); } else if (element.getKey().equals(TYPE)) { - this.setType(element.getValue().getAsString()); + try { + this.setType(element.getValue().getAsString()); + } catch (ParseException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } } else if (element.getKey().equals(ALGORITHM)) { this.setAlgorithm(element.getValue().getAsString()); } else if (element.getKey().equals(ENCRYPTION_METHOD)) { @@ -85,9 +91,13 @@ public class JwtHeader extends ClaimSet { /** * @param type the type to set + * @throws ParseException */ - public void setType(String type) { - setClaim(TYPE, type); + public void setType(String type) throws ParseException { + if(type == null) { + throw new NullPointerException("JWT header type value must not be null"); + } + setClaim(TYPE, Type.parse(type)); } diff --git a/openid-connect-common/src/main/java/org/mitre/jwt/model/Type.java b/openid-connect-common/src/main/java/org/mitre/jwt/model/Type.java new file mode 100644 index 000000000..c5efdb0e4 --- /dev/null +++ b/openid-connect-common/src/main/java/org/mitre/jwt/model/Type.java @@ -0,0 +1,72 @@ +package org.mitre.jwt.model; + +public enum Type { + + /** + * Type ({@code typ}) parameter indicating a JWT. + * + *

Corresponds to the follwoing {@code typ} values: + * + *

    + *
  • "JWT" + *
  • "urn:ietf:params:oauth:token-type:jwt" + *
+ */ + JWT, + + + /** + * Type ({@code typ}) parameter indicating a nested JWS. + * + *

Corresponds to the following {@code typ} value: + * + *

    + *
  • "JWS" + *
+ */ + JWS, + + + /** + * Type ({@code typ}) parameter indicating a nested JWE. + * + *

Corresponds to the follwoing {@code typ} value: + * + *

    + *
  • "JWE" + *
+ */ + JWE; + + + /** + * Parses the specified type string (case sensitive). + * + *

Note that both "JWT" and + * "urn:ietf:params:oauth:token-type:jwt" resolve to + * {@link #JWT}. + * + * @param s The string to parse. + * + * @throws java.text.ParseException If the string couldn't be + * parsed to a supported JWT + * header type. + */ + public static Type parse(final String s) + throws java.text.ParseException { + + if (s == null) + throw new NullPointerException("The parsed JWT header \"typ\" value must not be null"); + + if (s.equals("JWT") || s.equals("urn:ietf:params:oauth:token-type:jwt")) + return JWT; + + if (s.equals("JWS")) + return JWS; + + if (s.equals("JWE")) + return JWE; + + throw new java.text.ParseException("Unsupported JWT header \"typ\" value: " + s, 0); + } +} diff --git a/openid-connect-server/src/test/java/org/mitre/jwt/JwtTest.java b/openid-connect-server/src/test/java/org/mitre/jwt/JwtTest.java index b20195904..6630f1c45 100644 --- a/openid-connect-server/src/test/java/org/mitre/jwt/JwtTest.java +++ b/openid-connect-server/src/test/java/org/mitre/jwt/JwtTest.java @@ -27,6 +27,7 @@ import java.security.PublicKey; import java.security.cert.X509Certificate; import java.security.spec.RSAPrivateKeySpec; import java.security.spec.RSAPublicKeySpec; +import java.text.ParseException; import java.util.Date; import org.bouncycastle.jce.X509Principal; @@ -57,7 +58,12 @@ public class JwtTest { @Test public void testGenerateHmacSignature() { Jwt jwt = new Jwt(); - jwt.getHeader().setType("JWT"); + try { + jwt.getHeader().setType("JWT"); + } catch (ParseException e1) { + // TODO Auto-generated catch block + e1.printStackTrace(); + } jwt.getHeader().setAlgorithm("HS256"); jwt.getClaims().setExpiration(new Date(1300819380L * 1000L)); jwt.getClaims().setIssuer("joe");