Que signifie «javax.net.ssl.SSLHandshakeException: la modification du certificate de serveur est une ressortingction de la renégociation» et comment la prévenir?

Nous utilisons Oracle jdk 1.7.0_71 et Tomcat 7.0.55. Malheureusement, nous avons commencé à obtenir l’exception suivante lors de la connexion SSL entre les serveurs:

javax.net.ssl.SSLHandshakeException: server certificatee change is ressortingctedduring renegotiation 

Ce que cela veut dire? Comment le prévenir?

L’exception est disparue après le redémarrage de Tomcat.

La stack complète:

 Caused by: javax.net.ssl.SSLHandshakeException: server certificatee change is ressortingctedduring renegotiation at sun.security.ssl.Alerts.getSSLException(Alerts.java:192) ~[?:1.7.0_71] at sun.security.ssl.SSLSocketImpl.fatal(SSLSocketImpl.java:1884) ~[?:1.7.0_71] at sun.security.ssl.Handshaker.fatalSE(Handshaker.java:276) ~[?:1.7.0_71] at sun.security.ssl.Handshaker.fatalSE(Handshaker.java:266) ~[?:1.7.0_71] at sun.security.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1402) ~[?:1.7.0_71] at sun.security.ssl.ClientHandshaker.processMessage(ClientHandshaker.java:209) ~[?:1.7.0_71] at sun.security.ssl.Handshaker.processLoop(Handshaker.java:878) ~[?:1.7.0_71] at sun.security.ssl.Handshaker.process_record(Handshaker.java:814) ~[?:1.7.0_71] at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:1016) ~[?:1.7.0_71] at sun.security.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1312) ~[?:1.7.0_71] at sun.security.ssl.SSLSocketImpl.writeRecord(SSLSocketImpl.java:702) ~[?:1.7.0_71] at sun.security.ssl.AppOutputStream.write(AppOutputStream.java:122) ~[?:1.7.0_71] at java.io.BufferedOutputStream.flushBuffer(BufferedOutputStream.java:82) ~[?:1.7.0_71] at java.io.BufferedOutputStream.flush(BufferedOutputStream.java:140) ~[?:1.7.0_71] at org.apache.commons.httpclient.methods.EntityEnclosingMethod.writeRequestBody(EntityEnclosingMethod.java:506) ~[commons-httpclient-3.1.jar:?] at org.apache.commons.httpclient.HttpMethodBase.writeRequest(HttpMethodBase.java:2114) ~[commons-httpclient-3.1.jar:?] at org.apache.commons.httpclient.HttpMethodBase.execute(HttpMethodBase.java:1096) ~[commons-httpclient-3.1.jar:?] at org.apache.commons.httpclient.HttpMethodDirector.executeWithRetry(HttpMethodDirector.java:398) ~[commons-httpclient-3.1.jar:?] at org.apache.commons.httpclient.HttpMethodDirector.executeMethod(HttpMethodDirector.java:171) ~[commons-httpclient-3.1.jar:?] at org.apache.commons.httpclient.HttpClient.executeMethod(HttpClient.java:397) ~[commons-httpclient-3.1.jar:?] at org.apache.commons.httpclient.HttpClient.executeMethod(HttpClient.java:323) ~[commons-httpclient-3.1.jar:?] at org.springframework.remoting.httpinvoker.CommonsHttpInvokerRequestExecutor.executePostMethod(CommonsHttpInvokerRequestExecutor.java:205) ~[spring-web-3.2.9.RELEASE.jar:3.2.9.RELEASE] at org.springframework.remoting.httpinvoker.CommonsHttpInvokerRequestExecutor.doExecuteRequest(CommonsHttpInvokerRequestExecutor.java:140) ~[spring-web-3.2.9.RELEASE.jar:3.2.9.RELEASE] at org.springframework.remoting.httpinvoker.AbstractHttpInvokerRequestExecutor.executeRequest(AbstractHttpInvokerRequestExecutor.java:136) ~[spring-web-3.2.9.RELEASE.jar:3.2.9.RELEASE] at org.springframework.remoting.httpinvoker.HttpInvokerClientInterceptor.executeRequest(HttpInvokerClientInterceptor.java:192) ~[spring-web-3.2.9.RELEASE.jar:3.2.9.RELEASE] at org.springframework.remoting.httpinvoker.HttpInvokerClientInterceptor.executeRequest(HttpInvokerClientInterceptor.java:174) ~[spring-web-3.2.9.RELEASE.jar:3.2.9.RELEASE] at org.springframework.remoting.httpinvoker.HttpInvokerClientInterceptor.invoke(HttpInvokerClientInterceptor.java:142) ~[spring-web-3.2.9.RELEASE.jar:3.2.9.RELEASE] ... 160 more 

Ce message d’erreur dans le code de la couche client est une conséquence du durcissement du code suite à la vulnérabilité «SSL V3.0 Poodle – CVE-2014-3566» dans les dernières mises à jour Java. Et c’est un bogue – voici des solutions de rechange au cas où vous ne pourriez pas mettre à jour votre JRE immédiatement:

Une première option consiste à forcer le protocole TLS lors de l’établissement d’une connexion HTTPS:

Si vous pouvez mettre à jour HttpClient vers une version plus récente que 4.3.6, SSLv3 sera désactivé par défaut et votre code ne devrait plus signaler une telle exception.

Si vous ne pouvez pas mettre à niveau votre version de HttpClient, vous devrez utiliser le code de cette réponse pour restreindre les protocoles à TLS: https://stackoverflow.com/a/26439487/737790

Pour les autres access http à partir de l’exécution de Java 7, la propriété système suivante doit être définie

 -Dhttps.protocols="TLSv1" 

Vous trouverez tous les détails ici: clients Java http et POODLE

Une deuxième option consiste à assouplir le contrôle client pour autoriser la renégociation avec les propriétés suivantes:

 -Djdk.tls.allowUnsafeServerCertChange=true -Dsun.security.ssl.allowUnsafeRenegotiation=true 

Une troisième option consiste à “améliorer” vos certificates de serveur pour inclure toutes les adresses IP des membres de votre cluster en tant que noms alternatifs du sujet, conformément à cet article dans le forum Burp.

Une quasortingème option consiste à rétrograder votre version de Java avant que ces vérifications de certificate / renégociation aient été ajoutées, donc avant 7u41 (à confirmer)

Mises à jour Ce comportement est désormais corrigé dans les mises à jour JDK 7u85 et 8u60. Crédits à Pada pour avoir trouvé la référence JDK-8072385 .

Le code suivant a fonctionné pour nous dans un environnement d’entreprise dans les conditions suivantes:

  • la mise à jour transparente des certificates (d’exécution) est une condition essentielle
  • il est trop coûteux de mettre à jour le HTTPClient utilisé dans l’application
  • limiter le protocole https à “TLSv1” n’a pas d’effet
  • l’application est un client java servi JNLP et ni les “allowUnsafeServerCertChange” et “allowUnsafeRenegotiation” ne sont pas autorisés à être transmis à l’application client via les arguments JNLP (je suppose que JWS les bloque pour des raisons de sécurité)
  • la définition des appels “allowUnsafeServerCertChange” et “allowUnsafeRenegotiation” via System.setProperty () pendant le démarrage de l’application n’a pas d’effet.

     if (e.getCause() instanceof SSLHandshakeException) { logger.debug("server https certificatee has been altered"); try { Class c = Class.forName("sun.security.ssl.ClientHandshaker"); Field allowUnsafeServerCertChangeField = c.getDeclaredField("allowUnsafeServerCertChange"); allowUnsafeServerCertChangeField.setAccessible(true); Field modifiersField = Field.class.getDeclaredField("modifiers"); modifiersField.setAccessible(true); modifiersField.setInt(allowUnsafeServerCertChangeField, allowUnsafeServerCertChangeField.getModifiers() & ~Modifier.FINAL); allowUnsafeServerCertChangeField.set(null, true); logger.debug("client has been updated in order to support SSL certificatee change (re-negotiation) on runtime."); } catch (Exception ex) { logger.debug("client cannot be updated to support SSL certificatee change (re-negotiation) on runtime. Please restart the application.", ex); } } 

Veuillez noter que ceci devrait être considéré comme un hack (introduisant une vulnérabilité) et devrait être utilisé dans un environnement de confiance. On devrait essayer toutes les options dans la réponse d’Yves avant de suivre cette voie.

Cela peut également être dû à une connectivité mal configurée, telle qu’un haproxy avec un ou plusieurs cibles d’équilibrage de charge pointant vers une adresse IP incorrecte, de sorte que X% des requêtes obtiennent un certificate différent.

J’ai eu ce problème parce que le côté serveur a mis à jour ses certificates. Avant cela, notre client travaillait bien. Nous avons simplement relancé notre programme et nous sums revenus à la normale.