diff --git a/server/src/main/java/org/mitre/jwt/signer/impl/RsaSigner.java b/server/src/main/java/org/mitre/jwt/signer/impl/RsaSigner.java index c697db8ab..96f4e2e88 100644 --- a/server/src/main/java/org/mitre/jwt/signer/impl/RsaSigner.java +++ b/server/src/main/java/org/mitre/jwt/signer/impl/RsaSigner.java @@ -4,6 +4,7 @@ import java.io.UnsupportedEncodingException; import java.security.GeneralSecurityException; import java.security.KeyPair; import java.security.KeyPairGenerator; +import java.security.PrivateKey; import java.security.PublicKey; import java.security.Signature; import java.security.SignatureException; @@ -83,19 +84,14 @@ public class RsaSigner extends AbstractJwtSigner implements InitializingBean { private static Log logger = LogFactory.getLog(RsaSigner.class); - public static final String PROVIDER = "BC"; public static final String DEFAULT_PASSWORD = "changeit"; -// static { -// Security.addProvider(new BouncyCastleProvider()); -// } - private KeyStore keystore; private String alias; private String password; - private RSAPrivateKey privateKey; - private RSAPublicKey publicKey; + private PrivateKey privateKey; + private PublicKey publicKey; private Signature signer; /** @@ -113,7 +109,7 @@ public class RsaSigner extends AbstractJwtSigner implements InitializingBean { public RsaSigner(String algorithmName, KeyStore keystore, String alias) { this(algorithmName, keystore, alias, DEFAULT_PASSWORD); } - + /** * @param algorithmName * @param keystore @@ -136,14 +132,23 @@ public class RsaSigner extends AbstractJwtSigner implements InitializingBean { } } + /** + * Default constructor + */ + public RsaSigner(String algorithmName, RSAPublicKey publicKey, RSAPrivateKey privateKey) { + super(algorithmName); + this.publicKey = publicKey; + this.privateKey = privateKey; + } + @Override public void afterPropertiesSet() throws Exception { KeyPair keyPair = keystore.getKeyPairForAlias(alias, password); - publicKey = ((RSAPublicKey) keyPair.getPublic()); - privateKey = (RSAPrivateKey) keyPair.getPrivate(); + publicKey = keyPair.getPublic(); + privateKey = keyPair.getPrivate(); - logger.debug("RSA Signer ready for business"); + logger.debug( Algorithm.getByName(getAlgorithm()).getStandardName() + " RSA Signer ready for business"); } @@ -152,15 +157,17 @@ public class RsaSigner extends AbstractJwtSigner implements InitializingBean { */ @Override protected String generateSignature(String signatureBase) { - + try { signer.initSign(privateKey); signer.update(signatureBase.getBytes("UTF-8")); } catch (GeneralSecurityException e) { + System.out.println("boooom 1"); // TODO Auto-generated catch block e.printStackTrace(); } catch (UnsupportedEncodingException e) { // TODO Auto-generated catch block + System.out.println("boooom 2"); e.printStackTrace(); } @@ -176,7 +183,7 @@ public class RsaSigner extends AbstractJwtSigner implements InitializingBean { // TODO Auto-generated catch block e.printStackTrace(); } - + return sig; } @@ -192,6 +199,10 @@ public class RsaSigner extends AbstractJwtSigner implements InitializingBean { return password; } + public PrivateKey getPrivateKey() { + return privateKey; + } + public PublicKey getPublicKey() { return publicKey; } @@ -208,6 +219,10 @@ public class RsaSigner extends AbstractJwtSigner implements InitializingBean { this.password = password; } + public void setPrivateKey(RSAPrivateKey privateKey) { + this.privateKey = privateKey; + } + /* * (non-Javadoc) * @@ -220,6 +235,9 @@ public class RsaSigner extends AbstractJwtSigner implements InitializingBean { + ", publicKey=" + publicKey + ", signer=" + signer + "]"; } + /* (non-Javadoc) + * @see org.mitre.jwt.signer.AbstractJwtSigner#verify(java.lang.String) + */ @Override public boolean verify(String jwtString) { @@ -251,12 +269,4 @@ public class RsaSigner extends AbstractJwtSigner implements InitializingBean { return true; } - - public RSAPrivateKey getPrivateKey() { - return privateKey; - } - - public void setPrivateKey(RSAPrivateKey privateKey) { - this.privateKey = privateKey; - } } diff --git a/server/src/main/java/org/mitre/jwt/signer/service/impl/JwtSigningAndValidationServiceDefault.java b/server/src/main/java/org/mitre/jwt/signer/service/impl/JwtSigningAndValidationServiceDefault.java index 50723a51a..9af5f71c8 100644 --- a/server/src/main/java/org/mitre/jwt/signer/service/impl/JwtSigningAndValidationServiceDefault.java +++ b/server/src/main/java/org/mitre/jwt/signer/service/impl/JwtSigningAndValidationServiceDefault.java @@ -1,8 +1,11 @@ package org.mitre.jwt.signer.service.impl; import java.security.PublicKey; +import java.security.interfaces.RSAPublicKey; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; +import java.util.Map; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; @@ -23,31 +26,35 @@ public class JwtSigningAndValidationServiceDefault implements /** * default constructor - */ - public JwtSigningAndValidationServiceDefault() { + */ + public JwtSigningAndValidationServiceDefault() { } /** * Create JwtSigningAndValidationServiceDefault * - * @param signer List of JwtSigners to associate with this service + * @param signer + * List of JwtSigners to associate with this service */ - public JwtSigningAndValidationServiceDefault(List signer) { + public JwtSigningAndValidationServiceDefault( + List signer) { setSigners(signer); } - - - /* (non-Javadoc) - * @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet() + + /* + * (non-Javadoc) + * + * @see + * org.springframework.beans.factory.InitializingBean#afterPropertiesSet() */ @Override public void afterPropertiesSet() throws Exception { // used for debugging... if (!signers.isEmpty()) { - logger.info(this.toString()); + logger.info(this.toString()); } - - logger.info(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> JwtSigningAndValidationServiceDefault is open for business"); + + logger.info("JwtSigningAndValidationServiceDefault is open for business"); } /* @@ -59,30 +66,31 @@ public class JwtSigningAndValidationServiceDefault implements */ @Override public List getAllPublicKeys() { - // TODO Iterate through the signers, gather up, and return all the PublicKeys - - List publicKeys = new ArrayList(); - PublicKey publicKey; - - for (JwtSigner signer: signers) { - + + Map map = new HashMap(); + + PublicKey publicKey; + + for (JwtSigner signer : signers) { + if (signer instanceof RsaSigner) { - + publicKey = ((RsaSigner) signer).getPublicKey(); - + if (publicKey != null) - publicKeys.add(((RsaSigner) signer).getPublicKey()); - + map.put(((RSAPublicKey) publicKey).getModulus() + .toString(16).toUpperCase() + + ((RSAPublicKey) publicKey).getPublicExponent() + .toString(16).toUpperCase(), publicKey); + } else if (signer instanceof EcdsaSigner) { - - publicKey = ((EcdsaSigner) signer).getPublicKey(); - - if (publicKey != null) - publicKeys.add(publicKey); + + // TODO } } - - return publicKeys; + + return new ArrayList(map.values()); + } /** @@ -106,7 +114,7 @@ public class JwtSigningAndValidationServiceDefault implements // TODO Auto-generated method stub return false; } - + /** * Set the JwtSigners associated with this service * @@ -132,14 +140,14 @@ public class JwtSigningAndValidationServiceDefault implements */ @Override public boolean validateIssuedJwt(Jwt jwt) { - + // TODO Verify this is correct... - for (JwtSigner signer: signers) { + for (JwtSigner signer : signers) { if (signer.verify(jwt.toString())) return true; } - + return false; } @@ -153,11 +161,11 @@ public class JwtSigningAndValidationServiceDefault implements @Override public boolean validateSignature(String jwtString) { - for (JwtSigner signer: signers) { + for (JwtSigner signer : signers) { if (signer.verify(jwtString)) return true; } - + return false; } } diff --git a/server/src/main/java/org/mitre/jwt/signer/service/impl/KeyStore.java b/server/src/main/java/org/mitre/jwt/signer/service/impl/KeyStore.java index a9341d634..2f5ddcdaf 100644 --- a/server/src/main/java/org/mitre/jwt/signer/service/impl/KeyStore.java +++ b/server/src/main/java/org/mitre/jwt/signer/service/impl/KeyStore.java @@ -1,8 +1,5 @@ package org.mitre.jwt.signer.service.impl; -import java.io.File; -import java.io.FileInputStream; -import java.io.IOException; import java.io.InputStream; import java.security.GeneralSecurityException; import java.security.Key; @@ -10,7 +7,6 @@ import java.security.KeyPair; import java.security.PrivateKey; import java.security.Provider; import java.security.PublicKey; -import java.security.interfaces.RSAPrivateKey; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; @@ -107,8 +103,8 @@ public class KeyStore implements InitializingBean { // Get public key PublicKey publicKey = cert.getPublicKey(); - - return new KeyPair(publicKey, (RSAPrivateKey) key); + + return new KeyPair(publicKey, (PrivateKey) key); } return null; diff --git a/server/src/main/resources/keystore.jks b/server/src/main/resources/keystore.jks index bb424e264..b3f5de2df 100644 Binary files a/server/src/main/resources/keystore.jks and b/server/src/main/resources/keystore.jks differ diff --git a/server/src/test/java/org/mitre/jwt/JwtTest.java b/server/src/test/java/org/mitre/jwt/JwtTest.java index bc8a6481a..5a57c6839 100644 --- a/server/src/test/java/org/mitre/jwt/JwtTest.java +++ b/server/src/test/java/org/mitre/jwt/JwtTest.java @@ -1,6 +1,8 @@ package org.mitre.jwt; import static org.hamcrest.CoreMatchers.equalTo; +import static org.hamcrest.CoreMatchers.not; +import static org.hamcrest.CoreMatchers.nullValue; import static org.junit.Assert.assertThat; import java.io.UnsupportedEncodingException; @@ -15,7 +17,6 @@ import org.mitre.jwt.signer.impl.PlaintextSigner; import org.mitre.jwt.signer.impl.RsaSigner; import org.mitre.jwt.signer.service.impl.KeyStore; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; @@ -25,35 +26,8 @@ import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; public class JwtTest { @Autowired - @Qualifier("testKeystore") KeyStore keystore; - @Test - public void testToStringPlaintext() { - Jwt jwt = new Jwt(); - jwt.getHeader().setAlgorithm("none"); - jwt.getClaims().setExpiration(new Date(1300819380L * 1000L)); - jwt.getClaims().setIssuer("joe"); - jwt.getClaims().setClaim("http://example.com/is_root", Boolean.TRUE); - - // sign it with a blank signature - JwtSigner signer = new PlaintextSigner(); - signer.sign(jwt); - - /* - * Expected string based on the following structures, serialized exactly as follows and base64 encoded: - * - * header: {"alg":"none"} - * claims: {"exp":1300819380,"iss":"joe","http://example.com/is_root":true} - */ - String expected = "eyJhbGciOiJub25lIn0.eyJleHAiOjEzMDA4MTkzODAsImlzcyI6ImpvZSIsImh0dHA6Ly9leGFtcGxlLmNvbS9pc19yb290Ijp0cnVlfQ."; - - String actual = jwt.toString(); - - assertThat(actual, equalTo(expected)); - - } - @Test public void testGenerateHmacSignature() { Jwt jwt = new Jwt(); @@ -94,40 +68,70 @@ public class JwtTest { assertThat(jwt.getSignature(), equalTo(signature)); } - + + /** + * @throws Exception + */ /** * @throws Exception */ -// @Test -// public void testGenerateRsaSignature() throws Exception { -// -//// java.security.KeyStore ks = KeyStore.generateRsaKeyPair(keystore -//// .getLocation().getFile().getPath(), "OpenID Connect Server", -//// "twentyYears", KeyStore.PASSWORD, KeyStore.PASSWORD, 30, 365*20); -//// -//// keystore.setKeystore(ks); -// -// Jwt jwt = new Jwt(); -// jwt.getHeader().setType("JWT"); -// jwt.getHeader().setAlgorithm("RS256"); -// jwt.getClaims().setExpiration(new Date(1300819380L * 1000L)); -// jwt.getClaims().setIssuer("joe"); -// jwt.getClaims().setClaim("http://example.com/is_root", Boolean.TRUE); -// -// JwtSigner signer = new RsaSigner(RsaSigner.Algorithm.DEFAULT, keystore, "twentyYears"); -// ((RsaSigner) signer).afterPropertiesSet(); -// -// signer.sign(jwt); -// -// String signature = "TW0nOd_vr1rnV7yIS-lIV2-00V_zJMWxzOc3Z7k3gvMO2aIjIGjZ9nByZMI0iL5komMxYXPl_RCkbd9OKiPkk4iK5CDj7Mawbzu95LgEOOqdXO1f7-IqX9dIvJhVXXInLD3RsGvavyheIqNeFEVidLrJo30tBchB_niljEW7VeX8nSZfiCOdbOTW3hu0ycnon7wFpejb-cRP_S0iqGxCgbYXJzqPT192EHmRy_wmFxxIy9Lc84uqNkAZSIn1jVIeAemm22RoWbq0xLVLTRyiZoxJTUzac_VteiSPRNFlUQuOdxqNf0Hxqh_wVfX1mfXUzv0D8vHJVy6aIqTISmn-qg"; -// String expected = "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJleHAiOjEzMDA4MTkzODAsImlzcyI6ImpvZSIsImh0dHA6Ly9leGFtcGxlLmNvbS9pc19yb290Ijp0cnVlfQ.TW0nOd_vr1rnV7yIS-lIV2-00V_zJMWxzOc3Z7k3gvMO2aIjIGjZ9nByZMI0iL5komMxYXPl_RCkbd9OKiPkk4iK5CDj7Mawbzu95LgEOOqdXO1f7-IqX9dIvJhVXXInLD3RsGvavyheIqNeFEVidLrJo30tBchB_niljEW7VeX8nSZfiCOdbOTW3hu0ycnon7wFpejb-cRP_S0iqGxCgbYXJzqPT192EHmRy_wmFxxIy9Lc84uqNkAZSIn1jVIeAemm22RoWbq0xLVLTRyiZoxJTUzac_VteiSPRNFlUQuOdxqNf0Hxqh_wVfX1mfXUzv0D8vHJVy6aIqTISmn-qg"; -// -// String actual = jwt.toString(); -// -// assertThat(actual, equalTo(expected)); -// assertThat(jwt.getSignature(), equalTo(signature)); -// -// } + @Test + public void testGenerateRsaSignature() throws Exception { + + Jwt jwt = new Jwt(); + jwt.getHeader().setType("JWT"); + jwt.getHeader().setAlgorithm("RS256"); + jwt.getClaims().setExpiration(new Date(1300819380L * 1000L)); + jwt.getClaims().setIssuer("joe"); + jwt.getClaims().setClaim("http://example.com/is_root", Boolean.TRUE); + + JwtSigner signer = new RsaSigner(RsaSigner.Algorithm.RS256.toString(), keystore, "test", "changeit"); + ((RsaSigner)signer).afterPropertiesSet(); + + signer.sign(jwt); + + assertThat(jwt.getSignature(), not(nullValue())); + } + + @Test + public void testParse() { + String source = "eyJhbGciOiJub25lIn0.eyJleHAiOjEzMDA4MTkzODAsImlzcyI6ImpvZSIsImh0dHA6Ly9leGFtcGxlLmNvbS9pc19yb290Ijp0cnVlfQ."; + + + Jwt jwt = Jwt.parse(source); + + assertThat(jwt.getHeader().getAlgorithm(), equalTo(PlaintextSigner.PLAINTEXT)); + assertThat(jwt.getClaims().getIssuer(), equalTo("joe")); + assertThat(jwt.getClaims().getExpiration(), equalTo(new Date(1300819380L * 1000L))); + assertThat((Boolean)jwt.getClaims().getClaim("http://example.com/is_root"), equalTo(Boolean.TRUE)); + + } + + @Test + public void testToStringPlaintext() { + Jwt jwt = new Jwt(); + jwt.getHeader().setAlgorithm("none"); + jwt.getClaims().setExpiration(new Date(1300819380L * 1000L)); + jwt.getClaims().setIssuer("joe"); + jwt.getClaims().setClaim("http://example.com/is_root", Boolean.TRUE); + + // sign it with a blank signature + JwtSigner signer = new PlaintextSigner(); + signer.sign(jwt); + + /* + * Expected string based on the following structures, serialized exactly as follows and base64 encoded: + * + * header: {"alg":"none"} + * claims: {"exp":1300819380,"iss":"joe","http://example.com/is_root":true} + */ + String expected = "eyJhbGciOiJub25lIn0.eyJleHAiOjEzMDA4MTkzODAsImlzcyI6ImpvZSIsImh0dHA6Ly9leGFtcGxlLmNvbS9pc19yb290Ijp0cnVlfQ."; + + String actual = jwt.toString(); + + assertThat(actual, equalTo(expected)); + + } @Test public void testValidateHmacSignature() { @@ -158,19 +162,5 @@ public class JwtTest { assertThat(valid, equalTo(Boolean.TRUE)); } - - @Test - public void testParse() { - String source = "eyJhbGciOiJub25lIn0.eyJleHAiOjEzMDA4MTkzODAsImlzcyI6ImpvZSIsImh0dHA6Ly9leGFtcGxlLmNvbS9pc19yb290Ijp0cnVlfQ."; - - - Jwt jwt = Jwt.parse(source); - - assertThat(jwt.getHeader().getAlgorithm(), equalTo(PlaintextSigner.PLAINTEXT)); - assertThat(jwt.getClaims().getIssuer(), equalTo("joe")); - assertThat(jwt.getClaims().getExpiration(), equalTo(new Date(1300819380L * 1000L))); - assertThat((Boolean)jwt.getClaims().getClaim("http://example.com/is_root"), equalTo(Boolean.TRUE)); - - } } diff --git a/server/src/test/java/org/mitre/jwt/signer/service/impl/KeyStoreTest.java b/server/src/test/java/org/mitre/jwt/signer/service/impl/KeyStoreTest.java index 8a3e39d65..1aa39a18d 100644 --- a/server/src/test/java/org/mitre/jwt/signer/service/impl/KeyStoreTest.java +++ b/server/src/test/java/org/mitre/jwt/signer/service/impl/KeyStoreTest.java @@ -25,7 +25,7 @@ import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; -@SuppressWarnings({ "restriction", "deprecation" }) // I know... +@SuppressWarnings("deprecation") @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(locations = { "classpath:test-context.xml" }) @@ -36,7 +36,7 @@ public class KeyStoreTest { KeyStore keystore; static { - // Need to create the certificate + // Needed to create the certificate Security.addProvider(new BouncyCastleProvider()); } @@ -48,7 +48,7 @@ public class KeyStoreTest { * @param daysNotValidAfter * @return */ - private X509V3CertificateGenerator createCertificate( + private static X509V3CertificateGenerator createCertificate( String commonName, int daysNotValidBefore, int daysNotValidAfter) { // BC sez X509V3CertificateGenerator is deprecated and the docs say to // use another, but it seemingly isn't included jar... @@ -81,7 +81,7 @@ public class KeyStoreTest { * @throws GeneralSecurityException * @throws IOException */ - public java.security.KeyStore generateRsaKeyPair( + public static java.security.KeyStore generateRsaKeyPair(KeyStore keystore, String domainName, String alias, String aliasPassword, int daysNotValidBefore, int daysNotValidAfter) throws GeneralSecurityException, IOException { @@ -117,13 +117,14 @@ public class KeyStoreTest { return ks; } + @Test public void storeKeyPair() throws GeneralSecurityException, IOException { java.security.KeyStore ks = null; try { - ks = generateRsaKeyPair("OpenID Connect Server", "storeKeyPair", "changeit", 30, 365); + ks = KeyStoreTest.generateRsaKeyPair(keystore, "OpenID Connect Server", "storeKeyPair", "changeit", 30, 365); } catch (GeneralSecurityException e) { // TODO Auto-generated catch block @@ -135,19 +136,13 @@ public class KeyStoreTest { assertThat(ks, not(nullValue())); } - + @Test public void readKey() throws GeneralSecurityException { - + Key key = keystore.getKeystore().getKey("storeKeyPair", KeyStore.PASSWORD.toCharArray()); - - System.out.println("-----BEGIN PRIVATE KEY-----"); - System.out - .println(new sun.misc.BASE64Encoder().encode(key.getEncoded())); - System.out.println("-----END PRIVATE KEY-----"); - + assertThat(key, not(nullValue())); - assertThat(true, not(false)); } } diff --git a/server/src/test/resources/keystore.jks b/server/src/test/resources/keystore.jks index bb424e264..b3f5de2df 100644 Binary files a/server/src/test/resources/keystore.jks and b/server/src/test/resources/keystore.jks differ