SSLHandShakeException No Appropriate Protocol
JavaSslBufferedreaderJava Problem Overview
I recently added SSL to my website and it can be accessed over https. Now when my java application tries to make requests to my website and read from it with a buffered reader it produces this stack trace
Im not using a self signed certificate the cert is from Namecheap who uses COMODO SSL as the CA to sign my certificate. im using java 8
javax.net.ssl.SSLHandshakeException: No appropriate protocol (protocol is disabled or cipher suites are inappropriate)
at sun.security.ssl.Handshaker.activate(Handshaker.java:503)
at sun.security.ssl.SSLSocketImpl.kickstartHandshake(SSLSocketImpl.java:1482)
at sun.security.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1351)
at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1403)
at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1387)
at sun.net.www.protocol.https.HttpsClient.afterConnect(HttpsClient.java:559)
My code is very basic and simply tries to read the page on my site using a buffered reader
private void populateDataList() {
try {
URL url = new URL("https://myURL.com/Data/Data.txt");
URLConnection con = url.openConnection();
con.setRequestProperty("Connection", "close");
con.setDoInput(true);
con.setUseCaches(false);
BufferedReader in = new BufferedReader(new InputStreamReader(con.getInputStream()));
String line;
int i = 0;
while((line = in.readLine()) != null) {
this.url.add(i, line);
i++;
}
} catch (Exception e) {
e.printStackTrace();
}
}
Ive tried adding my SSL certificate to the JVM's Keystore and Ive also even tried to accept every certificate (which defeats the purpose of SSL I know) with this code
private void trustCertificate() {
TrustManager[] trustAllCerts = new TrustManager[] {
new X509TrustManager() {
public java.security.cert.X509Certificate[] getAcceptedIssuers() {
return new X509Certificate[0];
}
public void checkClientTrusted(
java.security.cert.X509Certificate[] certs, String authType) {
}
public void checkServerTrusted(
java.security.cert.X509Certificate[] certs, String authType) {
}
}
};
try {
SSLContext sc = SSLContext.getInstance("TLS");
sc.init(null, trustAllCerts, new java.security.SecureRandom());
HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
} catch (GeneralSecurityException e) {
}
try {
URL url = new URL("https://myURL.com/index.php");
URLConnection con = url.openConnection();
BufferedReader br = new BufferedReader(new InputStreamReader(con.getInputStream()));
String line;
while((line = br.readLine()) != null) {
System.out.println(line);
}
} catch (Exception e) {
}
}
Im stumped and any help would be much appreciated!
Java Solutions
Solution 1 - Java
In $JRE/lib/security/java.security
:
jdk.tls.disabledAlgorithms=SSLv3, TLSv1, RC4, DES, MD5withRSA, DH keySize < 1024, \
EC keySize < 224, 3DES_EDE_CBC, anon, NULL
This line is enabled, after I commented out this line, everything is working fine. Apparently after/in jre1.8.0_181 this line is enabled.
My Java version is "1.8.0_201.
Solution 2 - Java
I also run into this with the Java8 update 1.8.0.229 on Ubuntu 18.04.
I changed the following part:
# Example:
# jdk.tls.disabledAlgorithms=MD5, SSLv3, DSA, RSA keySize < 2048
#jdk.tls.disabledAlgorithms=SSLv3, TLSv1, TLSv1.1, RC4, DES, MD5withRSA, \
# DH keySize < 1024, EC keySize < 224, 3DES_EDE_CBC, anon, NULL, \
# include jdk.disabled.namedCurves
jdk.tls.disabledAlgorithms=SSLv3, RC4, DES, MD5withRSA, \
DH keySize < 1024, EC keySize < 224, 3DES_EDE_CBC, anon, NULL, \
include jdk.disabled.namedCurves
I removed TLSv1
and TLSv1.1
from the list of jdk.tls.disabledAlgorithms
inside the file
> /etc/java-8-openjdk/security/java.security
After checking this:
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 28
Server version: 5.7.33-0ubuntu0.18.04.1 (Ubuntu)
Copyright (c) 2000, 2021, Oracle and/or its affiliates.
Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
mysql> SHOW GLOBAL VARIABLES LIKE 'tls_version';
+---------------+-----------------------+
| Variable_name | Value |
+---------------+-----------------------+
| tls_version | TLSv1,TLSv1.1,TLSv1.2 |
+---------------+-----------------------+
1 row in set (0.00 sec)
mysql> exit
Solution 3 - Java
protocol is disabled or cipher suites are inappropriate
The key to the problem lies in that statement. What it basically means is either:
-
The TLS implementation used by the client does not support the cipher suites used by the server's certificate.
-
The TLS configuration on the server has disabled cipher suites supported by the client.
-
The TLS configurations on the client disable cipher suites offered by the server.
-
TLS version incompatibility between the client and server.
This leads to handshake failure in TLS, and the connection fails. Check one or all of the three scenarios above.
Solution 4 - Java
You can add the expected TLS protocol to your connection string like this:
jdbc:mysql://localhost:3306/database_name?enabledTLSProtocols=TLSv1.2
That fixed the problem for me.
Edit 04-02-2022:
As Yair's comment says:
> Since Connector/J 8.0.28 enabledTLSProtocols has been renamed to tlsVersions.
Solution 5 - Java
In my case I am runnig Centos 8 and had the same issue with Imap/Java. Had to update the system-wide cryptographic policy level.
update-crypto-policies --set LEGACY
- reboot machine.
Thats it.
Solution 6 - Java
We started experiencing this problem after upgrading to jre1.8.0_291. I commented out "jdk.tls.disabledAlgorithms=SSLv3, TLSv1, TLSv1.1, RC4, DES, MD5withRSA,
DH keySize < 1024, EC keySize < 224, 3DES_EDE_CBC, anon, NULL,
include jdk.disabled.namedCurves" in java.security located in C:\Program Files\Java\jre1.8.0_291\lib\security which resolved the problem.
Solution 7 - Java
> javax.net.ssl.SSLHandshakeException: No appropriate protocol (protocol is disabled or cipher suites are inappropriate)
For posterity, I recently bumped up against this using IBM's JDK8 implementation which specifically disables TLS1.1 and 1.2 by default (sic). If you want to see what TLS versions are supported by the JVM, run something like the following code:
SSLContext context = SSLContext.getInstance("TLS");
context.init(null, null, null);
String[] supportedProtocols = context.getDefaultSSLParameters().getProtocols();
System.out.println(Arrays.toString(supportedProtocols));
The code spits out [TLSv1]
by default under AIX JDK8. Not good. Under Redhat and Solaris it spits out [TLSv1, TLSv1.1, TLSv1.2]
.
I could not find any values in the java.security
file to fix this issue but there might be some for your architecture. In the IBM specific case, we have to add:
-Dcom.ibm.jsse2.overrideDefaultTLS=true
Solution 8 - Java
I have encountered
javax.net.ssl.SSLHandshakeException: No appropriate protocol (protocol is disabled or cipher suites are inappropriate)
error when accessing TLS 1.3 enabled endpoint from a Java 11 application. That is a usual case in GCP, for example.
The problem has gone away without any changes in my code just by upgrading from Java 11 to Java 14.
The Java 11 doesn't deprecate earlier TLS protocol versions by default. Instead of configuring it, simple upgrade of the runtime to Java 14 has helped.
Solution 9 - Java
In my case I had to upgrade the mysql client library to the latest version and it started working again:
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.24</version>
</dependency>
Solution 10 - Java
Apparently, if you have TLS 1.0 disabled the emails won't be sent out. TLS Versions 1.1 and 1.2 do not work. Peter's suggestion did the trick for me.
Solution 11 - Java
I was face with the same situation on a tomcat7 server, 5.7.34-0ubuntu0.18.04.1, openjdk version "1.8.0_292"
I tried many approaches like disabling SSL in the server.xml file, changing the connection strings etc etc
but in the end all i did was to edit the file java.security with sudo nano /usr/lib/jvm/java-8-openjdk-amd64/jre/lib/security/java.security
comment out and remove TLSv1 and TLSv1.1
# Comment the line below
#jdk.tls.disabledAlgorithms=SSLv3, TLSv1, TLSv1.1, RC4, DES, MD5withRSA, \
# DH keySize < 1024, EC keySize < 224, 3DES_EDE_CBC, anon, NULL, \
# include jdk.disabled.namedCurves
# your new line should read as beloew
jdk.tls.disabledAlgorithms=SSLv3, RC4, DES, MD5withRSA, \
DH keySize < 1024, EC keySize < 224, 3DES_EDE_CBC, anon, NULL, \
include jdk.disabled.namedCurves
Solution 12 - Java
For ME in this case :
javax.net.ssl.SSLHandshakeException: No appropriate protocol (protocol is disabled or cipher suites are inappropriate)
I found that this is JDK/JRE (Java\jdk1.8.0_291\jre\lib\security) config related, and in order to solve it you need to Disable the TLS anon and NULL cipher suites.
You can found how to do this in the oficial documentation here: https://www.java.com/en/configure_crypto.html
Also before doing this, consider the implications of using LEGACY algorithms.
Solution 13 - Java
upgraded from 1 to 2 + modifying the $JRE/lib/security/java.security file did the trick. before after mysql driver