How to include SNI in HTTP request using Apache HTTPComponents HttpClient?

I am trying to figure out how to send a successful HTTP GET request to a server requiring SNI.

I searched in SO and elsewhere and found several articles that said SNI is now supported in JDK7, as well as Apache HTTP components.

https://issues.apache.org/jira/browse/HTTPCLIENT-1119 https://wiki.apache.org/HttpComponents/SNISupport

Corresponding SO article: Certificate chain other than HTTPSURLconnection and Apache (System) DefaultHttpClient

-

However, I cannot find any documents that show how to make this work.

Here is the code I'm using ...

KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType()); String trustedCertsPath = System.getenv("JAVA_HOME") + "/jre/lib/security/cacerts"; FileInputStream certstream = new FileInputStream(new File(trustedCertsPath)); try { trustStore.load(certstream, "changeit".toCharArray()); } finally { certstream.close(); } // Trust own CA and all self-signed certs SSLContext sslcontext = SSLContexts.custom() .loadTrustMaterial(trustStore, new TrustSelfSignedStrategy()) .build(); // Allow TLSv1 protocol only SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory( sslcontext, new String[] { "TLSv1" }, null, SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER); CloseableHttpClient httpclient2 = HttpClients.custom() .setSSLSocketFactory(sslsf) .build(); CloseableHttpClient httpclient = HttpClients.createDefault(); HttpGet httpget = new HttpGet(uri); CloseableHttpResponse response = httpclient.execute(httpget); try { HttpEntity entity = response.getEntity(); if (entity != null) { tempFile = File.createTempFile(httpFile.getTempFilePrefix(), httpFile.getTempFilePosfix()); FileOutputStream os = new FileOutputStream(tempFile); InputStream instream = entity.getContent(); try { IOUtils.copy(instream, os); } finally { try { instream.close(); } catch (Exception e) {} try { os.close(); } catch (Exception e) {} } } } finally { response.close(); } 

When I run this, the request fails.

The server requires an SNI in the request, and without it, it returns an expired certificate that has the wrong CommonName, because of which it is rejected.

If I use an instance of httpclient2 that is configured using a custom SSL context to allow all hTTP certificates, the request succeeds. However, this is not what I want to enable on a server that does a lot of downloads per day against different hosts.

I am using httpclient v 4.3.5

Any help was appreciated.

Thanks.

+8
source share
1 answer

SNI should work completely transparently when running on Java 1.7 or later. No configuration required. If, for any reason, the SSL connection with the server with the SNI server turned on, you should be able to find out why (and regardless of whether the SNI extension was used correctly) by enabling SSL debugging logging as described here [1 ], and here [2]

Debugging SSL / TLS Connections may look outdated, but it can be useful in troubleshooting SSL-related issues.

[1] http://docs.oracle.com/javase/1.5.0/docs/guide/security/jsse/ReadDebug.html

[2] http://docs.oracle.com/javase/7/docs/technotes/guides/security/jsse/JSSERefGuide.html#Debug

+8
source

All Articles