SSLHandShakeException No Appropriate Protocol
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!
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.
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
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.