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]

Reply via email to