verified verificar type trustanchor tls not found for enabled conexion check certpathvalidatorexception certpath cert java android ssl cryptography sslsocketfactory

java - verificar - SSLSocket a través de otro SSLSocket



verificar ssl (4)

Estoy intentando crear un SSLSocket encima de otro SSLSocket en una aplicación de Android. La conexión inferior es una conexión con seguridad SSL a un proxy web seguro (proxy HTTP sobre SSL), la conexión superior es para HTTP sobre SSL (HTTPS).

Para esto, estoy usando la función createSocket() de createSocket() que permite pasar un Socket existente sobre el cual ejecutar la conexión SSL de esta manera:

private Socket doSSLHandshake(Socket socket, String host, int port) throws IOException { TrustManager[] trustAllCerts = new TrustManager[]{ new X509TrustManager(){ public X509Certificate[] getAcceptedIssuers(){ return null; } public void checkClientTrusted(X509Certificate[] certs, String authType) {} public void checkServerTrusted(X509Certificate[] certs, String authType) {} } }; try { SSLContext sslContext = SSLContext.getInstance("SSL"); sslContext.init(null, trustAllCerts, new SecureRandom()); SSLSocket sslSocket = (SSLSocket) sslContext.getSocketFactory().createSocket(socket, host, port, true); sslSocket.setEnabledProtocols(sslSocket.getSupportedProtocols()); sslSocket.setEnableSessionCreation(true); sslSocket.startHandshake(); return sslSocket; } catch (KeyManagementException | NoSuchAlgorithmException e) { throw new IOException("Could not do handshake: " + e); } }

Este código funciona bien cuando el socket subyacente es un Socket TCP normal, pero cuando uso como socket subyacente un SSLSocket que se creó anteriormente con el código anterior, el protocolo de enlace falla con la siguiente excepción:

javax.net.ssl.SSLHandshakeException: Handshake failed at com.android.org.conscrypt.OpenSSLSocketImpl.startHandshake(OpenSSLSocketImpl.java:429) at com.myapp.MyThreadClass.doSSLHandshake(MyThreadClass.java:148) at com.myapp.MyThreadClass.run(MyThreadClass.java:254) Caused by: javax.net.ssl.SSLProtocolException: SSL handshake aborted: ssl=0x7374d56e80: Failure in SSL library, usually a protocol error error:100000e3:SSL routines:OPENSSL_internal:UNKNOWN_ALERT_TYPE (external/boringssl/src/ssl/s3_pkt.c:618 0x738418ce7e:0x00000000) at com.android.org.conscrypt.NativeCrypto.SSL_do_handshake(Native Method) at com.android.org.conscrypt.OpenSSLSocketImpl.startHandshake(OpenSSLSocketImpl.java:357) ... 2 more

Estoy probando en Android 7.1.1. La aplicación está dirigida a nivel SDK 23.

  • ¿Qué podría estar haciendo mal?
  • ¿Cómo podría depurar más el problema?
  • ¿Alguien tiene un ejemplo funcional de un SSLSocket pasando por otro SSLSocket en una versión reciente de Android?

¡Cualquier ayuda es muy apreciada!

Actualización : el mismo código funciona en JRE 1.8 en una Mac, pero no en Android.

Actualización 2 : Conceptualmente, estos son los pasos por los que pasa la conexión:

  1. Desde la aplicación de Android, establezca una conexión con el servidor Proxy seguro (Socket)
  2. Realice un protocolo de enlace SSL / TLS con el servidor Proxy (SSLSocket sobre Socket)
  3. A través del SSLSocket, envíe el mensaje CONECTAR al servidor Proxy
  4. El proxy se conecta al servidor de destino (https) y solo copia bytes a partir de ahora
  5. Realice un protocolo de enlace SSL / TLS con el servidor de destino (https) (SSLSocket sobre SSLSocket sobre Socket)
  6. Envíe el mensaje GET al servidor de destino y lea la respuesta

El problema surge en el paso 5, cuando se realiza el apretón de manos en un SSLSocket que pasa por un SSLSocket (que pasa por un Socket).

Actualización 3 : ahora he abierto un repositorio de GitHub con un proyecto de ejemplo y tcpdumps: https://github.com/FD-/SSLviaSSL

Nota : He encontrado y leído una pregunta con un título muy similar , pero desafortunadamente no contenía mucha ayuda útil.


Así que intenté averiguar qué falla en el caso de Android, pero hasta ahora no he encontrado ningún problema con su código. Además, como el código funciona para JRE, afirma la hipótesis.

Desde el tcpdump que proporcionó, hay información sustancial para concluir cómo se comporta Android con el mismo conjunto de API que JRE.

Echemos un vistazo a JRE tcpdump:

  • Consulte los mensajes iniciales del protocolo de enlace (Cliente Hola, Servidor Hola, cambie la especificación de cifrado). Esto muestra el protocolo de enlace entre el cliente JRE y el servidor proxy. Esto tiene éxito.
  • Ahora no vemos el segundo saludo entre el cliente JRE y www.google.com (el servidor final), ya que está cifrado ya que estamos haciendo SSL sobre SSL. El servidor proxy los está copiando bit a bit al servidor final. Así que este es un comportamiento correcto.

Ahora veamos el android tcpdump:

  • Consulte los mensajes iniciales del protocolo de enlace (Cliente Hola, Servidor Hola, cambie la especificación de cifrado). Esto muestra el apretón de manos entre el cliente de Android y el servidor proxy. Esto tiene éxito.
  • Ahora, idealmente, no deberíamos ver el segundo saludo, ya que debería estar encriptado. Pero aquí podemos ver que el cliente de Android está enviando un "cliente hola" y lo está enviando a "www.google.com" a pesar de que el paquete se envía al servidor proxy.
  • Lo anterior está destinado a fallar, ya que se suponía que el paquete debía escribirse sobre el socket SSL y no sobre el socket plano inicial. Revisé su código y veo que está haciendo el segundo apretón de manos sobre SSLSocket y no sobre socket simple.

Análisis del proxy / stunnel wireshark:

Caso JRE:

En el caso de JRE, el cliente realiza el protocolo inicial de SSL con el servidor proxy / stunnel. Lo mismo se puede ver a continuación:

El apretón de manos es exitoso y la conexión está hecha

Luego, el cliente intenta conectarse al servidor remoto (www.google.com) e inicia el protocolo de enlace. Por lo tanto, el saludo del cliente enviado por el cliente se ve como un mensaje cifrado en el paquete # 34 y cuando Stunnel lo descifra, se ve en "Client hello", que es enviado al servidor proxy por stunnel.

Ahora veamos el caso del cliente de Android.

El protocolo inicial de SSL del cliente al stunnel / proxy es exitoso como se ve arriba.

Luego, cuando el cliente de Android inicie el protocolo de enlace con el control remoto (www.google.com), idealmente debería usar el socket SSL para el mismo. Si este fuera el caso, deberíamos ver el tráfico cifrado de Android a Stunnel (similar al paquete # 34 del caso JRE), Stunnel debería descifrar y enviar "hola del cliente" al proxy. Sin embargo, como puede ver a continuación, el cliente de Android está enviando un "cliente hola" a través de un socket simple.

Si compara el paquete # 24 con el paquete # 34 de JRE, podemos detectar esta diferencia.

Conclusión:

Este es un error con la implementación de Android SSL ( factory.createsocket() con socket SSL) y creo que puede que no haya una solución mágica para la misma usando el mismo conjunto de API. De hecho, encontré este problema en la lista de errores de Android. Vea el siguiente enlace: https://code.google.com/p/android/issues/detail?id=204159

Este problema sigue sin resolverse y probablemente pueda hacer un seguimiento con el equipo de desarrolladores de Android para solucionarlo.

Soluciones posibles:

Si llegamos a la conclusión de que el mismo conjunto de API no puede funcionar, solo le queda una opción:

  1. Escriba su propio contenedor SSL sobre el socket SSL. Puede hacer handshake manualmente o usar una implementación de terceros. Esto podría tomar un tiempo, pero parece que la única manera.

Desde HTTPS asegúrese de que ningún intermediario interrumpa la comunicación entre los dos. Es por eso que no puedes hacerlo. así que el segundo apretón de manos falla.

Aquí está el enlace podría ayudar.

Conexiones HTTPS sobre servidores proxy


No creo que estés haciendo nada malo. Parece que hay un error en la negociación del protocolo durante su segundo saludo. Un buen candidato estaría fallando en una extensión de protocolo de enlace NPN TLS.

Eche un vistazo a sus protocolos en esta llamada: sslSocket.setEnabledProtocols(sslSocket.getSupportedProtocols());

Puede recorrer los protocolos enumerados y probarlos individualmente. Vea si puede bloquear lo que está fallando y si necesita ese protocolo específico o extensión compatible.


No sé si esto ayuda pero
He construido su entorno de prueba de repo, y mi error es ligeramente diferente:

I/SurfaceTextureClient(20733): [0x52851b98] frames:2, duration:1.005000, fps:1.989805 I/System.out(20733): [socket][2] connection /192.168.1.100:10443;LocalPort=35380(0) I/System.out(20733): [CDS]connect[/192.168.1.100:10443] tm:90 I/System.out(20733): [socket][/192.168.1.123:35380] connected I/System.out(20733): Doing SSL handshake with 192.168.1.100:10443 I/System.out(20733): Supported protocols are: [SSLv3, TLSv1, TLSv1.1, TLSv1.2] E/NativeCrypto(20733): ssl=0x53c96268 cert_verify_callback x509_store_ctx=0x542e0a80 arg=0x0 E/NativeCrypto(20733): ssl=0x53c96268 cert_verify_callback calling verifyCertificateChain authMethod=RSA I/System.out(20733): Doing SSL handshake with 192.168.1.100:443 I/System.out(20733): Supported protocols are: [SSLv3, TLSv1, TLSv1.1, TLSv1.2] E/NativeCrypto(20733): Unknown error during handshake I/System.out(20733): Shutdown rx/tx I/System.out(20733): [CDS]close[35380] I/System.out(20733): close [socket][/0.0.0.0:35380] W/System.err(20733): javax.net.ssl.SSLHandshakeException: javax.net.ssl.SSLProtocolException: SSL handshake aborted: ssl=0x53c9c1d8: Failure in SSL library, usually a protocol error W/System.err(20733): error:140770FC:SSL routines: SSL23_GET_SERVER_HELLO: unknown protocol (external/openssl/ssl/s23_clnt.c:766 0x4e7cb3ad:0x00000000) W/System.err(20733): at org.apache.harmony.xnet.provider.jsse.OpenSSLSocketImpl.startHandshake(OpenSSLSocketImpl.java:413) W/System.err(20733): at com.bugreport.sslviassl.SecureWebProxyThread.doSSLHandshake(SecureWebProxyThread.java:147) W/System.err(20733): at com.bugreport.sslviassl.SecureWebProxyThread.run(SecureWebProxyThread.java:216) W/System.err(20733): Caused by: javax.net.ssl.SSLProtocolException: SSL handshake aborted: ssl=0x53c9c1d8: Failure in SSL library, usually a protocol error W/System.err(20733): error:140770FC:SSL routines: SSL23_GET_SERVER_HELLO:unknown protocol (external/openssl/ssl/s23_clnt.c:766 0x4e7cb3ad:0x00000000) W/System.err(20733): at org.apache.harmony.xnet.provider.jsse.NativeCrypto.SSL_do_handshake(Native Method) W/System.err(20733): at org.apache.harmony.xnet.provider.jsse.OpenSSLSocketImpl.startHandshake(OpenSSLSocketImpl.java:372) W/System.err(20733): ... 2 more I/SurfaceTextureClient(20733): [0x52851b98] frames:5, duration:1.010000, fps:4.946089

Un pensamiento en los hilos: ¿en qué hilo está ejecutando su método doSSLHandshake ()?

public void policy() { int SDK_INT = android.os.Build.VERSION.SDK_INT; if (SDK_INT > 8) { StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build(); StrictMode.setThreadPolicy(policy); } }