summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--java/client/src/main/java/org/apache/qpid/client/AMQConnectionDelegate_0_10.java5
-rw-r--r--java/client/src/main/java/org/apache/qpid/client/AMQTestConnection_0_10.java16
-rw-r--r--java/common/src/main/java/org/apache/qpid/ssl/SSLContextFactory.java102
-rw-r--r--java/common/src/main/java/org/apache/qpid/transport/network/security/ssl/QpidClientX509KeyManager.java80
-rw-r--r--java/common/src/main/java/org/apache/qpid/transport/network/security/ssl/SSLUtil.java78
-rw-r--r--java/systests/src/main/java/org/apache/qpid/client/ssl/SSLTest.java43
6 files changed, 265 insertions, 59 deletions
diff --git a/java/client/src/main/java/org/apache/qpid/client/AMQConnectionDelegate_0_10.java b/java/client/src/main/java/org/apache/qpid/client/AMQConnectionDelegate_0_10.java
index 9bded39af4..4717a9495b 100644
--- a/java/client/src/main/java/org/apache/qpid/client/AMQConnectionDelegate_0_10.java
+++ b/java/client/src/main/java/org/apache/qpid/client/AMQConnectionDelegate_0_10.java
@@ -398,4 +398,9 @@ public class AMQConnectionDelegate_0_10 implements AMQConnectionDelegate, Connec
}
return 0;
}
+
+ protected org.apache.qpid.transport.Connection getQpidConnection()
+ {
+ return _qpidConnection;
+ }
}
diff --git a/java/client/src/main/java/org/apache/qpid/client/AMQTestConnection_0_10.java b/java/client/src/main/java/org/apache/qpid/client/AMQTestConnection_0_10.java
new file mode 100644
index 0000000000..540b6042bf
--- /dev/null
+++ b/java/client/src/main/java/org/apache/qpid/client/AMQTestConnection_0_10.java
@@ -0,0 +1,16 @@
+package org.apache.qpid.client;
+
+import org.apache.qpid.transport.Connection;
+
+public class AMQTestConnection_0_10 extends AMQConnection
+{
+ public AMQTestConnection_0_10(String url) throws Exception
+ {
+ super(url);
+ }
+
+ public Connection getConnection()
+ {
+ return((AMQConnectionDelegate_0_10)_delegate).getQpidConnection();
+ }
+}
diff --git a/java/common/src/main/java/org/apache/qpid/ssl/SSLContextFactory.java b/java/common/src/main/java/org/apache/qpid/ssl/SSLContextFactory.java
index e142d21e06..702746b3da 100644
--- a/java/common/src/main/java/org/apache/qpid/ssl/SSLContextFactory.java
+++ b/java/common/src/main/java/org/apache/qpid/ssl/SSLContextFactory.java
@@ -27,10 +27,13 @@ import java.io.InputStream;
import java.security.GeneralSecurityException;
import java.security.KeyStore;
+import javax.net.ssl.KeyManager;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManagerFactory;
+import org.apache.qpid.transport.network.security.ssl.SSLUtil;
+
/**
* Factory used to create SSLContexts. SSL needs to be configured
* before this will work.
@@ -68,7 +71,7 @@ public class SSLContextFactory {
*/
private String _trustStoreCertType;
-
+ private KeyManager customKeyManager;
public SSLContextFactory(String trustStorePath, String trustStorePassword,
String trustStoreCertType)
@@ -90,7 +93,7 @@ public class SSLContextFactory {
_trustStorePath = trustStorePath;
_trustStorePassword = trustStorePassword;
- if (_trustStorePassword.equals("none"))
+ if (_trustStorePassword != null && _trustStorePassword.equals("none"))
{
_trustStorePassword = null;
}
@@ -99,7 +102,7 @@ public class SSLContextFactory {
_keyStorePath = keyStorePath;
_keyStorePassword = keyStorePassword;
- if (_keyStorePassword.equals("none"))
+ if (_keyStorePassword != null && _keyStorePassword.equals("none"))
{
_keyStorePassword = null;
}
@@ -113,29 +116,63 @@ public class SSLContextFactory {
}
}
+ public SSLContextFactory(String trustStorePath, String trustStorePassword, String trustStoreCertType,
+ KeyManager customKeyManager)
+ {
+
+ _trustStorePath = trustStorePath;
+ _trustStorePassword = trustStorePassword;
+
+ if (_trustStorePassword != null && _trustStorePassword.equals("none"))
+ {
+ _trustStorePassword = null;
+ }
+ _trustStoreCertType = trustStoreCertType;
+
+ if (_trustStorePath == null) {
+ throw new IllegalArgumentException("A TrustStore path or KeyStore path must be specified");
+ }
+ if (_trustStoreCertType == null) {
+ throw new IllegalArgumentException("Cert type must be specified");
+ }
+
+ this.customKeyManager = customKeyManager;
+ }
+
+
/**
* Builds a SSLContext appropriate for use with a server
* @return SSLContext
* @throws GeneralSecurityException
* @throws IOException
*/
+
public SSLContext buildServerContext() throws GeneralSecurityException, IOException
{
- // Create keystore
- KeyStore ks = getInitializedKeyStore(_keyStorePath,_keyStorePassword);
-
- // Set up key manager factory to use our key store
- KeyManagerFactory kmf = KeyManagerFactory.getInstance(_keyStoreCertType);
- kmf.init(ks, _keyStorePassword.toCharArray());
-
- KeyStore ts = getInitializedKeyStore(_trustStorePath,_trustStorePassword);
+ KeyStore ts = SSLUtil.getInitializedKeyStore(_trustStorePath,_trustStorePassword);
TrustManagerFactory tmf = TrustManagerFactory.getInstance(_trustStoreCertType);
tmf.init(ts);
// Initialize the SSLContext to work with our key managers.
- SSLContext sslContext = SSLContext.getInstance("TLS");
- sslContext.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
+ SSLContext sslContext = SSLContext.getInstance("TLS");
+
+ if (customKeyManager != null)
+ {
+ sslContext.init(new KeyManager[]{customKeyManager},
+ tmf.getTrustManagers(), null);
+
+ }
+ else
+ {
+ // Create keystore
+ KeyStore ks = SSLUtil.getInitializedKeyStore(_keyStorePath,_keyStorePassword);
+ // Set up key manager factory to use our key store
+ KeyManagerFactory kmf = KeyManagerFactory.getInstance(_keyStoreCertType);
+ kmf.init(ks, _keyStorePassword.toCharArray());
+ sslContext.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
+ }
+
return sslContext;
}
@@ -147,7 +184,7 @@ public class SSLContextFactory {
*/
public SSLContext buildClientContext() throws GeneralSecurityException, IOException
{
- KeyStore ks = getInitializedKeyStore(_trustStorePath,_trustStorePassword);
+ KeyStore ks = SSLUtil.getInitializedKeyStore(_trustStorePath,_trustStorePassword);
TrustManagerFactory tmf = TrustManagerFactory.getInstance(_trustStoreCertType);
tmf.init(ks);
SSLContext context = SSLContext.getInstance("TLS");
@@ -155,41 +192,4 @@ public class SSLContextFactory {
return context;
}
- private KeyStore getInitializedKeyStore(String storePath, String storePassword) throws GeneralSecurityException, IOException
- {
- KeyStore ks = KeyStore.getInstance("JKS");
- InputStream in = null;
- try
- {
- File f = new File(storePath);
- if (f.exists())
- {
- in = new FileInputStream(f);
- }
- else
- {
- in = Thread.currentThread().getContextClassLoader().getResourceAsStream(storePath);
- }
- if (in == null)
- {
- throw new IOException("Unable to load keystore resource: " + storePath);
- }
- ks.load(in, storePassword.toCharArray());
- }
- finally
- {
- if (in != null)
- {
- //noinspection EmptyCatchBlock
- try
- {
- in.close();
- }
- catch (IOException ignored)
- {
- }
- }
- }
- return ks;
- }
}
diff --git a/java/common/src/main/java/org/apache/qpid/transport/network/security/ssl/QpidClientX509KeyManager.java b/java/common/src/main/java/org/apache/qpid/transport/network/security/ssl/QpidClientX509KeyManager.java
new file mode 100644
index 0000000000..2a3aba9a95
--- /dev/null
+++ b/java/common/src/main/java/org/apache/qpid/transport/network/security/ssl/QpidClientX509KeyManager.java
@@ -0,0 +1,80 @@
+package org.apache.qpid.transport.network.security.ssl;
+
+import java.net.Socket;
+import java.security.KeyStore;
+import java.security.Principal;
+import java.security.PrivateKey;
+import java.security.cert.X509Certificate;
+
+import javax.net.ssl.KeyManagerFactory;
+import javax.net.ssl.SSLEngine;
+import javax.net.ssl.X509ExtendedKeyManager;
+
+import org.apache.qpid.transport.util.Logger;
+
+public class QpidClientX509KeyManager extends X509ExtendedKeyManager
+{
+ private static final Logger log = Logger.get(QpidClientX509KeyManager.class);
+
+ X509ExtendedKeyManager delegate;
+ String alias;
+
+ public QpidClientX509KeyManager(String alias, String keyStorePath,
+ String keyStorePassword,String keyStoreCertType) throws Exception
+ {
+ this.alias = alias;
+ KeyStore ks = SSLUtil.getInitializedKeyStore(keyStorePath,keyStorePassword);
+ KeyManagerFactory kmf = KeyManagerFactory.getInstance(keyStoreCertType);
+ kmf.init(ks, keyStorePassword.toCharArray());
+ this.delegate = (X509ExtendedKeyManager)kmf.getKeyManagers()[0];
+ }
+
+ @Override
+ public String chooseClientAlias(String[] keyType, Principal[] issuers, Socket socket)
+ {
+ log.debug("chooseClientAlias:Returning alias " + alias);
+ return alias;
+ }
+
+ @Override
+ public String chooseServerAlias(String keyType, Principal[] issuers, Socket socket)
+ {
+ return delegate.chooseServerAlias(keyType, issuers, socket);
+ }
+
+ @Override
+ public X509Certificate[] getCertificateChain(String alias)
+ {
+ return delegate.getCertificateChain(alias);
+ }
+
+ @Override
+ public String[] getClientAliases(String keyType, Principal[] issuers)
+ {
+ log.debug("getClientAliases:Returning alias " + alias);
+ return new String[]{alias};
+ }
+
+ @Override
+ public PrivateKey getPrivateKey(String alias)
+ {
+ return delegate.getPrivateKey(alias);
+ }
+
+ @Override
+ public String[] getServerAliases(String keyType, Principal[] issuers)
+ {
+ return delegate.getServerAliases(keyType, issuers);
+ }
+
+ public String chooseEngineClientAlias(String[] keyType, Principal[] issuers, SSLEngine engine)
+ {
+ log.debug("chooseEngineClientAlias:Returning alias " + alias);
+ return alias;
+ }
+
+ public String chooseEngineServerAlias(String keyType, Principal[] issuers, SSLEngine engine)
+ {
+ return delegate.chooseEngineServerAlias(keyType, issuers, engine);
+ }
+}
diff --git a/java/common/src/main/java/org/apache/qpid/transport/network/security/ssl/SSLUtil.java b/java/common/src/main/java/org/apache/qpid/transport/network/security/ssl/SSLUtil.java
index 130ce04adc..6c5c56a175 100644
--- a/java/common/src/main/java/org/apache/qpid/transport/network/security/ssl/SSLUtil.java
+++ b/java/common/src/main/java/org/apache/qpid/transport/network/security/ssl/SSLUtil.java
@@ -1,5 +1,11 @@
package org.apache.qpid.transport.network.security.ssl;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.security.GeneralSecurityException;
+import java.security.KeyStore;
import java.security.Principal;
import java.security.cert.Certificate;
import java.security.cert.X509Certificate;
@@ -63,7 +69,7 @@ public class SSLUtil
StringBuffer id = new StringBuffer();
try
{
- Certificate cert = engine.getSession().getPeerCertificates()[0];
+ Certificate cert = engine.getSession().getLocalCertificates()[0];
Principal p = ((X509Certificate)cert).getSubjectDN();
String dn = p.getName();
@@ -101,15 +107,71 @@ public class SSLUtil
public static SSLContext createSSLContext(ConnectionSettings settings) throws Exception
{
+ SSLContextFactory sslContextFactory;
- SSLContextFactory sslContextFactory = new SSLContextFactory(settings.getTrustStorePath(),
- settings.getTrustStorePassword(),
- settings.getTrustStoreCertType(),
- settings.getKeyStorePath(),
- settings.getKeyStorePassword(),
- settings.getKeyStoreCertType());
-
+ if (settings.getCertAlias() == null)
+ {
+ sslContextFactory =
+ new SSLContextFactory(settings.getTrustStorePath(),
+ settings.getTrustStorePassword(),
+ settings.getTrustStoreCertType(),
+ settings.getKeyStorePath(),
+ settings.getKeyStorePassword(),
+ settings.getKeyStoreCertType());
+
+ } else
+ {
+ sslContextFactory =
+ new SSLContextFactory(settings.getTrustStorePath(),
+ settings.getTrustStorePassword(),
+ settings.getTrustStoreCertType(),
+ new QpidClientX509KeyManager(settings.getCertAlias(),
+ settings.getKeyStorePath(),
+ settings.getKeyStorePassword(),
+ settings.getKeyStoreCertType()));
+
+ log.debug("Using custom key manager");
+ }
+
return sslContextFactory.buildServerContext();
}
+
+ public static KeyStore getInitializedKeyStore(String storePath, String storePassword) throws GeneralSecurityException, IOException
+ {
+ KeyStore ks = KeyStore.getInstance("JKS");
+ InputStream in = null;
+ try
+ {
+ File f = new File(storePath);
+ if (f.exists())
+ {
+ in = new FileInputStream(f);
+ }
+ else
+ {
+ in = Thread.currentThread().getContextClassLoader().getResourceAsStream(storePath);
+ }
+ if (in == null)
+ {
+ throw new IOException("Unable to load keystore resource: " + storePath);
+ }
+ ks.load(in, storePassword.toCharArray());
+ }
+ finally
+ {
+ if (in != null)
+ {
+ //noinspection EmptyCatchBlock
+ try
+ {
+ in.close();
+ }
+ catch (IOException ignored)
+ {
+ }
+ }
+ }
+ return ks;
+ }
}
diff --git a/java/systests/src/main/java/org/apache/qpid/client/ssl/SSLTest.java b/java/systests/src/main/java/org/apache/qpid/client/ssl/SSLTest.java
index 05118ffc0e..74326c02ec 100644
--- a/java/systests/src/main/java/org/apache/qpid/client/ssl/SSLTest.java
+++ b/java/systests/src/main/java/org/apache/qpid/client/ssl/SSLTest.java
@@ -6,10 +6,27 @@ import java.io.PrintStream;
import javax.jms.Session;
import org.apache.qpid.client.AMQConnection;
+import org.apache.qpid.client.AMQTestConnection_0_10;
import org.apache.qpid.test.utils.QpidTestCase;
+import org.apache.qpid.transport.Connection;
public class SSLTest extends QpidTestCase
{
+
+ @Override
+ protected void setUp() throws Exception
+ {
+ System.setProperty("javax.net.debug", "ssl");
+ super.setUp();
+ }
+
+ @Override
+ protected void tearDown() throws Exception
+ {
+ System.setProperty("javax.net.debug", "");
+ super.tearDown();
+ }
+
public void testCreateSSLContextFromConnectionURLParams()
{
if (Boolean.getBoolean("profile.use_ssl"))
@@ -52,6 +69,32 @@ public class SSLTest extends QpidTestCase
}
}
}
+
+ public void testMultipleCertsInSingleStore() throws Exception
+ {
+ if (Boolean.getBoolean("profile.use_ssl"))
+ {
+ String url = "amqp://guest:guest@test/?brokerlist='tcp://localhost:" +
+ System.getProperty("test.port.ssl") +
+ "?ssl='true'&ssl_cert_alias='app1''";
+
+ AMQTestConnection_0_10 con = new AMQTestConnection_0_10(url);
+ Connection transportCon = con.getConnection();
+ String userID = transportCon.getSecurityLayer().getUserID();
+ assertEquals("The correct certificate was not choosen","app1@acme.org",userID);
+ con.close();
+
+ url = "amqp://guest:guest@test/?brokerlist='tcp://localhost:" +
+ System.getProperty("test.port.ssl") +
+ "?ssl='true'&ssl_cert_alias='app2''";
+
+ con = new AMQTestConnection_0_10(url);
+ transportCon = con.getConnection();
+ userID = transportCon.getSecurityLayer().getUserID();
+ assertEquals("The correct certificate was not choosen","app2@acme.org",userID);
+ con.close();
+ }
+ }
public void testVerifyHostName()
{