Author: rgodfrey
Date: Wed Jun 3 16:07:24 2015
New Revision: 1683380
URL: http://svn.apache.org/r1683380
Log:
QPID-6552 : [Java Client] Allow client to use certificate/key files for client
auth
Modified:
qpid/java/trunk/broker-core/src/main/java/org/apache/qpid/server/security/NonJavaKeyStoreImpl.java
qpid/java/trunk/client/src/main/java/org/apache/qpid/client/AMQBrokerDetails.java
qpid/java/trunk/client/src/main/java/org/apache/qpid/jms/BrokerDetails.java
qpid/java/trunk/common/src/main/java/org/apache/qpid/ssl/SSLContextFactory.java
qpid/java/trunk/common/src/main/java/org/apache/qpid/transport/ConnectionSettings.java
qpid/java/trunk/common/src/main/java/org/apache/qpid/transport/network/security/SecurityLayerFactory.java
qpid/java/trunk/common/src/main/java/org/apache/qpid/transport/network/security/ssl/QpidClientX509KeyManager.java
qpid/java/trunk/common/src/main/java/org/apache/qpid/transport/network/security/ssl/SSLUtil.java
qpid/java/trunk/common/src/test/java/org/apache/qpid/ssl/SSLContextFactoryTest.java
qpid/java/trunk/doc/book/src/jms-client-0-8/JMS-Client-Connection-URL.xml
qpid/java/trunk/doc/book/src/jms-client-0-8/JMS-Client-Understanding.xml
qpid/java/trunk/systests/src/main/java/org/apache/qpid/systest/rest/RestTestHelper.java
qpid/java/trunk/systests/src/test/java/org/apache/qpid/client/ssl/SSLTest.java
Modified:
qpid/java/trunk/broker-core/src/main/java/org/apache/qpid/server/security/NonJavaKeyStoreImpl.java
URL:
http://svn.apache.org/viewvc/qpid/java/trunk/broker-core/src/main/java/org/apache/qpid/server/security/NonJavaKeyStoreImpl.java?rev=1683380&r1=1683379&r2=1683380&view=diff
==============================================================================
---
qpid/java/trunk/broker-core/src/main/java/org/apache/qpid/server/security/NonJavaKeyStoreImpl.java
(original)
+++
qpid/java/trunk/broker-core/src/main/java/org/apache/qpid/server/security/NonJavaKeyStoreImpl.java
Wed Jun 3 16:07:24 2015
@@ -20,28 +20,16 @@
*/
package org.apache.qpid.server.security;
-import java.io.BufferedReader;
-import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
-import java.io.InputStream;
-import java.io.StringReader;
-import java.math.BigInteger;
import java.net.MalformedURLException;
import java.net.URL;
-import java.nio.BufferUnderflowException;
import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets;
import java.security.GeneralSecurityException;
-import java.security.KeyFactory;
import java.security.PrivateKey;
import java.security.SecureRandom;
-import java.security.cert.CertificateException;
-import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
-import java.security.spec.InvalidKeySpecException;
-import java.security.spec.PKCS8EncodedKeySpec;
-import java.security.spec.RSAPrivateCrtKeySpec;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
@@ -54,7 +42,6 @@ import javax.naming.ldap.LdapName;
import javax.naming.ldap.Rdn;
import javax.net.ssl.KeyManager;
import javax.net.ssl.KeyManagerFactory;
-import javax.xml.bind.DatatypeConverter;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
@@ -73,6 +60,7 @@ import org.apache.qpid.server.model.Port
import org.apache.qpid.server.model.State;
import org.apache.qpid.server.model.StateTransition;
import org.apache.qpid.server.util.urlstreamhandler.data.Handler;
+import org.apache.qpid.transport.network.security.ssl.SSLUtil;
@ManagedObject( category = false )
public class NonJavaKeyStoreImpl extends
AbstractConfiguredObject<NonJavaKeyStoreImpl> implements
NonJavaKeyStore<NonJavaKeyStoreImpl>
@@ -228,11 +216,11 @@ public class NonJavaKeyStoreImpl extends
{
try
{
- readPrivateKey(getUrlFromString(keyStore.getPrivateKeyUrl()));
- readCertificates(getUrlFromString(keyStore.getCertificateUrl()));
+
SSLUtil.readPrivateKey(getUrlFromString(keyStore.getPrivateKeyUrl()));
+
SSLUtil.readCertificates(getUrlFromString(keyStore.getCertificateUrl()));
if(keyStore.getIntermediateCertificateUrl() != null)
{
-
readCertificates(getUrlFromString(keyStore.getIntermediateCertificateUrl()));
+
SSLUtil.readCertificates(getUrlFromString(keyStore.getIntermediateCertificateUrl()));
}
}
catch (IOException | GeneralSecurityException e )
@@ -248,12 +236,12 @@ public class NonJavaKeyStoreImpl extends
{
if (_privateKeyUrl != null && _certificateUrl != null)
{
- PrivateKey privateKey =
readPrivateKey(getUrlFromString(_privateKeyUrl));
- X509Certificate[] certs =
readCertificates(getUrlFromString(_certificateUrl));
+ PrivateKey privateKey =
SSLUtil.readPrivateKey(getUrlFromString(_privateKeyUrl));
+ X509Certificate[] certs =
SSLUtil.readCertificates(getUrlFromString(_certificateUrl));
if(_intermediateCertificateUrl != null)
{
List<X509Certificate> allCerts = new
ArrayList<>(Arrays.asList(certs));
-
allCerts.addAll(Arrays.asList(readCertificates(getUrlFromString(_intermediateCertificateUrl))));
+
allCerts.addAll(Arrays.asList(SSLUtil.readCertificates(getUrlFromString(_intermediateCertificateUrl))));
certs = allCerts.toArray(new
X509Certificate[allCerts.size()]);
}
@@ -297,166 +285,5 @@ public class NonJavaKeyStoreImpl extends
return url;
}
- public static X509Certificate[] readCertificates(URL certFile)
- throws IOException, GeneralSecurityException
- {
- List<X509Certificate> crt = new ArrayList<>();
- try (InputStream is = certFile.openStream())
- {
- do
- {
- CertificateFactory cf =
CertificateFactory.getInstance("X.509");
- crt.add( (X509Certificate) cf.generateCertificate(is));
- } while(is.available() != 0);
- }
- catch(CertificateException e)
- {
- if(crt.isEmpty())
- {
- throw e;
- }
- }
- return crt.toArray(new X509Certificate[crt.size()]);
- }
-
- private static PrivateKey readPrivateKey(final URL url)
- throws IOException, GeneralSecurityException
- {
- ByteArrayOutputStream buffer = new ByteArrayOutputStream();
- try (InputStream urlStream = url.openStream())
- {
- byte[] tmp = new byte[1024];
- int read;
- while((read = urlStream.read(tmp)) != -1)
- {
- buffer.write(tmp,0,read);
- }
- }
-
- byte[] content = buffer.toByteArray();
- String contentAsString = new String(content,
StandardCharsets.US_ASCII);
- if(contentAsString.contains("-----BEGIN ") &&
contentAsString.contains(" PRIVATE KEY-----"))
- {
- BufferedReader lineReader = new BufferedReader(new
StringReader(contentAsString));
-
- String line;
- do
- {
- line = lineReader.readLine();
- } while(line != null && !(line.startsWith("-----BEGIN ") &&
line.endsWith(" PRIVATE KEY-----")));
-
- if(line != null)
- {
- StringBuilder keyBuilder = new StringBuilder();
-
- while((line = lineReader.readLine()) != null)
- {
- if(line.startsWith("-----END ") && line.endsWith(" PRIVATE
KEY-----"))
- {
- break;
- }
- keyBuilder.append(line);
- }
-
- content =
DatatypeConverter.parseBase64Binary(keyBuilder.toString());
- }
- }
- PrivateKey key;
- try
- {
- PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(content);
- KeyFactory kf = KeyFactory.getInstance("RSA");
- key = kf.generatePrivate(keySpec);
- }
- catch(InvalidKeySpecException e)
- {
- // not in PCKS#8 format - try parsing as PKCS#1
- RSAPrivateCrtKeySpec keySpec = getRSAKeySpec(content);
- KeyFactory kf = KeyFactory.getInstance("RSA");
- try
- {
- key = kf.generatePrivate(keySpec);
- }
- catch(InvalidKeySpecException e2)
- {
- throw new InvalidKeySpecException("Cannot parse the provided
key as either PKCS#1 or PCKS#8 format");
- }
-
- }
- return key;
- }
-
-
- private static RSAPrivateCrtKeySpec getRSAKeySpec(byte[] keyBytes) throws
InvalidKeySpecException
- {
-
- ByteBuffer buffer = ByteBuffer.wrap(keyBytes);
- try
- {
- // PKCS#1 is encoded as a DER sequence of:
- // (version, modulus, publicExponent, privateExponent, primeP,
primeQ,
- // primeExponentP, primeExponentQ, crtCoefficient)
-
- int tag = ((int)buffer.get()) & 0xff;
-
- // check tag is that of a sequence
- if(((tag & 0x20) != 0x20) || ((tag & 0x1F) != 0x10))
- {
- throw new InvalidKeySpecException("Unable to parse key as
PKCS#1 format");
- }
-
- int length = getLength(buffer);
-
- buffer = buffer.slice();
- buffer.limit(length);
-
- // first tlv is version - which we'll ignore
- byte versionTag = buffer.get();
- int versionLength = getLength(buffer);
- buffer.position(buffer.position()+versionLength);
-
-
- RSAPrivateCrtKeySpec keySpec = new RSAPrivateCrtKeySpec(
- getInteger(buffer), getInteger(buffer),
getInteger(buffer), getInteger(buffer), getInteger(buffer),
- getInteger(buffer), getInteger(buffer),
getInteger(buffer));
-
- return keySpec;
- }
- catch(BufferUnderflowException e)
- {
- throw new InvalidKeySpecException("Unable to parse key as PKCS#1
format");
- }
- }
-
- private static int getLength(ByteBuffer buffer)
- {
-
- int i = ((int) buffer.get()) & 0xff;
-
- // length 0 <= i <= 127 encoded as a single byte
- if ((i & ~0x7F) == 0)
- {
- return i;
- }
-
- // otherwise the first octet gives us the number of octets needed to
read the length
- byte[] bytes = new byte[i & 0x7f];
- buffer.get(bytes);
-
- return new BigInteger(1, bytes).intValue();
- }
-
- private static BigInteger getInteger(ByteBuffer buffer) throws
InvalidKeySpecException
- {
- int tag = ((int) buffer.get()) & 0xff;
- // 0x02 indicates an integer type
- if((tag & 0x1f) != 0x02)
- {
- throw new InvalidKeySpecException("Unable to parse key as PKCS#1
format");
- }
- byte[] num = new byte[getLength(buffer)];
- buffer.get(num);
- return new BigInteger(num);
- }
}
Modified:
qpid/java/trunk/client/src/main/java/org/apache/qpid/client/AMQBrokerDetails.java
URL:
http://svn.apache.org/viewvc/qpid/java/trunk/client/src/main/java/org/apache/qpid/client/AMQBrokerDetails.java?rev=1683380&r1=1683379&r2=1683380&view=diff
==============================================================================
---
qpid/java/trunk/client/src/main/java/org/apache/qpid/client/AMQBrokerDetails.java
(original)
+++
qpid/java/trunk/client/src/main/java/org/apache/qpid/client/AMQBrokerDetails.java
Wed Jun 3 16:07:24 2015
@@ -477,6 +477,25 @@ public class AMQBrokerDetails implements
conSettings.setCertAlias(
getProperty(BrokerDetails.OPTIONS_SSL_CERT_ALIAS));
}
+
+ if (getProperty(BrokerDetails.OPTIONS_CLIENT_CERT_PRIV_KEY_PATH) !=
null)
+ {
+ conSettings.setClientCertificatePrivateKeyPath(
+
getProperty(BrokerDetails.OPTIONS_CLIENT_CERT_PRIV_KEY_PATH));
+ }
+
+ if (getProperty(BrokerDetails.OPTIONS_CLIENT_CERT_PATH) != null)
+ {
+ conSettings.setClientCertificatePath(
+ getProperty(BrokerDetails.OPTIONS_CLIENT_CERT_PATH));
+ }
+
+ if
(getProperty(BrokerDetails.OPTIONS_CLIENT_CERT_INTERMEDIARY_CERT_PATH) != null)
+ {
+ conSettings.setClientCertificateIntermediateCertsPath(
+
getProperty(BrokerDetails.OPTIONS_CLIENT_CERT_INTERMEDIARY_CERT_PATH));
+ }
+
// ----------------------------
boolean defaultSSLVerifyHostName = Boolean.parseBoolean(
Modified:
qpid/java/trunk/client/src/main/java/org/apache/qpid/jms/BrokerDetails.java
URL:
http://svn.apache.org/viewvc/qpid/java/trunk/client/src/main/java/org/apache/qpid/jms/BrokerDetails.java?rev=1683380&r1=1683379&r2=1683380&view=diff
==============================================================================
--- qpid/java/trunk/client/src/main/java/org/apache/qpid/jms/BrokerDetails.java
(original)
+++ qpid/java/trunk/client/src/main/java/org/apache/qpid/jms/BrokerDetails.java
Wed Jun 3 16:07:24 2015
@@ -43,14 +43,17 @@ public interface BrokerDetails
public static final String OPTIONS_TCP_NO_DELAY = "tcp_nodelay";
public static final String OPTIONS_SASL_PROTOCOL_NAME = "sasl_protocol";
public static final String OPTIONS_SASL_SERVER_NAME = "sasl_server";
-
+
public static final String OPTIONS_TRUST_STORE = "trust_store";
public static final String OPTIONS_TRUST_STORE_PASSWORD =
"trust_store_password";
public static final String OPTIONS_KEY_STORE = "key_store";
public static final String OPTIONS_KEY_STORE_PASSWORD =
"key_store_password";
public static final String OPTIONS_SSL_VERIFY_HOSTNAME =
"ssl_verify_hostname";
public static final String OPTIONS_SSL_CERT_ALIAS = "ssl_cert_alias";
-
+ String OPTIONS_CLIENT_CERT_PRIV_KEY_PATH = "client_cert_priv_key_path";
+ String OPTIONS_CLIENT_CERT_PATH = "client_cert_path";
+ String OPTIONS_CLIENT_CERT_INTERMEDIARY_CERT_PATH =
"client_cert_intermediary_cert_path" ;
+
public static final int DEFAULT_PORT = 5672;
public static final String TCP = "tcp";
@@ -70,7 +73,7 @@ public interface BrokerDetails
public static final String VIRTUAL_HOST = "virtualhost";
public static final String CLIENT_ID = "client_id";
public static final String USERNAME = "username";
- public static final String PASSWORD = "password";
+ public static final String PASSWORD = "password";
String getHost();
Modified:
qpid/java/trunk/common/src/main/java/org/apache/qpid/ssl/SSLContextFactory.java
URL:
http://svn.apache.org/viewvc/qpid/java/trunk/common/src/main/java/org/apache/qpid/ssl/SSLContextFactory.java?rev=1683380&r1=1683379&r2=1683380&view=diff
==============================================================================
---
qpid/java/trunk/common/src/main/java/org/apache/qpid/ssl/SSLContextFactory.java
(original)
+++
qpid/java/trunk/common/src/main/java/org/apache/qpid/ssl/SSLContextFactory.java
Wed Jun 3 16:07:24 2015
@@ -21,7 +21,6 @@
package org.apache.qpid.ssl;
import org.apache.qpid.transport.network.security.ssl.QpidClientX509KeyManager;
-import org.apache.qpid.transport.network.security.ssl.QpidMultipleTrustManager;
import org.apache.qpid.transport.network.security.ssl.SSLUtil;
import javax.net.ssl.KeyManager;
@@ -29,14 +28,12 @@ import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.TrustManagerFactory;
-import javax.net.ssl.X509TrustManager;
import java.io.IOException;
import java.security.GeneralSecurityException;
+import java.security.KeyManagementException;
import java.security.KeyStore;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
+import java.security.NoSuchAlgorithmException;
/**
* Factory used to create SSLContexts. SSL needs to be configured
@@ -52,56 +49,25 @@ public class SSLContextFactory
//no instances
}
- public static SSLContext buildClientContext(final String trustStorePath,
- final String trustStorePassword, final String trustStoreType,
- final String trustManagerFactoryAlgorithm, final String
keyStorePath,
- final String keyStorePassword, final String keyStoreType,
- final String keyManagerFactoryAlgorithm, final String certAlias)
- throws GeneralSecurityException, IOException
- {
- return buildContext(trustStorePath,
- trustStorePassword,
- trustStoreType,
- trustManagerFactoryAlgorithm,
- keyStorePath,
- keyStorePassword,
- keyStoreType,
- keyManagerFactoryAlgorithm,
- certAlias);
- }
-
- private static SSLContext buildContext(String trustStorePath,
- String trustStorePassword,
- String trustStoreType,
- String trustManagerFactoryAlgorithm,
- String keyStorePath,
- String keyStorePassword,
- String keyStoreType,
- String keyManagerFactoryAlgorithm,
String certAlias)
- throws GeneralSecurityException, IOException
+ public static SSLContext buildClientContext(final TrustManager[]
trustManagers, final KeyManager[] keyManagers)
+ throws NoSuchAlgorithmException, KeyManagementException
{
// Initialize the SSLContext to work with our key managers.
final SSLContext sslContext = SSLContext
.getInstance(TRANSPORT_LAYER_SECURITY_CODE);
- final TrustManager[] trustManagers;
- final KeyManager[] keyManagers;
-
- if (trustStorePath != null)
- {
- final KeyStore ts = SSLUtil.getInitializedKeyStore(trustStorePath,
- trustStorePassword, trustStoreType);
- final TrustManagerFactory tmf = TrustManagerFactory
- .getInstance(trustManagerFactoryAlgorithm);
- tmf.init(ts);
+ sslContext.init(keyManagers, trustManagers, null);
- trustManagers = tmf.getTrustManagers();
- }
- else
- {
- trustManagers = null;
- }
+ return sslContext;
+ }
+ public static KeyManager[] getKeyManagers(final String keyStorePath,
+ final String keyStorePassword,
+ final String keyStoreType,
+ final String
keyManagerFactoryAlgorithm,
+ final String certAlias) throws
GeneralSecurityException, IOException
+ {
+ final KeyManager[] keyManagers;
if (keyStorePath != null)
{
if (certAlias != null)
@@ -127,9 +93,31 @@ public class SSLContextFactory
{
keyManagers = null;
}
+ return keyManagers;
+ }
- sslContext.init(keyManagers, trustManagers, null);
+ public static TrustManager[] getTrustManagers(final String trustStorePath,
+ final String
trustStorePassword,
+ final String trustStoreType,
+ final String
trustManagerFactoryAlgorithm)
+ throws GeneralSecurityException, IOException
+ {
+ final TrustManager[] trustManagers;
+ if (trustStorePath != null)
+ {
+ final KeyStore ts = SSLUtil.getInitializedKeyStore(trustStorePath,
+
trustStorePassword, trustStoreType);
+ final TrustManagerFactory tmf = TrustManagerFactory
+ .getInstance(trustManagerFactoryAlgorithm);
+ tmf.init(ts);
- return sslContext;
+ trustManagers = tmf.getTrustManagers();
+ }
+ else
+ {
+ trustManagers = null;
+ }
+ return trustManagers;
}
+
}
Modified:
qpid/java/trunk/common/src/main/java/org/apache/qpid/transport/ConnectionSettings.java
URL:
http://svn.apache.org/viewvc/qpid/java/trunk/common/src/main/java/org/apache/qpid/transport/ConnectionSettings.java?rev=1683380&r1=1683379&r2=1683380&view=diff
==============================================================================
---
qpid/java/trunk/common/src/main/java/org/apache/qpid/transport/ConnectionSettings.java
(original)
+++
qpid/java/trunk/common/src/main/java/org/apache/qpid/transport/ConnectionSettings.java
Wed Jun 3 16:07:24 2015
@@ -38,13 +38,29 @@ import static org.apache.qpid.configurat
import static
org.apache.qpid.configuration.ClientProperties.LEGACY_RECEIVE_BUFFER_SIZE_PROP_NAME;
import static
org.apache.qpid.configuration.ClientProperties.LEGACY_SEND_BUFFER_SIZE_PROP_NAME;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.nio.charset.StandardCharsets;
+import java.security.GeneralSecurityException;
import java.security.KeyStore;
+import java.security.PrivateKey;
+import java.security.SecureRandom;
+import java.security.cert.X509Certificate;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
import java.util.Map;
+import javax.net.ssl.KeyManager;
import javax.net.ssl.KeyManagerFactory;
+import javax.net.ssl.TrustManager;
import javax.net.ssl.TrustManagerFactory;
import org.apache.qpid.configuration.QpidProperty;
+import org.apache.qpid.ssl.SSLContextFactory;
+import org.apache.qpid.transport.network.security.ssl.QpidClientX509KeyManager;
+import org.apache.qpid.transport.network.security.ssl.SSLUtil;
/**
@@ -57,6 +73,7 @@ public class ConnectionSettings
{
public static final String WILDCARD_ADDRESS = "*";
+ private static final SecureRandom RANDOM = new SecureRandom();
private String protocol = "tcp";
private String host = "localhost";
@@ -86,7 +103,11 @@ public class ConnectionSettings
private String trustStoreType =
System.getProperty("javax.net.ssl.trustStoreType",KeyStore.getDefaultType());
private String certAlias;
private boolean verifyHostname;
-
+
+ private String _clientCertificatePrivateKeyPath;
+ private String _clientCertificatePath;
+ private String _clientCertificateIntermediateCertsPath;
+
// SASL props
private String saslMechs = System.getProperty("qpid.sasl_mechs", null);
private String saslProtocol = System.getProperty("qpid.sasl_protocol",
"AMQP");
@@ -398,6 +419,36 @@ public class ConnectionSettings
this.trustStoreType = trustStoreType;
}
+ public String getClientCertificatePrivateKeyPath()
+ {
+ return _clientCertificatePrivateKeyPath;
+ }
+
+ public void setClientCertificatePrivateKeyPath(final String
clientCertificatePrivateKeyPath)
+ {
+ _clientCertificatePrivateKeyPath = clientCertificatePrivateKeyPath;
+ }
+
+ public String getClientCertificatePath()
+ {
+ return _clientCertificatePath;
+ }
+
+ public void setClientCertificatePath(final String clientCertificatePath)
+ {
+ _clientCertificatePath = clientCertificatePath;
+ }
+
+ public String getClientCertificateIntermediateCertsPath()
+ {
+ return _clientCertificateIntermediateCertsPath;
+ }
+
+ public void setClientCertificateIntermediateCertsPath(final String
clientCertificateIntermediateCertsPath)
+ {
+ _clientCertificateIntermediateCertsPath =
clientCertificateIntermediateCertsPath;
+ }
+
public int getConnectTimeout()
{
return connectTimeout;
@@ -428,4 +479,80 @@ public class ConnectionSettings
this.writeBufferSize = writeBufferSize;
}
+ public KeyManager[] getKeyManagers()
+ throws GeneralSecurityException, IOException
+ {
+ if(getKeyStorePath() != null)
+ {
+ return SSLContextFactory.getKeyManagers(getKeyStorePath(),
+ getKeyStorePassword(),
+ getKeyStoreType(),
+
getKeyManagerFactoryAlgorithm(),
+ getCertAlias());
+ }
+ else if(getClientCertificatePrivateKeyPath() != null)
+ {
+ return getKeyManagers(getClientCertificatePrivateKeyPath(),
getClientCertificatePath(), getClientCertificateIntermediateCertsPath(),
getKeyManagerFactoryAlgorithm());
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ public TrustManager[] getTrustManagers()
+ throws GeneralSecurityException, IOException
+ {
+ final TrustManager[] trustManagers;
+ trustManagers =
+ SSLContextFactory.getTrustManagers(getTrustStorePath(),
+ getTrustStorePassword(),
+ getTrustStoreType(),
+
getTrustManagerFactoryAlgorithm());
+ return trustManagers;
+ }
+
+ private KeyManager[] getKeyManagers(String privateKeyFile,
+ String certFile,
+ String intermediateFile,
+ String keyManagerFactoryAlgorithm)
throws GeneralSecurityException, IOException
+ {
+ System.err.println("**** RG : in getKeyManagers[] privateKey: "
+ + privateKeyFile
+ + " ; certFile: "
+ + certFile
+ + " ; intermediate: "
+ + intermediateFile);
+ try (FileInputStream privateKeyStream = new
FileInputStream(privateKeyFile);
+ FileInputStream certFileStream = new FileInputStream(certFile))
+ {
+ PrivateKey privateKey = SSLUtil.readPrivateKey(privateKeyStream);
+ X509Certificate[] certs = SSLUtil.readCertificates(certFileStream);
+ if (intermediateFile != null)
+ {
+ try (FileInputStream intermediateFileStream = new
FileInputStream(intermediateFile))
+ {
+ List<X509Certificate> allCerts = new
ArrayList<>(Arrays.asList(certs));
+
allCerts.addAll(Arrays.asList(SSLUtil.readCertificates(intermediateFileStream)));
+ certs = allCerts.toArray(new
X509Certificate[allCerts.size()]);
+ }
+ }
+ System.err.println("*** RG : cert count - " + certs.length);
+ java.security.KeyStore inMemoryKeyStore =
+
java.security.KeyStore.getInstance(java.security.KeyStore.getDefaultType());
+
+ byte[] bytes = new byte[64];
+ char[] chars = new char[64];
+ RANDOM.nextBytes(bytes);
+
StandardCharsets.US_ASCII.decode(ByteBuffer.wrap(bytes)).get(chars);
+ inMemoryKeyStore.load(null, chars);
+ inMemoryKeyStore.setKeyEntry("1", privateKey, chars, certs);
+
+
+ return new KeyManager[]{new QpidClientX509KeyManager("1",
+
inMemoryKeyStore,
+ new
String(chars),
+
keyManagerFactoryAlgorithm)};
+ }
+ }
}
Modified:
qpid/java/trunk/common/src/main/java/org/apache/qpid/transport/network/security/SecurityLayerFactory.java
URL:
http://svn.apache.org/viewvc/qpid/java/trunk/common/src/main/java/org/apache/qpid/transport/network/security/SecurityLayerFactory.java?rev=1683380&r1=1683379&r2=1683380&view=diff
==============================================================================
---
qpid/java/trunk/common/src/main/java/org/apache/qpid/transport/network/security/SecurityLayerFactory.java
(original)
+++
qpid/java/trunk/common/src/main/java/org/apache/qpid/transport/network/security/SecurityLayerFactory.java
Wed Jun 3 16:07:24 2015
@@ -20,8 +20,10 @@
*/
package org.apache.qpid.transport.network.security;
+import javax.net.ssl.KeyManager;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLEngine;
+import javax.net.ssl.TrustManager;
import org.apache.qpid.ssl.SSLContextFactory;
import org.apache.qpid.transport.ByteBufferReceiver;
@@ -74,16 +76,16 @@ public class SecurityLayerFactory
_layer = layer;
try
{
- sslCtx = SSLContextFactory
- .buildClientContext(settings.getTrustStorePath(),
- settings.getTrustStorePassword(),
- settings.getTrustStoreType(),
- settings.getTrustManagerFactoryAlgorithm(),
- settings.getKeyStorePath(),
- settings.getKeyStorePassword(),
- settings.getKeyStoreType(),
- settings.getKeyManagerFactoryAlgorithm(),
- settings.getCertAlias());
+
+ final TrustManager[] trustManagers;
+ final KeyManager[] keyManagers;
+
+ trustManagers = settings.getTrustManagers();
+
+ keyManagers = settings.getKeyManagers();
+
+
+ sslCtx = SSLContextFactory.buildClientContext(trustManagers,
keyManagers);
}
catch (Exception e)
{
Modified:
qpid/java/trunk/common/src/main/java/org/apache/qpid/transport/network/security/ssl/QpidClientX509KeyManager.java
URL:
http://svn.apache.org/viewvc/qpid/java/trunk/common/src/main/java/org/apache/qpid/transport/network/security/ssl/QpidClientX509KeyManager.java?rev=1683380&r1=1683379&r2=1683380&view=diff
==============================================================================
---
qpid/java/trunk/common/src/main/java/org/apache/qpid/transport/network/security/ssl/QpidClientX509KeyManager.java
(original)
+++
qpid/java/trunk/common/src/main/java/org/apache/qpid/transport/network/security/ssl/QpidClientX509KeyManager.java
Wed Jun 3 16:07:24 2015
@@ -20,6 +20,7 @@
*/
package org.apache.qpid.transport.network.security.ssl;
+import org.apache.qpid.transport.util.Functions;
import org.apache.qpid.transport.util.Logger;
import javax.net.ssl.KeyManagerFactory;
@@ -44,7 +45,7 @@ public class QpidClientX509KeyManager ex
public QpidClientX509KeyManager(String alias, String keyStorePath, String
keyStoreType,
String keyStorePassword, String
keyManagerFactoryAlgorithmName) throws GeneralSecurityException, IOException
{
- this.alias = alias;
+ this.alias = alias;
KeyStore ks =
SSLUtil.getInitializedKeyStore(keyStorePath,keyStorePassword,keyStoreType);
KeyManagerFactory kmf =
KeyManagerFactory.getInstance(keyManagerFactoryAlgorithmName);
kmf.init(ks, keyStorePassword.toCharArray());
@@ -61,6 +62,16 @@ public class QpidClientX509KeyManager ex
this.delegate = (X509ExtendedKeyManager)kmf.getKeyManagers()[0];
}
+ public QpidClientX509KeyManager(String alias, KeyStore ks,
+ String keyStorePassword, String
keyManagerFactoryAlgorithmName) throws GeneralSecurityException, IOException
+ {
+ this.alias = alias;
+ KeyManagerFactory kmf =
KeyManagerFactory.getInstance(keyManagerFactoryAlgorithmName);
+ kmf.init(ks, keyStorePassword.toCharArray());
+ this.delegate = (X509ExtendedKeyManager)kmf.getKeyManagers()[0];
+ }
+
+
public String chooseClientAlias(String[] keyType, Principal[] issuers,
Socket socket)
{
log.debug("chooseClientAlias:Returning alias " + alias);
Modified:
qpid/java/trunk/common/src/main/java/org/apache/qpid/transport/network/security/ssl/SSLUtil.java
URL:
http://svn.apache.org/viewvc/qpid/java/trunk/common/src/main/java/org/apache/qpid/transport/network/security/ssl/SSLUtil.java?rev=1683380&r1=1683379&r2=1683380&view=diff
==============================================================================
---
qpid/java/trunk/common/src/main/java/org/apache/qpid/transport/network/security/ssl/SSLUtil.java
(original)
+++
qpid/java/trunk/common/src/main/java/org/apache/qpid/transport/network/security/ssl/SSLUtil.java
Wed Jun 3 16:07:24 2015
@@ -20,20 +20,34 @@
*/
package org.apache.qpid.transport.network.security.ssl;
+import java.io.BufferedReader;
+import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
+import java.io.StringReader;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
+import java.math.BigInteger;
import java.net.URL;
+import java.nio.BufferUnderflowException;
+import java.nio.ByteBuffer;
+import java.nio.charset.StandardCharsets;
import java.security.GeneralSecurityException;
+import java.security.KeyFactory;
import java.security.KeyStore;
import java.security.Principal;
+import java.security.PrivateKey;
import java.security.cert.Certificate;
+import java.security.cert.CertificateException;
+import java.security.cert.CertificateFactory;
import java.security.cert.CertificateParsingException;
import java.security.cert.X509Certificate;
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.PKCS8EncodedKeySpec;
+import java.security.spec.RSAPrivateCrtKeySpec;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
@@ -50,6 +64,7 @@ import javax.net.ssl.SSLEngine;
import javax.net.ssl.SSLPeerUnverifiedException;
import javax.net.ssl.SSLServerSocket;
import javax.net.ssl.SSLSocket;
+import javax.xml.bind.DatatypeConverter;
import org.apache.qpid.transport.TransportException;
import org.apache.qpid.transport.util.Logger;
@@ -272,6 +287,183 @@ public class SSLUtil
return ks;
}
+ public static X509Certificate[] readCertificates(URL certFile)
+ throws IOException, GeneralSecurityException
+ {
+ try (InputStream is = certFile.openStream())
+ {
+ return readCertificates(certFile.openStream());
+ }
+ }
+
+ public static X509Certificate[] readCertificates(InputStream input)
+ throws IOException, GeneralSecurityException
+ {
+ List<X509Certificate> crt = new ArrayList<>();
+ try
+ {
+ do
+ {
+ CertificateFactory cf =
CertificateFactory.getInstance("X.509");
+ crt.add( (X509Certificate) cf.generateCertificate(input));
+ } while(input.available() != 0);
+ }
+ catch(CertificateException e)
+ {
+ if(crt.isEmpty())
+ {
+ throw e;
+ }
+ }
+ return crt.toArray(new X509Certificate[crt.size()]);
+ }
+
+ public static PrivateKey readPrivateKey(final URL url)
+ throws IOException, GeneralSecurityException
+ {
+ try (InputStream urlStream = url.openStream())
+ {
+ return readPrivateKey(urlStream);
+ }
+ }
+
+ public static PrivateKey readPrivateKey(InputStream input)
+ throws IOException, GeneralSecurityException
+ {
+ ByteArrayOutputStream buffer = new ByteArrayOutputStream();
+
+ byte[] tmp = new byte[1024];
+ int read;
+ while ((read = input.read(tmp)) != -1)
+ {
+ buffer.write(tmp, 0, read);
+ }
+
+ byte[] content = buffer.toByteArray();
+ String contentAsString = new String(content,
StandardCharsets.US_ASCII);
+ if(contentAsString.contains("-----BEGIN ") &&
contentAsString.contains(" PRIVATE KEY-----"))
+ {
+ BufferedReader lineReader = new BufferedReader(new
StringReader(contentAsString));
+
+ String line;
+ do
+ {
+ line = lineReader.readLine();
+ } while(line != null && !(line.startsWith("-----BEGIN ") &&
line.endsWith(" PRIVATE KEY-----")));
+
+ if(line != null)
+ {
+ StringBuilder keyBuilder = new StringBuilder();
+
+ while((line = lineReader.readLine()) != null)
+ {
+ if(line.startsWith("-----END ") && line.endsWith(" PRIVATE
KEY-----"))
+ {
+ break;
+ }
+ keyBuilder.append(line);
+ }
+
+ content =
DatatypeConverter.parseBase64Binary(keyBuilder.toString());
+ }
+ }
+ PrivateKey key;
+ try
+ {
+ PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(content);
+ KeyFactory kf = KeyFactory.getInstance("RSA");
+ key = kf.generatePrivate(keySpec);
+ }
+ catch(InvalidKeySpecException e)
+ {
+ // not in PCKS#8 format - try parsing as PKCS#1
+ RSAPrivateCrtKeySpec keySpec = getRSAKeySpec(content);
+ KeyFactory kf = KeyFactory.getInstance("RSA");
+ try
+ {
+ key = kf.generatePrivate(keySpec);
+ }
+ catch(InvalidKeySpecException e2)
+ {
+ throw new InvalidKeySpecException("Cannot parse the provided
key as either PKCS#1 or PCKS#8 format");
+ }
+
+ }
+ return key;
+ }
+
+ private static RSAPrivateCrtKeySpec getRSAKeySpec(byte[] keyBytes) throws
InvalidKeySpecException
+ {
+
+ ByteBuffer buffer = ByteBuffer.wrap(keyBytes);
+ try
+ {
+ // PKCS#1 is encoded as a DER sequence of:
+ // (version, modulus, publicExponent, privateExponent, primeP,
primeQ,
+ // primeExponentP, primeExponentQ, crtCoefficient)
+
+ int tag = ((int)buffer.get()) & 0xff;
+
+ // check tag is that of a sequence
+ if(((tag & 0x20) != 0x20) || ((tag & 0x1F) != 0x10))
+ {
+ throw new InvalidKeySpecException("Unable to parse key as
PKCS#1 format");
+ }
+
+ int length = getLength(buffer);
+
+ buffer = buffer.slice();
+ buffer.limit(length);
+
+ // first tlv is version - which we'll ignore
+ byte versionTag = buffer.get();
+ int versionLength = getLength(buffer);
+ buffer.position(buffer.position()+versionLength);
+
+
+ RSAPrivateCrtKeySpec keySpec = new RSAPrivateCrtKeySpec(
+ getInteger(buffer), getInteger(buffer),
getInteger(buffer), getInteger(buffer), getInteger(buffer),
+ getInteger(buffer), getInteger(buffer),
getInteger(buffer));
+
+ return keySpec;
+ }
+ catch(BufferUnderflowException e)
+ {
+ throw new InvalidKeySpecException("Unable to parse key as PKCS#1
format");
+ }
+ }
+
+ private static int getLength(ByteBuffer buffer)
+ {
+
+ int i = ((int) buffer.get()) & 0xff;
+
+ // length 0 <= i <= 127 encoded as a single byte
+ if ((i & ~0x7F) == 0)
+ {
+ return i;
+ }
+
+ // otherwise the first octet gives us the number of octets needed to
read the length
+ byte[] bytes = new byte[i & 0x7f];
+ buffer.get(bytes);
+
+ return new BigInteger(1, bytes).intValue();
+ }
+
+ private static BigInteger getInteger(ByteBuffer buffer) throws
InvalidKeySpecException
+ {
+ int tag = ((int) buffer.get()) & 0xff;
+ // 0x02 indicates an integer type
+ if((tag & 0x1f) != 0x02)
+ {
+ throw new InvalidKeySpecException("Unable to parse key as PKCS#1
format");
+ }
+ byte[] num = new byte[getLength(buffer)];
+ buffer.get(num);
+ return new BigInteger(num);
+ }
+
private static interface SSLEntity
{
String[] getEnabledCipherSuites();
Modified:
qpid/java/trunk/common/src/test/java/org/apache/qpid/ssl/SSLContextFactoryTest.java
URL:
http://svn.apache.org/viewvc/qpid/java/trunk/common/src/test/java/org/apache/qpid/ssl/SSLContextFactoryTest.java?rev=1683380&r1=1683379&r2=1683380&view=diff
==============================================================================
---
qpid/java/trunk/common/src/test/java/org/apache/qpid/ssl/SSLContextFactoryTest.java
(original)
+++
qpid/java/trunk/common/src/test/java/org/apache/qpid/ssl/SSLContextFactoryTest.java
Wed Jun 3 16:07:24 2015
@@ -19,8 +19,10 @@ package org.apache.qpid.ssl;
import org.apache.qpid.test.utils.QpidTestCase;
+import javax.net.ssl.KeyManager;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
+import javax.net.ssl.TrustManager;
import javax.net.ssl.TrustManagerFactory;
import java.io.IOException;
@@ -41,7 +43,26 @@ public class SSLContextFactoryTest exten
{
try
{
- SSLContextFactory.buildClientContext("/path/to/nothing",
STORE_PASSWORD, STORE_TYPE, DEFAULT_TRUST_MANAGER_ALGORITHM,
CLIENT_KEYSTORE_PATH, STORE_PASSWORD, STORE_TYPE,
DEFAULT_KEY_MANAGER_ALGORITHM, null);
+
+ final TrustManager[] trustManagers;
+ final KeyManager[] keyManagers;
+
+ trustManagers =
+ SSLContextFactory.getTrustManagers("/path/to/nothing",
+ STORE_PASSWORD,
+ STORE_TYPE,
+
DEFAULT_TRUST_MANAGER_ALGORITHM);
+
+ keyManagers =
+ SSLContextFactory.getKeyManagers(CLIENT_KEYSTORE_PATH,
+ STORE_PASSWORD,
+ STORE_TYPE,
+
DEFAULT_KEY_MANAGER_ALGORITHM,
+ null);
+
+ SSLContextFactory.buildClientContext(trustManagers, keyManagers);
+
+
fail("Exception was not thrown due to incorrect path");
}
catch (IOException e)
@@ -52,19 +73,69 @@ public class SSLContextFactoryTest exten
public void testBuildClientContextForSSLEncryptionOnly() throws Exception
{
- SSLContext context =
SSLContextFactory.buildClientContext(CLIENT_TRUSTSTORE_PATH, STORE_PASSWORD,
STORE_TYPE, DEFAULT_TRUST_MANAGER_ALGORITHM, null, null, null, null, null);
+
+ final TrustManager[] trustManagers;
+ final KeyManager[] keyManagers;
+
+ trustManagers =
+ SSLContextFactory.getTrustManagers(CLIENT_TRUSTSTORE_PATH,
+ STORE_PASSWORD,
+ STORE_TYPE,
+
DEFAULT_TRUST_MANAGER_ALGORITHM);
+
+ keyManagers =
+ SSLContextFactory.getKeyManagers(null, null, null, null, null);
+
+
+ SSLContext context =
SSLContextFactory.buildClientContext(trustManagers, keyManagers);
assertNotNull("SSLContext should not be null", context);
}
public void testBuildClientContextWithForClientAuth() throws Exception
{
- SSLContext context =
SSLContextFactory.buildClientContext(CLIENT_TRUSTSTORE_PATH, STORE_PASSWORD,
STORE_TYPE, DEFAULT_TRUST_MANAGER_ALGORITHM, CLIENT_KEYSTORE_PATH,
STORE_PASSWORD, STORE_TYPE, DEFAULT_KEY_MANAGER_ALGORITHM, null);
+
+ final TrustManager[] trustManagers;
+ final KeyManager[] keyManagers;
+
+ trustManagers =
+ SSLContextFactory.getTrustManagers(CLIENT_TRUSTSTORE_PATH,
+ STORE_PASSWORD,
+ STORE_TYPE,
+
DEFAULT_TRUST_MANAGER_ALGORITHM);
+
+ keyManagers =
+ SSLContextFactory.getKeyManagers(CLIENT_KEYSTORE_PATH,
+ STORE_PASSWORD,
+ STORE_TYPE,
+ DEFAULT_KEY_MANAGER_ALGORITHM,
+ null);
+
+
+ SSLContext context =
SSLContextFactory.buildClientContext(trustManagers, keyManagers);
assertNotNull("SSLContext should not be null", context);
}
public void testBuildClientContextWithForClientAuthWithCertAlias() throws
Exception
{
- SSLContext context =
SSLContextFactory.buildClientContext(CLIENT_TRUSTSTORE_PATH, STORE_PASSWORD,
STORE_TYPE, DEFAULT_TRUST_MANAGER_ALGORITHM, CLIENT_KEYSTORE_PATH,
STORE_PASSWORD, STORE_TYPE, DEFAULT_KEY_MANAGER_ALGORITHM, CERT_ALIAS_APP1);
+
+ final TrustManager[] trustManagers;
+ final KeyManager[] keyManagers;
+
+ trustManagers =
+ SSLContextFactory.getTrustManagers(CLIENT_TRUSTSTORE_PATH,
+ STORE_PASSWORD,
+ STORE_TYPE,
+
DEFAULT_TRUST_MANAGER_ALGORITHM);
+
+ keyManagers =
+ SSLContextFactory.getKeyManagers(CLIENT_KEYSTORE_PATH,
+ STORE_PASSWORD,
+ STORE_TYPE,
+ DEFAULT_KEY_MANAGER_ALGORITHM,
+ CERT_ALIAS_APP1);
+
+
+ SSLContext context =
SSLContextFactory.buildClientContext(trustManagers, keyManagers);
assertNotNull("SSLContext should not be null", context);
}
}
Modified:
qpid/java/trunk/doc/book/src/jms-client-0-8/JMS-Client-Connection-URL.xml
URL:
http://svn.apache.org/viewvc/qpid/java/trunk/doc/book/src/jms-client-0-8/JMS-Client-Connection-URL.xml?rev=1683380&r1=1683379&r2=1683380&view=diff
==============================================================================
--- qpid/java/trunk/doc/book/src/jms-client-0-8/JMS-Client-Connection-URL.xml
(original)
+++ qpid/java/trunk/doc/book/src/jms-client-0-8/JMS-Client-Connection-URL.xml
Wed Jun 3 16:07:24 2015
@@ -289,7 +289,32 @@
<entry> key_store_password </entry>
<entry> String </entry>
<entry> Key store password. Password
used to open the key store. </entry>
- </row>
+ </row>
+
+ <row
id="JMS-Client-0-8-Connection-URL-BrokerOptions-ClientCertPath">
+ <entry> client_cert_path </entry>
+ <entry> String </entry>
+ <entry> Path to the client certificate
file (in PEM or DER format). Used as an
+ alternative to using a Java
KeyStore to hold key information
+ for TLS client auth. When
used, the <literal>client_cert_priv_key_path</literal>
+ must also be supplied. </entry>
+ </row>
+ <row
id="JMS-Client-0-8-Connection-URL-BrokerOptions-ClientCertPrivKeyPath">
+ <entry> client_cert_priv_key_path
</entry>
+ <entry> String </entry>
+ <entry> Path to the client certificate
private key file (in PEM or DER format).
+ Used when supplying the key
information for TLS client auth using PEM/DER
+ files rather than a Java
KeyStore. </entry>
+ </row>
+ <row
id="JMS-Client-0-8-Connection-URL-BrokerOptions-ClientCertsIntermediaryCertPath">
+ <entry>
client_cert_intermediary_cert_path </entry>
+ <entry> String </entry>
+ <entry> Path to a file containing any
intermediary certificates (in PEM or DER format).
+ Used when supplying the key
information for TLS client auth using PEM/DER
+ files rather than a Java
KeyStore. Only required where intermediary certificates
+ are required in the
certificate chain. </entry>
+ </row>
+
<row
id="JMS-Client-0-8-Connection-URL-BrokerOptions-SslCertAlias">
<entry> ssl_cert_alias </entry>
<entry> String </entry>
Modified:
qpid/java/trunk/doc/book/src/jms-client-0-8/JMS-Client-Understanding.xml
URL:
http://svn.apache.org/viewvc/qpid/java/trunk/doc/book/src/jms-client-0-8/JMS-Client-Understanding.xml?rev=1683380&r1=1683379&r2=1683380&view=diff
==============================================================================
--- qpid/java/trunk/doc/book/src/jms-client-0-8/JMS-Client-Understanding.xml
(original)
+++ qpid/java/trunk/doc/book/src/jms-client-0-8/JMS-Client-Understanding.xml
Wed Jun 3 16:07:24 2015
@@ -230,6 +230,18 @@ amqp://guest:guest@clientid/?brokerlist=
amqp://guest:guest@clientid/?brokerlist='localhost:5671?key_store='/path/to/app1_client_cert.ks'&key_store_password='secret''&ssl='true']]>
</screen>
</example>
+ <para>Alternatively we can use <link
+
linkend="JMS-Client-0-8-Connection-URL-BrokerOptions-ClientCertPath"
+ ><literal>client_cert_path</literal></link> and <link
+
linkend="JMS-Client-0-8-Connection-URL-BrokerOptions-ClientCertPrivKeyPath"
+ ><literal>client_cert_priv_key_ath</literal></link> to specify
a path to a certificate file (in PEM or DER format)
+ and the private key information (again in either PEM or DER
format) respectively.</para>
+ <example>
+ <title>Connection URL configured for SSL - SSL client-auth
(2)</title>
+ <screen><![CDATA[
+amqp://guest:guest@clientid/?brokerlist='localhost:5671?client_cert_path='/path/to/app1_client.crt'&client_cert_priv_key_path='/path/to/app1_client.key''&ssl='true']]>
+ </screen>
+ </example>
</listitem>
</itemizedlist>
</section>
Modified:
qpid/java/trunk/systests/src/main/java/org/apache/qpid/systest/rest/RestTestHelper.java
URL:
http://svn.apache.org/viewvc/qpid/java/trunk/systests/src/main/java/org/apache/qpid/systest/rest/RestTestHelper.java?rev=1683380&r1=1683379&r2=1683380&view=diff
==============================================================================
---
qpid/java/trunk/systests/src/main/java/org/apache/qpid/systest/rest/RestTestHelper.java
(original)
+++
qpid/java/trunk/systests/src/main/java/org/apache/qpid/systest/rest/RestTestHelper.java
Wed Jun 3 16:07:24 2015
@@ -45,9 +45,11 @@ import java.util.List;
import java.util.Map;
import javax.net.ssl.HttpsURLConnection;
+import javax.net.ssl.KeyManager;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocketFactory;
+import javax.net.ssl.TrustManager;
import javax.net.ssl.TrustManagerFactory;
import javax.servlet.http.HttpServletResponse;
import javax.xml.bind.DatatypeConverter;
@@ -141,11 +143,24 @@ public class RestTestHelper
// We have to use a SSLSocketFactory from a new SSLContext so
that we don't re-use
// the JVM's defaults that may have been initialised in
previous tests.
- SSLContext sslContext = SSLContextFactory.buildClientContext(
- TRUSTSTORE, TRUSTSTORE_PASSWORD,
- KeyStore.getDefaultType(),
- TrustManagerFactory.getDefaultAlgorithm(),
- KEYSTORE, KEYSTORE_PASSWORD,
KeyStore.getDefaultType(), KeyManagerFactory.getDefaultAlgorithm(),
CERT_ALIAS_APP1);
+ final TrustManager[] trustManagers;
+ final KeyManager[] keyManagers;
+
+ trustManagers =
+ SSLContextFactory.getTrustManagers(TRUSTSTORE,
+ TRUSTSTORE_PASSWORD,
+
KeyStore.getDefaultType(),
+
TrustManagerFactory.getDefaultAlgorithm());
+
+ keyManagers =
+ SSLContextFactory.getKeyManagers(KEYSTORE,
+ KEYSTORE_PASSWORD,
+
KeyStore.getDefaultType(),
+
KeyManagerFactory.getDefaultAlgorithm(),
+ CERT_ALIAS_APP1);
+
+
+ SSLContext sslContext =
SSLContextFactory.buildClientContext(trustManagers, keyManagers);
SSLSocketFactory sslSocketFactory =
sslContext.getSocketFactory();
@@ -163,11 +178,20 @@ public class RestTestHelper
// We have to use a SSLSocketFactory from a new SSLContext so
that we don't re-use
// the JVM's defaults that may have been initialised in
previous tests.
- SSLContext sslContext = SSLContextFactory.buildClientContext(
- TRUSTSTORE, TRUSTSTORE_PASSWORD,
- KeyStore.getDefaultType(),
- TrustManagerFactory.getDefaultAlgorithm(),
- null, null, null, null, null);
+ final TrustManager[] trustManagers;
+ final KeyManager[] keyManagers;
+
+ trustManagers =
+ SSLContextFactory.getTrustManagers(TRUSTSTORE,
+ TRUSTSTORE_PASSWORD,
+
KeyStore.getDefaultType(),
+
TrustManagerFactory.getDefaultAlgorithm());
+
+ keyManagers =
+ SSLContextFactory.getKeyManagers(null, null, null,
null, null);
+
+
+ SSLContext sslContext =
SSLContextFactory.buildClientContext(trustManagers, keyManagers);
SSLSocketFactory sslSocketFactory =
sslContext.getSocketFactory();
Modified:
qpid/java/trunk/systests/src/test/java/org/apache/qpid/client/ssl/SSLTest.java
URL:
http://svn.apache.org/viewvc/qpid/java/trunk/systests/src/test/java/org/apache/qpid/client/ssl/SSLTest.java?rev=1683380&r1=1683379&r2=1683380&view=diff
==============================================================================
---
qpid/java/trunk/systests/src/test/java/org/apache/qpid/client/ssl/SSLTest.java
(original)
+++
qpid/java/trunk/systests/src/test/java/org/apache/qpid/client/ssl/SSLTest.java
Wed Jun 3 16:07:24 2015
@@ -26,7 +26,13 @@ import static org.apache.qpid.test.utils
import static org.apache.qpid.test.utils.TestSSLConstants.TRUSTSTORE_PASSWORD;
import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.InputStream;
import java.io.PrintStream;
+import java.security.Key;
+import java.security.cert.Certificate;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
@@ -35,6 +41,7 @@ import java.util.Map;
import javax.jms.Connection;
import javax.jms.JMSException;
import javax.jms.Session;
+import javax.xml.bind.DatatypeConverter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -49,6 +56,7 @@ import org.apache.qpid.server.model.Virt
import org.apache.qpid.server.model.VirtualHostNameAlias;
import org.apache.qpid.test.utils.QpidBrokerTestCase;
import org.apache.qpid.test.utils.TestBrokerConfiguration;
+import org.apache.qpid.test.utils.TestFileUtils;
public class SSLTest extends QpidBrokerTestCase
{
@@ -464,7 +472,31 @@ public class SSLTest extends QpidBrokerT
}
}
+ public void testCreateSSLWithCertFileAndPrivateKey() throws Exception
+ {
+ if (shouldPerformTest())
+ {
+ clearSslStoreSystemProperties();
+ File[] certAndKeyFiles = extractResourcesFromTestKeyStore(true);
+ //Start the broker (WANTing client certificate authentication)
+ configureJavaBrokerIfNecessary(true, true, true, false, false);
+ super.setUp();
+
+
+ String url =
"amqp://guest:guest@test/?brokerlist='tcp://localhost:%s" +
+ "?ssl='true'" +
+
"&trust_store='%s'&ssl_verify_hostname='false'&trust_store_password='%s'" +
+
"&client_cert_path='%s'&client_cert_priv_key_path='%s''";
+ url = String.format(url,QpidBrokerTestCase.DEFAULT_SSL_PORT,
TRUSTSTORE,TRUSTSTORE_PASSWORD, certAndKeyFiles[1].getCanonicalPath(),
certAndKeyFiles[0].getCanonicalPath());
+
+ final AMQConnectionURL connectionURL = new AMQConnectionURL(url);
+ Connection con = getConnection(connectionURL);
+ assertNotNull("connection should be successful", con);
+ Session ssn = con.createSession(false,Session.AUTO_ACKNOWLEDGE);
+ assertNotNull("create session should be successful", ssn);
+ }
+ }
private boolean shouldPerformTest()
{
// We run the SSL tests on all the Java broker profiles
@@ -524,4 +556,57 @@ public class SSLTest extends QpidBrokerT
setSystemProperty("javax.net.ssl.trustStore", null);
setSystemProperty("javax.net.ssl.trustStorePassword", null);
}
+
+ private File[] extractResourcesFromTestKeyStore(boolean pem) throws
Exception
+ {
+ java.security.KeyStore ks =
java.security.KeyStore.getInstance(java.security.KeyStore.getDefaultType());
+ try(InputStream is = new FileInputStream(KEYSTORE))
+ {
+ ks.load(is, KEYSTORE_PASSWORD.toCharArray() );
+ }
+
+
+ File privateKeyFile = TestFileUtils.createTempFile(this,
".private-key.der");
+ try(FileOutputStream kos = new FileOutputStream(privateKeyFile))
+ {
+ Key pvt = ks.getKey(CERT_ALIAS_APP1,
KEYSTORE_PASSWORD.toCharArray());
+ kos.write("-----BEGIN PRIVATE KEY-----\n".getBytes());
+ String base64encoded =
DatatypeConverter.printBase64Binary(pvt.getEncoded());
+ while(base64encoded.length() > 76)
+ {
+ kos.write(base64encoded.substring(0,76).getBytes());
+ kos.write("\n".getBytes());
+ base64encoded = base64encoded.substring(76);
+ }
+
+ kos.write(base64encoded.getBytes());
+ kos.write("\n-----END PRIVATE KEY-----".getBytes());
+ kos.flush();
+ }
+
+ File certificateFile = TestFileUtils.createTempFile(this,
".certificate.der");
+
+ try(FileOutputStream cos = new FileOutputStream(certificateFile))
+ {
+ Certificate[] chain = ks.getCertificateChain(CERT_ALIAS_APP1);
+ for(Certificate pub : chain)
+ {
+ cos.write("-----BEGIN CERTIFICATE-----\n".getBytes());
+ String base64encoded =
DatatypeConverter.printBase64Binary(pub.getEncoded());
+ while (base64encoded.length() > 76)
+ {
+ cos.write(base64encoded.substring(0, 76).getBytes());
+ cos.write("\n".getBytes());
+ base64encoded = base64encoded.substring(76);
+ }
+ cos.write(base64encoded.getBytes());
+
+ cos.write("\n-----END CERTIFICATE-----\n".getBytes());
+ }
+ cos.flush();
+ }
+
+ return new File[]{privateKeyFile,certificateFile};
+ }
+
}
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]