Javax.net.ssl.SSLHandshakeException: javax.net.ssl.SSLProtocolException: SSL-квитирование отменено: ошибка в библиотеке SSL, обычно ошибка протокола
Я пытаюсь запустить следующий код в 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();
В l_connection.connect()
это исключение SSLhandshakeException. Иногда он работает, но большую часть времени он дает исключение. Это происходит только на эмуляторе Android 4.0. Я тестировал его на Android 4.4 и 5.0, он отлично работает. Что может быть причиной этого? Пожалуйста помоги
ТРАССИРОВКИ СТЕКА
- Как сделать Java 6, которая не работает с SSL-соединением с неправильным отключением SSL-партнера, как Java 7?
- Сертификаты клиента Java через HTTPS / SSL
- Как отправить запрос HTTPS через прокси-сервер в Java?
- Получено фатальное предупреждение: handshake_failure через SSLHandshakeException
- Исключение SSLHandshake при подключении к сайту https
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
Я нашел решение для этого, проанализировав пакеты данных с помощью wirehark. Я обнаружил, что при создании безопасного соединения андроид возвращался к SSLv3 с TLSv1 . Это ошибка в версиях Android версии 4.4, и ее можно решить, удалив протокол SSLv3 из списка Enabled Protocols. Я создал собственный class socketFactory под названием NoSSLv3SocketFactory.java. Используйте это, чтобы сделать socketfactory.
/*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 distributed under the License is distributed 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 String[] getDefaultCipherSuites() { return delegate.getDefaultCipherSuites(); } @Override public String[] 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, String host, int port, boolean autoClose) throws IOException { return makeSocketSafe(delegate.createSocket(s, host, port, autoClose)); } @Override public Socket createSocket(String host, int port) throws IOException { return makeSocketSafe(delegate.createSocket(host, port)); } @Override public Socket createSocket(String 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(String[] 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 " + String.valueOf(enabledProtocols)); } protocols = enabledProtocols.toArray(new String[enabledProtocols.size()]); } super.setEnabledProtocols(protocols); } } public class DelegateSSLSocket extends SSLSocket { protected final SSLSocket delegate; DelegateSSLSocket(SSLSocket delegate) { this.delegate = delegate; } @Override public String[] getSupportedCipherSuites() { return delegate.getSupportedCipherSuites(); } @Override public String[] getEnabledCipherSuites() { return delegate.getEnabledCipherSuites(); } @Override public void setEnabledCipherSuites(String[] suites) { delegate.setEnabledCipherSuites(suites); } @Override public String[] getSupportedProtocols() { return delegate.getSupportedProtocols(); } @Override public String[] getEnabledProtocols() { return delegate.getEnabledProtocols(); } @Override public void setEnabledProtocols(String[] 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 String toString() { return delegate.toString(); } @Override public boolean equals(Object o) { return delegate.equals(o); } } } /*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 distributed under the License is distributed 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 String[] getDefaultCipherSuites() { return delegate.getDefaultCipherSuites(); } @Override public String[] 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, String host, int port, boolean autoClose) throws IOException { return makeSocketSafe(delegate.createSocket(s, host, port, autoClose)); } @Override public Socket createSocket(String host, int port) throws IOException { return makeSocketSafe(delegate.createSocket(host, port)); } @Override public Socket createSocket(String 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(String[] 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 " + String.valueOf(enabledProtocols)); } protocols = enabledProtocols.toArray(new String[enabledProtocols.size()]); } super.setEnabledProtocols(protocols); } } public class DelegateSSLSocket extends SSLSocket { protected final SSLSocket delegate; DelegateSSLSocket(SSLSocket delegate) { this.delegate = delegate; } @Override public String[] getSupportedCipherSuites() { return delegate.getSupportedCipherSuites(); } @Override public String[] getEnabledCipherSuites() { return delegate.getEnabledCipherSuites(); } @Override public void setEnabledCipherSuites(String[] suites) { delegate.setEnabledCipherSuites(suites); } @Override public String[] getSupportedProtocols() { return delegate.getSupportedProtocols(); } @Override public String[] getEnabledProtocols() { return delegate.getEnabledProtocols(); } @Override public void setEnabledProtocols(String[] 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 String toString() { return delegate.toString(); } @Override public boolean equals(Object o) { return delegate.equals(o); } } }
Используйте этот class следующим образом:
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();
ОБНОВИТЬ :
Теперь правильным решением было бы установить более новый поставщик безопасности с помощью Служб Google Play :
ProviderInstaller.installIfNeeded(getApplicationContext());
Это эффективно дает вашему приложению доступ к более новой версии OpenSSL и Java Security Provider, которая включает поддержку TLSv1.2 в SSLEngine. После установки нового провайдера вы можете создать SSLEngine, который поддерживает SSLv3, TLSv1, TLSv1.1 и TLSv1.2 обычным способом:
SSLContext sslContext = SSLContext.getInstance("TLSv1.2"); sslContext.init(null, null, null); SSLEngine engine = sslContext.createSSLEngine();
Или вы можете ограничить разрешенные протоколы с помощью engine.setEnabledProtocols
.
Не забудьте добавить следующую зависимость ( последняя версия, найденная здесь ):
compile 'com.google.android.gms:play-services-auth:11.8.0'
Для получения дополнительной информации ознакомьтесь с этой ссылкой .
сценарий
Я получал исключения SSLHandshake на устройствах с версиями Android ранее Android 5.0. В моем случае использования я также хотел создать TrustManager, чтобы доверять моему сертификату клиента.
Я внедрил NoSSLv3SocketFactory и NoSSLv3Factory для удаления SSLv3 из списка поддерживаемых протоколов моего клиента, но я не мог заставить ни одно из этих решений работать.
Некоторые вещи, которые я узнал:
- На устройствах старше Android 5.0 TLSv1.1 и TLSv1.2 протоколы по умолчанию не включены.
- Протокол SSLv3 по умолчанию не отключается на устройствах старше Android 5.0.
- SSLv3 не является безопасным протоколом, поэтому желательно удалить его из списка поддерживаемых протоколов нашего клиента до того, как будет установлено соединение.
Что сработало для меня
Разрешить Provider
безопасности Android обновляться при запуске приложения.
Поставщик по умолчанию до 5.0+ не отключает SSLv3. При условии, что у вас есть доступ к сервисам Google Play, относительно просто исправить прокси-сервер Android от вашего приложения.
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."); } }
Если теперь вы создаете свой OkHttpClient или HttpURLConnection TLSv1.1 и TLSv1.2 должны быть доступны в виде протоколов, а SSLv3 следует удалить. Если клиент / соединение (или, более конкретно, SSLContext) было инициализировано до вызова ProviderInstaller.installIfNeeded(...)
то его нужно будет воссоздать.
Не забудьте добавить следующую зависимость ( последняя версия, найденная здесь ):
compile 'com.google.android.gms:play-services-auth:11.8.0'
Источники:
- Закрепление поставщика безопасности поставщиком ProviderInstaller
- Использование SSLEngine для TLSv1.2 на Android (4.4.2)
В стороне
Мне не нужно было явно указывать, какие алгоритмы шифрования должен использовать мой клиент, но я нашел сообщение SO, рекомендующее те, которые считаются наиболее безопасными на момент написания: какие Cipher Suites включить для SSL Socket?
Это решило это для меня:
Документация Android для SSLSocket говорит о том, что TLS 1.1 и TLS 1.2 поддерживаются на уровне API для Android начиная с 16+ (Android 4.1, Jelly Bean). Но по умолчанию он отключен, но начиная с уровня API 20+ (Android 4.4 для часов, Kitkat Watch и Android 5.0 для телефона Lollipop) они включены. Но очень сложно найти документацию о том, как включить его для телефонов под управлением 4.1, например. Чтобы включить TLS 1.1 и 1.2, вам необходимо создать настраиваемый SSLSocketFactory, который будет проксировать все вызовы по умолчанию SSLSocketFactory. В дополнение к этому мы должны переопределить все методы createSocket и callsetEnabledProtocols на возвращаемом SSLSocket, чтобы включить TLS 1.1 и TLS 1.2. Для примера реализации просто следуйте приведенной ниже ссылке.
android 4.1. включить tls1.1 и tls 1.2
Также вы должны знать, что вы можете заставить TLS v1.2 для устройств Android 4.0, которые по умолчанию не включены:
Это должно быть в первой строке вашего приложения:
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(); }
Он воспроизводимый только тогда, когда я использую прокси-сервер для genymotion (<4.4).
Проверьте настройки прокси-сервера в настройках-> Беспроводные сети и Wi-Fi -> (Long Press WiredSSID) -> Изменить сеть
Выберите опцию show advanced options: установите для параметров прокси-сервера значение NONE.
Предположительно, я также решил эту проблему с пользовательской реализацией SSLFactory, но, согласно этим документам OkHttp, решение намного проще.
Мое окончательное решение с необходимыми шифрами для устройств 4.2+ выглядит следующим образом:
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); }
Обратите внимание, что набор поддерживаемых протоколов зависит от настроенного на вашем сервере.
Я решил проблему: 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 String[] getDefaultCipherSuites() { return delegate.getDefaultCipherSuites(); } @Override public String[] 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, String host, int port, boolean autoClose) throws IOException { return makeSocketSafe(delegate.createSocket(s, host, port, autoClose)); } @Override public Socket createSocket(String host, int port) throws IOException { return makeSocketSafe(delegate.createSocket(host, port)); } @Override public Socket createSocket(String 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(String[] 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 " + String.valueOf(enabledProtocols)); } protocols = enabledProtocols .toArray(new String[enabledProtocols.size()]); } // super.setEnabledProtocols(protocols); super.setEnabledProtocols(new String[]{"TLSv1.2"}); } } public class DelegateSSLSocket extends SSLSocket { protected final SSLSocket delegate; DelegateSSLSocket(SSLSocket delegate) { this.delegate = delegate; } @Override public String[] getSupportedCipherSuites() { return delegate.getSupportedCipherSuites(); } @Override public String[] getEnabledCipherSuites() { return delegate.getEnabledCipherSuites(); } @Override public void setEnabledCipherSuites(String[] suites) { delegate.setEnabledCipherSuites(suites); } @Override public String[] getSupportedProtocols() { return delegate.getSupportedProtocols(); } @Override public String[] getEnabledProtocols() { return delegate.getEnabledProtocols(); } @Override public void setEnabledProtocols(String[] 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 String toString() { return delegate.toString(); } @Override public boolean equals(Object o) { return delegate.equals(o); } } } 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 String[] getDefaultCipherSuites() { return delegate.getDefaultCipherSuites(); } @Override public String[] 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, String host, int port, boolean autoClose) throws IOException { return makeSocketSafe(delegate.createSocket(s, host, port, autoClose)); } @Override public Socket createSocket(String host, int port) throws IOException { return makeSocketSafe(delegate.createSocket(host, port)); } @Override public Socket createSocket(String 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(String[] 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 " + String.valueOf(enabledProtocols)); } protocols = enabledProtocols .toArray(new String[enabledProtocols.size()]); } // super.setEnabledProtocols(protocols); super.setEnabledProtocols(new String[]{"TLSv1.2"}); } } public class DelegateSSLSocket extends SSLSocket { protected final SSLSocket delegate; DelegateSSLSocket(SSLSocket delegate) { this.delegate = delegate; } @Override public String[] getSupportedCipherSuites() { return delegate.getSupportedCipherSuites(); } @Override public String[] getEnabledCipherSuites() { return delegate.getEnabledCipherSuites(); } @Override public void setEnabledCipherSuites(String[] suites) { delegate.setEnabledCipherSuites(suites); } @Override public String[] getSupportedProtocols() { return delegate.getSupportedProtocols(); } @Override public String[] getEnabledProtocols() { return delegate.getEnabledProtocols(); } @Override public void setEnabledProtocols(String[] 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 String toString() { return delegate.toString(); } @Override public boolean equals(Object o) { return delegate.equals(o); } } }
Основной class:
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());
Когда я получил эту ошибку, это было связано с тем, что поддерживаемые сервером протоколы (версии TLS) и / или шифрованные версии не были включены (и, возможно, даже не поддерживаются) устройством. Для API 16-19 TLSv1.1 и TLSv1.2 поддерживаются, но не включены по умолчанию. Как только я включил их для этих версий, у меня все еще появилась ошибка, потому что эти версии не поддерживают ни один из шифров нашего экземпляра AWS CloudFront.
Поскольку для Android нельзя добавлять шифры, нам пришлось переключить нашу версию CloudFront с TLSv1.2_2018 на TLSv1.1_2016 (которая все еще поддерживает TLSv1.2, она просто не требует этого), которая имеет четыре из шифров, поддерживаемых более ранние версии Android, два из которых по-прежнему считаются сильными.
В этот момент ошибка исчезла, а вызовы прошли (с TLSv1.2), потому что был хотя бы один протокол и по крайней мере один шифр, который разделял устройство и сервер.
Обратитесь к таблицам на этой странице, чтобы узнать, какие протоколы и шифры поддерживаются и разрешены в каких версиях Android.
Теперь Android действительно пытался использовать SSLv3, как подразумевается в сообщении об ошибке «sslv3 alert handshake failure» сообщения об ошибке? Я сомневаюсь в этом; Я подозреваю, что это старая паутина в библиотеке SSL, которая не была очищена, но я не могу сказать точно.
Чтобы включить TLSv1.2 (и TLSv1.1), я смог использовать гораздо более простой SSLSocketFactory
чем те, что были в других местах (например, NoSSLv3SocketFactory
). Он просто гарантирует, что включенные протоколы include в себя все поддерживаемые протоколы и что включенные шифры include все поддерживаемые шифры (последнее для меня не было необходимым, но это могло быть для других) – см. configure()
внизу. Если вы предпочитаете использовать только самые последние протоколы, вы можете заменить socket.supportedProtocols
на что-то вроде arrayOf("TLSv1.1", "TLSv1.2")
(аналогично для шифров):
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: String, port: Int, autoClose: Boolean): Socket { return configure(socketFactory.createSocket(s, host, port, autoClose) as SSLSocket) } override fun createSocket(host: String, 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: String, 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 } }