Java, Apache HttpClient, TLSv1.2 and OpenJDK 7

We have a small group of Tomcat servers running OpenJDK v1.7.0_111. We have plans to update and port them this summer, but we found that the client API we are interacting with is moving to require TLSv1.2 in the near future. My ultimate wish is to find a configuration change to resolve this.

The application hosted there creates the SSL context in a fairly simple way:

SSLContext sslContext = SSLContexts.createDefault()
SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslContext);

      

SSLContexts

is from the Apache httpclient library (version 4.4.1) and also describes quite straightforwardly how it creates an SSL context:

public static SSLContext createDefault() throws SSLInitializationException {
    try {
        SSLContext ex = SSLContext.getInstance("TLS");
        ex.init((KeyManager[])null, (TrustManager[])null, (SecureRandom)null);
        return ex;
    } catch (NoSuchAlgorithmException var1) {
        throw new SSLInitializationException(var1.getMessage(), var1);
    } catch (KeyManagementException var2) {
        throw new SSLInitializationException(var2.getMessage(), var2);
    }
}

      

And digging through the class SSLConnectionSocketFactory

, it seems like it is just using a method SSLSocket.getEnabledProtocols()

to determine what protocols are available to use. Please note that this.supportedProtocols

in my case is null.

public Socket createLayeredSocket(Socket socket, String target, int port, HttpContext context) throws IOException {
        SSLSocket sslsock = (SSLSocket)this.socketfactory.createSocket(socket, target, port, true);
        if(this.supportedProtocols != null) {
            sslsock.setEnabledProtocols(this.supportedProtocols);
        } else {
            String[] allProtocols = sslsock.getEnabledProtocols();
            ArrayList enabledProtocols = new ArrayList(allProtocols.length);
            String[] arr$ = allProtocols;
            int len$ = allProtocols.length;

            for(int i$ = 0; i$ < len$; ++i$) {
                String protocol = arr$[i$];
                if(!protocol.startsWith("SSL")) {
                    enabledProtocols.add(protocol);
                }
            }

            if(!enabledProtocols.isEmpty()) {
                sslsock.setEnabledProtocols((String[])enabledProtocols.toArray(new String[enabledProtocols.size()]));
            }
        }

      

The problem is that when running multiple pre-tests, I cannot get these clients to connect to an API that requires TLSv1.2.

In the following example, I can get the code URLConnection

to complete by enabling the parameter -Dhttps.protocols=TLSv1.2

, but I cannot connect the Apache connection.

public static void main(String[] args) throws Exception{
        String testURL = "https://testapi.com";

        SSLContext sslcontext = SSLContext.getInstance("TLS");
        sslcontext.init(null, null, null);

        try {
            SSLConnectionSocketFactory socketFactory = new SSLConnectionSocketFactory(sslcontext);
            CloseableHttpClient client = HttpClients.custom().setSSLSocketFactory(socketFactory).build();

            HttpGet httpget = new HttpGet(testURL);

            CloseableHttpResponse response = client.execute(httpget);
            System.out.println("Response Code (Apache): " + response.getStatusLine().getStatusCode());
        }
        catch (Exception e){
            System.err.println("Apache HTTP Client Failed");
            e.printStackTrace();
        }

        try {
            HttpsURLConnection urlConnection = (HttpsURLConnection) new URL(testURL).openConnection();
            urlConnection.setSSLSocketFactory(sslcontext.getSocketFactory());
            urlConnection.connect();
            System.out.println("Response Code (URLConnection): " + urlConnection.getResponseCode());
        }
        catch (Exception e){
            System.err.println("HttpsURLConnection Failed");
            e.printStackTrace();
        }

    }

      

Along with -Dhttps.protocols=TLSv1.2

I tried options -Djdk.tls.client.protocols=TLSv1.2

and -Ddeployment.security.TLSv1.2=true

JVM with no luck.

Does anyone have any thoughts on how to enable TLSv1.2 in this configuration without upgrading to v8, or modify the application to request an instance of TLSv1.2?

+3


source to share


2 answers


jdk.tls.client.protocols

only works on Java 8 (and presumably 9) which you are not using.

https.protocols

only works by default in HttpsURLConnection

that doesn't use httpclient.

deployment.*

only applies to JNLP and applets (if any browser still allows applets) that you are not using.



The answer to your Q as indicated is at least 4.5, if you are using HttpClientBuilder

or HttpClients

(which you did not say) should be used .createSystem()

or .useSystemProperties()

respectively; they use the same system properties as *URLConnection

- or at least many of them, including https.protocols

. You should check that none of the other properties included in this set are configured for what you don't want. This requires application changes but not application changes to request ... TLSv1.2.

Alternatively, you can configure SSLConnectionSocketFactory

to specify the exact protocols allowed as @pvg related , or SSLContexts.custom().useProtocol(String).build()

to specify the upper bound - this is sufficient for your case, because offering a range of "up to 1.2" to a server that requires 1.2 would choose 1.2.

+4


source


Here is the recommended way to configure Apache HttpClient 4.x to use a specific TLS / SSL version

CloseableHttpClient client = HttpClientBuilder.create()
    .setSSLSocketFactory(new SSLConnectionSocketFactory(SSLContext.getDefault(), new String[] { "TLSv1.2" }, null, SSLConnectionSocketFactory.getDefaultHostnameVerifier()))
    .build();

      



Vote until answer dave_thompson_085

0


source







All Articles