Recently, there is a error occurs when access website via ssl connection like below although it worked fine several days ago.
- // Enable SSL connection
- HttpsURLConnection.setDefaultSSLSocketFactory(new MySocketFactory1());
- HttpsURLConnection.setDefaultHostnameVerifier(new HostnameVerifier() {
- public boolean verify(String hostname, SSLSession session) {
- return true;
- }
- });
-
- URL address = new URL(url);
- HttpsURLConnection urlConnection = (HttpsURLConnection) address.openConnection();
- InputStream in = urlConnection.getInputStream();
- ByteArrayOutputStream baos = new ByteArrayOutputStream();
- byte[] buffer = new byte[128];
- int len = 0;
- while ((len = in.read(buffer)) > 0) {
- baos.write(buffer, 0, len);
- }
- baos.close();
- in.close();
MySocketFactory1.java
- package com.prhythm.google.myapplication2.app;
-
- import javax.net.ssl.SSLContext;
- import javax.net.ssl.SSLSocketFactory;
- import javax.net.ssl.X509TrustManager;
- import java.io.IOException;
- import java.net.InetAddress;
- import java.net.Socket;
- import java.net.UnknownHostException;
- import java.security.KeyManagementException;
- import java.security.NoSuchAlgorithmException;
- import java.security.SecureRandom;
- import java.security.cert.CertificateException;
- import java.security.cert.X509Certificate;
-
- /**
- * Created by nanashi07 on 15/5/23.
- */
- public class MySocketFactory1 extends SSLSocketFactory {
-
- SSLContext context;
- SSLSocketFactory factory;
-
- public MySocketFactory1() {
- try {
- init();
- } catch (KeyManagementException e) {
- e.printStackTrace();
- } catch (NoSuchAlgorithmException e) {
- e.printStackTrace();
- }
- }
-
- void init() throws KeyManagementException, NoSuchAlgorithmException {
- context = SSLContext.getInstance("SSL");
- context.init(null, new X509TrustManager[]{new X509TrustManager() {
- public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
- }
-
- public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
- }
-
- public X509Certificate[] getAcceptedIssuers() {
- return new X509Certificate[0];
- }
- }}, new SecureRandom());
- factory = context.getSocketFactory();
- }
-
- @Override
- public String[] getDefaultCipherSuites() {
- return factory.getDefaultCipherSuites();
- }
-
- @Override
- public String[] getSupportedCipherSuites() {
- return factory.getSupportedCipherSuites();
- }
-
- @Override
- public Socket createSocket(Socket s, String host, int port, boolean autoClose) throws IOException {
- return factory.createSocket(s, host, port, autoClose);
- }
-
- @Override
- public Socket createSocket(String host, int port) throws IOException, UnknownHostException {
- return factory.createSocket(host, port);
- }
-
- @Override
- public Socket createSocket(String host, int port, InetAddress localHost, int localPort) throws IOException, UnknownHostException {
- return factory.createSocket(host, port, localHost, localPort);
- }
-
- @Override
- public Socket createSocket(InetAddress host, int port) throws IOException {
- return factory.createSocket(host, port);
- }
-
- @Override
- public Socket createSocket(InetAddress address, int port, InetAddress localAddress, int localPort) throws IOException {
- return factory.createSocket(address, port, localAddress, localPort);
- }
- }
javax.net.ssl.SSLHandshakeException: Connection closed by peer
- 05-24 07:54:11.626 1697-1716/com.prhythm.google.myapplication2.app E/Test﹕ error
- javax.net.ssl.SSLHandshakeException: Connection closed by peer
- at com.android.org.conscrypt.NativeCrypto.SSL_do_handshake(Native Method)
- at com.android.org.conscrypt.OpenSSLSocketImpl.startHandshake(OpenSSLSocketImpl.java:302)
- at com.android.okhttp.Connection.upgradeToTls(Connection.java:197)
- at com.android.okhttp.Connection.connect(Connection.java:151)
- at com.android.okhttp.internal.http.HttpEngine.connect(HttpEngine.java:276)
- at com.android.okhttp.internal.http.HttpEngine.sendRequest(HttpEngine.java:211)
- at com.android.okhttp.internal.http.HttpURLConnectionImpl.execute(HttpURLConnectionImpl.java:373)
- at com.android.okhttp.internal.http.HttpURLConnectionImpl.getResponse(HttpURLConnectionImpl.java:323)
- at com.android.okhttp.internal.http.HttpURLConnectionImpl.getInputStream(HttpURLConnectionImpl.java:190)
- at com.android.okhttp.internal.http.DelegatingHttpsURLConnection.getInputStream(DelegatingHttpsURLConnection.java:210)
- at com.android.okhttp.internal.http.HttpsURLConnectionImpl.getInputStream(HttpsURLConnectionImpl.java:25)
- at com.prhythm.google.myapplication2.app.MainActivity$1.doInBackground(MainActivity.java:41)
- at com.prhythm.google.myapplication2.app.MainActivity$1.doInBackground(MainActivity.java:26)
- at android.os.AsyncTask$2.call(AsyncTask.java:288)
- at java.util.concurrent.FutureTask.run(FutureTask.java:237)
- at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:231)
- at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112)
- at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587)
- at java.lang.Thread.run(Thread.java:818)
After track and search from some technical articles, I found this TLS/SSL Default Configuration Changes, finally. Base on this, I've made some changes for my SSLSocketFactory to add cipher suites setting. Now it works fine again.
MySocketFactory2.java
- package com.prhythm.google.myapplication2.app;
-
- import com.prhythm.core.generic.util.Cube;
-
- import javax.net.ssl.*;
- import java.io.IOException;
- import java.net.InetAddress;
- import java.net.Socket;
- import java.net.UnknownHostException;
- import java.security.KeyManagementException;
- import java.security.NoSuchAlgorithmException;
- import java.security.SecureRandom;
- import java.security.cert.CertificateException;
- import java.security.cert.X509Certificate;
- import java.util.Arrays;
- import java.util.Set;
-
- /**
- * Created by nanashi07 on 15/5/23.
- */
- public class MySocketFactory2 extends SSLSocketFactory {
-
- SSLContext context;
- SSLSocketFactory factory;
- String type;
-
- public MySocketFactory2() {
- try {
- init();
- } catch (KeyManagementException e) {
- e.printStackTrace();
- } catch (NoSuchAlgorithmException e) {
- e.printStackTrace();
- }
- }
-
- void init() throws KeyManagementException, NoSuchAlgorithmException {
- context = SSLContext.getInstance(type = Cube.from("SSL", "TLS").random());
- context.init(null, new TrustManager[]{new X509TrustManager() {
- public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
- System.out.printf("[CLIENT] chain = %s, authType = %s%n", Arrays.toString(chain), authType);
- }
-
- public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
- System.out.printf("[SERVER] chain = %s, authType = %s%n", Arrays.toString(chain), authType);
- }
-
- public X509Certificate[] getAcceptedIssuers() {
- return new X509Certificate[0];
- }
- }}, new SecureRandom());
- factory = context.getSocketFactory();
- }
-
- @Override
- public String[] getDefaultCipherSuites() {
- return getCipherSuites().toArray(String.class);
- }
-
- @Override
- public String[] getSupportedCipherSuites() {
- return getCipherSuites().toArray(String.class);
- }
-
- @Override
- public Socket createSocket(Socket s, String host, int port, boolean autoClose) throws IOException {
- return configCipherSuites(factory.createSocket(s, host, port, autoClose));
- }
-
- @Override
- public Socket createSocket(String host, int port) throws IOException, UnknownHostException {
- return configCipherSuites(factory.createSocket(host, port));
- }
-
- @Override
- public Socket createSocket(String host, int port, InetAddress localHost, int localPort) throws IOException, UnknownHostException {
- return configCipherSuites(factory.createSocket(host, port, localHost, localPort));
- }
-
- @Override
- public Socket createSocket(InetAddress host, int port) throws IOException {
- return configCipherSuites(factory.createSocket(host, port));
- }
-
- @Override
- public Socket createSocket(InetAddress address, int port, InetAddress localAddress, int localPort) throws IOException {
- return configCipherSuites(factory.createSocket(address, port, localAddress, localPort));
- }
-
- Cube<String> getCipherSuites() {
- return Cube.from("SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA",
- "SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA",
- "SSL_DHE_DSS_WITH_DES_CBC_SHA",
- "SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA",
- "SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA",
- "SSL_DHE_RSA_WITH_DES_CBC_SHA",
- "SSL_DH_anon_EXPORT_WITH_DES40_CBC_SHA",
- "SSL_DH_anon_EXPORT_WITH_RC4_40_MD5",
- "SSL_DH_anon_WITH_3DES_EDE_CBC_SHA",
- "SSL_DH_anon_WITH_DES_CBC_SHA",
- "SSL_DH_anon_WITH_RC4_128_MD5",
- "SSL_RSA_EXPORT_WITH_DES40_CBC_SHA",
- "SSL_RSA_EXPORT_WITH_RC4_40_MD5",
- "SSL_RSA_WITH_3DES_EDE_CBC_SHA",
- "SSL_RSA_WITH_DES_CBC_SHA",
- "SSL_RSA_WITH_NULL_MD5",
- "SSL_RSA_WITH_NULL_SHA",
- "SSL_RSA_WITH_RC4_128_MD5",
- "SSL_RSA_WITH_RC4_128_SHA",
- "TLS_DHE_DSS_WITH_AES_128_CBC_SHA",
- "TLS_DHE_DSS_WITH_AES_128_CBC_SHA256",
- "TLS_DHE_DSS_WITH_AES_128_GCM_SHA256",
- "TLS_DHE_DSS_WITH_AES_256_CBC_SHA",
- "TLS_DHE_DSS_WITH_AES_256_CBC_SHA256",
- "TLS_DHE_DSS_WITH_AES_256_GCM_SHA384",
- "TLS_DHE_RSA_WITH_AES_128_CBC_SHA",
- "TLS_DHE_RSA_WITH_AES_128_CBC_SHA256",
- "TLS_DHE_RSA_WITH_AES_128_GCM_SHA256",
- "TLS_DHE_RSA_WITH_AES_256_CBC_SHA",
- "TLS_DHE_RSA_WITH_AES_256_CBC_SHA256",
- "TLS_DHE_RSA_WITH_AES_256_GCM_SHA384",
- "TLS_DH_anon_WITH_AES_128_CBC_SHA",
- "TLS_DH_anon_WITH_AES_128_CBC_SHA256",
- "TLS_DH_anon_WITH_AES_128_GCM_SHA256",
- "TLS_DH_anon_WITH_AES_256_CBC_SHA",
- "TLS_DH_anon_WITH_AES_256_CBC_SHA256",
- "TLS_DH_anon_WITH_AES_256_GCM_SHA384",
- "TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA",
- "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA",
- "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256",
- "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256",
- "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA",
- "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384",
- "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384",
- "TLS_ECDHE_ECDSA_WITH_NULL_SHA",
- "TLS_ECDHE_ECDSA_WITH_RC4_128_SHA",
- "TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA",
- "TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA",
- "TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA",
- "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA",
- "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256",
- "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
- "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA",
- "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384",
- "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384",
- "TLS_ECDHE_RSA_WITH_NULL_SHA",
- "TLS_ECDHE_RSA_WITH_RC4_128_SHA",
- "TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA",
- "TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA",
- "TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256",
- "TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256",
- "TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA",
- "TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384",
- "TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384",
- "TLS_ECDH_ECDSA_WITH_NULL_SHA",
- "TLS_ECDH_ECDSA_WITH_RC4_128_SHA",
- "TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA",
- "TLS_ECDH_RSA_WITH_AES_128_CBC_SHA",
- "TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256",
- "TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256",
- "TLS_ECDH_RSA_WITH_AES_256_CBC_SHA",
- "TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384",
- "TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384",
- "TLS_ECDH_RSA_WITH_NULL_SHA",
- "TLS_ECDH_RSA_WITH_RC4_128_SHA",
- "TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA",
- "TLS_ECDH_anon_WITH_AES_128_CBC_SHA",
- "TLS_ECDH_anon_WITH_AES_256_CBC_SHA",
- "TLS_ECDH_anon_WITH_NULL_SHA",
- "TLS_ECDH_anon_WITH_RC4_128_SHA",
- "TLS_EMPTY_RENEGOTIATION_INFO_SCSV",
- "TLS_FALLBACK_SCSV",
- "TLS_PSK_WITH_3DES_EDE_CBC_SHA",
- "TLS_PSK_WITH_AES_128_CBC_SHA",
- "TLS_PSK_WITH_AES_256_CBC_SHA",
- "TLS_PSK_WITH_RC4_128_SHA",
- "TLS_RSA_WITH_AES_128_CBC_SHA",
- "TLS_RSA_WITH_AES_128_CBC_SHA256",
- "TLS_RSA_WITH_AES_128_GCM_SHA256",
- "TLS_RSA_WITH_AES_256_CBC_SHA",
- "TLS_RSA_WITH_AES_256_CBC_SHA256",
- "TLS_RSA_WITH_AES_256_GCM_SHA384",
- "TLS_RSA_WITH_NULL_SHA256")
- .where(new Cube.Selection<String>() {
- @Override
- public boolean predicate(String item, int index) {
- return item.startsWith(type);
- }
- });
- }
-
- Socket configCipherSuites(Socket socket) {
- if (!(socket instanceof SSLSocket)) return socket;
- SSLSocket sslsocket = (SSLSocket) socket;
- // 處理不合的cipher suite
- Set<String> suites = getCipherSuites().toSet();
- while (suites.size() > 0) {
- try {
- sslsocket.setEnabledCipherSuites(suites.toArray(new String[suites.size()]));
- break;
- } catch (Throwable e) {
- String message = e.getMessage();
- for (String cipher : suites) {
- if (message.toLowerCase().contains(cipher.toLowerCase())) {
- suites.remove(cipher);
- System.out.printf("Cipher suite %s has been removed.%n", cipher);
- break;
- }
- }
- }
- }
- return socket;
- }
- }