2015-03-09 10 views
36

Gemäß den Dokumenten in Android für SSLSocket und SSLContext werden TLS v1.1 und v1.2 Protokolle in API-Ebene 16+ unterstützt, sind aber nicht standardmäßig aktiviert. http://developer.android.com/reference/javax/net/ssl/SSLSocket.html http://developer.android.com/reference/javax/net/ssl/SSLContext.htmlSo aktivieren Sie TLS 1.2-Unterstützung in einer Android-Anwendung (unter Android 4.1 JB)

Wie aktiviere ich es auf einem Gerät mit Android 4.1 oder höher (aber unter 5,0)?

Ich habe versucht, eine benutzerdefinierte SSLSocketFactory zu schaffen, die die unterstützten alle Protokolle ermöglicht, wenn Socket ‚s erstellt und später meine benutzerdefinierte Implementierung verwenden wie:

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

Aber es immer noch eine Ausnahme gibt, während Sie versuchen, Stellen Sie eine Verbindung mit einem Server her, auf dem Nur TLS 1.2 aktiviert ist. Hier

ist die Ausnahme, die ich erhalten:

03-09 09:21:38.427: W/System.err(2496): javax.net.ssl.SSLHandshakeException: javax.net.ssl.SSLProtocolException: SSL handshake aborted: ssl=0xb7fa0620: Failure in SSL library, usually a protocol error

03-09 09:21:38.427: W/System.err(2496): error:14077410:SSL routines:SSL23_GET_SERVER_HELLO:sslv3 alert handshake failure (external/openssl/ssl/s23_clnt.c:741 0xa90e6990:0x00000000)

+1

In meinen Tests fand ich, dass während TLSv1. 2 ist verfügbar und kann auf API 16-18 aktiviert werden. Es gibt immer noch Probleme mit bestimmten Anwendungen, z. B. das Bereitstellen von Clientzertifikaten, auch nach dem Einbeziehen von Play Services. Keine Lösung noch. – hooby3dfx

+1

Was das noch verwirrender macht ist, dass SSLEngine die Unterstützung für TLS1.1/1.2 nur in API20 + angibt. http://developer.android.com/reference/javax/net/ssl/SSLEngine.html –

Antwort

2

sollten Sie

SSLContext.getInstance("TLSv1.2"); 

für bestimmte Protokollversion verwenden.

Die zweite Ausnahme trat auf, weil default socketFactory das SSLV3-Ausfallprotokoll für Fehler verwendete.

können Sie verwenden NoSSLFactory von Haupt Antwort hier für seine Unterdrückung How to disable SSLv3 in android for HttpsUrlConnection?

Auch sollten Sie SSL-Kontext init mit allen Zertifikaten (Client und vertrauenswürdiger, wenn Du sie benötigen)

Aber all das ist nutzlos ohne mit

ProviderInstaller.installIfNeeded(getContext()) 

ist hier mehr Informationen mit der richtigen Einsatzszenario https://developer.android.com/training/articles/security-gms-provider.html

Hoffe es hilft.

+0

Nach diesem - http://grepcode.com/file/repo1.maven.org/maven2/org.ektorp/org. ektorp.android/1.2.2/org/ektorp/android/http/AndroidSSLSocketFactory.java?av=h#AndroidSSLSocketFactory - nur "TLS", "SSL" und "SSLV2" werden akzeptiert. –

+0

Dies scheint das Problem mit 4.1.2 Clients nicht zu beheben – frank

+0

Vielleicht ist es dumm, aber ich habe versucht, com.google.android lib in 4.0.1.2-Version zu meinem grandle hinzufügen, und ich kann com.google.android nicht importieren. gms.security. * Also von welchem ​​Paket importierst du ProviderInstaller? –

11

2 Möglichkeiten TLSv1.1 und TLSv1.2 zu aktivieren:

  1. Verwendung dieser Richtlinie: http://blog.dev-area.net/2015/08/13/android-4-1-enable-tls-1-1-and-tls-1-2/
  2. Verwendung dieser Klasse 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));
+0

Dies funktioniert bei L. Danke! – Fadils

+0

Ich habe Ihren zweiten Vorschlag als solchen verwendet und ich stehe vor Problemen. In der createSocket() - Methode der TlsSniSocketFactory-Klasse ist die zurückgegebene SSL-Sitzung ungültig. Ich weiß nicht warum, aber das passiert sowohl in API 17 als auch in API 24 Gerät? Bitte werfen Sie einen Blick auf meine detaillierte Abfrage darüber bitte: http://stackoverflow.com/questions/40684898/why-does-createsocket-returns-invalid-session-in-sslsession – LoveForDroid

0

@Inherently Curious - Dank um dies zu veröffentlichen. Sie sind fast da - Sie müssen der SSLContext.init() -Methode zwei weitere Parameter hinzufügen.

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

es beginnt zu arbeiten. Nochmals vielen Dank für das Posten. Ich habe dieses/mein Problem mit deinem Code gelöst.

6

Ich löste dieses Problem nach der Angabe im Artikel http://blog.dev-area.net/2015/08/13/android-4-1-enable-tls-1-1-and-tls-1-2/ mit kleinen Änderungen.

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

Dies ist der Code des benutzerdefinierten TLSSocketFactory:

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

HALLO, es hat nicht für mich funktioniert ,, irgendeine Idee warum? wird großartig sein, wenn Sie helfen können –

+0

Ich habe Ihre Antwort verwendet, um MQTT SSL-Verbindung zu etablieren und es hat gut funktioniert! Vielen Dank. #UP –

+0

@StoicaMircea das wird tatsächlich die Verbindung ohne SSL machen. das ist nicht sicher. Sie können meine Problemumgehung hier verwenden: https://stackoverflow.com/questions/47410689/how-to-use-a-self-signed-certificate-to-connect-to-a-mqtt-server-in-android-pah –

1

ich oben Antworten einige Ergänzungen haben erwähnt Es ist ein infact Hack von Jesse Wilson von okhttp erwähnt, quadratisch here. Nach diesem Hack, musste ich

private SSLSocketFactory delegate; 

Hinweis meine SSLSocketFactory Variable umbenennen, dass es Fehler werfen würde, wenn Sie einen beliebigen Namen als Delegierter andere geben. Iam meine komplette Lösung Posting unter

Das ist meine TLSSocketFactory Klasse

public class TLSSocketFactory extends SSLSocketFactory { 

private SSLSocketFactory delegate; 

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

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

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

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

@Override 
public Socket createSocket(Socket s, String host, int port, boolean autoClose) throws IOException { 
    return enableTLSOnSocket(delegate.createSocket(s, host, port, autoClose)); 
} 

@Override 
public Socket createSocket(String host, int port) throws IOException, UnknownHostException { 
    return enableTLSOnSocket(delegate.createSocket(host, port)); 
} 

@Override 
public Socket createSocket(String host, int port, InetAddress localHost, int localPort) throws IOException, UnknownHostException { 
    return enableTLSOnSocket(delegate.createSocket(host, port, localHost, localPort)); 
} 

@Override 
public Socket createSocket(InetAddress host, int port) throws IOException { 
    return enableTLSOnSocket(delegate.createSocket(host, port)); 
} 

@Override 
public Socket createSocket(InetAddress address, int port, InetAddress localAddress, int localPort) throws IOException { 
    return enableTLSOnSocket(delegate.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; 
} 
} 

und das ist, wie ich verwenden es mit okhttp und Nachrüstung

OkHttpClient client=new OkHttpClient(); 
    try { 
     client = new OkHttpClient.Builder() 
       .sslSocketFactory(new TLSSocketFactory()) 
       .build(); 
    } catch (KeyManagementException e) { 
     e.printStackTrace(); 
    } catch (NoSuchAlgorithmException e) { 
     e.printStackTrace(); 
    } 

    Retrofit retrofit = new Retrofit.Builder() 
      .baseUrl(URL) 
      .client(client) 
      .addConverterFactory(GsonConverterFactory.create()) 
      .build(); 
Verwandte Themen