2016-05-23 2 views
1

Я разрабатываю Android приложение для уровня API 16+ и от того, что я видел по умолчанию TLS v1.1 и TLS v1.2 поддерживаются, но не включена на Android 4.1+Android 4.2.2, Как включить TLS 1.2 для HttpsURLConnection?

Я использовал SSLSocketFacory здесь :

http://blog.dev-area.net/2015/08/13/android-4-1-enable-tls-1-1-and-tls-1-2/

Что я сумел получить работу на следующем примере:

public class TLSSocketFactory extends SSLSocketFactory { 

    private SSLSocketFactory internalSSLSocketFactory; 

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

} 

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

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

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

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

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

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

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

@Override 
public Socket createSocket(InetAddress address, int port, InetAddress localAddress, int localPort) throws IOException { 
    return enableTLSOnSocket(internalSSLSocketFactory.createSocket(address, port, localAddress, localPort)); 
} 

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

и я использую следующий назвать:

public class MainActivity extends AppCompatActivity { 
    @Override 
    protected void onCreate(Bundle savedInstanceState) { 
    super.onCreate(savedInstanceState); 
    setContentView(R.layout.activity_main); 

    try{ 

     SSLContext context = SSLContext.getDefault(); 
     TLSSocketFactory factory = new TLSSocketFactory(); 
     SSLSocket socket = (SSLSocket)factory.createSocket(); 
     String[] protocols = socket.getSupportedProtocols(); 

     // this now has the correct protocols enabled for sockets 
     String[] enabled = socket.getEnabledProtocols(); 



     HttpsURLConnection.setDefaultSSLSocketFactory(new TLSSocketFactory()); 
     URL url = new URL("https://mysslsite/"); 
     HttpsURLConnection connection = (HttpsURLConnection) url.openConnection(); 
     connection.setSSLSocketFactory(new TLSSocketFactory()); 

     Log.i("", ""); 
    }catch(Exception ex){ 
     ex.printStackTrace(); 
    } 
    } 
} 

Я вижу соединение сокета. Теперь у меня есть правильные разрешенные протоколы, однако как включить эти протоколы для соединения с URL? как бы я также проверить, что эти протоколы были включены для HttpsURLConnection?

Я попытался установить фабрику сокетов ssl для подключения, но я не уверен, как проверить, что протоколы были включены?

UPDATE: Я изменил свой код следующим образом:

    String myURL = "https://mysslservice"; 
        SSLContext sslcontext = SSLContext.getInstance("TLS"); 
        sslcontext.init(null, null, null); 
        SSLSocketFactory noSSLv3Factory = new NoSSLv3SocketFactory(sslcontext.getSocketFactory()); 
        HttpsURLConnection.setDefaultSSLSocketFactory(noSSLv3Factory); 

        URL url = new URL(myURL); 

        HttpsURLConnection l_connection = (HttpsURLConnection) url.openConnection(); 
        l_connection.connect(); 

Я использовал следующую реализацию SSL завода

общественного класса NoSSLv3SocketFactory расширяет SSLSocketFactory { частный окончательный SSLSocketFactory делегат;

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<String> enabledProtocols = new ArrayList<String>(Arrays.asList(delegate.getSupportedProtocols())); 
      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); 
    } 
} 

}

однако я получаю следующее исключение:

javax.net.ssl.SSLHandshakeException: javax.net.ssl.SSLProtocolException: SSL рукопожатия прерванный: SSL = 0xb838faa0: Сбой в SSL библиотеки, как правило, ошибка протокола ошибка: 14077410: SSL процедуры: SSL23_GET_SERVER_HELLO: SSLv3 предупреждение отказ рукопожатия (внешняя/OpenSSL/SSL/s23_clnt.c: 741 0x9da83901: 0x00000000)

служба SSL имеет только TLSv1.2 Enabl ed и SSLv3 отключен, однако, похоже, приложение все еще использует sslv3?

ответ

0

Ваш код уже содержит строку

HttpsURLConnection.setDefaultSSLSocketFactory(new TLSSocketFactory()); 

, который устанавливает свой TLSSocketFactory для всех соединений в вашем приложении, которые установлены впоследствии. Поэтому вызов connection.setSSLSocketFactory(new TLSSocketFactory()); является избыточным и не должен иметь никакого эффекта.

Примечание. Возможно, возникла проблема с уже открытыми соединениями, которые были установлены до того, как вы вызвали setDefaultSSLSocketFactory и которые были кэшированы изнутри и повторно использованы. Поэтому перед тем, как открыть какое-либо сетевое соединение, рекомендуется установить фабрику сокетов по умолчанию.

0

UPDATE: Это теперь решено вопрос был вопросом сертификата SSL, и может подтвердить, что оба метода работает на андроид уровня апите 16+

0

Я решил эту проблему в соответствии с указанием, предусмотренным в статье http://blog.dev-area.net/2015/08/13/android-4-1-enable-tls-1-1-and-tls-1-2/ с несколько изменений.

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

Это код пользовательского 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 the 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; 
    } 
} 

Вы также можете проверить сертификат сервера с помощью онлайн-услуг, таких как https://www.ssllabs.com/ssltest/analyze.html, чтобы убедиться, что сервер имеет сертификат, включаемого

Смежные вопросы