tls1.2http2apache-httpcomponentsasynchttpclient

Setting SSL Parameters on Apache http5 Client


I am upgrading from Apache httpcomponents 4 to version 5 in order to get http2/http1.1 support. I need to specify the ciphers my client offers. I assume that H2/1.1 ALPN is the default behavior for the AsyncHttpClient.

Here is my current code for the httpcomponents 4 client

    // TLS
    SSLConnectionSocketFactory sslConnectionFactory = new SSLConnectionSocketFactory(
            SSLContexts.createDefault(),
            new String[] { "TLSv1.2" },
            new String[] {"TLS_AES_128_GCM_SHA256", "TLS_AES_256_GCM_SHA384",
                    "TLS_CHACHA20_POLY1305_SHA256", "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256",
                    "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256", "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384",
                    "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384", "TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256",
                    "TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256", "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA",
                    "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA", "TLS_RSA_WITH_AES_128_GCM_SHA256",
                    "TLS_RSA_WITH_AES_256_GCM_SHA384", "TLS_RSA_WITH_AES_128_CBC_SHA",
                    "TLS_RSA_WITH_AES_256_CBC_SHA"},
            SSLConnectionSocketFactory.getDefaultHostnameVerifier());

    // Proxy
    HttpHost proxyhost = new HttpHost(proxyAddress, proxyPort);
    HttpRoutePlanner routePlanner = new DefaultProxyRoutePlanner(proxyhost);
    CredentialsProvider credentialsProvider = new BasicCredentialsProvider();
    credentialsProvider.setCredentials(
            new AuthScope(proxyAddress, proxyPort),
            new UsernamePasswordCredentials(proxyUsername, proxyPassword)
    );

    httpClient = HttpClients.custom()
            .setRoutePlanner(routePlanner)
            .setSSLSocketFactory(sslConnectionFactory)
            .setDefaultCredentialsProvider(credentialsProvider)
            .setRedirectStrategy(new LaxRedirectStrategy())
            .setDefaultCookieStore(cookieStore)
            .build();

Everything seems to be roughly the same for creating the asyc client except specifying the SSL factory. So setting the TLS parameters appears to take a different route. I've spent about an hour looking for examples and documentation with no luck. Some examples show a class called TLSConfig, but I can't find any documentation on it.

Any help is greatly appreciated.


Solution

  • You need to build a custom TlsStrategy pretty much the same way as shown in the "Custom SSL context" example on the project website [1]

    TLSConfig will be available as of 5.2 release which is going to go BETA soon.

    final TlsStrategy tlsStrategy = ClientTlsStrategyBuilder.create()
        .setTlsVersions(TLS.V_1_2)
        .setCiphers("TLS_AES_128_GCM_SHA256", "TLS_AES_256_GCM_SHA384",
                "TLS_CHACHA20_POLY1305_SHA256", "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256",
                "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256", "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384",
                "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384", "TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256",
                "TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256", "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA",
                "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA", "TLS_RSA_WITH_AES_128_GCM_SHA256",
                "TLS_RSA_WITH_AES_256_GCM_SHA384", "TLS_RSA_WITH_AES_128_CBC_SHA",
                "TLS_RSA_WITH_AES_256_CBC_SHA")
        .build();
    
    final PoolingAsyncClientConnectionManager cm = PoolingAsyncClientConnectionManagerBuilder.create()
        .setTlsStrategy(tlsStrategy)
        .build();
    try (final CloseableHttpAsyncClient client = HttpAsyncClients.custom()
        .setConnectionManager(cm)
        .build()) {
    
    client.start();
    
    final HttpHost target = new HttpHost("https", "httpbin.org");
    final HttpClientContext clientContext = HttpClientContext.create();
    
    final SimpleHttpRequest request = SimpleRequestBuilder.get()
            .setHttpHost(target)
            .setPath("/")
            .build();
    
    System.out.println("Executing request " + request);
    final Future<SimpleHttpResponse> future = client.execute(
            SimpleRequestProducer.create(request),
            SimpleResponseConsumer.create(),
            clientContext,
            new FutureCallback<SimpleHttpResponse>() {
    
                @Override
                public void completed(final SimpleHttpResponse response) {
                    System.out.println(request + "->" + new StatusLine(response));
                    final SSLSession sslSession = clientContext.getSSLSession();
                    if (sslSession != null) {
                        System.out.println("SSL protocol " + sslSession.getProtocol());
                        System.out.println("SSL cipher suite " + sslSession.getCipherSuite());
                    }
                    System.out.println(response.getBody());
                }
    
                @Override
                public void failed(final Exception ex) {
                    System.out.println(request + "->" + ex);
                }
    
                @Override
                public void cancelled() {
                    System.out.println(request + " cancelled");
                }
    
            });
    future.get();
    
    System.out.println("Shutting down");
    client.close(CloseMode.GRACEFUL);
    

    [1] https://hc.apache.org/httpcomponents-client-5.1.x/examples-async.html