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.
Related
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
I'd like my TLS server app to keep stats on which cipher suites its clients have requested -- so that in future I can make informed decisions about the user impact of disabling a given cipher suite.
Using JSSE I can easily get at the cipher suite agreed upon by the handshake, using HandshakeCompletedEvent.getCipherSuite().
But browsing through the Javadocs, I can't see anything that lets me see details of the client_hello, and thus the other cipher suites listed as acceptable to the client. Is there an API into that, that I've failed to find?
But browsing through the Javadocs, I can't see anything that lets me see details of the client_hello, and thus the other cipher suites listed as acceptable to the client.
There isn't one.
Is there an API into that, that I've failed to find?
No.
You shouldn't disable any cipher suite unless there is a security problem with it, and in that case it is just bad luck if any client relied on it. This is really very unlikely.
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 am working on configuring a Java client which its job is to make TLS connections to servers. I want to configure my client with these 3 ciphers:
TLS_RSA_WITH_RC4_128_SHA
TLS_RSA_WITH_3DES_EDE_CBC_SHA
TLS_RSA_WITH_RC4_128_MD5
In Java supported cipher suites, I found the same ciphers but with SSL at the beginning NOT TLS. The question, if I configured my client with:
SSL_RSA_WITH_RC4_128_SHA
SSL_RSA_WITH_3DES_EDE_CBC_SHA
SSL_RSA_WITH_RC4_128_MD5
Are the two lists exactly the same and will be interpreted by the server same? I am worried if I configured the client with SSL_* ciphers this mean something different than TLS_* and may be some servers do not support SSL_*. How can I be sure?
Yes, they are the same. See Java Cryptography Architecture
Standard Algorithm Name Documentation:
Some JSSE cipher suite names were defined before TLSv1.0 was finalized, and were therefore given the SSL_ prefix. The names mentioned in the TLS RFCs prefixed with TLS_ are functionally equivalent to the JSSE cipher suites prefixed with SSL_.
(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)