Just letting folks know about an issue I had that many seemed to have had after upgrading to Java 1.8. Not all of the solutions are the same hence posting how I resolved this.
But first... This is not a solution worthy of production systems since security is being effectively downgraded. However, if you are blocked testing etc. it is probably quite suitable.
My issue was that no matter what I did... enabled SSLv3 etc. I always received
"javax.net.ssl.SSLHandshakeException: Received fatal alert: handshake_failure".
Here are the steps I took to 'solve' this.
First, I discovered which cipher the server was using. I did this via openssl.
openssl s_client -host yourproblemhost.com -port 443
This yields (at the end...)
SSL-Session:
Protocol : TLSv1.2
Cipher : RC4-MD5
Now.. what do we use 'Java-wise' to enable that cipher?
Oracle link
In that link, it has the names and their Java counterpart. So for RC4-MD5, we have SSL_RSA_WITH_RC4_128_MD5.
ok good. Now I added a System property.
-Dhttps.cipherSuites=SSL_RSA_WITH_RC4_128_MD5
And in my code...
Security.setProperty("jdk.tls.disabledAlgorithms", "" /*disabledAlgorithms */ );
Again.. this is an absolute last resort 'fix'... But if you're hitting your head aganst a wall to get it running (for testing), I hope it comes in useful.
With JDK 1.8.0_51 release RC4 is no longer supported from Java as client (also as server) to negotiate SSL handshake, RC4 is considered weak (and compromised ) cipher and that is the reason for removal
http://bugs.java.com/view_bug.do?bug_id=8076221
You can still however enable it by removing RC4 from jdk.tls.disabledAlgorithms from your Java security config or progamatically enabling them using setEnabledCipherSuites() method
However better solution would be to update the server configuration (if it is under your control) to upgrade to stronger Ciphers
RC4 is now considered as a compromised cipher. RC4 cipher suites have been removed from both client and server default enabled cipher suite list in Oracle JSSE implementation. These cipher suites can still be enabled by SSLEngine.setEnabledCipherSuites() and SSLSocket.setEnabledCipherSuites() methods.
As to your approach on setting it by using Security.setProperty(), it is not reliable way because the fields which hold disabled algorithms are static and final, So if that class gets loaded first you don't have controll over it, you could alternatively try by creating a properties file
like this
## override it to remove RC4, in disabledcipher.properties
jdk.tls.disabledAlgorithms=DHE
and in your JVM, you could refer it as system property like this
java -Djava.security.properties=disabledcipher.properties blah...
RC4 was effectively cracked - 14 years ago.
The Fluhrer, Mantin and Shamir (FMS) attack, published in their 2001
paper "Weaknesses in the Key Scheduling Algorithm of RC4", takes
advantage of a weakness in the RC4 key scheduling algorithm to
reconstruct the key from encrypted messages.
The problem isn't in Java 8.
The problem is your server is using RC4.
Thanks alton for sharing such a life saver information.
Only one thing I'd like to change
since
openssl s_client -host yourproblemhost.com -port 443
returned ->
Protocol : TLSv1.2
Cipher : 0000
openssl s_client -connect X.X.X.X:993 -prexit -tls1
returned -> the expected response as
Protocol : TLSv1
Cipher : RC4-MD5
Related
I am trying to record a https site through jmeter (version 2.13, java version - 1.8u31) and I am getting SSLHandshakeException while connecting to a https site. The error message is
javax.net.ssl.SSLHandshakeException: Received fatal alert: handshake_failure
at sun.security.ssl.Alerts.getSSLException(Alerts.java:192)
at sun.security.ssl.Alerts.getSSLException(Alerts.java:154)
at sun.security.ssl.SSLSocketImpl.recvAlert(SSLSocketImpl.java:2011)
at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:1113)
at sun.security.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1363)
at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1391)
at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1375)
at org.apache.http.conn.ssl.SSLSocketFactory.connectSocket(SSLSocketFactory.java:436)
at org.apache.http.impl.conn.DefaultClientConnectionOperator.openConnection(DefaultClientConnectionOperator.java:180)
at org.apache.http.impl.conn.ManagedClientConnectionImpl.open(ManagedClientConnectionImpl.java:294)
at org.apache.jmeter.protocol.http.sampler.MeasuringConnectionManager$MeasuredConnection.open(MeasuringConnectionManager.java:107)
at org.apache.http.impl.client.DefaultRequestDirector.tryConnect(DefaultRequestDirector.java:643)
at org.apache.http.impl.client.DefaultRequestDirector.execute(DefaultRequestDirector.java:479)
at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:906)
at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:805)
at org.apache.jmeter.protocol.http.sampler.HTTPHC4Impl.executeRequest(HTTPHC4Impl.java:517)
at org.apache.jmeter.protocol.http.sampler.HTTPHC4Impl.sample(HTTPHC4Impl.java:331)
at org.apache.jmeter.protocol.http.sampler.HTTPSamplerProxy.sample(HTTPSamplerProxy.java:74)
at org.apache.jmeter.protocol.http.sampler.HTTPSamplerBase.sample(HTTPSamplerBase.java:1146)
at org.apache.jmeter.protocol.http.proxy.Proxy.run(Proxy.java:240)
I have turned on debug logging for SSL but I wasn't able to understand the root cause. It seems that the java client sends the ClientHello but does not receive the ServerHello message (where the server chooses the highest version of SSL and the best cipher suite that both the client and server support and sends this information to the client). I see differences between the protocol versions being sent, read and received by the client (TLSv1.1 vs TLSv1.2)
Is this the root cause ? If so, how can I fix it?
The logs are pasted here - Java SSLHandshakeException Logs - Pastebin.com
Update
As #Anand Bhatt suggested, I analyzed the site with ssllabs and understood the following
The server does not support TLSv1.2 which is supported by java 8
The server supports only one cipher suite - TLS_RSA_WITH_AES_256_CBC_SHA
Java 8u31 doesn't support the cipher suite that the server supports and that's most probably the issue.
Does that sound right? If so, how do we make the java 8 client support the cipher suite that the server supports?
SSLlabs is apparently testing "out of the box" support. Java crypto has a crock dating back to the 1990s when the US government severely restricted export of crypto software,
and as a result the JRE (or JDK) as distributed by then-Sun now-Oracle does not permit use of 256-bit symmetric encryption, which your server is demanding. You must download and install
the "JCE Unlimited Strength Jurisdiction Policy Files" for your Java (major) version; 8 is at http://www.oracle.com/technetwork/java/javase/downloads/jce8-download-2133166.html .
The README in the file gives longwinded details, but basically you replace two tiny jar files in JRE/lib/security.
TLSv1.2 is not a real issue now. TLS protocol automatically negotiates the highest version supported (and enabled) by both ends.
Java 8 implements SSLv3, TLSv1.0, TLSv1.1 and TLSv1.2, but recent updates (8u31 or 7u75 and up) disable SSLv3 by default because of POODLE;
you can re-enable it if you choose, but you should be reluctant to. (Java 7 implements the same protocol versions, but client by default disables 1.1 and 1.2 because of compatibility concerns at its release several years ago.)
However, because of POODLE and BEAST some security authorities no longer accept SSLv3 and TLSv1.0
as adequately secure; an important example is credit and debit cards, as detailed in https://security.stackexchange.com/a/87077/39571 .
TLSv1.2 includes some technical improvements over 1.1, making it preferred today, and there might be future discoveries that make those
improvements crucial; if your server can't support 1.2 (and maybe higher) at that point you would be in trouble. Similarly the fact that the server's only
supported suite uses plain-RSA key-exchange, i.e. NOT forward secrecy, is considered suboptimal now, and over time may become unacceptable.
keytool (at least with the normally used keystore and truststore files) has nothing to do with symmetric cryptography.
It could likely be relevant if the server uses a CA root (or more exactly and slightly more general, trust anchor)
that your JRE and/or application does not trust, and/or if the server wants client authentication at SSL/TLS level,
which is fairly rare. (Most websites authenticate at the web-application level, or at least HTTP level, if at all.)
SSLLabs checking of the server cert chain (and several other things also) is generally stricter than Java's, and they
didn't complain in that area, so it's unlikely you have a problem there.
The only change between tests is changing the TLS version. Behavior is the same between Chrome and FireFox.
TLSv1, and TLSv1.1 both get 90 MegaByte/sec. They get this speed on Java 6 (TLSv1), and Java 8 (TLSv1/TLSv1.1).
TLSv1.2 however drastically drops the speed. We get 4 MegaByte/sec. No ciphers were changed, no other settings, etc. Not only our dev machine, but customers have reported the same thing, Windows OS, Java 8, TLSv1.2. We are using OS X, Java 8, TLSv1.2. So it seems to be a general trend. The tests are being done on localhost, Xeon 6 core processor, SSD drive. If we don't use HTTPS we get over 200MB/sec. So 4MB/sec is just a terrible insult to what we can do.
This isn't the initial connection, or cache, or renegotiation, etc. This is just the raw transport speed. I didn't find any known java bugs on this, does anyone have any guesses?
This is what Chrome reports for the connection and cipher:
TLSv1.2
Your connection to 127.0.0.1 is encrypted with modern cryptography.
The connection uses TLS 1.2.
The connection is encrypted and authenticated using AES_128_GCM and uses ECDHE_RSA as the key exchange mechanism.
TLSv1.1
Your connection to 127.0.0.1 is encrypted with obsolete cryptography.
The connection uses TLS 1.1.
The connection is encrypted using AES_128_CBC, with SHA1 for message authentication and ECDHE_RSA as the key exchange mechanism.
Ideas?
Hate answering my own question, but I just realized TLS v1.2 allowed for a newer cipher. Its the cipher that causes Java 8 to use software for handling the encryption aspect instead of using hardware acceleration, and resulting in the horrible speeds.
Disabling all the GCM ciphers on the server resulted in the same speeds as chrome used a CBC cipher.
Slow AES GCM encryption and decryption with Java 8u20
--Ben
I'm actually configuring an WL12c environment for a Webapp project of my Master Degree that will be used through SSL.
For the typical configuration I just add on the JVM props the following:
-Dweblogic.security.SSL.Ciphersuites=ECDHE-RSA-AES128-GCM-SHA384,ECDHE-RSA-AES128-GCM-SHA128,DHE-RSA-AES128-GCM-SHA384,DHE-RSA-AES128-GCM-SHA128,ECDHE-RSA-AES128-SHA384,ECDHE-RSA-AES128-SHA128,ECDHE-RSA-AES128-SHA,ECDHE-RSA-AES128-SHA,DHE-RSA-AES128-SHA128,DHE-RSA-AES128-SHA128,DHE-RSA-AES128-SHA,DHE-RSA-AES128-SHA,ECDHE-RSA-DES-CBC3-SHA,EDH-RSA-DES-CBC3-SHA,AES128-GCM-SHA384,AES128-GCM-SHA128,AES128-SHA128,AES128-SHA128,AES128-SHA,AES128-SHA,DES-CBC3-SHA
-Dweblogic.security.SSL.protocolVersion=TLS1
I'm OK with the TLS1+ configuration since I'm avoiding RC4 and CBC ciphers..
My real question is, for other products, I have a flag that ensures the cipher order, answering with "the more powerful" at first. Please check the lines with SSLHonorCipherOrder and ssl_prefer_server_ciphers :
# apache
SSLProtocol all -SSLv2 -SSLv3
SSLHonorCipherOrder on
SSLCipherSuite "EECDH+ECDSA+AESGCM EECDH+aRSA+AESGCM EECDH+ECDSA+SHA384 \
EECDH+ECDSA+SHA256 EECDH+aRSA+SHA384 EECDH+aRSA+SHA256 EECDH+aRSA+RC4 \
EECDH EDH+aRSA RC4 !aNULL !eNULL !LOW !3DES !MD5 !EXP !PSK !SRP !DSS"
# nginx
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_prefer_server_ciphers on;
ssl_ciphers "EECDH+ECDSA+AESGCM EECDH+aRSA+AESGCM EECDH+ECDSA+SHA384 \
EECDH+ECDSA+SHA256 EECDH+aRSA+SHA384 EECDH+aRSA+SHA256 EECDH+aRSA+RC4 \
EECDH EDH+aRSA RC4 !aNULL !eNULL !LOW !3DES !MD5 !EXP !PSK !SRP !DSS";
Weblogic 12c have some kind of flag like that?
The order used on weblogic.security.SSL.Ciphersuites is enough?
I don't have any confirmation from the Oracle docs on my findings.
EDIT: I'm using Java 1.7
Thanks
No WL have flag to ensure that. No plans to implement this soon as well.
From Oracle Support:
Reply 1:
No, with the JSSE implementation there is no documented feature in WLS 12.1.2 of honoring the server-side SSL cipher suite preferred order.
Reply 2:
Thank you for you patience while I was obtaining the confirmation regarding any possible ordering of cipher suites.
Unfortunately, as of WLS 12.1.2 there is no documented feature of honoring the server-side SSL cipher suite preferred order.
This may change for future WLS versions. I'm currently trying to obtain information if this feature would be planed to be added in any future version, if this would be of your interest.
Reply 3:
I have received confirmation from our product management that such a option like 'SSLHonorCipherOrder' is not planned to be included in the future.
But maybe this is actually not needed by you as the following is true for WLS and I believe that is what you actually want to achieve:
During an SSL handshake, the client sends a list of cipher suites, and the server then chooses from it's own list the strongest cipher that the client also supports.
If you would be concerned about any particular weak cipher suites, you should exclude those, i.e. configure only the strong cipher suites which you want to be used.
I don't understand how does Java picks the most prefered cipher to use on Server Hello.
I have a Tomcat 5 configuration and I set in the SSL connector the ciphers=TLS_RSA_WITH_AES_128_CBC_SHA, TLS_RSA_WITH_AES_256_CBC_SHA, SSL_RSA_WITH_3DES_EDE_CBC_SHA, etc
Server i.e. Java picks TLS_RSA_WITH_AES_128_CBC_SHA on Server Hello as the prefered among the client's supported. But this is not the most secure and it is not the prefered accoding to http://docs.huihoo.com/java/javase/7/technotes/guides/security/SunProviders.html#SunJSSEProvider which lists that TLS_RSA_WITH_AES_256_CBC_SHA has preference.
Then I thought it was the order in the server.xml attribute that made the difference and I put another cipher first (TLS_DHE_RSA_WITH_AES_256_CBC_SHA) which I see in the Client Hello that it is supported. But this was not selected either and TLS_RSA_WITH_AES_128_CBC_SHA was again selected.
So how does JSSE picks the cipher of preference? Is this documented somewhere? I can not figure out what's going on here.
It doesn't have to. All that RFC 2246 says is "The server will select a cipher suite". Nowhere does it say it will pick the most secure, or indeed anything about how it will make that selection.
Something to realize: the client has a say in the selection also. If the client is saying it can only support the 128 bit cipher then that is what will be picked. See id your client even supports AES 256 by removing all supported ciphers but that one.
You are not providing a list of ciphers in order of preference. You are providing a list of acceptable ciphers that has to match one from the client. If any of those are not acceptable remove them.
While your statement that 2246 (or 5256) does not say that the server picks the cipher suite from mutually supported cipher suites in the preference order supplied by the client is correct, NIST 800-57 Part 3, in section 4.3, Procurement Guidance, states:
Implementations should select cipher suites in the order of preference submitted by the client.
(Disclaimer: I am by no stretch of the imagination a security expert nor a windows expert for that matter)
Setup:
server on our end: java 1.6 (already added bouncycastle to the security file) on windows 2003 server
third party client: windows 2008 server with biztalk
all renegotiation system properties introduced due to the renegotiation attack are "enabled" on the server side (not safe I know)
Ideally we want to fix this at our end but it is possible to propose a fix to the client if necessary.
The client server has to connect to our server over a HTTPS connection but it always fails, wireshark shows the following conversation:
> TLSv1: Client Hello
< TLSv1: Alert (21): Unexpected Message
As per the RFC (http://www.ietf.org/rfc/rfc2246.txt) the alert(21) refers to a failed decryption and from what I can see in wireshark, none of the ciphers proposed by the client are actually supported by JRE 1.6 (as per http://docs.oracle.com/javase/6/docs/technotes/guides/security/SunProviders.html#SupportedCipherSuites)
In an effort to reproduce the error to be able to examine it closer, I tested with some other software:
wfetch on windows xp with "https" selected will perform the initial client handshake in SSLv2, the server will switch to TLSv1 to answer, this works
wfetch on windows xp with configured to use "TLSv1" for the initial handshake will fail in the same way as the biztalk server
wfetch on windows 2008 with configured "https" will use "TLSv1" for the initial handshake and fail in the same way as the biztalk server
IE (on windows xp) will initially try a TLSv1 handshake with the same failed result but immediately tries again using SSLv3 which works
(at this point I figure all microsoft software uses a central configuration available at HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\SecurityProviders\Schannel)
firefox uses SSLv3 for the entire conversation, so no problem there
OpenSSL performs an initial handshake in SSLv2, and the server switches to TLSv1 when it answers, no problem there
OpenSSL can be forced to do the initial handshake in TLSv1 as well, it offers a list of 27 ciphers (as opposed to the 11 ciphers proposed by windows-based software) and can connect without a problem
To my untrained eye this reinforces the idea that an incompatible cipher proposition is the root cause where windows only supports cipher suites that are not supported by JVM (for TLSv1).
I have installed bouncy castle as an additional provider in the java.security file to no avail.
I have searched high and low and only found a reference that maybe websphere supports the windows ciphers for TLSv1 but no way of downloading a standalone provider to test it.
JRE 1.7 is not supported by the software we run on our JVM, so upgrading is not an option (perhaps the security provider can be downgraded safely? I haven't found a download for it yet though)
I have found no way to add a cipher to windows short of writing c++ code (I've played around with the above mentioned registry settings without effect).
So in conclusion I wonder if one of the following things would fix it and how they should be accomplished:
add a provider to the jvm that can work with the ciphers for TLSv1 that are proposed by windows
somehow force the client to do the initial handshake in SSLv3 (preferably not SSLv2) or at least retry if the TLSv1 handshake fails
somehow add a JVM-supported cipher for TLSv1 to the client windows
Any other solutions are of course also appreciated.
EDIT
The Java version is Java version (64 bit): 1.6.0_19-b04.
The list of proposed ciphers is:
TLS_RSA_WITH_RC4_128_MD5
TLS_RSA_WITH_RC4_128_SHA
TLS_RSA_WITH_3DES_EDE_CBC_SHA
TLS_RSA_WITH_DES_CBC_SHA
TLS_RSA_EXPORT1024_WITH_RC4_56_SHA
TLS_RSA_EXPORT1024_WITH_DES_CBC_SHA
TLS_RSA_EXPORT_WITH_RC4_40_MD5
TLS_RSA_EXPORT_WITH_RC2_CBC_40_MD5
TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA
TLS_DHE_DSS_WITH_DES_CBC_SHA
TLS_DHE_DSS_EXPORT1024_WITH_DES_CBC_SHA
The unlimited strength cryptography policy files are installed. I have tried to set javax.net.debug=all and started the server from the console, no additional output appeared. I have set sun.security.ssl.allowUnsafeRenegotiation=true to no avail.
EDIT 2
It turns out the software we are using uses a custom stack for HTTPs instead of the default. A fix was issued which seems to solve the problem though I don't know exactly which part of the TLS request triggered the error (seeing as most TLSv1 handshakes did succeed).
Thanks for the feedback, it has been an interesting if futile search. Live and learn.
It turns out the software we are using uses a custom stack for HTTPs instead of the default. A fix was issued which seems to solve the problem though I don't know exactly which part of the TLS request triggered the error (seeing as most TLSv1 handshakes did succeed).
Thanks for the feedback, it has been an interesting if futile search. Live and learn.
You could read my article on detecting cipher strength (just to make sure you installed the jce ciphers correctly) . In your question you say you installed unlimited ciphers but then you reference 128 and 40-bit keys. So, I am confused by what you have. Also, could you check the cipher strength on the SSL cert you are trying to connect to and let us know what it is and what the algorithm is? Also, make sure your policy file for JDK has the proper rights to allow unlimited strength.
Finally, can you connect to a "known good" SSL site to verify your client handshakes correctly? (Gmail web for example)