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.
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
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 looking at the JSSE reference guide, I need to obtain an instance of SSLContext in order to create a SSLEngine, so I can use it with Netty to enable security.
To obtain an instance of SSLContext, I use SSLContext.getInstance(). I see that the method is overridden multiple times, so I can chose the protocol and security provider to use.
Here, I can see the list of algorithms that can be used. Which algorithm should I use to enable secure communication?
Also, since it is possible to specify the security provider to use, which provider should I use?
Thanks
As you can see in the standard names documentation, all entries (SSLv3, TLSv1.0, TLSv1.1, ...) say that they may support other versions.
In practice, in the Oracle JDK (and OpenJDK), they all do. If you look at the source code, the TLS10Context class is what's used for TLS, SSL, SSLv3 and TLS10, TLS11Context is used for TLSv1.1 and TLS12Context for TLSv1.2. All support all versions of SSL/TLS, it's what's enabled by default that varies.
This may be different with another provider or JRE vendor. You should of course pick one that's at least going to support the protocol version you want to use.
Note that the protocol used is determined later on using SSLSocket.setEnabledProtocols(...) or its SSLEngine equivalent.
As a general rule, use the highest version number you can (SSLv3 < TLSv1.0 < TLSv1.1 ...), which may depend on what the parties with which you want to communicate support.
Which protocols are enabled by default varies depending on the exact version of the Oracle JRE.
When looking at the source code for sun.security.ssl.SunJSSE in OpenJDK 7u40-b43, TLS is simply an alias for TLSv1 (and so are SSL and SSLv3), in terms of SSLContext protocols. Looking at the various implementations of SSLContextImpl (which are inner classes of SSLContextImpl itself):
All support all protocols.
All protocols are enabled on the server side by default.
the client-side protocols enabled by default vary:
TLS10Context (used for protocol SSL, SSLv3, TLS, TLSv1) enables SSLv3 to TLSv1.0 by default on the client side.
TLS11Context (used for protocol TLSv1.1) also enables TLSv1.1 by default.
TLS12Context (used for protocol TLSv1.2) also enables TLSv1.2 by default.
If FIPS is enabled, SSL is not supported (so not enabled by default).
This changes in Java 8, in conjunction with the new jdk.tls.client.protocols system property.
Again, when looking at the source code for sun.security.ssl.SunJSSE in OpenJDK 8u40-b25, SSLContext protocols TLSv1, TLSv1.1, and TLSv1.2 also make use of TLS10Context, TLS11Context and TLS12Context, which follow the same logic as in Java 7.
However, protocol TLS is no longer aliased to any of them. Rather, it uses TLSContext which relies on the values in the jdk.tls.client.protocols system properties. From the JSSE Reference guide:
To enable specific SunJSSE protocols on the client, specify them in a comma-separated list within quotation marks; all other supported protocols are then disabled on the client. For example, if the value of this property is "TLSv1,TLSv1.1", then the default protocol settings on the client for TLSv1 and TLSv1.1 are enabled on the client, while SSLv3, TLSv1.2, and SSLv2Hello are disabled on the client.
If this property is empty, all protocols are enabled by default on both client and server side.
Of course, in recent versions of Oracle JRE 8, SSL is also completely disabled by default (so removed from those lists).
Note that in both cases (JRE 7 and 8), the SSLContext you get by default via SSLContext.getDefault() out of the box is more or less equivalent to an SSLContext obtained with protocol TLS and initialised with the default truststore parameters and so on.
There is no default for the protocol, so I would use the latest one supported by your JDK, which is either TLSv1, TLSv1.1 or TLSv1.2: see which works, or have a look at getSupportedProtocols(). The default security provider is used by avoiding all the APIs where you specify it, or else e.g. KeyStore.getDefaultType().
And when you come to get your SSLEngines, make sure you use the method that takes a hostname and port. Otherwise you will get no SSL session sharing.
(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)
I have a webapp that sends a SOAP request to a 3rd party server. When the request is made on my local computer it works without a problem, but when I deploy my application to my server I get an error with the following causes:
com.sun.xml.messaging.saaj.SOAPExceptionImpl: java.security.PrivilegedActionException: com.sun.xml.messaging.saaj.SOAPExceptionImpl: Message send failed
Caused by: javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path validation failed: java.security.cert.CertPathValidatorException: algorithm check failed: MD2withRSA is disabled
I've searched around but I can't find anything relevant to my situation. It's probably worth noting that the request I'm making is to an https url. My computer is running Windows XP and the server is running Slackware Linux. Any ideas what might be causing the server to reject the request?
Check your Java versions on your local machine, and your server.
From here, it seems the jvm 6u17 disabled MD2 as it is insecure, and whatever you connect to is using MD2
MD2withRSA is highly vulnerable and therefore deactivated in Sun... aeh Oracle's JVM. You should ask the owner of the remote service, whether his server supports more secure encryption methods (I think, older Apache HTTPd versions do offer MD2withRSA by default...). In order to resolve this problem without forcing the provider to change the method, you may use your own implementation of the X509TrustManager that accepts the old method.
A Google search on "MD2withRSA" showed this URL as the first hit, that seems to point to a change in a certain Java version. Probably the verasiuons on your local computer and the server do not match.
Newer Java 7 (version 1.7) allows re-enabling MD2 via $JAVA_HOME/jre/lib/security/java.security file. Download and install Java 7 and modify java.security file in text editor as follows
1) Remove MD2 from following property
jdk.certpath.disabledAlgorithms= # MD2
2) Ensure following property is commented out
# jdk.tls.disabledAlgorithms=MD5, SHA1, DSA, RSA keySize < 2048
3) Restart java application
Warning: MD2 is disabled by default in Jdk 7 because it is insecure. However, it can be enabled as described above to support older deployments.