web-dev-qa-db-fra.com

Comment activer le support TLS 1.2 dans une application Android (s'exécutant sur Android 4.1 JB)

Selon les documents dans Android pour SSLSocket et SSLContext, les protocoles TLS v1.1 et v1.2 sont pris en charge par les API de niveau 16+, mais ne sont pas activés par défaut . http://developer.Android.com/ reference/javax/net/ssl/SSLSocket.htmlhttp://developer.Android.com/reference/javax/net/ssl/SSLContext.html

Comment l'activer sur un appareil fonctionnant sous Android 4.1 ou ultérieur (mais inférieur à 5.0)?

J'ai essayé de créer un SSLSocketFactory personnalisé qui active tous les protocoles pris en charge lors de la création de Socket et utilise plus tard mon implémentation personnalisée en tant que:

HttpsURLConnection.setDefaultSSLSocketFactory (nouveau 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;
        }
    }

Mais il donne toujours une exception lorsqu’on essaie d’établir une connexion avec un serveur sur lequel Only TLS 1.2 est activé.

Voici l'exception que je reçois:

03-09 09: 21: 38.427: W/System.err (2496): javax.net.ssl.SSLHandshakeException: javax.net.ssl.SSLProtocolException: négociation SSL interrompue: ssl = 0xb7fa0620: Echec dans la bibliothèque SSL, généralement une erreur de protocole 

03-09 09: 21: 38.427: W/System.err (2496): erreur: 14077410: SSL routines: SSL23_GET_SERVER_HELLO: échec de la négociation de l'alerte sslv3 (external/openssl/ssl/s23_clnt.c: 741 0xa90e6990: 0x00000000)

56

2 façons d'activer TLSv1.1 et TLSv1.2: 

  1. utilisez cette directive: http://blog.dev-area.net/2015/08/13/Android-4-1-enable-tls-1-1-and-tls-1-2/
  2. utiliser cette classe 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));
18
tran minh linh

J'ai résolu ce problème en suivant les indications de l'article http://blog.dev-area.net/2015/08/13/Android-4-1-enable-tls-1-1-and-tls-1 -2/ avec de petits changements.

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

Voici le code de la TLSSocketFactory personnalisée:

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;
    }
}

Edit: Merci à ademar111190 pour l'implémentation de kotlin ( link )

class TLSSocketFactory constructor(
        private val internalSSLSocketFactory: SSLSocketFactory
) : SSLSocketFactory() {

    private val protocols = arrayOf("TLSv1.2", "TLSv1.1")

    override fun getDefaultCipherSuites(): Array<String> = internalSSLSocketFactory.defaultCipherSuites

    override fun getSupportedCipherSuites(): Array<String> = internalSSLSocketFactory.supportedCipherSuites

    override fun createSocket(s: Socket, Host: String, port: Int, autoClose: Boolean) =
            enableTLSOnSocket(internalSSLSocketFactory.createSocket(s, Host, port, autoClose))

    override fun createSocket(Host: String, port: Int) =
            enableTLSOnSocket(internalSSLSocketFactory.createSocket(Host, port))

    override fun createSocket(Host: String, port: Int, localHost: InetAddress, localPort: Int) =
            enableTLSOnSocket(internalSSLSocketFactory.createSocket(Host, port, localHost, localPort))

    override fun createSocket(Host: InetAddress, port: Int) =
            enableTLSOnSocket(internalSSLSocketFactory.createSocket(Host, port))

    override fun createSocket(address: InetAddress, port: Int, localAddress: InetAddress, localPort: Int) =
            enableTLSOnSocket(internalSSLSocketFactory.createSocket(address, port, localAddress, localPort))

    private fun enableTLSOnSocket(socket: Socket?) = socket?.apply {
        if (this is SSLSocket && isTLSServerEnabled(this)) {
            enabledProtocols = protocols
        }
    }

    private fun isTLSServerEnabled(sslSocket: SSLSocket) = sslSocket.supportedProtocols.any { it in protocols }

}
11
carlol

Tu devrais utiliser

 SSLContext.getInstance("TLSv1.2"); 

pour une version de protocole spécifique.

La deuxième exception s'est produite parce que socketFactory par défaut utilisait le protocole de remplacement SSLv3 pour les échecs.

Vous pouvez utiliser NoSSLFactory de la réponse principale ici pour sa suppression Comment désactiver SSLv3 dans Android pour HttpsUrlConnection?

De plus, vous devez initialiser SSLContext avec tous vos certificats (clients et certificats de confiance si vous en avez besoin)

Mais tout cela est inutile sans utiliser 

ProviderInstaller.installIfNeeded(getContext())

Voici plus d'informations avec le scénario d'utilisation approprié https://developer.Android.com/training/articles/security-gms-provider.html

J'espère que ça aide.

4
Vladimir Mezentsev

Comme l'OP l'a indiqué, les protocoles TLS v1.1 et v1.2 sont pris en charge par les API de niveaux 16 et supérieur, mais ne sont pas activés par défaut. Nous devons simplement l'activer.

Exemple ici utilise HttpsUrlConnection, pas HttpUrlConnection. Suivez https://blog.dev-area.net/2015/08/13/Android-4-1-enable-tls-1-1-and-tls-1-2/ , nous pouvons créer un usine

class MyFactory extends SSLSocketFactory {

    private javax.net.ssl.SSLSocketFactory internalSSLSocketFactory;

    public MyFactory() throws KeyManagementException, NoSuchAlgorithmException {
        SSLContext context = SSLContext.getInstance("TLS");
        context.init(null, null, null);
        internalSSLSocketFactory = context.getSocketFactory();
    }

    @Override
    public String[] getDefaultCipherSuites() {
        return internalSSLSocketFactory.getDefaultCipherSuites();
    }

    @Override
    public String[] getSupportedCipherSuites() {
        return internalSSLSocketFactory.getSupportedCipherSuites();
    }

    @Override
    public Socket createSocket() throws IOException {
        return enableTLSOnSocket(internalSSLSocketFactory.createSocket());
    }

    @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));
    }

    private Socket enableTLSOnSocket(Socket socket) {
        if(socket != null && (socket instanceof SSLSocket)) {
            ((SSLSocket)socket).setEnabledProtocols(new String[] {"TLSv1.1", "TLSv1.2"});
        }
        return socket;
    }
}

Quelle que soit la bibliothèque de mise en réseau que vous utilisez, assurez-vous que ((SSLSocket)socket).setEnabledProtocols(new String[] {"TLSv1.1", "TLSv1.2"}); est appelé pour que le Socket active les protocoles TLS.

Maintenant, vous pouvez utiliser cela dans HttpsUrlConnection

class MyHttpRequestTask extends AsyncTask<String,Integer,String> {

    @Override
    protected String doInBackground(String... params) {
        String my_url = params[0];
        try {
            URL url = new URL(my_url);
            HttpsURLConnection httpURLConnection = (HttpsURLConnection) url.openConnection();
            httpURLConnection.setSSLSocketFactory(new MyFactory());
            // setting the  Request Method Type
            httpURLConnection.setRequestMethod("GET");
            // adding the headers for request
            httpURLConnection.setRequestProperty("Content-Type", "application/json");


            String result = readStream(httpURLConnection.getInputStream());
            Log.e("My Networking", "We have data" + result.toString());


        }catch (Exception e){
            e.printStackTrace();
            Log.e("My Networking", "Oh no, error occurred " + e.toString());
        }

        return null;
    }

    private static String readStream(InputStream is) throws IOException {
        final BufferedReader reader = new BufferedReader(new InputStreamReader(is, Charset.forName("US-ASCII")));
        StringBuilder total = new StringBuilder();
        String line;
        while ((line = reader.readLine()) != null) {
            total.append(line);
        }
        if (reader != null) {
            reader.close();
        }
        return total.toString();
    }
}

Par exemple

new MyHttpRequestTask().execute(myUrl);

De plus, n'oubliez pas de déplacer minSdkVersion dans build.gradle to 16

minSdkVersion 16
0
onmyway133

Ajouter la bibliothèque play-services-safetynet dans Android build.gradle:

implementation 'com.google.Android.gms:play-services-safetynet:+'

et ajoutez ce code à votre MainApplication.Java:

@Override
  public void onCreate() {
    super.onCreate();
    upgradeSecurityProvider();
    SoLoader.init(this, /* native exopackage */ false);
  }

  private void upgradeSecurityProvider() {
    ProviderInstaller.installIfNeededAsync(this, new ProviderInstallListener() {
      @Override
      public void onProviderInstalled() {

      }

      @Override
      public void onProviderInstallFailed(int errorCode, Intent recoveryIntent) {
//        GooglePlayServicesUtil.showErrorNotification(errorCode, MainApplication.this);
        GoogleApiAvailability.getInstance().showErrorNotification(MainApplication.this, errorCode);
      }
    });
  }
0
sajad abbasi

@ Inherently Curious - merci d'avoir posté ceci. Vous y êtes presque - vous devez ajouter deux paramètres supplémentaires à la méthode SSLContext.init ().

TrustManager[] trustManagers = new TrustManager[] { new TrustManagerManipulator() };
sc.init(null, trustManagers, new SecureRandom());

ça va commencer à fonctionner. Encore une fois, merci beaucoup d'avoir posté ceci. J'ai résolu ce problème/mon problème avec votre code.

0