Author: sebb
Date: Wed Sep 4 00:51:26 2013
New Revision: 1519890
URL: http://svn.apache.org/r1519890
Log:
Proxy SSL recording does not handle external embedded resources well
Part 1: Add methods to create the necessary certificate and keystore
Bugzilla Id: 55507
Modified:
jmeter/trunk/src/jorphan/org/apache/jorphan/exec/KeyToolUtils.java
Modified: jmeter/trunk/src/jorphan/org/apache/jorphan/exec/KeyToolUtils.java
URL: http://svn.apache.org/viewvc/jmeter/trunk/src/jorphan/org/apache/jorphan/exec/KeyToolUtils.java?rev=1519890&r1=1519889&r2=1519890&view=diff
==============================================================================
--- jmeter/trunk/src/jorphan/org/apache/jorphan/exec/KeyToolUtils.java (original)
+++ jmeter/trunk/src/jorphan/org/apache/jorphan/exec/KeyToolUtils.java Wed Sep 4 00:51:26
2013
@@ -13,13 +13,17 @@
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
- *
+ *
*/
package org.apache.jorphan.exec;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
import java.util.ArrayList;
import java.util.List;
@@ -31,24 +35,28 @@ public class KeyToolUtils {
// The DNAME which is used if none is provided
private static final String DEFAULT_DNAME = "cn=JMeter Proxy (DO NOT TRUST)"; // $NON-NLS-1$
+ private static final String DNAME_ROOT_KEY = "cn=Apache JMeter Proxy root (TEMPORARY
TRUST ONLY)";
+ private static final String DNAME_CA_KEY = "cn=Apache JMeter Proxy server CA (TEMPORARY
TRUST ONLY)";
+ private static final String CACERT = "ApacheJMeterTemporaryCA.crt";
+
private KeyToolUtils() {
// not instantiable
}
/**
* Generate a self-signed keypair using the algorithm "RSA".
- *
+ *
* @param keystore the keystore; if it already contains the alias the command will fail
- * @param alias the alias to use, not null
+ * @param alias the alias to use, not null
* @param password the password to use for the store and the key
* @param validity the validity period in days, greater than 0
* @param dname the dname value, if omitted use "cn=JMeter Proxy (DO NOT TRUST)"
* @param ext if not null, the extension (-ext) to add (e.g. "bc:c")
- *
- * @throws InterruptedException
+ *
+ * @throws InterruptedException
* @throws IOException
*/
- public static void genkeypair(final File keystore, String alias, final String password,
int validity, String dname, String ext)
+ public static void genkeypair(final File keystore, String alias, final String password,
int validity, String dname, String ext)
throws IOException, InterruptedException {
final File workingDir = keystore.getParentFile();
final SystemCommand nativeCommand = new SystemCommand(workingDir, null);
@@ -72,7 +80,7 @@ public class KeyToolUtils {
arguments.add(Integer.toString(validity));
if (ext != null) {
arguments.add("-ext"); // $NON-NLS-1$
- arguments.add(ext);
+ arguments.add(ext);
}
int exitVal = nativeCommand.run(arguments);
if (exitVal != 0) {
@@ -81,8 +89,74 @@ public class KeyToolUtils {
}
/**
+ * Create a self-signed CA certificate that can be used to sign SSL domain certificates.
+ * The certificate file is created in the same directory as the keystore.
+ *
+ * @param keystore the keystore in which to store everything
+ * @param password the password for keystore and keys
+ * @param validity the validity period in days, must be greater than 0
+ *
+ * @throws InterruptedException
+ * @throws IOException
+ */
+ public static void generateProxyCA(File keystore, String password, int validity) throws
IOException, InterruptedException{
+ keystore.delete(); // any existing entries will be invalidated anyway
+ new File(CACERT).delete(); // not strictly needed
+
+ // Create the self-signed keypairs (requires Java 7 for -ext flag)
+ KeyToolUtils.genkeypair(keystore, "root", password, validity, DNAME_ROOT_KEY, "bc:c");
+ KeyToolUtils.genkeypair(keystore, "ca", password, validity, DNAME_CA_KEY, "bc:c");
+
+ // Create cert for CA using root (requires Java 7 for gencert)
+ ByteArrayOutputStream certReqOut = new ByteArrayOutputStream();
+ // generate the request
+ KeyToolUtils.keytool("-certreq", keystore, password, "ca", null, certReqOut);
+
+ // generate the certificate and store in output file
+ InputStream certReqIn = new ByteArrayInputStream(certReqOut.toByteArray());
+ KeyToolUtils.keytool("-gencert", keystore, password, "ca", certReqIn, null, "-ext",
"BC:0", "-outfile", CACERT);
+
+ // import the signed CA cert into the store (root already there) - both are needed
to sign the domain certificates
+ KeyToolUtils.keytool("-importcert", keystore, password, "ca", null, null, "-file",
CACERT);
+ }
+
+ /**
+ * Create a domain certificate and sign it with the CA certificate.
+ *
+ * @param keystore the keystore to use
+ * @param password the password to use for the keystore and keys
+ * @param domain the domain, e.g. apache.org
+ * @param validity the validity period for the key
+ *
+ * @throws InterruptedException
+ * @throws IOException
+ *
+ */
+ public static void generateDomainCert(File keystore, String password, String domain,
int validity) throws IOException, InterruptedException {
+ // generate the keypair for the domain
+ String alias = domain;
+ String dname = "cn=*."+domain+", o=JMeter Proxy (TEMPORARY TRUST ONLY";
+ KeyToolUtils.genkeypair(keystore, alias, password, validity, dname, null);
+ //rem generate cert for DOMAIN using CA (requires Java7 for gencert) and import it
+
+ // get the certificate request
+ ByteArrayOutputStream certReqOut = new ByteArrayOutputStream();
+ KeyToolUtils.keytool("-certreq", keystore, password, alias, null, certReqOut);
+
+ // create the certificate
+ //rem ku:c=dig,keyE means KeyUsage:criticial=digitalSignature,keyEncipherment
+ InputStream certReqIn = new ByteArrayInputStream(certReqOut.toByteArray());
+ ByteArrayOutputStream certOut = new ByteArrayOutputStream();
+ KeyToolUtils.keytool("-gencert", keystore, password, "ca", certReqIn, certOut, "-ext",
"ku:c=dig,keyE");
+
+ // inport the certificate
+ InputStream certIn = new ByteArrayInputStream(certOut.toByteArray());
+ KeyToolUtils.keytool("-importcert", keystore, password, alias, certIn, null, "-noprompt");
+ }
+
+ /**
* List the contents of a keystore
- *
+ *
* @param keystore the keystore file
* @param storePass the keystore password
* @return the output from the command "keytool -list -v"
@@ -105,4 +179,43 @@ public class KeyToolUtils {
}
return nativeCommand.getOutResult();
}
+
+ /**
+ * Helper method to simplify chaining keytool commands.
+ *
+ * @param command the command, not null
+ * @param keystore the keystore, not nill
+ * @param password the password used for keystore and key, not null
+ * @param alias the alias, not null
+ * @param input where to source input, may be null
+ * @param output where to send output, may be null
+ * @param parameters additional parameters to the command, may be null
+ * @throws IOException
+ * @throws InterruptedException
+ */
+ static void keytool(String command, File keystore, String password, String alias,
+ InputStream input, OutputStream output, String ... parameters)
+ throws IOException, InterruptedException {
+ final File workingDir = keystore.getParentFile();
+ final SystemCommand nativeCommand = new SystemCommand(workingDir, 0L, 0, null, input,
output, null);
+ final List<String> arguments = new ArrayList<String>();
+ arguments.add("keytool"); // $NON-NLS-1$
+ arguments.add(command);
+ arguments.add("-keystore"); // $NON-NLS-1$
+ arguments.add(keystore.getName());
+ arguments.add("-storepass"); // $NON-NLS-1$
+ arguments.add(password);
+ arguments.add("-keypass"); // $NON-NLS-1$
+ arguments.add(password);
+ arguments.add("-alias"); // $NON-NLS-1$
+ arguments.add(alias);
+ for (String parameter : parameters) {
+ arguments.add(parameter);
+ }
+
+ int exitVal = nativeCommand.run(arguments);
+ if (exitVal != 0) {
+ throw new IOException("Command failed, code: " + exitVal + "\n" + nativeCommand.getOutResult());
+ }
+ }
}
|