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)?

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)

2 maneras de habilitar TLSv1.1 y TLSv1.2:

  1. Utilice esta guía: http://blog.dev-area.net/2015/08/13/android-4-1-enable-tls-1-1-and-tls-1-2/
  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.

  • El proxy Charles falla en el método de conexión SSL
  • Certificado auto-firmado de Android: Ancla de confianza para la ruta de certificación no encontrada
  • Android y HTTPS con SSL
  • Javax.net.ssl.sslpeerunverifiedexception sin certificado de igualdad
  • Utilice DefaultHttpClient simple o un almacén de claves creado con BouncyCastle incluido en la aplicación.
  • Solicitud de Android HTTPS
  • ¿Cómo instalar el certificado de CA de confianza en un dispositivo Android?
  • ¿Cómo enviar solicitudes de proxy a api.twitter.com incluyendo certificados SSL?
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.