2017-05-04 2 views
3

Nous avons un petit groupe de serveurs Tomcat exécutant OpenJDK v1.7.0_111. Nous avons l'intention de les mettre à jour et de les migrer cet été, mais nous avons constaté qu'une API client avec laquelle nous interagissons est en train d'exiger TLSv1.2 à court terme. Mon ultime désir est de trouver un changement de configuration pour permettre cela.Java, Apache HttpClient, TLSv1.2 et OpenJDK 7

L'application hébergée, il crée son contexte SSL de manière assez simple:

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

SSLContexts est de la bibliothèque de httpclient d'Apache (version 4.4.1) et est en avant aussi assez simple avec la façon dont il crée le SSL contexte:

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

Et creuser à travers la classe SSLConnectionSocketFactory, il semble qu'il est tout simplement en utilisant la méthode SSLSocket.getEnabledProtocols() pour déterminer quels protocoles sont disponibles. Notez que this.supportedProtocols est null dans mon cas.

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

Le problème que je vais avoir est que lors de l'exécution quelques tests préliminaires, je suis incapable d'obtenir ces clients de se connecter à une API nécessitant TLSv1.2.

Dans l'exemple suivant, je peux obtenir le code URLConnection pour terminer en incluant le paramètre -Dhttps.protocols=TLSv1.2, mais je n'arrive pas à connecter la connexion Apache.

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

    } 

Avec le -Dhttps.protocols=TLSv1.2 j'ai essayé les -Djdk.tls.client.protocols=TLSv1.2 et les paramètres JVM -Ddeployment.security.TLSv1.2=true sans chance.

Quelqu'un a-t-il des idées sur la façon d'activer TLSv1.2 dans cette configuration sans mettre à niveau vers v8 ou modifier l'application pour demander spécifiquement une instance de TLSv1.2?

+0

Avez-vous essayé les params et les tests présentés ici https: //blogs.oracle.com/java-platform-group/jdk-8-will-use-tls-12-as-default – pvg

+0

En outre, vous pouvez inclure un raccourci [MCVE] pour que les autres utilisateurs du JDK 7 puissent reproduire vous essayez. – pvg

+0

Vous ne devez pas activer tous les protocoles pris en charge, car ils incluent les suites de chiffrement anonymes non sécurisées. – EJP

Répondre

3

jdk.tls.client.protocols ne fonctionne que sur Java 8 (et probablement 9) que vous n'utilisez pas. Ne fonctionne que par défaut dans HttpsURLConnection, que httpclient n'utilise pas.

https.protocols S'applique uniquement à JNLP et aux applets (si un navigateur autorise toujours les applets) que vous n'utilisez pas.

Une réponse à votre Q comme indiqué, au moins pour 4,5, en supposant vous utilisez HttpClientBuilder ou HttpClients (que vous n'avez pas dit), est d'utiliser respectivement .createSystem() ou .useSystemProperties(); ces font utilisent les mêmes propriétés système que *URLConnection - ou au moins plusieurs d'entre eux, y compris https.protocols. Vous devriez vérifier qu'aucune des autres propriétés incluses dans cet ensemble n'est configurée pour faire quelque chose que vous ne voulez pas. Ce ne nécessite pas de changer les applications, mais pas en les changeant 'pour demander spécifiquement ... TLSv1.2'.

Autre que vous pouvez configurer le SSLConnectionSocketFactory pour spécifier les protocoles exacts autorisés comme dans the Q linked by @pvg, ou SSLContexts.custom().useProtocol(String).build() pour spécifier la limite supérieure - ce qui est suffisant pour votre cas, car offrant la gamme « jusqu'à 1,2 » à un serveur nécessite 1.2 sélectionnera 1.2.

+0

'jdk.tls.client.protocols' devrait être disponible dans OpenJDK 7u91 et plus et 6u115 et plus si je comprends [cette demande d'amélioration OpenJDK] (https://bugs.openjdk.java.net/browse/JDK- 8076369) correctement. – russianmario

0

Voici la méthode recommandée pour la configuration d'Apache HttpClient 4.x utiliser une version TLS/SSL spécifique

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

Vote à la réponse de dave_thompson_085