Conexión de Https con conexión cerrada por peer en Android 6.0

Tengo un problema con la comunicación a través de SSL (TSL) entre el dispositivo Android (Samsung Galaxy con Android 6.0) y Simple Java App que está usando com.sun.net.httpserver.HttpsServer. Tengo que decir que en otro dispositivo con Android 4.4 todo funciona bien.

Cuando Android 6.0 intenta hacer apretón de manos, el lado del servidor termina la comunicación, en android a see below stacktrace

W/System.err: javax.net.ssl.SSLHandshakeException: Connection closed by peer W/System.err: at com.android.org.conscrypt.NativeCrypto.SSL_do_handshake(Native Method) W/System.err: at com.android.org.conscrypt.OpenSSLSocketImpl.startHandshake(OpenSSLSocketImpl.java:353) W/System.err: at com.android.okhttp.internal.http.SocketConnector.connectTls(SocketConnector.java:212) W/System.err: at com.android.okhttp.Connection.connect(Connection.java:1322) W/System.err: at com.android.okhttp.Connection.connectAndSetOwner(Connection.java:1410) W/System.err: at com.android.okhttp.OkHttpClient$1.connectAndSetOwner(OkHttpClient.java:128) W/System.err: at com.android.okhttp.internal.http.HttpEngine.nextConnection(HttpEngine.java:466) W/System.err: at com.android.okhttp.internal.http.HttpEngine.connect(HttpEngine.java:447) W/System.err: at com.android.okhttp.internal.http.HttpEngine.sendRequest(HttpEngine.java:353) W/System.err: at com.android.okhttp.internal.huc.HttpURLConnectionImpl.execute(HttpURLConnectionImpl.java:468) 08-28 06:47:21.322 3676-5603/pl.com.szb.gateopener W/System.err: at com.android.okhttp.internal.huc.HttpURLConnectionImpl.connect(HttpURLConnectionImpl.java:118) 08-28 06:47:21.322 3676-5603/pl.com.szb.gateopener W/System.err: at com.android.okhttp.internal.huc.HttpURLConnectionImpl.getOutputStream(HttpURLConnectionImpl.java:249) W/System.err: at com.android.okhttp.internal.huc.DelegatingHttpsURLConnection.getOutputStream(DelegatingHttpsURLConnection.java:218) W/System.err: at com.android.okhttp.internal.huc.HttpsURLConnectionImpl.getOutputStream(HttpsURLConnectionImpl.java:25) W/System.err: at org.ksoap2.transport.HttpsServiceConnectionSE.openOutputStream(HttpsServiceConnectionSE.java:127) W/System.err: at org.ksoap2.transport.HttpTransportSE.sendData(HttpTransportSE.java:292) W/System.err: at org.ksoap2.transport.HttpTransportSE.call(HttpTransportSE.java:184) W/System.err: at org.ksoap2.transport.HttpTransportSE.call(HttpTransportSE.java:118) W/System.err: at pl.com.szb.gateopener.client.PSBGOImplPortBinding.sendRequest(PSBGOImplPortBinding.java:99) W/System.err: at pl.com.szb.gateopener.client.PSBGOImplPortBinding.execute(PSBGOImplPortBinding.java:284) W/System.err: at pl.com.szb.gateopener.client.PSBGOImplPortBinding.getGates(PSBGOImplPortBinding.java:142) W/System.err: at pl.com.szb.gateopener.client.PSBGOImplPortBinding$2.Func(PSBGOImplPortBinding.java:165) W/System.err: at pl.com.szb.gateopener.client.PSBGOImplPortBinding$2.Func(PSBGOImplPortBinding.java:163) W/System.err: at pl.com.szb.gateopener.client.PSBGOImplPortBinding$7.doInBackground(PSBGOImplPortBinding.java:318) W/System.err: at pl.com.szb.gateopener.client.PSBGOImplPortBinding$7.doInBackground(PSBGOImplPortBinding.java:308) W/System.err: at android.os.AsyncTask$2.call(AsyncTask.java:295) W/System.err: at java.util.concurrent.FutureTask.run(FutureTask.java:237) W/System.err: at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:234) W/System.err: at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1113) W/System.err: at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:588) W/System.err: at java.lang.Thread.run(Thread.java:818) 

Código de Android para la iniciación de SSL

  `private void initSSL() throws Exception { Log.d(TAG,"initSSL"); TrustManager tm = new CustomX509TrustManager(); SSLContext customSSLContext = SSLContext.getInstance("TLSv1.1"); customSSLContext.init(null , new TrustManager[] { tm } , null); sslSocketFactory = customSSLContext.getSocketFactory(); HttpsURLConnection.setDefaultSSLSocketFactory(sslSocketFactory); HostnameVerifier hv = new HostnameVerifier() { public boolean verify(String hostname, SSLSession session) { Log.d(TAG, String.format("Verifying %s , sessionId: %s", hostname, Arrays.toString(session.getId()))); return true; } }; HttpsURLConnection.setDefaultHostnameVerifier(hv); } public class CustomX509TrustManager implements X509TrustManager { private String TAG = "CustomX509TrustManager"; @Override public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException { Log.d(TAG, "checkClientTrusted"); } @Override public void checkServerTrusted(java.security.cert.X509Certificate[] certs, String authType) throws CertificateException { Log.d(TAG, "checkServerTrusted"); // Here you can verify the servers certificate. (eg against one which is stored on mobile device) InputStream inStream = null; try { inStream = getResources().openRawResource(R.raw.goserver_10y); CertificateFactory cf = CertificateFactory.getInstance("X.509"); X509Certificate ca = (X509Certificate) cf.generateCertificate(inStream); inStream.close(); for (X509Certificate cert : certs) { // Verifing by public key cert.verify(ca.getPublicKey()); } } catch (Exception e) { Log.w(TAG, e.getMessage()); throw new CertificateException(e); } finally { try { inStream.close(); } catch (IOException e) { e.printStackTrace(); } } } public X509Certificate[] getAcceptedIssuers() { Log.d(TAG, "getAcceptedIssuers"); return null; } }` 

Y un código de servidor:

 `private void initServer() throws Exception{ Config config = getContext().system().settings().config(); host = getConfigString("pl.com.szb.GOImpl.host", config, "0.0.0.0"); port = getConfigInt("port", config, 10000); useSSL = getConfigBoolean("use_ssl", config, true); endpointLocation = getConfigString("endpointLocation", config, "/go"); String fullURL = String.format("%s://%s:%d%s",(useSSL ? "https" : "http"), host, port, endpointLocation); log.info(String.format("WSDL : %s?wsdl", fullURL)); if (useSSL) { keystorePass = getConfigString("keystorePass", config, "secret"); keystoreName = getConfigString("keystoreName", config, "second/server.bks"); char[] pass = keystorePass.toCharArray(); ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); InputStream is = classLoader.getResourceAsStream(keystoreName); KeyStore ks = KeyStore.getInstance("BKS"); ks.load(is, pass); KeyManagerFactory kmf = KeyManagerFactory.getInstance("PKIX"); kmf.init(ks, pass); SSLContext sslContext = SSLContext.getInstance("TLSv1.2"); sslContext.init(kmf.getKeyManagers(), null, null); server = HttpsServer.create(new InetSocketAddress(host, port), 0); ((HttpsServer)server).setHttpsConfigurator(new HttpsConfigurator(sslContext) { public void configure(HttpsParameters params) { try { log.debug(String.format("Got client: %s, wantAuth: %b, needAuth: %b", params.getClientAddress().toString(), params.getWantClientAuth(), params.getNeedClientAuth() )); params.setWantClientAuth(false); params.setNeedClientAuth(false); //what to do more?? } catch (Exception ex) { log.warn(String.format("Failed to create HTTPS port, cause " + ex.getMessage())); } } }); } else { server = HttpServer.create(new InetSocketAddress(host, port), 0); } server.setExecutor(java.util.concurrent.Executors.newCachedThreadPool()); server.start(); HttpContext httpContext = server.createContext(endpointLocation); endpoint = Endpoint.create(SOAPBinding.SOAP11HTTP_BINDING,this); endpoint.publish(httpContext); } 

Lo que he comprobado:

  • cada enlace que google y stackoverflow sugieren después de que el título fue escrito (especialmente enlace Https conexión cerrada por peer en android 5.0 lollipop – pero sin suerte)
  • Cifra siute en ambos dispositivos y en teoría ambos deben ser capaces de terminar el apretón de manos. Existen algoritmos correspondientes.
  • Comprobé ambas comunicaciones con wireshark. Descubrí que incluso si i delcare (en Android) TLSv1.2 versión TLS 1.0 es enviar en cabecera SSL (ver adjunto wireshark dump – use 'Decode as' -> SSL) En la línea 140 vemos la comunicación desde Android 6.0, Bellow (en línea 145 vemos la comunicación de trabajo de Android 4.4) 10.0.0.203 es el Android 6.0, 10.0.0.99 es el servidor, 10.0.0.200 es el Android 4.4
  • He leído sobre 'Conexión cerrada por peer' y en muchos temas chicos están hablando de certificado equivocado, pero en mi caso creo que SSL se bloquea durante las negociaciones de protocolo no durante el intercambio de certificados (que viene más tarde).

El sitio del servidor es un poco viejo (es un servicio de SOAP), pero creo que no es importante lo que sirve el servidor.

Por favor ayuda, es mi primer post.

  • Android HttpsUrlConnection javax.net.ssl.SSLException La conexión se cerró por el error del apretón de manos del par al usar el truststore local
  • Android: evitar el olfateo (por ejemplo, con CharlesProxy) de tráfico SSL
  • Carga de un archivo a través de SSL con Client Side Certificate y HttpsURLConnection de Android
  • SSL handshake Excepción en la aplicación navegar desde otros países
  • Administrador SDK Host desconocido dl-ssl.google.com
  • Conexión HTTPS con certificado de cliente en una aplicación para Android
  • WebView con certificado de cliente SSL en Android 4 ICS
  • ¿Cómo comprobar la huella digital del certificado SSL auto-firmado en Android?
  • Cadena de confianza de Android SSL con certificados intermedios (Apache HttpClient 4.X)
  • Cómo agregar un certificado pkcs12 de cliente a Postman Chrome, W7?
  • Administrador de descargas de Android no descargar archivos desde https
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.