I have a java test app that makes a Restful SSL connection/call to a remote server but same code run from servlet under Tomcat returns Bad_Certificate error.
Test app version successfully connects to remote after referencing my keyStore and trustStore that I specify through System.setProperty("javax.net.ssl....? statements for file locations and passwords. This test program is a stand-alone simple class with a main method that successfully establishes connection and gets a response. However, if I move this same code to my servlet that runs on Tomcat I get a "SSLHandshakeException" Bad_Certificate error. And ssl:all:verbose debug trace doesn't provide any help because it appears that it's not getting to the handshake stage. I can recreate this error on my test app only if I don't set the System Properties pointing to the certificates. It appears that setting System.setProperty is being overridden when running from Tomcat. I also tried putting locations in web.xml but that didn't have any affect either.
My code is not readily available because it is exists behind a firewall that won't allow me to copy anything. But I'll fat-finger anything in that you want to verify.
OS: Redhat 7.4
Tomcat: 7.0.76
Java: JDK 10.0.2
javax.net.ssl.SSLHandshakeException: Received fatal alert: bad_certificate
java.base/sun.security.ssl.Alerts.getSSLException(Alerts.java 198)
java.base/sun.security.ssl.Alerts.getSSLException(Alerts.java 159)
java.base/sun.security.ssl.SSLSocketImpl.recvAlert(SSLSocketImpl.java:2046)
java.base/sun.security.ssl.SSLSocketImpl.processInputRecord(SSLSocketImpl.java:1207)
java.base/sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:1074)
java.base/sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:973)
java.base/sun.security.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1402)
java.base/sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1429)
java.base/sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1413)
java.base/sun.net.www.protocol.https.HttpsClient.afterConnect(HttpsClient.java:567)
java.base/sun.net.www.protocol.https.AbstractDelegateHttpsURLConnection.connect(AbstractDelegateHttpsURLConnection.java:185)
java.base/sun.net.www.protocol.http.HttpURLConnection.getInputStream0(HttpURLConnection.java:1581)
java.base/sun.net.www.protocol.http.HttpURLConnection.getInputStream(HttpURLConnection.java:1509)
java.base/java.net.HttpURLConnection.getResponseCode(HttpURLConnection.java:527)
java.base/sun.net.www.protocol.https.HttpsURLConnectionImpl.getResponseCode(HttpsURLConnectionImpl.java:329)
Since adding debug to JAVA_OPTS in Tomcat configuration file, I'm getting more detail. Prior to the stacktrace that I provided yesterday I'm seeing the handshake now. And the last part of the handshake looks as follows:
update handshake state: finished
upcoming handshake states: server change_cipher_spec[-1]
upcoming handshake states: server finished [20]
ajp-bio-8009-exec-1, WRITE TLSv1.2 Handshake, length = 32
ajp-bio-8009-exec-1, READ TLSv1.2 Alert, length = 2
ajp-bio-8009-exec-1, RECV TLSv1.2 ALERT: fatal, bad certificate
%%invalidated: [Session-3 TLS_RSA_WITH_AES_128_CBC_SHA]
ajp-bio-8009-exec-1, call closeSocket()
But I'm not sure what to do about this.
My code connects to apns for push notification. Am using clevertap library from git(https://github.com/CleverTap/apns-http2). It uses okhttp for the connection. When I run code on IBM WAS 8.5.5 and am receiving SSLHandshakeException. Details below. Can you pls help me on how to address this? Am trying with Synchronous mode of sending push message. I use Java 1.7, WAS 8.5.5. Pls let me know if you need more details.
javax.net.ssl.SSLHandshakeException: Received fatal alert: handshake_failure
at com.ibm.jsse2.j.a(j.java:23)
at com.ibm.jsse2.j.a(j.java:21)
at com.ibm.jsse2.qc.b(qc.java:465)
at com.ibm.jsse2.qc.a(qc.java:451)
at com.ibm.jsse2.qc.h(qc.java:759)
at com.ibm.jsse2.qc.a(qc.java:353)
at com.ibm.jsse2.qc.startHandshake(qc.java:800)
at okhttp3.internal.connection.RealConnection.connectTls(RealConnection.java:299)
at okhttp3.internal.connection.RealConnection.establishProtocol(RealConnection.java:268)
at okhttp3.internal.connection.RealConnection.connect(RealConnection.java:160)
When I googled for the issue, it seems the issue is because of IBMJSSE2, the JSSE implementation used by Websphere, in not compatible with this solution.
The problem is that for this implementation, the cipher suite names may starts with SSL_ or TLS_ (IBM documentation), both accepted: but that is not true for OkHttp. But I could not find a work around that I can use to fix the problem.
I read that version 3.7 of the jar will fix the problem but am using 3.9.1 and still running into the same issue.
I have the certificate imported into WAS trust store. I also have TLS 1.2 in the environment.
I have a Java program that connects to a webserver using SSL/TLS, and sends various HTTP requests over that connection. The server is localhost and is using a self-signed cert, but my code is using custom TrustManagers, and ignores invalid certificates. It has worked perfectly until now.
The only difference on the server is that it used to run jboss 6 and is now running jboss 7. I'm not sure if this is a configuration issue, or whether there is a problem with my code, but I get the same errors if I try to connect using other Java-based programs like WebScarab or ZAP.
In any case, is there anything I can do to my code to get around this problem? Here is the error in full:
Received fatal alert: handshake_failure
javax.net.ssl.SSLHandshakeException: Received fatal alert: handshake_failure
at com.sun.net.ssl.internal.ssl.Alerts.getSSLException(Unknown Source)
at com.sun.net.ssl.internal.ssl.Alerts.getSSLException(Unknown Source)
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.recvAlert(Unknown Source)
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.readRecord(Unknown Source)
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.performInitialHandshake(Unknown Source)
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.startHandshake(Unknown Source)
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.startHandshake(Unknown Source)
at sun.net.www.protocol.https.HttpsClient.afterConnect(Unknown Source)
at sun.net.www.protocol.https.AbstractDelegateHttpsURLConnection.connect(Unknown Source)
at sun.net.www.protocol.https.HttpsURLConnectionImpl.connect(Unknown Source)
Here are the debug messages before the failure:
main, WRITE: TLSv1 Handshake, length = 75
main, WRITE: SSLv2 client hello message, length = 101
main, READ: TLSv1 Alert, length = 2
main, RECV TLSv1 ALERT: fatal, handshake_failure
So I found the problem. There might be a bug in Java, but the client seems to initiate a TLSv1 Handshake, but then sends an SSLv2 client hello message, at which point the server rejects the connection.
This happens even if you create your SSLContext with an instance of TLS:
SSLContext sslContext = SSLContext.getInstance("TLS");
The solution is to set a system property before any connection attempts are made:
System.setProperty("https.protocols", "TLSv1");
There are probably other solutions to it, but this one worked for me.
The info you provide is very little as well as your stack trace.
I'll take a guess here.
What I suspect is that in the new server the protocol is TLSv1 while your clients try to connect with SSLv3 (or less) and as a result the handshake fails.
Change you clients to use higher version of TLS
or
Make your webserver support SSLv3 as well. I know how to do this in Tomcat but not in JBoss.
If this doesn't work update the post with more info (and a full stack trace).
You should enable ssl debug info -Djavax.net.debug=ssl
Was this ever resolved?
I had the exact same problem, essentially I was receiving a handshake exception immediately following the clientHello. So The chain of events was
I would present my certificate to the server
Server would imediately respond with a handshake failure. (I would not even get a Server Hello back).
Eventually I found that the server was requiring a stronger encryption/decryption algorithm than what I Was supplying in the initial handshake phase (Ie. Client and Server could not agree on a mutual encryption algorithm to use for the ssl communication).
I need to install the Unlimited Java JCE (Java Cryptography Extension Policy). There are export rules on using this, so if you ship your code overseas that may have implications..however this is what solved my problem.
This link explains how to install the updated policies
http://suhothayan.blogspot.com/2012/05/how-to-install-java-cryptography.html
This was also a great link that helped me understand exactly what was going on
https://support.f5.com/kb/en-us/solutions/public/15000/200/sol15292.html#id
This may or may not be the issue, but when the handshake fails immediately after the client Hello, it looks like the client and the server can not agree on something (in many cases its the encryption algorithms that they will mutually need to communicate).
You are seeing this error most probably because the keystore that your JBoss 6 had access to is not accessible to your JBoss 7 instance.
What I would recommend is the following.
Your self-signed server certificate must be imported into a truststore
keytool -import -alias gridserver -file server.crt -storepass $YOUR_PASSWORD_HERE -keystore server.keystore
Add the following properties to your run.conf
-Djavax.net.ssl.keyStoreType=pkcs12
-Djavax.net.ssl.trustStoreType=jks
-Djavax.net.ssl.keyStore=clientcertificate.p12
-Djavax.net.ssl.trustStore=server.keystore
-Djavax.net.debug=ssl # very verbose debug. Turn this off after everything looks good.
-Djavax.net.ssl.keyStorePassword=$YOUR_PASSWORD_HERE
-Djavax.net.ssl.trustStorePassword=$YOUR_PASSWORD_HERE
The stack trace is from you client code and your client 'Received [a] fatal alert'. In other words, the SSL error happened in Jboss, not your client.
Your client side custom TrustManagers have therefore nothing to do with it. My wild guess is that your new Jboss 7 is configured to require client certificate and your client did not present any.
To debug your SSL connection, use openssl and try this:
openssl s_client -connect jboss.server.com:443
or is it is an SSLV3 server
openssl s_client -connect jboss.server.com:443 -ssl3
This should print a lot of interesting information.
I think this is related to a Java 7 bug. It is hard to be sure without more details.
For me solution was : System.setProperty("https.protocols", "TLSv1.1,TLSv1.2");
This question already has answers here:
Received fatal alert: handshake_failure through SSLHandshakeException
(20 answers)
Closed 5 years ago.
I am posting this question after trying many options from two days. Below are the options I tried.
Disable ssl certificate validation
By downloading crt from browser and converting to .jks and importing keystore.
Still I am getting this issue, any help very much appreciated in advance.
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:1943)
at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:1059)
at sun.security.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1294)
at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1321)
at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1305)
at sun.net.www.protocol.https.HttpsClient.afterConnect(HttpsClient.java:523)
at sun.net.www.protocol.https.AbstractDelegateHttpsURLConnection.connect(AbstractDelegateHttpsURLConnection.java:185)
at sun.net.www.protocol.http.HttpURLConnection.getInputStream(HttpURLConnection.java:1296)
at sun.net.www.protocol.https.HttpsURLConnectionImpl.getInputStream(HttpsURLConnectionImpl.java:254)
at com.honeywell.sensibo.api.NewMain.main(NewMain.java:73)
Issue resolved.!!! Below are the solutions.
For Java 6:
Add below jars into {JAVA_HOME}/jre/lib/ext.
1. bcprov-ext-jdk15on-154.jar
2. bcprov-jdk15on-154.jar
Add property into {JAVA_HOME}/jre/lib/security/java.security
security.provider.1=org.bouncycastle.jce.provider.BouncyCastleProvider
Java 7:download jar from below link and add to {JAVA_HOME}/jre/lib/security
http://www.oracle.com/technetwork/java/javase/downloads/jce-7-download-432124.html
Java 8:download jar from below link and add to {JAVA_HOME}/jre/lib/security http://www.oracle.com/technetwork/java/javase/downloads/jce8-download-2133166.html
Issue is that it is failed to decrypt 256 bits of encryption.
I am getting similar errors recently because recent JDKs (and browsers, and the Linux TLS stack, etc.) refuse to communicate with some servers in my customer's corporate network. The reason of this is that some servers in this network still have SHA-1 certificates.
Please see:
https://www.entrust.com/understanding-sha-1-vulnerabilities-ssl-longer-secure/
https://blog.qualys.com/ssllabs/2014/09/09/sha1-deprecation-what-you-need-to-know
If this would be your current case (recent JDK vs deprecated certificate encription) then your best move is to update your network to the proper encription technology.
In case that you should provide a temporal solution for that, please see another answers to have an idea about how to make your JDK trust or distrust certain encription algorithms:
How to force java server to accept only tls 1.2 and reject tls 1.0 and tls 1.1 connections
Anyway I insist that, in case that I have guessed properly your problem, this is not a good solution to the problem and that your network admin should consider removing these deprecated certificates and get a new one.
I'm getting this error while trying to execute and old MapleStory server on linux, I've tried same file on windows and worked without problem. I've tried with serveral Java version without success.
This could be because a root CA's certificate is not present in trust store. For more details refer to previous answer.