diff --git a/src/main/java/org/mitre/dsmiley/httpproxy/ProxyServlet.java b/src/main/java/org/mitre/dsmiley/httpproxy/ProxyServlet.java
index 0ee7c04f..2b6694df 100644
--- a/src/main/java/org/mitre/dsmiley/httpproxy/ProxyServlet.java
+++ b/src/main/java/org/mitre/dsmiley/httpproxy/ProxyServlet.java
@@ -30,6 +30,7 @@
import org.apache.http.client.utils.URIUtils;
import org.apache.http.entity.InputStreamEntity;
import org.apache.http.impl.client.DefaultHttpClient;
+import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager;
import org.apache.http.message.BasicHeader;
import org.apache.http.message.BasicHttpEntityEnclosingRequest;
@@ -168,6 +169,7 @@ protected void initTarget() throws ServletException {
* SystemDefaultHttpClient uses PoolingClientConnectionManager. In any case, it should be thread-safe. */
@SuppressWarnings({"unchecked", "deprecation"})
protected HttpClient createHttpClient(HttpParams hcParams) {
+ /*
try {
//as of HttpComponents v4.2, this class is better since it uses System
// Properties:
@@ -182,6 +184,10 @@ protected HttpClient createHttpClient(HttpParams hcParams) {
//Fallback on using older client:
return new DefaultHttpClient(new ThreadSafeClientConnManager(), hcParams);
+ */
+
+ return HttpClientBuilder.create().useSystemProperties().disableCookieManagement().disableRedirectHandling()
+ .setSSLSocketFactory(SNISSLSocketFactory.createFromSystem()).build();
}
/** The http client used.
diff --git a/src/main/java/org/mitre/dsmiley/httpproxy/SNISSLSocketFactory.java b/src/main/java/org/mitre/dsmiley/httpproxy/SNISSLSocketFactory.java
new file mode 100644
index 00000000..ac291851
--- /dev/null
+++ b/src/main/java/org/mitre/dsmiley/httpproxy/SNISSLSocketFactory.java
@@ -0,0 +1,123 @@
+/*
+ * Copyright MITRE
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * 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.mitre.dsmiley.httpproxy;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.http.HttpHost;
+import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
+import org.apache.http.conn.ssl.X509HostnameVerifier;
+import org.apache.http.protocol.HttpContext;
+import org.apache.http.util.TextUtils;
+
+import javax.net.ssl.SSLParameters;
+import javax.net.ssl.SSLSocket;
+import javax.net.ssl.SSLSocketFactory;
+import java.io.IOException;
+import java.lang.reflect.InvocationTargetException;
+import java.net.InetSocketAddress;
+import java.net.Socket;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * An SSL Socket Factory supporting SNI,
+ * at least on the Sun/Oracle JDK. {@link SSLConnectionSocketFactory} was introduced in
+ * HttpClient 4.3; previously this was possible using
+ * {@link org.apache.http.conn.ssl.SSLSocketFactory} which is deprecated.
+ */
+public class SNISSLSocketFactory extends SSLConnectionSocketFactory {
+ /** Use commons-logging because that's what HttpClient uses (no new dependencies). */
+ private final Log log = LogFactory.getLog(getClass());
+
+ public static SNISSLSocketFactory createFromSystem() {
+ // See HttpClientBuilder.build when it creates an SSLSocketFactory when systemProperties==true
+ return new SNISSLSocketFactory(
+ (SSLSocketFactory) SSLSocketFactory.getDefault(),
+ split(System.getProperty("https.protocols")),
+ split(System.getProperty("https.cipherSuites")),
+ null);//hostnameVerifier will default
+ }
+
+// public SNISSLSocketFactory(SSLSocketFactory sslSocketFactory,
+// String[] supportedProtocols, String[] supportedCipherSuites,
+// HostnameVerifier hostnameVerifier) {
+// super(sslSocketFactory, supportedProtocols, supportedCipherSuites, hostnameVerifier)
+// }
+
+// copy of HttpClientBuilder.split
+ private static String[] split(String s) {
+ return TextUtils.isBlank(s) ? null : s.split(" *, *");
+ }
+
+ // note: the constructors of our superclass are all either introduced in v4.4 or are
+ // v4.4+
+
+ /** Note: We support HttpClient v4.3 so we must use a deprecated constructor. */
+ @SuppressWarnings({"deprecation"})
+ public SNISSLSocketFactory(SSLSocketFactory sslSocketFactory,
+ String[] supportedProtocols, String[] supportedCipherSuites,
+ X509HostnameVerifier hostnameVerifier) {
+ super(sslSocketFactory, supportedProtocols, supportedCipherSuites, hostnameVerifier);
+ }
+
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public Socket createSocket(HttpContext context) throws IOException {
+ return SSLSocketFactory.getDefault().createSocket();
+ }
+
+ @Override
+ public Socket connectSocket(
+ int connectTimeout,
+ Socket socket,
+ HttpHost host,
+ InetSocketAddress remoteAddress,
+ InetSocketAddress localAddress,
+ HttpContext context) throws IOException {
+ // For SNI support, we call setHost(hostname) on the socket. But this method isn't part of
+ // the SNLSocket JDK class; it's on a Sun/Oracle implementation class:
+ // sun.security.ssl.SSLSocketImpl So we invoke it via reflection.
+ /*
+ try {
+ socket.getClass().getDeclaredMethod("setHost", String.class)
+ .invoke(socket, host.getHostName());
+ } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException ex) {
+ log.debug("Couldn't invoke setHost on " + socket.getClass() + " for SNI support.", ex);
+ }
+ */
+ if (socket instanceof SSLSocket) {
+
+ // see https://docs.oracle.com/javase/8/docs/technotes/guides/security/jsse/JSSERefGuide.html#SNIExtension
+
+ final SSLSocket sslSocket = (SSLSocket) socket;
+ final javax.net.ssl.SNIHostName serverName = new javax.net.ssl.SNIHostName(host.getHostName());
+ final List serverNames = new ArrayList<>(1);
+ serverNames.add(serverName);
+
+ final SSLParameters params = sslSocket.getSSLParameters();
+ params.setServerNames(serverNames);
+ sslSocket.setSSLParameters(params);
+ }
+
+ return super.connectSocket(connectTimeout, socket, host, remoteAddress,
+ localAddress, context);
+ }
+}