jmeter-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From fschumac...@apache.org
Subject svn commit: r1856146 - in /jmeter/trunk: src/core/org/apache/jmeter/util/SSLManager.java src/core/org/apache/jmeter/util/keystore/JmeterKeyStore.java xdocs/changes.xml xdocs/usermanual/component_reference.xml
Date Sun, 24 Mar 2019 13:13:41 GMT
Author: fschumacher
Date: Sun Mar 24 13:13:40 2019
New Revision: 1856146

URL: http://svn.apache.org/viewvc?rev=1856146&view=rev
Log:
Enable PKCS11 keystores for usage with KeyStore Manager

Based on a patch by Clifford Harms (clifford.harms at gmail.com).
Bugzilla Id: 62863

Modified:
    jmeter/trunk/src/core/org/apache/jmeter/util/SSLManager.java
    jmeter/trunk/src/core/org/apache/jmeter/util/keystore/JmeterKeyStore.java
    jmeter/trunk/xdocs/changes.xml
    jmeter/trunk/xdocs/usermanual/component_reference.xml

Modified: jmeter/trunk/src/core/org/apache/jmeter/util/SSLManager.java
URL: http://svn.apache.org/viewvc/jmeter/trunk/src/core/org/apache/jmeter/util/SSLManager.java?rev=1856146&r1=1856145&r2=1856146&view=diff
==============================================================================
--- jmeter/trunk/src/core/org/apache/jmeter/util/SSLManager.java (original)
+++ jmeter/trunk/src/core/org/apache/jmeter/util/SSLManager.java Sun Mar 24 13:13:40 2019
@@ -26,10 +26,13 @@ import java.net.HttpURLConnection;
 import java.security.KeyStore;
 import java.security.Provider;
 import java.security.Security;
+import java.util.Arrays;
 import java.util.Locale;
 
 import javax.swing.JOptionPane;
+import javax.swing.JPasswordField;
 
+import org.apache.commons.lang3.Validate;
 import org.apache.jmeter.gui.GuiPackage;
 import org.apache.jmeter.util.keystore.JmeterKeyStore;
 import org.slf4j.Logger;
@@ -123,10 +126,16 @@ public abstract class SSLManager {
                 throw new IllegalArgumentException("Could not create keystore: "+e.getMessage(),
e);
             }
 
-            try {
-                File initStore = new File(fileName);
+           try {
 
-                if (fileName.length() >0 && initStore.exists()) {
+              // The string 'NONE' is used for the keystore location when using PKCS11
+              // https://docs.oracle.com/javase/8/docs/technotes/guides/security/p11guide.html#JSSE
+              if ("NONE".equalsIgnoreCase(fileName)) {
+                 this.keyStore.load(null, Validate.notNull(getPassword(), "Password should
not be null"));
+                 log.info("Total of {} aliases loaded OK from PKCS11", Integer.valueOf(keyStore.getAliasCount()));
+              } else {
+                 File initStore = new File(fileName);
+                 if (fileName.length() > 0 && initStore.exists()) {
                     try (InputStream fis = new FileInputStream(initStore);
                             InputStream fileInputStream = new BufferedInputStream(fis)) {
                         this.keyStore.load(fileInputStream, getPassword());
@@ -136,18 +145,19 @@ public abstract class SSLManager {
                                     Integer.valueOf(keyStore.getAliasCount()));
                         }
                     }
-                } else {
+                 } else {
                     log.warn("Keystore file not found, loading empty keystore");
                     this.defaultpw = ""; // Ensure not null
                     this.keyStore.load(null, "");
-                }
-            } catch (Exception e) {
-                log.error("Problem loading keystore: {}", e.getMessage(), e);
-            }
-
-            if (log.isDebugEnabled()) {
-                log.debug("JmeterKeyStore type: {}", this.keyStore.getClass());
-            }
+                 }
+              }
+           } catch (Exception e) {
+              log.error("Problem loading keystore: {}", e.getMessage(), e);
+           }
+
+           if (log.isDebugEnabled()) {
+              log.debug("JmeterKeyStore type: {}", this.keyStore.getClass());
+           }
         }
 
         return this.keyStore;
@@ -156,26 +166,31 @@ public abstract class SSLManager {
     /*
      * The password can be defined as a property; this dialogue is provided to allow it
      * to be entered at run-time.
-     *
-     * However, this does not gain much, as the dialogue does not (yet) support hidden input
...
-     *
-    */
+     */
     private String getPassword() {
         String password = this.defaultpw;
         if (null == password) {
             final GuiPackage guiInstance = GuiPackage.getInstance();
             if (guiInstance != null) {
                 synchronized (this) { // TODO is sync really needed?
-                    this.defaultpw = JOptionPane.showInputDialog(
-                            guiInstance.getMainFrame(),
-                            JMeterUtils.getResString("ssl_pass_prompt"),  // $NON-NLS-1$
-                            JMeterUtils.getResString("ssl_pass_title"),  // $NON-NLS-1$
-                            JOptionPane.QUESTION_MESSAGE);
-                    System.setProperty(KEY_STORE_PASSWORD, this.defaultpw);
-                    password = this.defaultpw;
-                }
+                  JPasswordField pwf = new JPasswordField(64);
+                  pwf.setEchoChar('*');
+                  int choice = JOptionPane.showConfirmDialog(
+                          guiInstance.getMainFrame(),
+                          pwf,
+                          JMeterUtils.getResString("ssl_pass_prompt"),
+                          JOptionPane.OK_CANCEL_OPTION,
+                          JOptionPane.PLAIN_MESSAGE);
+                  if (choice == JOptionPane.OK_OPTION) {
+                     char[] pwchars = pwf.getPassword();
+                     this.defaultpw = new String(pwchars);
+                     Arrays.fill(pwchars, '*');
+                  }
+                  System.setProperty(KEY_STORE_PASSWORD, this.defaultpw);
+                  password = this.defaultpw;
+               }
             } else {
-                log.warn("No password provided, and no GUI present so cannot prompt");
+               log.warn("No password provided, and no GUI present so cannot prompt");
             }
         }
         return password;

Modified: jmeter/trunk/src/core/org/apache/jmeter/util/keystore/JmeterKeyStore.java
URL: http://svn.apache.org/viewvc/jmeter/trunk/src/core/org/apache/jmeter/util/keystore/JmeterKeyStore.java?rev=1856146&r1=1856145&r2=1856146&view=diff
==============================================================================
--- jmeter/trunk/src/core/org/apache/jmeter/util/keystore/JmeterKeyStore.java (original)
+++ jmeter/trunk/src/core/org/apache/jmeter/util/keystore/JmeterKeyStore.java Sun Mar 24 13:13:40
2019
@@ -113,57 +113,73 @@ public final class JmeterKeyStore {
      */
     public void load(InputStream is, String pword)
             throws NoSuchAlgorithmException, CertificateException, IOException, KeyStoreException,
UnrecoverableKeyException {
-        char[] pw = pword==null ? null : pword.toCharArray();
+        char[] pw = toCharArrayOrNull(pword);
         store.load(is, pw);
-    
+
         List<String> aliasesList = new ArrayList<>();
         this.privateKeyByAlias = new HashMap<>();
         this.certsByAlias = new HashMap<>();
 
-        if (null != is){ // No point checking an empty keystore
-            PrivateKey privateKey = null;
-            int index = 0;
-            Enumeration<String> aliases = store.aliases();
-            while (aliases.hasMoreElements()) {
-                String alias = aliases.nextElement();
-                if (store.isKeyEntry(alias)) {
-                    if (index >= startIndex && (endIndex== -1 || index <= endIndex))
{
-                        privateKey = (PrivateKey) store.getKey(alias, pw);
-                        if (null == privateKey) {
-                            throw new IOException("No key found for alias: " + alias); //
Should not happen
-                        }
-                        Certificate[] chain = store.getCertificateChain(alias);
-                        if (null == chain) {
-                            throw new IOException("No certificate chain found for alias:
" + alias);
-                        }
-                        aliasesList.add(alias);
-                        X509Certificate[] x509certs = new X509Certificate[chain.length];
-                        for (int i = 0; i < x509certs.length; i++) {
-                            x509certs[i] = (X509Certificate)chain[i];
-                        }
-
-                        privateKeyByAlias.put(alias, privateKey);
-                        certsByAlias.put(alias, x509certs);
-                    }
-                    index++;
+       PrivateKey privateKey = null;
+       int index = 0;
+       Enumeration<String> aliases = store.aliases();
+       while (aliases.hasMoreElements()) {
+          String alias = aliases.nextElement();
+          if (store.isKeyEntry(alias)) {
+                if (isIndexInConfiguredRange(index)) {
+                    privateKey = validateNotNull(
+                            (PrivateKey) store.getKey(alias, pw),
+                            "No key found for alias: " + alias);
+                    Certificate[] chain = validateNotNull(
+                            store.getCertificateChain(alias),
+                            "No certificate chain found for alias" + alias);
+                    aliasesList.add(alias);
+                    privateKeyByAlias.put(alias, privateKey);
+                    certsByAlias.put(alias, toX509Certificates(chain));
                 }
+             index++;
+          }
+       }
+
+       if (is != null) { // only check for keys, if we were given a file as inputstream
+           validateNotNull(privateKey, "No key(s) found");
+            if (endIndex != -1 && index <= endIndex - startIndex && log.isWarnEnabled())
{
+                log.warn("Did not find as much aliases as configured in indexes Start={},
end={}, found={}", startIndex,
+                        endIndex, certsByAlias.size());
             }
-    
-            if (null == privateKey) {
-                throw new IOException("No key(s) found");
-            }
-            if (endIndex != -1 && index <= endIndex-startIndex && log.isWarnEnabled())
{
-                log.warn("Did not find as much aliases as configured in indexes Start={},
end={}, found={}",
-                        startIndex, endIndex, certsByAlias.size());
-            }
-        }
-    
+       }
+
         /*
-         * Note: if is == null, the arrays will be empty
+         * Note: if is == null and no pkcs11 store is configured, the arrays will be empty
          */
         this.names = aliasesList.toArray(new String[aliasesList.size()]);
     }
 
+    private <T> T validateNotNull(T object, String message) throws IOException {
+        if (null == object) {
+            throw new IOException(message);
+        }
+        return object;
+    }
+
+    private X509Certificate[] toX509Certificates(Certificate[] chain) {
+        X509Certificate[] x509certs = new X509Certificate[chain.length];
+        for (int i = 0; i < x509certs.length; i++) {
+           x509certs[i] = (X509Certificate) chain[i];
+        }
+        return x509certs;
+    }
+
+    private boolean isIndexInConfiguredRange(int index) {
+        return index >= startIndex && (endIndex == -1 || index <= endIndex);
+    }
+
+    private char[] toCharArrayOrNull(String pword) {
+        if (pword == null) {
+            return null; // NOSONAR the api used requires null for "no password used"
+        }
+        return pword.toCharArray();
+    }
 
     /**
      * Get the ordered certificate chain for a specific alias.

Modified: jmeter/trunk/xdocs/changes.xml
URL: http://svn.apache.org/viewvc/jmeter/trunk/xdocs/changes.xml?rev=1856146&r1=1856145&r2=1856146&view=diff
==============================================================================
--- jmeter/trunk/xdocs/changes.xml [utf-8] (original)
+++ jmeter/trunk/xdocs/changes.xml [utf-8] Sun Mar 24 13:13:40 2019
@@ -97,6 +97,7 @@ to view the last major behaviors with th
 
 <h3>Timers, Assertions, Config, Pre- &amp; Post-Processors</h3>
 <ul>
+  <li><bug>62863</bug>Enable PKCS11 keystores for usage with KeyStore Manager.
Based on patch by Clifford Harms (clifford.harms at gmail.com).</li>
 </ul>
 
 <h3>Functions</h3>
@@ -169,6 +170,7 @@ to view the last major behaviors with th
 <p>We thank all contributors mentioned in bug and improvement sections above:
 </p>
 <ul>
+  <li>Clifford Harms (clifford.harms at gmail.com)</li>
 </ul>
 <p>We also thank bug reporters who helped us improve JMeter.</p>
 <ul>

Modified: jmeter/trunk/xdocs/usermanual/component_reference.xml
URL: http://svn.apache.org/viewvc/jmeter/trunk/xdocs/usermanual/component_reference.xml?rev=1856146&r1=1856145&r2=1856146&view=diff
==============================================================================
--- jmeter/trunk/xdocs/usermanual/component_reference.xml (original)
+++ jmeter/trunk/xdocs/usermanual/component_reference.xml Sun Mar 24 13:13:40 2019
@@ -4080,6 +4080,8 @@ This component is typically used in HTTP
     </ul>
 </li>
 </ol>
+<p>To use PKCS11 as the source for the store, you need to set <code>javax.net.ssl.keyStoreType</code>
to <code>PKCS11</code>
+and <code>javax.net.ssl.keyStore</code> to <code>NONE</code>.</p>
 </description>
 
 <properties>



Mime
View raw message