Cómo habilitar la compatibilidad con TLS 1.2 en una aplicación de Android (en ejecución en Android 4.1 JB)
Según los documentos en Android para SSLSocket
y SSLContext
, los protocolos TLS v1.1 y v1.2 se admiten en el nivel 16+ de API, pero no están habilitados de forma predeterminada. Http://developer.android.com/reference/javax/net/ssl/SSLSocket.html http://developer.android.com/reference/javax/net/ssl/SSLContext.html
¿Cómo se habilita en un dispositivo con Android 4.1 o posterior (pero inferior a 5.0)?
- ¿Cómo actualizo el SSL cert en mis aplicaciones Android?
- Lista de CA de confianza en android?
- Android / Java - ¿Cómo crear una conexión HTTPS?
- Comportamiento de HttpURLConnection para URL con certificado SSL revocado?
- Android: streaming de video por servidor HTTPS local: certificado SSL rechazado
He intentado crear un SSLSocketFactory personalizado que permite que todos los protocolos apoyados cuando Socket
se creen y después utilicen mi puesta en práctica de encargo como:
HttpsURLConnection.setDefaultSSLSocketFactory (nuevo MySSLSocketFactory ());
public class MySSLSocketFactory extends SSLSocketFactory { private SSLContext sc; private SSLSocketFactory ssf; public MySSLSocketFactory() { try { sc = SSLContext.getInstance("TLS"); sc.init(null, null, null); ssf = sc.getSocketFactory(); } catch (NoSuchAlgorithmException e) { e.printStackTrace(); } catch (KeyManagementException e) { e.printStackTrace(); } } @Override public Socket createSocket(Socket s, String host, int port, boolean autoClose) throws IOException { SSLSocket ss = (SSLSocket) ssf.createSocket(s, host, port, autoClose); ss.setEnabledProtocols(ss.getSupportedProtocols()); ss.setEnabledCipherSuites(ss.getSupportedCipherSuites()); return ss; } @Override public String[] getDefaultCipherSuites() { return ssf.getDefaultCipherSuites(); } @Override public String[] getSupportedCipherSuites() { return ssf.getSupportedCipherSuites(); } @Override public Socket createSocket(String host, int port) throws IOException, UnknownHostException { SSLSocket ss = (SSLSocket) ssf.createSocket(host, port); ss.setEnabledProtocols(ss.getSupportedProtocols()); ss.setEnabledCipherSuites(ss.getSupportedCipherSuites()); return ss; } @Override public Socket createSocket(InetAddress host, int port) throws IOException { SSLSocket ss = (SSLSocket) ssf.createSocket(host, port); ss.setEnabledProtocols(ss.getSupportedProtocols()); ss.setEnabledCipherSuites(ss.getSupportedCipherSuites()); return ss; } @Override public Socket createSocket(String host, int port, InetAddress localHost, int localPort) throws IOException, UnknownHostException { SSLSocket ss = (SSLSocket) ssf.createSocket(host, port, localHost, localPort); ss.setEnabledProtocols(ss.getSupportedProtocols()); ss.setEnabledCipherSuites(ss.getSupportedCipherSuites()); return ss; } @Override public Socket createSocket(InetAddress address, int port, InetAddress localAddress, int localPort) throws IOException { SSLSocket ss = (SSLSocket) ssf.createSocket(address, port, localAddress, localPort); ss.setEnabledProtocols(ss.getSupportedProtocols()); ss.setEnabledCipherSuites(ss.getSupportedCipherSuites()); return ss; } }
Pero todavía da una excepción al intentar establecer una conexión con un servidor en el que Only TLS 1.2 está habilitado.
Aquí está la excepción que recibo:
03-09 09: 21: 38.427: W / System.err (2496): javax.net.ssl.SSLHandshakeException: javax.net.ssl.SSLProtocolException: protocolo SSL abortado: ssl = 0xb7fa0620: Error en la biblioteca SSL, normalmente un protocolo error
03-09 09: 21: 38.427: W / System.err (2496): error: 14077410: rutinas SSL: SSL23_GET_SERVER_HELLO: error de handshake de alerta sslv3 (external / openssl / ssl / s23_clnt.c: 741 0xa90e6990: 0x00000000)
- SSLPeerUnverifiedException al crear una conexión SSL en Android
- Aplicación de Android con SSL
- Verificando servidores Verisign certificates throws No es una excepción de certificado de servidor de confianza
- SSLSocket a través de otro SSLSocket
- Javax.net.ssl.SSLHandshakeException: Conexión cerrada por peer en com.android.org.conscrypt.NativeCrypto.SSL_do_handshake (Native Method)
- Recibir y validar certificado del servidor HTTPS - android
- Android <4.3 WebView https error: Retroceder a SSLv3 porque host es TLS intolerante
- Aceptación de SSL auto-firmada en Android
2 maneras de habilitar TLSv1.1 y TLSv1.2:
- Utilice esta guía: http://blog.dev-area.net/2015/08/13/android-4-1-enable-tls-1-1-and-tls-1-2/
- Utilice esta clase https://github.com/erickok/transdroid/blob/master/app/src/main/java/org/transdroid/daemon/util/TlsSniSocketFactory.java
schemeRegistry.register(new Scheme("https", new TlsSniSocketFactory(), port));
Resolví este problema siguiendo la indicación proporcionada en el artículo http://blog.dev-area.net/2015/08/13/android-4-1-enable-tls-1-1-and-tls-1-2 / Con pequeños cambios.
SSLContext context = SSLContext.getInstance("TLS"); context.init(null, null, null); SSLSocketFactory noSSLv3Factory = null; if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.KITKAT) { noSSLv3Factory = new TLSSocketFactory(sslContext.getSocketFactory()); } else { noSSLv3Factory = sslContext.getSocketFactory(); } connection.setSSLSocketFactory(noSSLv3Factory);
Este es el código del TLSSocketFactory personalizado:
public static class TLSSocketFactory extends SSLSocketFactory { private SSLSocketFactory internalSSLSocketFactory; public TLSSocketFactory(SSLSocketFactory delegate) throws KeyManagementException, NoSuchAlgorithmException { internalSSLSocketFactory = delegate; } @Override public String[] getDefaultCipherSuites() { return internalSSLSocketFactory.getDefaultCipherSuites(); } @Override public String[] getSupportedCipherSuites() { return internalSSLSocketFactory.getSupportedCipherSuites(); } @Override public Socket createSocket(Socket s, String host, int port, boolean autoClose) throws IOException { return enableTLSOnSocket(internalSSLSocketFactory.createSocket(s, host, port, autoClose)); } @Override public Socket createSocket(String host, int port) throws IOException, UnknownHostException { return enableTLSOnSocket(internalSSLSocketFactory.createSocket(host, port)); } @Override public Socket createSocket(String host, int port, InetAddress localHost, int localPort) throws IOException, UnknownHostException { return enableTLSOnSocket(internalSSLSocketFactory.createSocket(host, port, localHost, localPort)); } @Override public Socket createSocket(InetAddress host, int port) throws IOException { return enableTLSOnSocket(internalSSLSocketFactory.createSocket(host, port)); } @Override public Socket createSocket(InetAddress address, int port, InetAddress localAddress, int localPort) throws IOException { return enableTLSOnSocket(internalSSLSocketFactory.createSocket(address, port, localAddress, localPort)); } /* * Utility methods */ private static Socket enableTLSOnSocket(Socket socket) { if (socket != null && (socket instanceof SSLSocket) && isTLSServerEnabled((SSLSocket) socket)) { // skip the fix if server doesn't provide there TLS version ((SSLSocket) socket).setEnabledProtocols(new String[]{TLS_v1_1, TLS_v1_2}); } return socket; } private static boolean isTLSServerEnabled(SSLSocket sslSocket) { System.out.println("__prova__ :: " + sslSocket.getSupportedProtocols().toString()); for (String protocol : sslSocket.getSupportedProtocols()) { if (protocol.equals(TLS_v1_1) || protocol.equals(TLS_v1_2)) { return true; } } return false; } }
Deberías usar
SSLContext.getInstance("TLSv1.2");
Para la versión específica del protocolo.
La segunda excepción se produjo porque el socketFactory predeterminado utilizó el protocolo SSLv3 de fallback para los fallos.
Puede utilizar NoSSLFactory desde la respuesta principal aquí para su supresión ¿Cómo deshabilitar SSLv3 en android para HttpsUrlConnection?
También debe init SSLContext con todos sus certificados (cliente y de confianza si los necesita)
Pero todo eso es inútil sin usar
ProviderInstaller.installIfNeeded(getContext())
Aquí hay más información con el escenario de uso adecuado https://developer.android.com/training/articles/security-gms-provider.html
Espero eso ayude.
@Inherently Curious – gracias por publicar esto. Usted está casi allí – usted tiene que agregar dos más params al método de SSLContext.init ().
TrustManager[] trustManagers = new TrustManager[] { new TrustManagerManipulator() }; sc.init(null, trustManagers, new SecureRandom());
Comenzará a funcionar. De nuevo muchas gracias por publicar esto. He resuelto este / mi problema con su código.
- No hay respuesta de cliente remoto: error durante la transferencia de archivos usando asmack
- Cómo configurar un botón gris y unclickable?