How to set TLS version on apache HttpClient
The solution is:
SSLContext sslContext = SSLContexts.custom()
.useTLS()
.build();
SSLConnectionSocketFactory f = new SSLConnectionSocketFactory(
sslContext,
new String[]{"TLSv1", "TLSv1.1"},
null,
BROWSER_COMPATIBLE_HOSTNAME_VERIFIER);
httpClient = HttpClients.custom()
.setSSLSocketFactory(f)
.build();
This requires org.apache.httpcomponents.httpclient 4.3.x though.
How do I force Apache's CloseableHttpClient to use TLSv1.2?
While creating SSLContext specify that it has to use TLS instead of getting the default one:
SSLContext sslContext = SSLContextBuilder.create().build();
Or:
SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(....);
Or simply use:
SSLContext sslContext = SSLContexts.custom().build()
Based on your code here is the running example (it makes the connection to google.com
). I have enabled the debug log. Look for negotiated protocol: TLSv1.2
in the log. Now, change the TLS
version to 1.1
while creating the http client(new String[] { "TLSv1.1" }
), run the program and observe that string 'negotiated protocol..' changed to TLSv1.1
.
What you earlier printed that is HTTP protocol version.
import org.apache.http.HttpHost;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.ssl.SSLContextBuilder;
import org.apache.http.ssl.SSLContexts;
import javax.net.ssl.SSLContext;
import java.io.OutputStreamWriter;
import java.io.PrintStream;
import java.io.StringWriter;
public class ForceTLS12 {
public static void main(String[] args) {
try {
System.setProperty("org.apache.commons.logging.Log", "org.apache.commons.logging.impl.SimpleLog");
System.setProperty("org.apache.commons.logging.simplelog.showdatetime","true");
System.setProperty("org.apache.commons.logging.simplelog.log.org.apache.http","DEBUG");
System.setProperty("org.apache.commons.logging.simplelog.log.org.apache.http.wire","DEBUG");
//SSLContext sslContext = SSLContext.getInstance("TLS");
@SuppressWarnings("static-access")
CloseableHttpClient httpclient = HttpClientBuilder.create()
.setSSLSocketFactory(new SSLConnectionSocketFactory(SSLContexts.custom().build(), new String[] { "TLSv1.2" }, null, SSLConnectionSocketFactory.getDefaultHostnameVerifier()))
.build();
HttpHost target = new HttpHost("www.google.com", 443, "https");
//String call = "/vivisimo/cgi-bin/velocity";
HttpGet getRequest = new HttpGet(target.toURI());
CloseableHttpResponse resposne = httpclient.execute(getRequest);
System.out.println(resposne.getEntity().getContentType());
System.out.println("Protocol Version:" + getRequest.getProtocolVersion());
} catch (Exception e) {
e.printStackTrace();
}
}
}
This executable code sample is available at github as well.
Java, Apache HttpClient, TLSv1.2 & OpenJDK 7
jdk.tls.client.protocols
only works on Java 8 (and presumably 9) which you aren't using.
https.protocols
only works by default in HttpsURLConnection
which httpclient doesn't use.
deployment.*
only applies to JNLP and applets (if any browser still permits applets) which you aren't using.
An answer to your Q as stated, at least for 4.5, assuming you use HttpClientBuilder
or HttpClients
(which you didn't say), is to use .useSystemProperties()
or .createSystem()
, respectively; these do use the same system properties as *URLConnection
-- or at least many of them including https.protocols
. You should check none of the other properties included in this set is configured to do something you don't want. This does require changing the apps, but not changing them 'to specifically request ... TLSv1.2'.
Other than that you can configure the SSLConnectionSocketFactory
to specify the exact protocols allowed as in the Q linked by @pvg, or SSLContexts.custom().useProtocol(String).build()
to specify the upper bound -- which is enough for your case because offering the range 'up to 1.2' to a server that requires 1.2 will select 1.2.
How to force Commons HTTPClient 3.1 to use TLS 1.2 only for HTTPS?
Too bad nobody answered; I was able to do it, first you write a CustomHttpSocketFactory, then you do:
String scheme = "https";
Protocol baseHttps = Protocol.getProtocol(scheme);
int defaultPort = baseHttps.getDefaultPort();
ProtocolSocketFactory baseFactory = baseHttps.getSocketFactory();
ProtocolSocketFactory customFactory = new CustomHttpsSocketFactory(baseFactory);
Protocol customHttps = new Protocol(scheme, customFactory, defaultPort);
Protocol.registerProtocol(scheme, customHttps);
A sample custom socket factory code is found here, but instead I did:
public class CustomHttpsSocketFactory implements SecureProtocolSocketFactory
{
private final SecureProtocolSocketFactory base;
public CustomHttpsSocketFactory(ProtocolSocketFactory base)
{
if(base == null || !(base instanceof SecureProtocolSocketFactory)) throw new IllegalArgumentException();
this.base = (SecureProtocolSocketFactory) base;
}
private Socket acceptOnlyTLS12(Socket socket)
{
if(!(socket instanceof SSLSocket)) return socket;
SSLSocket sslSocket = (SSLSocket) socket;
sslSocket.setEnabledProtocols(new String[]{"TLSv1.2" });
return sslSocket;
}
@Override
public Socket createSocket(String host, int port) throws IOException
{
return acceptOnlyTLS12(base.createSocket(host, port));
}
@Override
public Socket createSocket(String host, int port, InetAddress localAddress, int localPort) throws IOException
{
return acceptOnlyTLS12(base.createSocket(host, port, localAddress, localPort));
}
@Override
public Socket createSocket(String host, int port, InetAddress localAddress, int localPort, HttpConnectionParams params) throws IOException
{
return acceptOnlyTLS12(base.createSocket(host, port, localAddress, localPort, params));
}
@Override
public Socket createSocket(Socket socket, String host, int port, boolean autoClose) throws IOException
{
return acceptOnlyTLS12(base.createSocket(socket, host, port, autoClose));
}
}
Related Topics
Do/Can Abstract Classes Replace Interfaces
Java Naming Convention with Acronyms
How to I Output Org.W3C.Dom.Element to String Format in Java
How to Simulate a Real Mouse Click Using Java
Where Is the Correct Location to Put Log4J.Properties in an Eclipse Project
Java Io Ugly Try-Finally Block
Java's Virtual MAChine's Endianness
Fixedthreadpool VS Cachedthreadpool: the Lesser of Two Evils
Java Getting an Error for Implementing Interface Method with Weaker Access
Compile Error: Package Javax.Servlet Does Not Exist
Differencebetween a Hashmap and a Treemap
What to Return If Spring MVC Controller Method Doesn't Return Value
Java 8 Stream with Batch Processing
Which Loop Has Better Performance? Why