I have TLS client writen in JAVA. When i set
sslContext = TLS1.2
and enabled protocols to SSLv3 TLSv1 TLSv1.1 TLS1.2
it works fine with almost all servers. Client start handshake with TLSv1.2. If server can only TLSv1, connection downgrades to TLSv1 during handshake.
But! We use about 15 such TLSv1 services and 4 of them fails to downgrade. Servers are all different:
Microsoft-IIS/7.5, nginx, IBM_HTTP_SERVER, SQLAnywhere.
Errors like this:
SEND TLSv1 ALERT: fatal, description = unexpected_message X2
handling exception: javax.net.ssl.SSLException: Invalid Padding length: 139
javaException : Received fatal alert: unexpected_message
If i set enabled protocols to TLSv1, that servers works fine. But i want set sslContext and enabled protocols to be compatible with all services and preferably work with TLSv1.2
Any suggestions will be appreciated!
But i want set sslContext and enabled protocols to be compatible with all services and preferably work with TLSv1.2
First, there are enough servers out there which don't do TLS 1.2 but the best they can do is TLS 1.0 (and some even only SSL 3.0). A proper implementation of the TLS stack would in this case simply send a TLS 1.0 reply and thus enforcing the connection to be TLS 1.0 which is supported in your client. Forcing these servers to TLS 1.2 will not work because they don't implement it. All you could do is replace the servers with newer implementations.
And then there are several implementations out there which incorrectly implement the protocol. Some of these simply close the connection if you send a TLS 1.2 ClientHello or use some TLS extensions they never heard of. If you can not replace these servers you have to communicate with them in a way they will understand, like speaking only TLS 1.0 etc. Browsers already deal with this rotten servers by slowly downgrading the connection, i.e. if TLS 1.2 causes a handshake failure they will try again with TLS 1.0 etc. Often browsers even have hard coded a list of servers which are too rotten to even play nice after trying simple downgrads and which need to have special ciphers or something like this.
Related
We initialise our SSL context with the following code and are running on Java 8.
SSLContext context = SSLContext.getInstance("SSL");
Since Java 8 uses TLSv1.2 by default? Does it mean the above code will start sending TLSv1.2 requests if my server supports it.
Want to understand if "SSL" protocol name is just an alias but java runtime starts sending the requests with default TLS version.
UPDATE
I ran my code against "https://www.google.co.in/" and found this in fiddler
A SSLv3-compatible ClientHello handshake was found. Fiddler extracted the parameters below.
Version: 3.3 (TLS/1.2
And also if i change my protocol to TLSv1 which only supports 1.0. Then Fiddler tells me
A SSLv3-compatible ClientHello handshake was found. Fiddler extracted the parameters below.
Version: 3.1 (TLS/1.0)
So, I guess the above code with "SSL" protocol name should work well with TLS 1.2 servers.
Yes. In Java 7, server side default TLS version was 1.2. In Java 8 both server and client have default TLS version 1.2.
As TLS version is backward compatible on both side unless server is configured strictly to specific version should not be an issue.
I have enabled logs in my application using -Djavax.net.debug=all option. Code that have written is supposed to use SSLv3 protocol, but in logs when I am checking it is displaying as ::
*** ClientHello, TLSv1
*** ServerHello, TLSv1
As far as I understand from reading is, Client and Server using TLSv1 for handshake, but as I have used SSLv3 in my code while initiating socket, ideally it should print SSLv3 instead TLSv1.
Below is the code snippet I have used :
SSLContextBuilder builder = new SSLContextBuilder();
builder.useProtocol("SSLv3");
SSLContext sslContext = builder.build();
Can someone please clarify the reason for the same, or is there something else I have missed out. Just to add on I am on Java 7.
Most probably SSLv3 is just not supported by server (which is recommended configuration nowadays because of security), so the lib uses least supported TLS version.
UPD: seems that hello format says nothing about what protocol will be used in fact. There's something from Java docs:
Currently, the SSLv3, TLSv1, and TLSv1.1 protocols allow you to send SSLv3, TLSv1, and TLSv1.1 hellos encapsulated in an SSLv2 format hello. For more details on the reasons for allowing this compatibility in these protocols, see Appendix E in the appropriate RFCs (previously listed).
Note that some SSL/TLS servers do not support the v2 hello format and require that client hellos conform to the SSLv3 or TLSv1 client hello formats.
The SSLv2Hello option controls the SSLv2 encapsulation. If SSLv2Hello is disabled on the client, then all outgoing messages will conform to the SSLv3/TLSv1 client hello format. If SSLv2Hello is disabled on the server, then all incoming messages must conform to the SSLv3/TLSv1 client hello format.
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
This is a follow-up question to "SSL Handshaking Using Self-Signed Certs and SSLEngine (JSSE)".
I have implemented a NIO Webserver that can process SSL and non-SSL messages on the same port. In order to distinguish between SSL and non-SSL messages, I check the first byte of the inbound request to see if it is a SSL/TLS message. Example:
byte a = read(buf);
if (totalBytesRead==1 && (a>19 && a<25)){
parseTLS(buf);
}
In the parseTLS() method I instantiate an SSLEngine, initiate the handshake, wrap/unwrap messages, etc. Everything seems to work fine for most modern web browsers (Firefox 10, IE 9, Safari 5, etc).
Problem is that older web browsers like IE 6 and libraries like Java's URLConnection class seem to initiate the SSL/TLS handshake differently. For example, the first few bytes from IE 6 look something like this (hex values):
80 4F 01 03 00 ...
If I pass the message to the SSLEngine, it doesn't seem to recognize the message and throws an Exception.
javax.net.ssl.SSLException: Unsupported record version Unknown-0.0
So what exactly is IE 6 and Java's URLConnection class sending over? Is this a valid SSL/TLS message that the JSSE SSLEngine can support? Do I have to do some pre-processing or negotiate with the client to send a different message?
Thanks in advance!
UPDATE
Thanks to Bruno and EJP and some further debugging I have a much better understanding of what's going on. As Bruno correctly pointed out, the IE6 and Java 6 clients are sending over a SSLv2 ClientHello. Contrary to one of my earlier comments, the SSLEngine in Java 1.6 can in fact unwrap the SSLv2 message and generate a valid response to send back to the client. The SSLException I reported earlier was an error on my side and has nothing to do with the SSLEngine (I incorrectly assumed that the client was done sending data over and I ended up with an empty ByteBuffer when the SSLEngine was expecting more data to unwrap).
This looks like an SSLv2 Client Hello (see TLS specification):
TLS 1.1 clients that support SSL Version 2.0 servers MUST send SSL
Version 2.0 client hello messages [SSL2]. TLS servers SHOULD accept
either client hello format if they wish to support SSL 2.0 clients on
the same connection port. The only deviations from the Version 2.0
specification are the ability to specify a version with a value of
three and the support for more ciphering types in the CipherSpec.
80 4F is the length and the high bit must be set to 1 (see msg_length description).
01 is the message type (Client Hello)
03 00 is the highest supported version (SSLv3 here)
Since Java 7, this is now disabled by default.
EDIT:
Just to clarify, this isn't really an SSLv2 Client Hello, this is a Client Hello for SSLv3 in the SSLv2 format. In this case, the server will reply with a (proper) SSLv3 Server Hello (corresponding to the 03 00 requested version number). The same also works for TLS 1.0, 1.1 and 1.2, although the usage of this format is progressively deprecated.
A JSSE 7 SSLServerSocket will still understand such a Client Hello and reply appropriately with the SSLv3/TLS1.x Server Hello.