Como habilitar o SNI na solicitação HTTP usando o Apache HTTPComponents HttpClient?

Estou tentando descobrir como enviar uma solicitação HTTP GET bem-sucedida para um servidor que requer SNI.

Pesquisei no SO e em outros lugares e encontrei alguns artigos que diziam que o SNI agora é suportado no JDK7, bem como no Apache HTTP Components.

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

Artigo relevante do SO:Cadeia de certificados diferente entre HTTPSURLconnection e Apache (System) DefaultHttpClient

-

No entanto, não consigo encontrar nenhum documento que mostre como fazer isso funcionar.

Aqui está o código que estou usando ...


            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();
            }<p></p>

        // 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();
        }

Quando executo isso, a solicitação falha.

O servidor requer SNI na solicitação e, sem ela, retorna um certificado expirado com o CommonName errado, devido ao qual é rejeitado.

Se eu usar a instância httpclient2, que é configurada usando um contexto SSL personalizado para permitir todos os certificados hTTP, a solicitação será bem-sucedida. No entanto, isso não é algo que eu desejo habilitar em um servidor que faz muitos downloads por dia em hosts diferentes.

Estou usando o httpclient v 4.3.5

Qualquer ajuda apreciada.

Obrigado.

questionAnswers(1)

yourAnswerToTheQuestion