Javax.net.ssl.SSLHandshakeException: javax.net.ssl.SSLProtocolException: établissement de liaison SSL interrompu: échec de la bibliothèque SSL, généralement une erreur de protocole

J’essaie d’exécuter le code suivant dans Android

URLConnection l_connection = null; // Create connection uzip=new UnZipData(mContext); l_url = new URL(serverurl); if ("https".equals(l_url.getProtocol())) { System.out.println("<<<<<<<<<<<<>>>>>>>>>>>"); sslcontext = SSLContext.getInstance("TLS"); System.out.println("<<<<<<<<<<<<>>>>>>>>>>>"); sslcontext.init(null, new TrustManager[] { new CustomTrustManager()}, new java.security.SecureRandom()); HttpsURLConnection .setDefaultHostnameVerifier(new CustomHostnameVerifier()); HttpsURLConnection.setDefaultSSLSocketFactory(sslcontext .getSocketFactory()); l_connection = (HttpsURLConnection) l_url.openConnection(); ((HttpsURLConnection) l_connection).setRequestMethod("POST"); } else { l_connection = (HttpURLConnection) l_url.openConnection(); ((HttpURLConnection) l_connection).setRequestMethod("POST"); } /*System.setProperty("http.agent", "Android_Phone");*/ l_connection.setConnectTimeout(10000); l_connection.setRequestProperty("Content-Language", "en-US"); l_connection.setUseCaches(false); l_connection.setDoInput(true); l_connection.setDoOutput(true); System.out.println("<<<<<<<<<<<<>>>>>>>>>>>"); l_connection.connect(); 

Sur l_connection.connect() , il donne cette exception SSLhandshakeException. Parfois, cela fonctionne, mais la plupart du temps, cela fait exception. Cela ne se produit que sur un émulateur Android 4.0. Je l’ai testé sur Android 4.4 et 5.0, cela fonctionne bien. Quelle pourrait en être la cause? S’il vous plaît aider

TRACE DE LA PILE

  04-28 15:51:13.143: W/System.err(2915): javax.net.ssl.SSLHandshakeException: javax.net.ssl.SSLProtocolException: SSL handshake aborted: ssl=0x870c918: Failure in SSL library, usually a protocol error 04-28 15:51:13.143: W/System.err(2915): error:14077410:SSL routines:SSL23_GET_SERVER_HELLO:sslv3 alert handshake failure (external/openssl/ssl/s23_clnt.c:658 0xb7c393a1:0x00000000) 04-28 15:51:13.143: W/System.err(2915): at org.apache.harmony.xnet.provider.jsse.OpenSSLSocketImpl.startHandshake(OpenSSLSocketImpl.java:460) 04-28 15:51:13.143: W/System.err(2915): at org.apache.harmony.xnet.provider.jsse.OpenSSLSocketImpl.startHandshake(OpenSSLSocketImpl.java:257) 04-28 15:51:13.143: W/System.err(2915): at libcore.net.http.HttpConnection.setupSecureSocket(HttpConnection.java:210) 04-28 15:51:13.143: W/System.err(2915): at libcore.net.http.HttpsURLConnectionImpl$HttpsEngine.makeSslConnection(HttpsURLConnectionImpl.java:477) 04-28 15:51:13.153: W/System.err(2915): at libcore.net.http.HttpsURLConnectionImpl$HttpsEngine.connect(HttpsURLConnectionImpl.java:441) 04-28 15:51:13.153: W/System.err(2915): at libcore.net.http.HttpEngine.sendSocketRequest(HttpEngine.java:282) 04-28 15:51:13.153: W/System.err(2915): at libcore.net.http.HttpEngine.sendRequest(HttpEngine.java:232) 04-28 15:51:13.153: W/System.err(2915): at libcore.net.http.HttpURLConnectionImpl.connect(HttpURLConnectionImpl.java:80) 04-28 15:51:13.153: W/System.err(2915): at libcore.net.http.HttpsURLConnectionImpl.connect(HttpsURLConnectionImpl.java:164) 04-28 15:51:13.153: W/System.err(2915): at com.ofss.fcdb.mobile.android.rms.helpers.NetworkConnector.getConnection(NetworkConnector.java:170) 04-28 15:51:13.153: W/System.err(2915): at com.ofss.fcdb.mobile.android.rms.util.InitiateRMS$2.run(InitiateRMS.java:221) 04-28 15:51:13.153: W/System.err(2915): at java.lang.Thread.run(Thread.java:856) 04-28 15:51:13.153: W/System.err(2915): Caused by: javax.net.ssl.SSLProtocolException: SSL handshake aborted: ssl=0x870c918: Failure in SSL library, usually a protocol error 04-28 15:51:13.153: W/System.err(2915): error:14077410:SSL routines:SSL23_GET_SERVER_HELLO:sslv3 alert handshake failure (external/openssl/ssl/s23_clnt.c:658 0xb7c393a1:0x00000000) 04-28 15:51:13.153: W/System.err(2915): at org.apache.harmony.xnet.provider.jsse.NativeCrypto.SSL_do_handshake(Native Method) 04-28 15:51:13.153: W/System.err(2915): at org.apache.harmony.xnet.provider.jsse.OpenSSLSocketImpl.startHandshake(OpenSSLSocketImpl.java:410) 04-28 15:51:13.153: W/System.err(2915): ... 11 more 04-28 16:42:44.139: W/ResourceType(3140): No package identifier when getting value for resource number 0x00000000 

    J’ai trouvé la solution en analysant les paquets de données à l’aide de wireshark. Ce que j’ai trouvé, c’est qu’en faisant une connexion sécurisée, Android retombait sur SSLv3 de TLSv1 . C’est un bogue dans les versions Android <4.4, et cela peut être résolu en supprimant le protocole SSLv3 de la liste Enabled Protocols. J'ai créé une classe socketFactory personnalisée appelée NoSSLv3SocketFactory.java. Utilisez ceci pour créer une socket.

     /*Copyright 2015 Bhavit Singh Sengar Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License.You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software dissortingbuted under the License is dissortingbuted on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.*/ import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.InetAddress; import java.net.Socket; import java.net.SocketAddress; import java.net.SocketException; import java.nio.channels.SocketChannel; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import javax.net.ssl.HandshakeCompletedListener; import javax.net.ssl.HttpsURLConnection; import javax.net.ssl.SSLSession; import javax.net.ssl.SSLSocket; import javax.net.ssl.SSLSocketFactory; public class NoSSLv3SocketFactory extends SSLSocketFactory{ private final SSLSocketFactory delegate; public NoSSLv3SocketFactory() { this.delegate = HttpsURLConnection.getDefaultSSLSocketFactory(); } public NoSSLv3SocketFactory(SSLSocketFactory delegate) { this.delegate = delegate; } @Override public Ssortingng[] getDefaultCipherSuites() { return delegate.getDefaultCipherSuites(); } @Override public Ssortingng[] getSupportedCipherSuites() { return delegate.getSupportedCipherSuites(); } private Socket makeSocketSafe(Socket socket) { if (socket instanceof SSLSocket) { socket = new NoSSLv3SSLSocket((SSLSocket) socket); } return socket; } @Override public Socket createSocket(Socket s, Ssortingng host, int port, boolean autoClose) throws IOException { return makeSocketSafe(delegate.createSocket(s, host, port, autoClose)); } @Override public Socket createSocket(Ssortingng host, int port) throws IOException { return makeSocketSafe(delegate.createSocket(host, port)); } @Override public Socket createSocket(Ssortingng host, int port, InetAddress localHost, int localPort) throws IOException { return makeSocketSafe(delegate.createSocket(host, port, localHost, localPort)); } @Override public Socket createSocket(InetAddress host, int port) throws IOException { return makeSocketSafe(delegate.createSocket(host, port)); } @Override public Socket createSocket(InetAddress address, int port, InetAddress localAddress, int localPort) throws IOException { return makeSocketSafe(delegate.createSocket(address, port, localAddress, localPort)); } private class NoSSLv3SSLSocket extends DelegateSSLSocket { private NoSSLv3SSLSocket(SSLSocket delegate) { super(delegate); } @Override public void setEnabledProtocols(Ssortingng[] protocols) { if (protocols != null && protocols.length == 1 && "SSLv3".equals(protocols[0])) { List enabledProtocols = new ArrayList(Arrays.asList(delegate.getEnabledProtocols())); if (enabledProtocols.size() > 1) { enabledProtocols.remove("SSLv3"); System.out.println("Removed SSLv3 from enabled protocols"); } else { System.out.println("SSL stuck with protocol available for " + Ssortingng.valueOf(enabledProtocols)); } protocols = enabledProtocols.toArray(new Ssortingng[enabledProtocols.size()]); } super.setEnabledProtocols(protocols); } } public class DelegateSSLSocket extends SSLSocket { protected final SSLSocket delegate; DelegateSSLSocket(SSLSocket delegate) { this.delegate = delegate; } @Override public Ssortingng[] getSupportedCipherSuites() { return delegate.getSupportedCipherSuites(); } @Override public Ssortingng[] getEnabledCipherSuites() { return delegate.getEnabledCipherSuites(); } @Override public void setEnabledCipherSuites(Ssortingng[] suites) { delegate.setEnabledCipherSuites(suites); } @Override public Ssortingng[] getSupportedProtocols() { return delegate.getSupportedProtocols(); } @Override public Ssortingng[] getEnabledProtocols() { return delegate.getEnabledProtocols(); } @Override public void setEnabledProtocols(Ssortingng[] protocols) { delegate.setEnabledProtocols(protocols); } @Override public SSLSession getSession() { return delegate.getSession(); } @Override public void addHandshakeCompletedListener(HandshakeCompletedListener listener) { delegate.addHandshakeCompletedListener(listener); } @Override public void removeHandshakeCompletedListener(HandshakeCompletedListener listener) { delegate.removeHandshakeCompletedListener(listener); } @Override public void startHandshake() throws IOException { delegate.startHandshake(); } @Override public void setUseClientMode(boolean mode) { delegate.setUseClientMode(mode); } @Override public boolean getUseClientMode() { return delegate.getUseClientMode(); } @Override public void setNeedClientAuth(boolean need) { delegate.setNeedClientAuth(need); } @Override public void setWantClientAuth(boolean want) { delegate.setWantClientAuth(want); } @Override public boolean getNeedClientAuth() { return delegate.getNeedClientAuth(); } @Override public boolean getWantClientAuth() { return delegate.getWantClientAuth(); } @Override public void setEnableSessionCreation(boolean flag) { delegate.setEnableSessionCreation(flag); } @Override public boolean getEnableSessionCreation() { return delegate.getEnableSessionCreation(); } @Override public void bind(SocketAddress localAddr) throws IOException { delegate.bind(localAddr); } @Override public synchronized void close() throws IOException { delegate.close(); } @Override public void connect(SocketAddress remoteAddr) throws IOException { delegate.connect(remoteAddr); } @Override public void connect(SocketAddress remoteAddr, int timeout) throws IOException { delegate.connect(remoteAddr, timeout); } @Override public SocketChannel getChannel() { return delegate.getChannel(); } @Override public InetAddress getInetAddress() { return delegate.getInetAddress(); } @Override public InputStream getInputStream() throws IOException { return delegate.getInputStream(); } @Override public boolean getKeepAlive() throws SocketException { return delegate.getKeepAlive(); } @Override public InetAddress getLocalAddress() { return delegate.getLocalAddress(); } @Override public int getLocalPort() { return delegate.getLocalPort(); } @Override public SocketAddress getLocalSocketAddress() { return delegate.getLocalSocketAddress(); } @Override public boolean getOOBInline() throws SocketException { return delegate.getOOBInline(); } @Override public OutputStream getOutputStream() throws IOException { return delegate.getOutputStream(); } @Override public int getPort() { return delegate.getPort(); } @Override public synchronized int getReceiveBufferSize() throws SocketException { return delegate.getReceiveBufferSize(); } @Override public SocketAddress getRemoteSocketAddress() { return delegate.getRemoteSocketAddress(); } @Override public boolean getReuseAddress() throws SocketException { return delegate.getReuseAddress(); } @Override public synchronized int getSendBufferSize() throws SocketException { return delegate.getSendBufferSize(); } @Override public int getSoLinger() throws SocketException { return delegate.getSoLinger(); } @Override public synchronized int getSoTimeout() throws SocketException { return delegate.getSoTimeout(); } @Override public boolean getTcpNoDelay() throws SocketException { return delegate.getTcpNoDelay(); } @Override public int getTrafficClass() throws SocketException { return delegate.getTrafficClass(); } @Override public boolean isBound() { return delegate.isBound(); } @Override public boolean isClosed() { return delegate.isClosed(); } @Override public boolean isConnected() { return delegate.isConnected(); } @Override public boolean isInputShutdown() { return delegate.isInputShutdown(); } @Override public boolean isOutputShutdown() { return delegate.isOutputShutdown(); } @Override public void sendUrgentData(int value) throws IOException { delegate.sendUrgentData(value); } @Override public void setKeepAlive(boolean keepAlive) throws SocketException { delegate.setKeepAlive(keepAlive); } @Override public void setOOBInline(boolean oobinline) throws SocketException { delegate.setOOBInline(oobinline); } @Override public void setPerformancePreferences(int connectionTime, int latency, int bandwidth) { delegate.setPerformancePreferences(connectionTime, latency, bandwidth); } @Override public synchronized void setReceiveBufferSize(int size) throws SocketException { delegate.setReceiveBufferSize(size); } @Override public void setReuseAddress(boolean reuse) throws SocketException { delegate.setReuseAddress(reuse); } @Override public synchronized void setSendBufferSize(int size) throws SocketException { delegate.setSendBufferSize(size); } @Override public void setSoLinger(boolean on, int timeout) throws SocketException { delegate.setSoLinger(on, timeout); } @Override public synchronized void setSoTimeout(int timeout) throws SocketException { delegate.setSoTimeout(timeout); } @Override public void setTcpNoDelay(boolean on) throws SocketException { delegate.setTcpNoDelay(on); } @Override public void setTrafficClass(int value) throws SocketException { delegate.setTrafficClass(value); } @Override public void shutdownInput() throws IOException { delegate.shutdownInput(); } @Override public void shutdownOutput() throws IOException { delegate.shutdownOutput(); } @Override public Ssortingng toSsortingng() { return delegate.toSsortingng(); } @Override public boolean equals(Object o) { return delegate.equals(o); } } } 

    Utilisez cette classe comme ça en connectant:

     SSLContext sslcontext = SSLContext.getInstance("TLSv1"); sslcontext.init(null, null, null); SSLSocketFactory NoSSLv3Factory = new NoSSLv3SocketFactory(sslcontext.getSocketFactory()); HttpsURLConnection.setDefaultSSLSocketFactory(NoSSLv3Factory); l_connection = (HttpsURLConnection) l_url.openConnection(); l_connection.connect(); 

    METTRE À JOUR :

    Maintenant, la solution correcte serait d’installer un nouveau fournisseur de sécurité à l’aide des services Google Play :

      ProviderInstaller.installIfNeeded(getApplicationContext()); 

    Cela donne à votre application l’access à une version plus récente d’OpenSSL et du fournisseur de sécurité Java, qui inclut la prise en charge de TLSv1.2 dans SSLEngine. Une fois le nouveau fournisseur installé, vous pouvez créer un SSLEngine qui prend en charge SSLv3, TLSv1, TLSv1.1 et TLSv1.2 de la manière habituelle:

      SSLContext sslContext = SSLContext.getInstance("TLSv1.2"); sslContext.init(null, null, null); SSLEngine engine = sslContext.createSSLEngine(); 

    Ou vous pouvez restreindre les protocoles activés à l’aide de engine.setEnabledProtocols .

    N’oubliez pas d’append la dépendance suivante ( dernière version trouvée ici ):

     comstack 'com.google.android.gms:play-services-auth:11.8.0' 

    Pour plus d’informations, consultez ce lien .

    Scénario

    J’obtenais des exceptions SSLHandshake sur les appareils exécutant des versions d’Android antérieures à Android 5.0. Dans mon cas d’utilisation, je voulais également créer un TrustManager pour faire confiance à mon certificate client.

    J’ai implémenté NoSSLv3SocketFactory et NoSSLv3Factory pour supprimer SSLv3 de la liste des protocoles pris en charge par mon client, mais je n’ai pu obtenir aucune de ces solutions.

    Quelques choses que j’ai apsockets:

    • Sur les appareils antérieurs à Android 5.0, les protocoles TLSv1.1 et TLSv1.2 ne sont pas activés par défaut.
    • Le protocole SSLv3 n’est pas désactivé par défaut sur les périphériques antérieurs à Android 5.0.
    • SSLv3 n’est pas un protocole sécurisé et il est donc souhaitable de le supprimer de la liste des protocoles pris en charge par notre client avant d’établir une connexion.

    Qu’est-ce qui a fonctionné pour moi

    Autoriser le Provider sécurité Android à se mettre à jour au démarrage de votre application.

    Le fournisseur par défaut avant la version 5.0+ ne désactive pas SSLv3. Si vous avez access aux services Google Play, il est relativement simple de patcher le fournisseur de sécurité d’Android depuis votre application.

     private void updateAndroidSecurityProvider(Activity callingActivity) { try { ProviderInstaller.installIfNeeded(this); } catch (GooglePlayServicesRepairableException e) { // Thrown when Google Play Services is not installed, up-to-date, or enabled // Show dialog to allow users to install, update, or otherwise enable Google Play services. GooglePlayServicesUtil.getErrorDialog(e.getConnectionStatusCode(), callingActivity, 0); } catch (GooglePlayServicesNotAvailableException e) { Log.e("SecurityException", "Google Play Services not available."); } } 

    Si vous créez maintenant votre OkHttpClient ou HttpURLConnection, TLSv1.1 et TLSv1.2 devraient être disponibles en tant que protocoles et SSLv3 devrait être supprimé. Si le client / la connexion (ou plus précisément SSLContext) a été initialisé avant d’appeler ProviderInstaller.installIfNeeded(...) il devra être recréé.

    N’oubliez pas d’append la dépendance suivante ( dernière version trouvée ici ):

     comstack 'com.google.android.gms:play-services-auth:11.8.0' 

    Sources:

    • Correction du fournisseur de sécurité avec le fournisseur ProviderInstaller
    • Faire SSLEngine utiliser TLSv1.2 sur Android (4.4.2)

    De côté

    Je n’ai pas eu besoin de définir explicitement les algorithmes de chiffrement que mon client doit utiliser, mais j’ai trouvé un article SO recommandant ceux considérés comme les plus sécurisés au moment de la rédaction: Quelles suites de chiffrement activer pour SSL Socket?

    Cela l’a résolu pour moi:

    La documentation Android pour SSLSocket indique que TLS 1.1 et TLS 1.2 sont pris en charge dans Android au démarrage de l’API de niveau 16+ (Android 4.1, Jelly Bean). Mais il est désactivé par défaut mais à partir de l’API niveau 20+ (Android 4.4 pour la montre, Kitkat Watch et Android 5.0 pour le téléphone, Lollipop), ils sont activés. Mais il est très difficile de trouver de la documentation sur la façon de l’activer pour les téléphones fonctionnant par exemple en 4.1. Pour activer TLS 1.1 et 1.2, vous devez créer une SSLSocketFactory personnalisée qui va transférer tous les appels vers une implémentation SSLSocketFactory par défaut. En plus de cela, nous devons remplacer toutes les méthodes createSocket et callsetEnabledProtocols sur le SSLSocket renvoyé pour activer TLS 1.1 et TLS 1.2. Pour un exemple d’implémentation, suivez simplement le lien ci-dessous.

    Android 4.1. activer tls1.1 et tls 1.2

    Vous devez également savoir que vous pouvez forcer TLS v1.2 pour les appareils Android 4.0 qui ne sont pas activés par défaut:

    Cela devrait être dans la première ligne de votre application:

     try { ProviderInstaller.installIfNeeded(getApplicationContext()); SSLContext sslContext; sslContext = SSLContext.getInstance("TLSv1.2"); sslContext.init(null, null, null); sslContext.createSSLEngine(); } catch (GooglePlayServicesRepairableException | GooglePlayServicesNotAvailableException | NoSuchAlgorithmException | KeyManagementException e) { e.printStackTrace(); } 

    C’était reproductible seulement quand j’utilise proxy sur genymotion (<4.4).

    Vérifiez vos parameters de proxy dans Paramètres-> Sans fil et réseaux-> WiFi -> (Appuyez longuement sur WiredSSID) -> Modifier le réseau

    Sélectionnez Afficher les options avancées: définissez les parameters du proxy sur NONE.

    Auparavant, j’ai également résolu ce problème avec l’implémentation SSLFactory personnalisée, mais selon cette documentation OkHttp, la solution est beaucoup plus simple.

    Ma solution finale avec les chiffrements nécessaires pour les périphériques 4.2+ ressemble à ceci:

     public UsersApi provideUsersApi() { private ConnectionSpec spec = new ConnectionSpec.Builder(ConnectionSpec.COMPATIBLE_TLS) .supportsTlsExtensions(true) .tlsVersions(TlsVersion.TLS_1_2, TlsVersion.TLS_1_1, TlsVersion.TLS_1_0) .cipherSuites( CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, CipherSuite.TLS_DHE_RSA_WITH_AES_128_GCM_SHA256, CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, CipherSuite.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, CipherSuite.TLS_ECDHE_ECDSA_WITH_RC4_128_SHA, CipherSuite.TLS_ECDHE_RSA_WITH_RC4_128_SHA, CipherSuite.TLS_DHE_RSA_WITH_AES_128_CBC_SHA, CipherSuite.TLS_DHE_DSS_WITH_AES_128_CBC_SHA, CipherSuite.TLS_DHE_RSA_WITH_AES_256_CBC_SHA) .build(); OkHttpClient client = new OkHttpClient.Builder() .connectionSpecs(Collections.singletonList(spec)) .build(); return new Retrofit.Builder() .baseUrl(USERS_URL) .addConverterFactory(GsonConverterFactory.create()) .client(client) .build() .create(UsersApi.class); } 

    Notez que cet ensemble de protocoles pris en charge dépend de la configuration de votre serveur.

    J’ai résolu le problème par ceci: NoSSLv3SocketFactory.java

     import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.InetAddress; import java.net.Socket; import java.net.SocketAddress; import java.net.SocketException; import java.nio.channels.SocketChannel; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import javax.net.ssl.HandshakeCompletedListener; import javax.net.ssl.HttpsURLConnection; import javax.net.ssl.SSLSession; import javax.net.ssl.SSLSocket; import javax.net.ssl.SSLSocketFactory; public class NoSSLv3SocketFactory extends SSLSocketFactory { private final SSLSocketFactory delegate; public NoSSLv3SocketFactory() { this.delegate = HttpsURLConnection.getDefaultSSLSocketFactory(); } public NoSSLv3SocketFactory(SSLSocketFactory delegate) { this.delegate = delegate; } @Override public Ssortingng[] getDefaultCipherSuites() { return delegate.getDefaultCipherSuites(); } @Override public Ssortingng[] getSupportedCipherSuites() { return delegate.getSupportedCipherSuites(); } private Socket makeSocketSafe(Socket socket) { if (socket instanceof SSLSocket) { socket = new NoSSLv3SSLSocket((SSLSocket) socket); } return socket; } @Override public Socket createSocket(Socket s, Ssortingng host, int port, boolean autoClose) throws IOException { return makeSocketSafe(delegate.createSocket(s, host, port, autoClose)); } @Override public Socket createSocket(Ssortingng host, int port) throws IOException { return makeSocketSafe(delegate.createSocket(host, port)); } @Override public Socket createSocket(Ssortingng host, int port, InetAddress localHost, int localPort) throws IOException { return makeSocketSafe(delegate.createSocket(host, port, localHost, localPort)); } @Override public Socket createSocket(InetAddress host, int port) throws IOException { return makeSocketSafe(delegate.createSocket(host, port)); } @Override public Socket createSocket(InetAddress address, int port, InetAddress localAddress, int localPort) throws IOException { return makeSocketSafe(delegate.createSocket(address, port, localAddress, localPort)); } private class NoSSLv3SSLSocket extends DelegateSSLSocket { private NoSSLv3SSLSocket(SSLSocket delegate) { super(delegate); } @Override public void setEnabledProtocols(Ssortingng[] protocols) { if (protocols != null && protocols.length == 1 && "SSLv3".equals(protocols[0])) { List enabledProtocols = new ArrayList( Arrays.asList(delegate.getEnabledProtocols())); if (enabledProtocols.size() > 1) { enabledProtocols.remove("SSLv3"); System.out.println("Removed SSLv3 from enabled protocols"); } else { System.out.println("SSL stuck with protocol available for " + Ssortingng.valueOf(enabledProtocols)); } protocols = enabledProtocols .toArray(new Ssortingng[enabledProtocols.size()]); } // super.setEnabledProtocols(protocols); super.setEnabledProtocols(new Ssortingng[]{"TLSv1.2"}); } } public class DelegateSSLSocket extends SSLSocket { protected final SSLSocket delegate; DelegateSSLSocket(SSLSocket delegate) { this.delegate = delegate; } @Override public Ssortingng[] getSupportedCipherSuites() { return delegate.getSupportedCipherSuites(); } @Override public Ssortingng[] getEnabledCipherSuites() { return delegate.getEnabledCipherSuites(); } @Override public void setEnabledCipherSuites(Ssortingng[] suites) { delegate.setEnabledCipherSuites(suites); } @Override public Ssortingng[] getSupportedProtocols() { return delegate.getSupportedProtocols(); } @Override public Ssortingng[] getEnabledProtocols() { return delegate.getEnabledProtocols(); } @Override public void setEnabledProtocols(Ssortingng[] protocols) { delegate.setEnabledProtocols(protocols); } @Override public SSLSession getSession() { return delegate.getSession(); } @Override public void addHandshakeCompletedListener( HandshakeCompletedListener listener) { delegate.addHandshakeCompletedListener(listener); } @Override public void removeHandshakeCompletedListener( HandshakeCompletedListener listener) { delegate.removeHandshakeCompletedListener(listener); } @Override public void startHandshake() throws IOException { delegate.startHandshake(); } @Override public void setUseClientMode(boolean mode) { delegate.setUseClientMode(mode); } @Override public boolean getUseClientMode() { return delegate.getUseClientMode(); } @Override public void setNeedClientAuth(boolean need) { delegate.setNeedClientAuth(need); } @Override public void setWantClientAuth(boolean want) { delegate.setWantClientAuth(want); } @Override public boolean getNeedClientAuth() { return delegate.getNeedClientAuth(); } @Override public boolean getWantClientAuth() { return delegate.getWantClientAuth(); } @Override public void setEnableSessionCreation(boolean flag) { delegate.setEnableSessionCreation(flag); } @Override public boolean getEnableSessionCreation() { return delegate.getEnableSessionCreation(); } @Override public void bind(SocketAddress localAddr) throws IOException { delegate.bind(localAddr); } @Override public synchronized void close() throws IOException { delegate.close(); } @Override public void connect(SocketAddress remoteAddr) throws IOException { delegate.connect(remoteAddr); } @Override public void connect(SocketAddress remoteAddr, int timeout) throws IOException { delegate.connect(remoteAddr, timeout); } @Override public SocketChannel getChannel() { return delegate.getChannel(); } @Override public InetAddress getInetAddress() { return delegate.getInetAddress(); } @Override public InputStream getInputStream() throws IOException { return delegate.getInputStream(); } @Override public boolean getKeepAlive() throws SocketException { return delegate.getKeepAlive(); } @Override public InetAddress getLocalAddress() { return delegate.getLocalAddress(); } @Override public int getLocalPort() { return delegate.getLocalPort(); } @Override public SocketAddress getLocalSocketAddress() { return delegate.getLocalSocketAddress(); } @Override public boolean getOOBInline() throws SocketException { return delegate.getOOBInline(); } @Override public OutputStream getOutputStream() throws IOException { return delegate.getOutputStream(); } @Override public int getPort() { return delegate.getPort(); } @Override public synchronized int getReceiveBufferSize() throws SocketException { return delegate.getReceiveBufferSize(); } @Override public SocketAddress getRemoteSocketAddress() { return delegate.getRemoteSocketAddress(); } @Override public boolean getReuseAddress() throws SocketException { return delegate.getReuseAddress(); } @Override public synchronized int getSendBufferSize() throws SocketException { return delegate.getSendBufferSize(); } @Override public int getSoLinger() throws SocketException { return delegate.getSoLinger(); } @Override public synchronized int getSoTimeout() throws SocketException { return delegate.getSoTimeout(); } @Override public boolean getTcpNoDelay() throws SocketException { return delegate.getTcpNoDelay(); } @Override public int getTrafficClass() throws SocketException { return delegate.getTrafficClass(); } @Override public boolean isBound() { return delegate.isBound(); } @Override public boolean isClosed() { return delegate.isClosed(); } @Override public boolean isConnected() { return delegate.isConnected(); } @Override public boolean isInputShutdown() { return delegate.isInputShutdown(); } @Override public boolean isOutputShutdown() { return delegate.isOutputShutdown(); } @Override public void sendUrgentData(int value) throws IOException { delegate.sendUrgentData(value); } @Override public void setKeepAlive(boolean keepAlive) throws SocketException { delegate.setKeepAlive(keepAlive); } @Override public void setOOBInline(boolean oobinline) throws SocketException { delegate.setOOBInline(oobinline); } @Override public void setPerformancePreferences(int connectionTime, int latency, int bandwidth) { delegate.setPerformancePreferences(connectionTime, latency, bandwidth); } @Override public synchronized void setReceiveBufferSize(int size) throws SocketException { delegate.setReceiveBufferSize(size); } @Override public void setReuseAddress(boolean reuse) throws SocketException { delegate.setReuseAddress(reuse); } @Override public synchronized void setSendBufferSize(int size) throws SocketException { delegate.setSendBufferSize(size); } @Override public void setSoLinger(boolean on, int timeout) throws SocketException { delegate.setSoLinger(on, timeout); } @Override public synchronized void setSoTimeout(int timeout) throws SocketException { delegate.setSoTimeout(timeout); } @Override public void setTcpNoDelay(boolean on) throws SocketException { delegate.setTcpNoDelay(on); } @Override public void setTrafficClass(int value) throws SocketException { delegate.setTrafficClass(value); } @Override public void shutdownInput() throws IOException { delegate.shutdownInput(); } @Override public void shutdownOutput() throws IOException { delegate.shutdownOutput(); } @Override public Ssortingng toSsortingng() { return delegate.toSsortingng(); } @Override public boolean equals(Object o) { return delegate.equals(o); } } } 

    Classe principale:

     URL url = new URL("https://www.example.com/test.png"); URLConnection l_connection = null; SSLContext sslcontext = SSLContext.getInstance("TLSv1.2"); sslcontext.init(null, null, null); SSLSocketFactory NoSSLv3Factory = new NoSSLv3SocketFactory(sslcontext.getSocketFactory()); 

    Lorsque j’ai eu cette erreur, c’était parce que les protocoles (versions TLS) et / ou les suites de chiffrement pris en charge par le serveur n’étaient pas activés (et peut-être même pas pris en charge) par le périphérique. Pour les API 16-19, TLSv1.1 et TLSv1.2 sont pris en charge mais ne sont pas activés par défaut. Une fois que je les ai activés pour ces versions, j’ai toujours l’erreur, car ces versions ne prennent en charge aucun des chiffrements sur notre instance AWS CloudFront.

    Comme il n’est pas possible d’append des chiffrements à Android, nous avons dû passer de TLSv1.2_2018 à TLSv1.1_2016 (qui supporte toujours TLSv1.2; il ne le nécessite tout simplement pas), avec quatre des chiffrements pris en charge par les versions antérieures d’Android, dont deux sont toujours considérées comme fortes.

    A ce moment, l’erreur a disparu et les appels ont été transmis (avec TLSv1.2) car il y avait au moins un protocole et au moins un chiffrement partagés par le périphérique et le serveur.

    Reportez-vous aux tableaux de cette page pour connaître les protocoles et les chiffrements pris en charge et activés sur les versions d’Android.

    Est-ce qu’Android essayait vraiment d’utiliser SSLv3 comme impliqué par la partie “sslv3 alert handshake failure” du message d’erreur? J’en doute; Je soupçonne que c’est une vieille canvas d’araignée dans la bibliothèque SSL qui n’a pas été nettoyée mais je ne peux pas le dire avec certitude.

    Afin d’activer TLSv1.2 (et TLSv1.1), j’ai pu utiliser une SSLSocketFactory beaucoup plus simple que celles vues ailleurs (comme NoSSLv3SocketFactory ). Il s’assure simplement que les protocoles activés incluent tous les protocoles pris en charge et que les chiffrements activés incluent tous les chiffrements pris en charge (ce dernier n’était pas nécessaire pour moi mais pourrait l’être pour d’autres) – voir configure() en bas. Si vous préférez activer uniquement les derniers protocoles, vous pouvez remplacer socket.supportedProtocols par quelque chose comme arrayOf("TLSv1.1", "TLSv1.2") (également pour les chiffrements):

     class TLSSocketFactory : SSLSocketFactory() { private val socketFactory: SSLSocketFactory init { val sslContext = SSLContext.getInstance("TLS") sslContext.init(null, null, null) socketFactory = sslContext.socketFactory } override fun getDefaultCipherSuites(): Array { return socketFactory.defaultCipherSuites } override fun getSupportedCipherSuites(): Array { return socketFactory.supportedCipherSuites } override fun createSocket(s: Socket, host: Ssortingng, port: Int, autoClose: Boolean): Socket { return configure(socketFactory.createSocket(s, host, port, autoClose) as SSLSocket) } override fun createSocket(host: Ssortingng, port: Int): Socket { return configure(socketFactory.createSocket(host, port) as SSLSocket) } override fun createSocket(host: InetAddress, port: Int): Socket { return configure(socketFactory.createSocket(host, port) as SSLSocket) } override fun createSocket(host: Ssortingng, port: Int, localHost: InetAddress, localPort: Int): Socket { return configure(socketFactory.createSocket(host, port, localHost, localPort) as SSLSocket) } override fun createSocket(address: InetAddress, port: Int, localAddress: InetAddress, localPort: Int): Socket { return configure(socketFactory.createSocket(address, port, localAddress, localPort) as SSLSocket) } private fun configure(socket: SSLSocket): SSLSocket { socket.enabledProtocols = socket.supportedProtocols socket.enabledCipherSuites = socket.supportedCipherSuites return socket } }