You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tez.apache.org by ab...@apache.org on 2020/11/11 14:16:04 UTC

[tez] branch master updated: TEZ-4237: Upgrade async-http-client-1.9.40 due to CVE-2017-14063 (László Bodor reviewed by Ashutosh Chauhan)

This is an automated email from the ASF dual-hosted git repository.

abstractdog pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/tez.git


The following commit(s) were added to refs/heads/master by this push:
     new 4c33901  TEZ-4237: Upgrade async-http-client-1.9.40 due to CVE-2017-14063 (László Bodor reviewed by Ashutosh Chauhan)
4c33901 is described below

commit 4c339011383b0501e8080729c015ef642b7a2bbc
Author: László Bodor <bo...@gmail.com>
AuthorDate: Wed Nov 11 14:58:24 2020 +0100

    TEZ-4237: Upgrade async-http-client-1.9.40 due to CVE-2017-14063 (László Bodor reviewed by Ashutosh Chauhan)
    
    Signed-off-by: Laszlo Bodor <bo...@gmail.com>
---
 pom.xml                                            |  6 +-
 tez-plugins/tez-aux-services/pom.xml               | 12 ++++
 tez-runtime-library/pom.xml                        |  2 +-
 .../main/java/org/apache/tez/http/SSLFactory.java  | 24 ++++---
 .../tez/http/async/netty/AsyncHttpConnection.java  | 27 ++++----
 .../async/netty/TezBodyDeferringAsyncHandler.java  | 30 +++++----
 .../common/shuffle/impl/ShuffleManager.java        |  3 +-
 .../shuffle/orderedgrouped/ShuffleScheduler.java   |  1 +
 .../org/apache/tez/http/TestHttpConnection.java    | 24 ++-----
 .../org/apache/tez/test/TestSecureShuffle.java     | 75 ++++++++++++++++++++--
 10 files changed, 140 insertions(+), 64 deletions(-)

diff --git a/pom.xml b/pom.xml
index 26b20d8..04088bd 100644
--- a/pom.xml
+++ b/pom.xml
@@ -233,9 +233,9 @@
         <version>${slf4j.version}</version>
       </dependency>
       <dependency>
-        <groupId>com.ning</groupId>
-	      <artifactId>async-http-client</artifactId>
-	      <version>1.9.40</version>
+        <groupId>org.asynchttpclient</groupId>
+        <artifactId>async-http-client</artifactId>
+        <version>2.12.1</version>
       </dependency>
       <dependency>
         <groupId>org.slf4j</groupId>
diff --git a/tez-plugins/tez-aux-services/pom.xml b/tez-plugins/tez-aux-services/pom.xml
index 0a80788..97096c8 100644
--- a/tez-plugins/tez-aux-services/pom.xml
+++ b/tez-plugins/tez-aux-services/pom.xml
@@ -55,6 +55,12 @@
       <groupId>org.apache.hadoop</groupId>
       <artifactId>hadoop-hdfs</artifactId>
       <scope>provided</scope>
+      <exclusions>
+        <exclusion>
+          <groupId>io.netty</groupId>
+          <artifactId>*</artifactId>
+        </exclusion>
+      </exclusions>
     </dependency>
     <dependency>
       <groupId>org.apache.hadoop</groupId>
@@ -126,6 +132,12 @@
       <artifactId>hadoop-hdfs</artifactId>
       <scope>test</scope>
       <type>test-jar</type>
+      <exclusions>
+        <exclusion>
+          <groupId>io.netty</groupId>
+          <artifactId>*</artifactId>
+        </exclusion>
+      </exclusions>
     </dependency>
    <dependency>
      <groupId>org.apache.tez</groupId>
diff --git a/tez-runtime-library/pom.xml b/tez-runtime-library/pom.xml
index b59d2fb..ecabf89 100644
--- a/tez-runtime-library/pom.xml
+++ b/tez-runtime-library/pom.xml
@@ -30,7 +30,7 @@
       <artifactId>RoaringBitmap</artifactId>
     </dependency>
     <dependency>
-      <groupId>com.ning</groupId>
+      <groupId>org.asynchttpclient</groupId>
       <artifactId>async-http-client</artifactId>
     </dependency>
     <dependency>
diff --git a/tez-runtime-library/src/main/java/org/apache/tez/http/SSLFactory.java b/tez-runtime-library/src/main/java/org/apache/tez/http/SSLFactory.java
index 203eb40..4147be8 100644
--- a/tez-runtime-library/src/main/java/org/apache/tez/http/SSLFactory.java
+++ b/tez-runtime-library/src/main/java/org/apache/tez/http/SSLFactory.java
@@ -18,7 +18,12 @@
 
 package org.apache.tez.http;
 
-import com.ning.http.client.AsyncHttpClientConfig;
+import org.asynchttpclient.DefaultAsyncHttpClientConfig;
+
+import io.netty.handler.ssl.ClientAuth;
+import io.netty.handler.ssl.JdkSslContext;
+import io.netty.handler.ssl.SupportedCipherSuiteFilter;
+
 import org.apache.hadoop.classification.InterfaceAudience;
 import org.apache.hadoop.classification.InterfaceStability;
 import org.apache.hadoop.conf.Configuration;
@@ -223,17 +228,20 @@ public class SSLFactory implements ConnectionConfigurator {
   }
 
   /**
-   * Set ssl context for {@link com.ning.http.client.AsyncHttpClientConfig.Builder}
+   * Set ssl context for {@link org.asynchttpclient.DefaultAsyncHttpClientConfig.Builder}
    *
-   * @param asyncNingBuilder {@link com.ning.http.client.AsyncHttpClientConfig.Builder} instance to
+   * @param builder {@link org.asynchttpclient.DefaultAsyncHttpClientConfig.Builder} instance to
    *                configure.
    * @throws IOException if an IO error occurred.
    */
-  public void configure(AsyncHttpClientConfig.Builder asyncNingBuilder) throws IOException {
-    if (asyncNingBuilder != null) {
-      asyncNingBuilder.setSSLContext(context);
-      asyncNingBuilder.setHostnameVerifier(getHostnameVerifier());
+  public void configure(DefaultAsyncHttpClientConfig.Builder builder) throws IOException {
+    if (builder != null) {
+      JdkSslContext jdkSslContext =
+          new JdkSslContext(context, mode.equals(Mode.CLIENT), /* ciphers */null,
+              SupportedCipherSuiteFilter.INSTANCE, /* ApplicationProtocolConfig */ null,
+              requireClientCert ? ClientAuth.REQUIRE : ClientAuth.OPTIONAL, enabledProtocols,
+              /* startTls */ true);
+      builder.setSslContext(jdkSslContext);
     }
   }
-
 }
\ No newline at end of file
diff --git a/tez-runtime-library/src/main/java/org/apache/tez/http/async/netty/AsyncHttpConnection.java b/tez-runtime-library/src/main/java/org/apache/tez/http/async/netty/AsyncHttpConnection.java
index ac0a49c..43f64b8 100644
--- a/tez-runtime-library/src/main/java/org/apache/tez/http/async/netty/AsyncHttpConnection.java
+++ b/tez-runtime-library/src/main/java/org/apache/tez/http/async/netty/AsyncHttpConnection.java
@@ -20,12 +20,13 @@ package org.apache.tez.http.async.netty;
 
 import com.google.common.annotations.VisibleForTesting;
 import org.apache.tez.common.Preconditions;
-import com.ning.http.client.AsyncHttpClient;
-import com.ning.http.client.AsyncHttpClientConfig;
-import com.ning.http.client.ListenableFuture;
-import com.ning.http.client.Request;
-import com.ning.http.client.RequestBuilder;
-import com.ning.http.client.Response;
+import org.asynchttpclient.AsyncHttpClient;
+import org.asynchttpclient.DefaultAsyncHttpClient;
+import org.asynchttpclient.DefaultAsyncHttpClientConfig;
+import org.asynchttpclient.ListenableFuture;
+import org.asynchttpclient.Request;
+import org.asynchttpclient.RequestBuilder;
+import org.asynchttpclient.Response;
 import org.apache.commons.io.IOUtils;
 import org.apache.tez.http.BaseHttpConnection;
 import org.apache.tez.http.HttpConnectionParams;
@@ -76,7 +77,7 @@ public class AsyncHttpConnection extends BaseHttpConnection {
       synchronized (AsyncHttpConnection.class) {
         if (httpAsyncClient == null) {
           LOG.info("Initializing AsyncClient (TezBodyDeferringAsyncHandler)");
-          AsyncHttpClientConfig.Builder builder = new AsyncHttpClientConfig.Builder();
+          DefaultAsyncHttpClientConfig.Builder builder = new DefaultAsyncHttpClientConfig.Builder();
           if (httpConnParams.isSslShuffle()) {
             //Configure SSL
             SSLFactory sslFactory = httpConnParams.getSslFactory();
@@ -91,16 +92,16 @@ public class AsyncHttpConnection extends BaseHttpConnection {
            * setMaxConnections & addRequestFilter.
            */
           builder
-              .setAllowPoolingConnections(httpConnParams.isKeepAlive())
-              .setAllowPoolingSslConnections(httpConnParams.isKeepAlive())
+              .setKeepAlive(httpConnParams.isKeepAlive())
               .setCompressionEnforced(false)
               //.setExecutorService(applicationThreadPool)
-              //.addRequestFilter(new ThrottleRequestFilter())
+              //.addRequestFilter(new ThrottleRequestFilter(1))
               .setMaxConnectionsPerHost(1)
               .setConnectTimeout(httpConnParams.getConnectionTimeout())
-              .setDisableUrlEncodingForBoundedRequests(true)
+              .setDisableUrlEncodingForBoundRequests(true)
               .build();
-            httpAsyncClient = new AsyncHttpClient(builder.build());
+          DefaultAsyncHttpClientConfig config = builder.build();
+          httpAsyncClient = new DefaultAsyncHttpClient(config);
         }
       }
     }
@@ -208,7 +209,7 @@ public class AsyncHttpConnection extends BaseHttpConnection {
   }
 
   @VisibleForTesting
-  public void close() {
+  public void close() throws IOException {
     httpAsyncClient.close();
     httpAsyncClient = null;
   }
diff --git a/tez-runtime-library/src/main/java/org/apache/tez/http/async/netty/TezBodyDeferringAsyncHandler.java b/tez-runtime-library/src/main/java/org/apache/tez/http/async/netty/TezBodyDeferringAsyncHandler.java
index 8e83eac..acbdab7 100644
--- a/tez-runtime-library/src/main/java/org/apache/tez/http/async/netty/TezBodyDeferringAsyncHandler.java
+++ b/tez-runtime-library/src/main/java/org/apache/tez/http/async/netty/TezBodyDeferringAsyncHandler.java
@@ -17,15 +17,16 @@
  */
 package org.apache.tez.http.async.netty;
 
-import com.ning.http.client.AsyncHandler;
-import com.ning.http.client.HttpResponseBodyPart;
-import com.ning.http.client.HttpResponseHeaders;
-import com.ning.http.client.HttpResponseStatus;
-import com.ning.http.client.Response;
+import org.asynchttpclient.AsyncHandler;
+import org.asynchttpclient.HttpResponseBodyPart;
+import org.asynchttpclient.HttpResponseStatus;
+import org.asynchttpclient.Response;
 import org.apache.hadoop.classification.InterfaceAudience;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import io.netty.handler.codec.http.HttpHeaders;
+
 import java.io.FilterInputStream;
 import java.io.IOException;
 import java.io.InputStream;
@@ -38,8 +39,8 @@ import java.util.concurrent.Semaphore;
 import java.util.concurrent.TimeUnit;
 
 /**
- * Same as {@link com.ning.http.client.BodyDeferringAsyncHandler} with additional checks handle
- * errors in getResponse(). Based on testing, at very high load {@link com.ning.http.client
+ * Same as {@link org.asynchttpclient.BodyDeferringAsyncHandler} with additional checks handle
+ * errors in getResponse(). Based on testing, at very high load {@link org.asynchttpclient
  * .BodyDeferringAsyncHandler} gets to hung state in getResponse() as it tries to wait
  * indefinitely for headers to arrive.  This class tries to fix the problem by waiting only for
  * the connection timeout.
@@ -92,27 +93,28 @@ class TezBodyDeferringAsyncHandler implements AsyncHandler<Response> {
     }
   }
 
-  public AsyncHandler.STATE onStatusReceived(HttpResponseStatus responseStatus) throws Exception {
+  public AsyncHandler.State onStatusReceived(HttpResponseStatus responseStatus) throws Exception {
     responseBuilder.reset();
     responseBuilder.accumulate(responseStatus);
     statusReceived = true;
-    return AsyncHandler.STATE.CONTINUE;
+    return AsyncHandler.State.CONTINUE;
   }
 
-  public AsyncHandler.STATE onHeadersReceived(HttpResponseHeaders headers) throws Exception {
+  @Override
+  public AsyncHandler.State onHeadersReceived(HttpHeaders headers) throws Exception {
     responseBuilder.accumulate(headers);
-    return AsyncHandler.STATE.CONTINUE;
+    return AsyncHandler.State.CONTINUE;
   }
 
-  public AsyncHandler.STATE onBodyPartReceived(HttpResponseBodyPart bodyPart) throws Exception {
+  public AsyncHandler.State onBodyPartReceived(HttpResponseBodyPart bodyPart) throws Exception {
     // body arrived, flush headers
     if (!responseSet) {
       response = responseBuilder.build();
       responseSet = true;
       headersArrived.countDown();
     }
-    bodyPart.writeTo(output);
-    return AsyncHandler.STATE.CONTINUE;
+    output.write(bodyPart.getBodyPartBytes());
+    return AsyncHandler.State.CONTINUE;
   }
 
   protected void closeOut() throws IOException {
diff --git a/tez-runtime-library/src/main/java/org/apache/tez/runtime/library/common/shuffle/impl/ShuffleManager.java b/tez-runtime-library/src/main/java/org/apache/tez/runtime/library/common/shuffle/impl/ShuffleManager.java
index 2b83ad8..901ee08 100644
--- a/tez-runtime-library/src/main/java/org/apache/tez/runtime/library/common/shuffle/impl/ShuffleManager.java
+++ b/tez-runtime-library/src/main/java/org/apache/tez/runtime/library/common/shuffle/impl/ShuffleManager.java
@@ -337,7 +337,8 @@ public class ShuffleManager implements FetcherCallback {
         + ifileReadAhead + ", ifileReadAheadLength=" + ifileReadAheadLength +", "
         + "localDiskFetchEnabled=" + localDiskFetchEnabled + ", "
         + "sharedFetchEnabled=" + sharedFetchEnabled + ", "
-        + httpConnectionParams.toString() + ", maxTaskOutputAtOnce=" + maxTaskOutputAtOnce);
+        + httpConnectionParams.toString() + ", maxTaskOutputAtOnce=" + maxTaskOutputAtOnce
+        + ", asyncHttp=" + asyncHttp);
   }
 
   public void updateApproximateInputRecords(int delta) {
diff --git a/tez-runtime-library/src/main/java/org/apache/tez/runtime/library/common/shuffle/orderedgrouped/ShuffleScheduler.java b/tez-runtime-library/src/main/java/org/apache/tez/runtime/library/common/shuffle/orderedgrouped/ShuffleScheduler.java
index e7f63ab..416041e 100644
--- a/tez-runtime-library/src/main/java/org/apache/tez/runtime/library/common/shuffle/orderedgrouped/ShuffleScheduler.java
+++ b/tez-runtime-library/src/main/java/org/apache/tez/runtime/library/common/shuffle/orderedgrouped/ShuffleScheduler.java
@@ -441,6 +441,7 @@ class ShuffleScheduler {
         + ", maxStallTimeFraction=" + maxStallTimeFraction
         + ", minReqProgressFraction=" + minReqProgressFraction
         + ", checkFailedFetchSinceLastCompletion=" + checkFailedFetchSinceLastCompletion
+        + ", asyncHttp=" + asyncHttp
     );
   }
 
diff --git a/tez-runtime-library/src/test/java/org/apache/tez/http/TestHttpConnection.java b/tez-runtime-library/src/test/java/org/apache/tez/http/TestHttpConnection.java
index ed4ed54..afeb6e5 100644
--- a/tez-runtime-library/src/test/java/org/apache/tez/http/TestHttpConnection.java
+++ b/tez-runtime-library/src/test/java/org/apache/tez/http/TestHttpConnection.java
@@ -24,8 +24,6 @@ import org.apache.tez.common.security.JobTokenSecretManager;
 import org.junit.AfterClass;
 import org.junit.BeforeClass;
 import org.junit.Test;
-import org.mockito.invocation.InvocationOnMock;
-import org.mockito.stubbing.Answer;
 
 import java.io.IOException;
 import java.net.ConnectException;
@@ -42,7 +40,7 @@ import java.util.concurrent.ThreadFactory;
 
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
-import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.any;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.when;
@@ -78,6 +76,7 @@ public class TestHttpConnection {
         });
     url = new URL(NOT_HOSTED_URL);
     tokenSecretManager = mock(JobTokenSecretManager.class);
+    when(tokenSecretManager.computeHash(any())).thenReturn("1234".getBytes());
   }
 
   @AfterClass
@@ -89,7 +88,7 @@ public class TestHttpConnection {
       InterruptedException {
     long startTime = System.currentTimeMillis();
     try {
-      Future future = executorService.submit(worker);
+      Future<Void> future = executorService.submit(worker);
       future.get();
     } catch (ExecutionException e) {
       assertTrue(e.getCause().getCause() instanceof IOException);
@@ -117,14 +116,13 @@ public class TestHttpConnection {
   }
 
   @Test(timeout = 20000)
-  @SuppressWarnings("unchecked")
   //Should be interruptible
   public void testAsyncHttpConnectionInterrupt()
       throws IOException, InterruptedException, ExecutionException {
     CountDownLatch latch = new CountDownLatch(1);
     HttpConnectionParams params = getConnectionParams();
     AsyncHttpConnection asyncHttpConn = getAsyncHttpConnection(params);
-    Future future = executorService.submit(new Worker(latch, asyncHttpConn, true));
+    Future<Void> future = executorService.submit(new Worker(latch, asyncHttpConn, true));
 
     while(currentThread == null) {
       synchronized (this) {
@@ -153,24 +151,14 @@ public class TestHttpConnection {
   HttpConnection getHttpConnection(HttpConnectionParams params) throws IOException {
     HttpConnection realConn = new HttpConnection(url, params, "log", tokenSecretManager);
     HttpConnection connection = spy(realConn);
-
-    doAnswer(new Answer() {
-      public Void answer(InvocationOnMock invocation) {
-        return null;
-      }
-    }).when(connection).computeEncHash();
+    realConn.computeEncHash();
     return connection;
   }
 
   AsyncHttpConnection getAsyncHttpConnection(HttpConnectionParams params) throws IOException {
     AsyncHttpConnection realConn = new AsyncHttpConnection(url, params, "log", tokenSecretManager);
     AsyncHttpConnection connection = spy(realConn);
-
-    doAnswer(new Answer() {
-      public Void answer(InvocationOnMock invocation) {
-        return null;
-      }
-    }).when(connection).computeEncHash();
+    realConn.computeEncHash();
     return connection;
   }
 
diff --git a/tez-tests/src/test/java/org/apache/tez/test/TestSecureShuffle.java b/tez-tests/src/test/java/org/apache/tez/test/TestSecureShuffle.java
index 6d34464..aed2409 100644
--- a/tez-tests/src/test/java/org/apache/tez/test/TestSecureShuffle.java
+++ b/tez-tests/src/test/java/org/apache/tez/test/TestSecureShuffle.java
@@ -25,8 +25,13 @@ import java.io.BufferedWriter;
 import java.io.File;
 import java.io.IOException;
 import java.io.OutputStreamWriter;
+import java.net.InetAddress;
+import java.security.KeyPair;
+import java.security.cert.X509Certificate;
 import java.util.ArrayList;
 import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
 
 import org.apache.hadoop.conf.Configuration;
 import org.apache.hadoop.fs.FSDataOutputStream;
@@ -37,7 +42,7 @@ import org.apache.hadoop.hdfs.MiniDFSCluster;
 import org.apache.hadoop.hdfs.server.namenode.EditLogFileOutputStream;
 import org.apache.hadoop.mapreduce.MRConfig;
 import org.apache.hadoop.security.ssl.KeyStoreTestUtil;
-import org.apache.hadoop.yarn.conf.YarnConfiguration;
+import org.apache.hadoop.security.ssl.SSLFactory;
 import org.apache.tez.dag.api.TezConfiguration;
 import org.apache.tez.mapreduce.examples.TestOrderedWordCount;
 import org.apache.tez.runtime.library.api.TezRuntimeConfiguration;
@@ -133,7 +138,7 @@ public class TestSecureShuffle {
     conf.setInt(TezRuntimeConfiguration.TEZ_RUNTIME_SHUFFLE_FETCH_FAILURES_LIMIT, 2);
 
     conf.setLong(TezConfiguration.TEZ_AM_SLEEP_TIME_BEFORE_EXIT_MILLIS, 500);
-
+    conf.setBoolean(TezRuntimeConfiguration.TEZ_RUNTIME_SHUFFLE_USE_ASYNC_HTTP, asyncHttp);
     String sslConf = conf.get(SSL_CLIENT_CONF_KEY, "ssl-client.xml");
     conf.addResource(sslConf);
 
@@ -205,10 +210,68 @@ public class TestSecureShuffle {
    */
   private static void setupKeyStores() throws Exception {
     keysStoresDir.mkdirs();
-    String sslConfsDir =
-        KeyStoreTestUtil.getClasspathDir(TestSecureShuffle.class);
+    String sslConfsDir = KeyStoreTestUtil.getClasspathDir(TestSecureShuffle.class);
+
+    setupSSLConfig(keysStoresDir.getAbsolutePath(), sslConfsDir, conf, true, true, "");
+  }
+
+  /**
+   * This is a copied version of hadoop's KeyStoreTestUtil.setupSSLConfig which was needed to create
+   * server certs with actual hostname in CN instead of "localhost". While upgrading async http
+   * client in TEZ-4237, it turned out that netty doesn't support custom hostname verifiers anymore
+   * (as discussed in https://github.com/AsyncHttpClient/async-http-client/issues/928), that's why
+   * it cannot be set for an async http connection. So instead of hacking an ALLOW_ALL verifier
+   * somehow (which cannot be propagated to netty), a valid certificate with the actual hostname
+   * should be generated in setupSSLConfig, so the only change is the usage of
+   * "InetAddress.getLocalHost().getHostName()".
+   */
+  public static void setupSSLConfig(String keystoresDir, String sslConfDir, Configuration config,
+      boolean useClientCert, boolean trustStore, String excludeCiphers) throws Exception {
+    String clientKS = keystoresDir + "/clientKS.jks";
+    String clientPassword = "clientP";
+    String serverKS = keystoresDir + "/serverKS.jks";
+    String serverPassword = "serverP";
+    String trustKS = null;
+    String trustPassword = "trustP";
+
+    File sslClientConfFile = new File(sslConfDir, KeyStoreTestUtil.getClientSSLConfigFileName());
+    File sslServerConfFile = new File(sslConfDir, KeyStoreTestUtil.getServerSSLConfigFileName());
+
+    Map<String, X509Certificate> certs = new HashMap<String, X509Certificate>();
+
+    if (useClientCert) {
+      KeyPair cKP = KeyStoreTestUtil.generateKeyPair("RSA");
+      X509Certificate cCert =
+          KeyStoreTestUtil.generateCertificate("CN=localhost, O=client", cKP, 30, "SHA1withRSA");
+      KeyStoreTestUtil.createKeyStore(clientKS, clientPassword, "client", cKP.getPrivate(), cCert);
+      certs.put("client", cCert);
+    }
+
+    String localhostName = InetAddress.getLocalHost().getHostName();
+    KeyPair sKP = KeyStoreTestUtil.generateKeyPair("RSA");
+    X509Certificate sCert =
+        KeyStoreTestUtil.generateCertificate("CN="+localhostName+", O=server", sKP, 30, "SHA1withRSA");
+    KeyStoreTestUtil.createKeyStore(serverKS, serverPassword, "server", sKP.getPrivate(), sCert);
+    certs.put("server", sCert);
+
+    if (trustStore) {
+      trustKS = keystoresDir + "/trustKS.jks";
+      KeyStoreTestUtil.createTrustStore(trustKS, trustPassword, certs);
+    }
+
+    Configuration clientSSLConf = KeyStoreTestUtil.createClientSSLConfig(clientKS, clientPassword,
+        clientPassword, trustKS, excludeCiphers);
+    Configuration serverSSLConf = KeyStoreTestUtil.createServerSSLConfig(serverKS, serverPassword,
+        serverPassword, trustKS, excludeCiphers);
+
+    KeyStoreTestUtil.saveConfig(sslClientConfFile, clientSSLConf);
+    KeyStoreTestUtil.saveConfig(sslServerConfFile, serverSSLConf);
+
+    // this will be ignored for AsyncHttpConnection, see method comments above
+    config.set(SSLFactory.SSL_HOSTNAME_VERIFIER_KEY, "ALLOW_ALL");
 
-    KeyStoreTestUtil.setupSSLConfig(keysStoresDir.getAbsolutePath(),
-      sslConfsDir, conf, true);
+    config.set(SSLFactory.SSL_CLIENT_CONF_KEY, sslClientConfFile.getName());
+    config.set(SSLFactory.SSL_SERVER_CONF_KEY, sslServerConfFile.getName());
+    config.setBoolean(SSLFactory.SSL_REQUIRE_CLIENT_CERT_KEY, useClientCert);
   }
 }