What means "javax.net.ssl.SSLHandshakeException: server certificate change is restrictedduring renegotiation" and how to prevent it?

Michael picture Michael · Nov 24, 2014 · Viewed 56k times · Source

We use Oracle jdk 1.7.0_71 and Tomcat 7.0.55. Unfortunately we started to get the following exception during SSL connection between servers:

javax.net.ssl.SSLHandshakeException: server certificate change is restrictedduring renegotiation

What it means? How to prevent it?

The exception is disappeared after the Tomcat restart.

The full stack:

Caused by: javax.net.ssl.SSLHandshakeException: server certificate change is restrictedduring 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

Answer

Yves Martin picture Yves Martin · Dec 8, 2014

This error message in client layer code is a consequence of code hardening following "SSL V3.0 Poodle Vulnerability - CVE-2014-3566" in recent Java updates. And it is a bug - here are work-arounds in case you cannot update your JRE immediately:

A first option is to force TLS protocol when establishing HTTPS connection:

If you can update HttpClient to a more recent version than 4.3.6, then SSLv3 will be disabled by default and your code should no longer report such exception.

If you cannot upgrade your HttpClient version, you will have to use this answer's code to restrict protocols to TLS: https://stackoverflow.com/a/26439487/737790

For other http access from Java 7 runtime, the following system property must be set

-Dhttps.protocols="TLSv1"

Full details can be found here: Java http clients and POODLE


A second option is to relax client check to still allow renegotiation with the following properties:

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


A third option is to "improve" your server certificates to include all IP addresses of your cluster members as Subject Alternative Names according to this post in Burp forum


A fourth option is to downgrade your Java version before this certificate/renegotiation checks have been added, so before 7u41 (to be confirmed)

Updates This buggy behaviour is now fixed in JDK updates 7u85 and 8u60. Credits to Pada for having found the JDK-8072385 reference.