Popular Posts
javax.net.ssl.SSLHandshakeException: Connection closed by peer in Android 5.0 Lollipop Recently, there is a error occurs when access website via ssl connection like below although it worked fine several days ago. // Enable SSL... Enable SSL connection for Jsoup import org.jsoup.Connection; import org.jsoup.Jsoup; import javax.net.ssl.*; import java.io.IOException; import java.security.KeyManagement... Copy/Delete/Permission directory using System; using System.IO; using System.Security.AccessControl; namespace Bruce.Lib {     public class DirHelper     {         /// <...
Stats
javax.net.ssl.SSLHandshakeException: Connection closed by peer in Android 5.0 Lollipop

Recently, there is a error occurs when access website via ssl connection like below although it worked fine several days ago.

  1. // Enable SSL connection
  2. HttpsURLConnection.setDefaultSSLSocketFactory(new MySocketFactory1());
  3. HttpsURLConnection.setDefaultHostnameVerifier(new HostnameVerifier() {
  4. public boolean verify(String hostname, SSLSession session) {
  5. return true;
  6. }
  7. });
  8.  
  9. URL address = new URL(url);
  10. HttpsURLConnection urlConnection = (HttpsURLConnection) address.openConnection();
  11. InputStream in = urlConnection.getInputStream();
  12. ByteArrayOutputStream baos = new ByteArrayOutputStream();
  13. byte[] buffer = new byte[128];
  14. int len = 0;
  15. while ((len = in.read(buffer)) > 0) {
  16. baos.write(buffer, 0, len);
  17. }
  18. baos.close();
  19. in.close();
MySocketFactory1.java
  1. package com.prhythm.google.myapplication2.app;
  2.  
  3. import javax.net.ssl.SSLContext;
  4. import javax.net.ssl.SSLSocketFactory;
  5. import javax.net.ssl.X509TrustManager;
  6. import java.io.IOException;
  7. import java.net.InetAddress;
  8. import java.net.Socket;
  9. import java.net.UnknownHostException;
  10. import java.security.KeyManagementException;
  11. import java.security.NoSuchAlgorithmException;
  12. import java.security.SecureRandom;
  13. import java.security.cert.CertificateException;
  14. import java.security.cert.X509Certificate;
  15.  
  16. /**
  17. * Created by nanashi07 on 15/5/23.
  18. */
  19. public class MySocketFactory1 extends SSLSocketFactory {
  20.  
  21. SSLContext context;
  22. SSLSocketFactory factory;
  23.  
  24. public MySocketFactory1() {
  25. try {
  26. init();
  27. } catch (KeyManagementException e) {
  28. e.printStackTrace();
  29. } catch (NoSuchAlgorithmException e) {
  30. e.printStackTrace();
  31. }
  32. }
  33.  
  34. void init() throws KeyManagementException, NoSuchAlgorithmException {
  35. context = SSLContext.getInstance("SSL");
  36. context.init(null, new X509TrustManager[]{new X509TrustManager() {
  37. public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
  38. }
  39.  
  40. public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
  41. }
  42.  
  43. public X509Certificate[] getAcceptedIssuers() {
  44. return new X509Certificate[0];
  45. }
  46. }}, new SecureRandom());
  47. factory = context.getSocketFactory();
  48. }
  49.  
  50. @Override
  51. public String[] getDefaultCipherSuites() {
  52. return factory.getDefaultCipherSuites();
  53. }
  54.  
  55. @Override
  56. public String[] getSupportedCipherSuites() {
  57. return factory.getSupportedCipherSuites();
  58. }
  59.  
  60. @Override
  61. public Socket createSocket(Socket s, String host, int port, boolean autoClose) throws IOException {
  62. return factory.createSocket(s, host, port, autoClose);
  63. }
  64.  
  65. @Override
  66. public Socket createSocket(String host, int port) throws IOException, UnknownHostException {
  67. return factory.createSocket(host, port);
  68. }
  69.  
  70. @Override
  71. public Socket createSocket(String host, int port, InetAddress localHost, int localPort) throws IOException, UnknownHostException {
  72. return factory.createSocket(host, port, localHost, localPort);
  73. }
  74.  
  75. @Override
  76. public Socket createSocket(InetAddress host, int port) throws IOException {
  77. return factory.createSocket(host, port);
  78. }
  79.  
  80. @Override
  81. public Socket createSocket(InetAddress address, int port, InetAddress localAddress, int localPort) throws IOException {
  82. return factory.createSocket(address, port, localAddress, localPort);
  83. }
  84. }
javax.net.ssl.SSLHandshakeException: Connection closed by peer
  1. 05-24 07:54:11.626 1697-1716/com.prhythm.google.myapplication2.app E/Test error
  2. javax.net.ssl.SSLHandshakeException: Connection closed by peer
  3. at com.android.org.conscrypt.NativeCrypto.SSL_do_handshake(Native Method)
  4. at com.android.org.conscrypt.OpenSSLSocketImpl.startHandshake(OpenSSLSocketImpl.java:302)
  5. at com.android.okhttp.Connection.upgradeToTls(Connection.java:197)
  6. at com.android.okhttp.Connection.connect(Connection.java:151)
  7. at com.android.okhttp.internal.http.HttpEngine.connect(HttpEngine.java:276)
  8. at com.android.okhttp.internal.http.HttpEngine.sendRequest(HttpEngine.java:211)
  9. at com.android.okhttp.internal.http.HttpURLConnectionImpl.execute(HttpURLConnectionImpl.java:373)
  10. at com.android.okhttp.internal.http.HttpURLConnectionImpl.getResponse(HttpURLConnectionImpl.java:323)
  11. at com.android.okhttp.internal.http.HttpURLConnectionImpl.getInputStream(HttpURLConnectionImpl.java:190)
  12. at com.android.okhttp.internal.http.DelegatingHttpsURLConnection.getInputStream(DelegatingHttpsURLConnection.java:210)
  13. at com.android.okhttp.internal.http.HttpsURLConnectionImpl.getInputStream(HttpsURLConnectionImpl.java:25)
  14. at com.prhythm.google.myapplication2.app.MainActivity$1.doInBackground(MainActivity.java:41)
  15. at com.prhythm.google.myapplication2.app.MainActivity$1.doInBackground(MainActivity.java:26)
  16. at android.os.AsyncTask$2.call(AsyncTask.java:288)
  17. at java.util.concurrent.FutureTask.run(FutureTask.java:237)
  18. at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:231)
  19. at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112)
  20. at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587)
  21. 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
  1. package com.prhythm.google.myapplication2.app;
  2.  
  3. import com.prhythm.core.generic.util.Cube;
  4.  
  5. import javax.net.ssl.*;
  6. import java.io.IOException;
  7. import java.net.InetAddress;
  8. import java.net.Socket;
  9. import java.net.UnknownHostException;
  10. import java.security.KeyManagementException;
  11. import java.security.NoSuchAlgorithmException;
  12. import java.security.SecureRandom;
  13. import java.security.cert.CertificateException;
  14. import java.security.cert.X509Certificate;
  15. import java.util.Arrays;
  16. import java.util.Set;
  17.  
  18. /**
  19.  * Created by nanashi07 on 15/5/23.
  20.  */
  21. public class MySocketFactory2 extends SSLSocketFactory {
  22.  
  23.     SSLContext context;
  24.     SSLSocketFactory factory;
  25.     String type;
  26.  
  27.     public MySocketFactory2() {
  28.         try {
  29.             init();
  30.         } catch (KeyManagementException e) {
  31.             e.printStackTrace();
  32.         } catch (NoSuchAlgorithmException e) {
  33.             e.printStackTrace();
  34.         }
  35.     }
  36.  
  37.     void init() throws KeyManagementException, NoSuchAlgorithmException {
  38.         context = SSLContext.getInstance(type = Cube.from("SSL", "TLS").random());
  39.         context.init(null, new TrustManager[]{new X509TrustManager() {
  40.             public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
  41.                 System.out.printf("[CLIENT] chain = %s, authType = %s%n", Arrays.toString(chain), authType);
  42.             }
  43.  
  44.             public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
  45.                 System.out.printf("[SERVER] chain = %s, authType = %s%n", Arrays.toString(chain), authType);
  46.             }
  47.  
  48.             public X509Certificate[] getAcceptedIssuers() {
  49.                 return new X509Certificate[0];
  50.             }
  51.         }}, new SecureRandom());
  52.         factory = context.getSocketFactory();
  53.     }
  54.  
  55.     @Override
  56.     public String[] getDefaultCipherSuites() {
  57.         return getCipherSuites().toArray(String.class);
  58.     }
  59.  
  60.     @Override
  61.     public String[] getSupportedCipherSuites() {
  62.         return getCipherSuites().toArray(String.class);
  63.     }
  64.  
  65.     @Override
  66.     public Socket createSocket(Socket s, String host, int port, boolean autoClose) throws IOException {
  67.         return configCipherSuites(factory.createSocket(s, host, port, autoClose));
  68.     }
  69.  
  70.     @Override
  71.     public Socket createSocket(String host, int port) throws IOException, UnknownHostException {
  72.         return configCipherSuites(factory.createSocket(host, port));
  73.     }
  74.  
  75.     @Override
  76.     public Socket createSocket(String host, int port, InetAddress localHost, int localPort) throws IOException, UnknownHostException {
  77.         return configCipherSuites(factory.createSocket(host, port, localHost, localPort));
  78.     }
  79.  
  80.     @Override
  81.     public Socket createSocket(InetAddress host, int port) throws IOException {
  82.         return configCipherSuites(factory.createSocket(host, port));
  83.     }
  84.  
  85.     @Override
  86.     public Socket createSocket(InetAddress address, int port, InetAddress localAddress, int localPort) throws IOException {
  87.         return configCipherSuites(factory.createSocket(address, port, localAddress, localPort));
  88.     }
  89.  
  90.     Cube<String> getCipherSuites() {
  91.         return Cube.from("SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA",
  92.                 "SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA",
  93.                 "SSL_DHE_DSS_WITH_DES_CBC_SHA",
  94.                 "SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA",
  95.                 "SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA",
  96.                 "SSL_DHE_RSA_WITH_DES_CBC_SHA",
  97.                 "SSL_DH_anon_EXPORT_WITH_DES40_CBC_SHA",
  98.                 "SSL_DH_anon_EXPORT_WITH_RC4_40_MD5",
  99.                 "SSL_DH_anon_WITH_3DES_EDE_CBC_SHA",
  100.                 "SSL_DH_anon_WITH_DES_CBC_SHA",
  101.                 "SSL_DH_anon_WITH_RC4_128_MD5",
  102.                 "SSL_RSA_EXPORT_WITH_DES40_CBC_SHA",
  103.                 "SSL_RSA_EXPORT_WITH_RC4_40_MD5",
  104.                 "SSL_RSA_WITH_3DES_EDE_CBC_SHA",
  105.                 "SSL_RSA_WITH_DES_CBC_SHA",
  106.                 "SSL_RSA_WITH_NULL_MD5",
  107.                 "SSL_RSA_WITH_NULL_SHA",
  108.                 "SSL_RSA_WITH_RC4_128_MD5",
  109.                 "SSL_RSA_WITH_RC4_128_SHA",
  110.                 "TLS_DHE_DSS_WITH_AES_128_CBC_SHA",
  111.                 "TLS_DHE_DSS_WITH_AES_128_CBC_SHA256",
  112.                 "TLS_DHE_DSS_WITH_AES_128_GCM_SHA256",
  113.                 "TLS_DHE_DSS_WITH_AES_256_CBC_SHA",
  114.                 "TLS_DHE_DSS_WITH_AES_256_CBC_SHA256",
  115.                 "TLS_DHE_DSS_WITH_AES_256_GCM_SHA384",
  116.                 "TLS_DHE_RSA_WITH_AES_128_CBC_SHA",
  117.                 "TLS_DHE_RSA_WITH_AES_128_CBC_SHA256",
  118.                 "TLS_DHE_RSA_WITH_AES_128_GCM_SHA256",
  119.                 "TLS_DHE_RSA_WITH_AES_256_CBC_SHA",
  120.                 "TLS_DHE_RSA_WITH_AES_256_CBC_SHA256",
  121.                 "TLS_DHE_RSA_WITH_AES_256_GCM_SHA384",
  122.                 "TLS_DH_anon_WITH_AES_128_CBC_SHA",
  123.                 "TLS_DH_anon_WITH_AES_128_CBC_SHA256",
  124.                 "TLS_DH_anon_WITH_AES_128_GCM_SHA256",
  125.                 "TLS_DH_anon_WITH_AES_256_CBC_SHA",
  126.                 "TLS_DH_anon_WITH_AES_256_CBC_SHA256",
  127.                 "TLS_DH_anon_WITH_AES_256_GCM_SHA384",
  128.                 "TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA",
  129.                 "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA",
  130.                 "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256",
  131.                 "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256",
  132.                 "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA",
  133.                 "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384",
  134.                 "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384",
  135.                 "TLS_ECDHE_ECDSA_WITH_NULL_SHA",
  136.                 "TLS_ECDHE_ECDSA_WITH_RC4_128_SHA",
  137.                 "TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA",
  138.                 "TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA",
  139.                 "TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA",
  140.                 "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA",
  141.                 "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256",
  142.                 "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
  143.                 "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA",
  144.                 "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384",
  145.                 "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384",
  146.                 "TLS_ECDHE_RSA_WITH_NULL_SHA",
  147.                 "TLS_ECDHE_RSA_WITH_RC4_128_SHA",
  148.                 "TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA",
  149.                 "TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA",
  150.                 "TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256",
  151.                 "TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256",
  152.                 "TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA",
  153.                 "TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384",
  154.                 "TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384",
  155.                 "TLS_ECDH_ECDSA_WITH_NULL_SHA",
  156.                 "TLS_ECDH_ECDSA_WITH_RC4_128_SHA",
  157.                 "TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA",
  158.                 "TLS_ECDH_RSA_WITH_AES_128_CBC_SHA",
  159.                 "TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256",
  160.                 "TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256",
  161.                 "TLS_ECDH_RSA_WITH_AES_256_CBC_SHA",
  162.                 "TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384",
  163.                 "TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384",
  164.                 "TLS_ECDH_RSA_WITH_NULL_SHA",
  165.                 "TLS_ECDH_RSA_WITH_RC4_128_SHA",
  166.                 "TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA",
  167.                 "TLS_ECDH_anon_WITH_AES_128_CBC_SHA",
  168.                 "TLS_ECDH_anon_WITH_AES_256_CBC_SHA",
  169.                 "TLS_ECDH_anon_WITH_NULL_SHA",
  170.                 "TLS_ECDH_anon_WITH_RC4_128_SHA",
  171.                 "TLS_EMPTY_RENEGOTIATION_INFO_SCSV",
  172.                 "TLS_FALLBACK_SCSV",
  173.                 "TLS_PSK_WITH_3DES_EDE_CBC_SHA",
  174.                 "TLS_PSK_WITH_AES_128_CBC_SHA",
  175.                 "TLS_PSK_WITH_AES_256_CBC_SHA",
  176.                 "TLS_PSK_WITH_RC4_128_SHA",
  177.                 "TLS_RSA_WITH_AES_128_CBC_SHA",
  178.                 "TLS_RSA_WITH_AES_128_CBC_SHA256",
  179.                 "TLS_RSA_WITH_AES_128_GCM_SHA256",
  180.                 "TLS_RSA_WITH_AES_256_CBC_SHA",
  181.                 "TLS_RSA_WITH_AES_256_CBC_SHA256",
  182.                 "TLS_RSA_WITH_AES_256_GCM_SHA384",
  183.                 "TLS_RSA_WITH_NULL_SHA256")
  184.                 .where(new Cube.Selection<String>() {
  185.                     @Override
  186.                     public boolean predicate(String item, int index) {
  187.                         return item.startsWith(type);
  188.                     }
  189.                 });
  190.     }
  191.  
  192.     Socket configCipherSuites(Socket socket) {
  193.         if (!(socket instanceof SSLSocket)) return socket;
  194.         SSLSocket sslsocket = (SSLSocket) socket;
  195.         // 處理不合的cipher suite
  196.         Set<String> suites = getCipherSuites().toSet();
  197.         while (suites.size() > 0) {
  198.             try {
  199.                 sslsocket.setEnabledCipherSuites(suites.toArray(new String[suites.size()]));
  200.                 break;
  201.             } catch (Throwable e) {
  202.                 String message = e.getMessage();
  203.                 for (String cipher : suites) {
  204.                     if (message.toLowerCase().contains(cipher.toLowerCase())) {
  205.                         suites.remove(cipher);
  206.                         System.out.printf("Cipher suite %s has been removed.%n", cipher);
  207.                         break;
  208.                     }
  209.                 }
  210.             }
  211.         }
  212.         return socket;
  213.     }
  214. }