Author: sebb
Date: Sun Oct 23 01:50:55 2011
New Revision: 1187840
URL: http://svn.apache.org/viewvc?rev=1187840&view=rev
Log:
Bug 52033 - Allowing multiple certificates (JKS)
Modified:
jakarta/jmeter/trunk/bin/jmeter.properties
jakarta/jmeter/trunk/src/core/org/apache/jmeter/util/JsseSSLManager.java
jakarta/jmeter/trunk/src/core/org/apache/jmeter/util/SSLManager.java
jakarta/jmeter/trunk/src/core/org/apache/jmeter/util/keystore/DefaultKeyStore.java
jakarta/jmeter/trunk/src/core/org/apache/jmeter/util/keystore/JmeterKeyStore.java
jakarta/jmeter/trunk/xdocs/changes.xml
Modified: jakarta/jmeter/trunk/bin/jmeter.properties
URL:
http://svn.apache.org/viewvc/jakarta/jmeter/trunk/bin/jmeter.properties?rev=1187840&r1=1187839&r2=1187840&view=diff
==============================================================================
--- jakarta/jmeter/trunk/bin/jmeter.properties (original)
+++ jakarta/jmeter/trunk/bin/jmeter.properties Sun Oct 23 01:50:55 2011
@@ -78,6 +78,11 @@ xml.parser=org.apache.xerces.parsers.SAX
# set the value to 'false' to reset the SSL context each iteration
#https.use.cached.ssl.context=true
+# Start and end index to be used with keystores with many entries
+# The default is to use entry 0, i.e. the first
+#https.keyStoreStartIndex=0
+#https.keyStoreEndIndex=0
+
#---------------------------------------------------------------------------
# Look and Feel configuration
#---------------------------------------------------------------------------
Modified:
jakarta/jmeter/trunk/src/core/org/apache/jmeter/util/JsseSSLManager.java
URL:
http://svn.apache.org/viewvc/jakarta/jmeter/trunk/src/core/org/apache/jmeter/util/JsseSSLManager.java?rev=1187840&r1=1187839&r2=1187840&view=diff
==============================================================================
--- jakarta/jmeter/trunk/src/core/org/apache/jmeter/util/JsseSSLManager.java
(original)
+++ jakarta/jmeter/trunk/src/core/org/apache/jmeter/util/JsseSSLManager.java
Sun Oct 23 01:50:55 2011
@@ -70,6 +70,9 @@ public class JsseSSLManager extends SSLM
private static final int cps;
+ //@GuardedBy("this")
+ private static int last_user;
+
static {
log.info("Using default SSL protocol: "+DEFAULT_SSL_PROTOCOL);
log.info("SSL session context: "+(SHARED_SESSION_CONTEXT ? "shared" :
"per-thread"));
@@ -314,8 +317,12 @@ public class JsseSSLManager extends SSLM
*/
public String[] getClientAliases(String keyType, Principal[] issuers) {
log.debug("WrappedX509Manager: getClientAliases: ");
- log.debug(this.store.getAlias());
- return new String[] { this.store.getAlias() };
+ int count = this.store.getAliasCount();
+ String[] aliases = new String[count];
+ for(int i = 0; i < aliases.length; i++) {
+ aliases[i] = this.store.getAlias(i);
+ }
+ return aliases;
}
/**
@@ -343,7 +350,7 @@ public class JsseSSLManager extends SSLM
*/
public X509Certificate[] getCertificateChain(String alias) {
log.debug("WrappedX509Manager: getCertificateChain(" + alias +
")");
- return this.store.getCertificateChain();
+ return this.store.getCertificateChain(alias);
}
/**
@@ -354,8 +361,9 @@ public class JsseSSLManager extends SSLM
* @return The PrivateKey value
*/
public PrivateKey getPrivateKey(String alias) {
- log.debug("WrappedX509Manager: getPrivateKey: " +
this.store.getPrivateKey());
- return this.store.getPrivateKey();
+ PrivateKey privateKey = this.store.getPrivateKey(alias);
+ log.debug("WrappedX509Manager: getPrivateKey: " + privateKey);
+ return privateKey;
}
/**
@@ -372,14 +380,28 @@ public class JsseSSLManager extends SSLM
* @see javax.net.ssl.X509KeyManager#chooseClientAlias(String[],
Principal[], Socket)
*/
public String chooseClientAlias(String[] keyType, Principal[] issuers,
Socket socket) {
- String alias = this.store.getAlias();
- log.debug("ClientAlias: " + alias);
+ log.debug("keyType: " + keyType[0]);
+ int aliasCount = this.store.getAliasCount();
+ String alias = this.store.getAlias(getNextIndex(aliasCount));
if (alias == null || alias.length() == 0) {
log.debug("ClientAlias not found.");
}
return alias;
}
+ private int getNextIndex(int aliasCount) {
+ if (aliasCount == 1) {
+ return 0;
+ }
+ synchronized(this) {
+ last_user ++;
+ if (last_user >= aliasCount) {
+ last_user = 0;
+ }
+ return last_user;
+ }
+ }
+
/**
* Choose the server alias for the SSLServerSockets. This are not used
* in JMeter.
Modified: jakarta/jmeter/trunk/src/core/org/apache/jmeter/util/SSLManager.java
URL:
http://svn.apache.org/viewvc/jakarta/jmeter/trunk/src/core/org/apache/jmeter/util/SSLManager.java?rev=1187840&r1=1187839&r2=1187840&view=diff
==============================================================================
--- jakarta/jmeter/trunk/src/core/org/apache/jmeter/util/SSLManager.java
(original)
+++ jakarta/jmeter/trunk/src/core/org/apache/jmeter/util/SSLManager.java Sun
Oct 23 01:50:55 2011
@@ -64,7 +64,7 @@ public abstract class SSLManager {
private static final Provider sslProvider = null;
/** Cache the KeyStore instance */
- private JmeterKeyStore keyStore;
+ private volatile JmeterKeyStore keyStore;
/** Cache the TrustStore instance - null if no truststore name was
provided */
private KeyStore trustStore = null;
@@ -126,7 +126,9 @@ public abstract class SSLManager {
if (initStore.exists()) {
fileInputStream = new FileInputStream(initStore);
this.keyStore.load(fileInputStream, getPassword());
- log.info("Keystore loaded OK from file, found alias:
"+keyStore.getAlias());
+ if (log.isInfoEnabled()) {
+ log.info("Total of " + keyStore.getAliasCount() + "
aliases loaded OK from keystore");
+ }
} else {
log.warn("Keystore file not found, loading empty
keystore");
this.defaultpw = ""; // Ensure not null
Modified:
jakarta/jmeter/trunk/src/core/org/apache/jmeter/util/keystore/DefaultKeyStore.java
URL:
http://svn.apache.org/viewvc/jakarta/jmeter/trunk/src/core/org/apache/jmeter/util/keystore/DefaultKeyStore.java?rev=1187840&r1=1187839&r2=1187840&view=diff
==============================================================================
---
jakarta/jmeter/trunk/src/core/org/apache/jmeter/util/keystore/DefaultKeyStore.java
(original)
+++
jakarta/jmeter/trunk/src/core/org/apache/jmeter/util/keystore/DefaultKeyStore.java
Sun Oct 23 01:50:55 2011
@@ -23,21 +23,35 @@ import java.security.KeyStore;
import java.security.PrivateKey;
import java.security.cert.Certificate;
import java.security.cert.X509Certificate;
+import java.util.ArrayList;
import java.util.Enumeration;
+import org.apache.jmeter.util.JMeterUtils;
+
/**
* Use this Keystore to wrap the normal KeyStore implementation.
*
*/
public class DefaultKeyStore extends JmeterKeyStore {
- private X509Certificate[] certChain;
+ private X509Certificate[][] certChains;
- private PrivateKey key;
+ private PrivateKey[] keys;
- private String alias;
+ private String[] names;
private final KeyStore store;
+ private static final String KEY_STORE_START_INDEX =
"https.keyStoreStartIndex"; // $NON-NLS-1$
+ private static final String KEY_STORE_END_INDEX =
"https.keyStoreEndIndex"; // $NON-NLS-1$
+
+ private static final int startIndex;
+ private static final int endIndex;
+
+ static {
+ startIndex = JMeterUtils.getPropDefault(KEY_STORE_START_INDEX, 0);
+ endIndex = JMeterUtils.getPropDefault(KEY_STORE_END_INDEX, 0);
+ }
+
public DefaultKeyStore(String type) throws Exception {
this.store = KeyStore.getInstance(type);
}
@@ -46,54 +60,96 @@ public class DefaultKeyStore extends Jme
@Override
public void load(InputStream is, String pword) throws Exception {
store.load(is, pword.toCharArray());
- PrivateKey _key = null;
- X509Certificate[] _certChain = null;
- if (null != is){ // No point checking an empty keystore
+ ArrayList<String> v_names = new ArrayList<String>();
+ ArrayList<PrivateKey> v_keys = new ArrayList<PrivateKey>();
+ ArrayList<X509Certificate[]> v_certChains = new
ArrayList<X509Certificate[]>();
+ if (null != is){ // No point checking an empty keystore
+ PrivateKey _key = null;
+ int index = 0;
Enumeration<String> aliases = store.aliases();
while (aliases.hasMoreElements()) {
- this.alias = aliases.nextElement();
+ String alias = aliases.nextElement();
if (store.isKeyEntry(alias)) {
- _key = (PrivateKey) store.getKey(alias,
pword.toCharArray());
- Certificate[] chain = store.getCertificateChain(alias);
- _certChain = new X509Certificate[chain.length];
-
- for (int i = 0; i < chain.length; i++) {
- _certChain[i] = (X509Certificate) chain[i];
+ if ((index >= startIndex && index <= endIndex)) {
+ _key = (PrivateKey) store.getKey(alias,
pword.toCharArray());
+ if (null == _key) {
+ throw new Exception("No key found for alias: " +
alias); // Should not happen
+ }
+ Certificate[] chain = store.getCertificateChain(alias);
+ if (null == chain) {
+ throw new Exception("No certificate chain found
for alias: " + alias);
+ }
+ v_names.add(alias);
+ v_keys.add(_key);
+ v_certChains.add((X509Certificate[]) chain);
}
-
- break;
}
+ index++;
}
if (null == _key) {
- throw new Exception("No key found");
- }
- if (null == _certChain) {
- throw new Exception("No certificate chain found");
+ throw new Exception("No key(s) found");
}
}
- this.key = _key;
- this.certChain = _certChain;
+ /*
+ * Note: if is == null, the arrays will be empty
+ */
+ int v_size = v_names.size();
+
+ this.names = new String[v_size];
+ this.names = v_names.toArray(names);
+
+ this.keys = new PrivateKey[v_size];
+ this.keys = v_keys.toArray(keys);
+
+ this.certChains = new X509Certificate[v_size][];
+ this.certChains = v_certChains.toArray(certChains);
}
- /** {@inheritDoc} */
@Override
- public final X509Certificate[] getCertificateChain() {
- return this.certChain;
+ public final X509Certificate[] getCertificateChain(String alias) {
+ int entry = findAlias(alias);
+ if (entry >=0) {
+ return this.certChains[entry];
+ }
+ return null;
}
- /** {@inheritDoc} */
@Override
- public final PrivateKey getPrivateKey() {
- return this.key;
+ public final PrivateKey getPrivateKey(String alias) {
+ int entry = findAlias(alias);
+ if (entry >=0) {
+ return this.keys[entry];
+ }
+ return null;
}
- /** {@inheritDoc} */
@Override
- public final String getAlias() {
- return this.alias;
+ public final String getAlias(int index) {
+ int length = this.names.length;
+ if (length == 0 && index == 0) { // i.e. is == null
+ return null;
+ }
+ if (index >= length || index < 0) {
+ throw new ArrayIndexOutOfBoundsException(index);
+ }
+ return this.names[index];
+ }
+
+ @Override
+ public int getAliasCount() {
+ return this.names.length;
+ }
+
+ private int findAlias(String alias) {
+ for(int i = 0; i < names.length; i++) {
+ if (alias.equals(names[i])){
+ return i;
+ }
+ }
+ return -1;
}
}
Modified:
jakarta/jmeter/trunk/src/core/org/apache/jmeter/util/keystore/JmeterKeyStore.java
URL:
http://svn.apache.org/viewvc/jakarta/jmeter/trunk/src/core/org/apache/jmeter/util/keystore/JmeterKeyStore.java?rev=1187840&r1=1187839&r2=1187840&view=diff
==============================================================================
---
jakarta/jmeter/trunk/src/core/org/apache/jmeter/util/keystore/JmeterKeyStore.java
(original)
+++
jakarta/jmeter/trunk/src/core/org/apache/jmeter/util/keystore/JmeterKeyStore.java
Sun Oct 23 01:50:55 2011
@@ -34,16 +34,18 @@ public abstract class JmeterKeyStore {
public abstract void load(InputStream is, String password) throws
Exception;
/**
- * Get the ordered certificate chain.
+ * Get the ordered certificate chain for a specific alias.
*/
- public abstract X509Certificate[] getCertificateChain();
+ public abstract X509Certificate[] getCertificateChain(String alias);
- public abstract String getAlias();
+ public abstract int getAliasCount();
+
+ public abstract String getAlias(int index);
/**
- * Return the private Key
+ * Return the private Key for a specific alias
*/
- public abstract PrivateKey getPrivateKey();
+ public abstract PrivateKey getPrivateKey(String alias);
public static final JmeterKeyStore getInstance(String type) throws
Exception {
// JAVA 1.4 now handles all keystore types, so just use default
Modified: jakarta/jmeter/trunk/xdocs/changes.xml
URL:
http://svn.apache.org/viewvc/jakarta/jmeter/trunk/xdocs/changes.xml?rev=1187840&r1=1187839&r2=1187840&view=diff
==============================================================================
--- jakarta/jmeter/trunk/xdocs/changes.xml (original)
+++ jakarta/jmeter/trunk/xdocs/changes.xml Sun Oct 23 01:50:55 2011
@@ -137,6 +137,7 @@ Mirror server now uses default port 8081
<h3>HTTP Samplers</h3>
<ul>
<li>Bug 51981 - Better support for file: protocol in HTTP sampler</li>
+<li>Bug 52033 - Allowing multiple certificates (JKS)</li>
</ul>
<h3>Other samplers</h3>
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]