2015-03-25 71 views
11

啓用TLSv1.2工作我用OKHttp我的項目。我想爲我的服務呼叫啓用TLSv1.2。任何機構都可以告訴我如何啓用它。的Android在OKHttp

+0

它是如何爲你工作? 請告訴我我不能問的問題stackoverflow – 2015-11-26 23:39:12

+0

這個解決方案解決了我的問題:https://stackoverflow.com/a/45853669/3448003 – 2017-08-24 07:15:12

回答

5

據我所知OKHttp不包括自己的SSL/TLS庫,因此它只是使用由Android提供的標準的SSLSocket。

什麼都支持TLS版本(和啓用)取決於所使用的Android版本。 在某些電話上支持TLS 1.2,但默認情況下未啓用。在這種情況下,您可以通過實現自定義包裝器SSLSocketFactory來啓用它,該包裝器在內部使用默認的SSLSocketFactory,並在創建的每個套接字上調用setEnabledProtocols(new String{"TLS1.2"})

6

見OkHttp的HTTPS documentation

ConnectionSpec spec = new ConnectionSpec.Builder(ConnectionSpec.MODERN_TLS) 
    .tlsVersions(TlsVersion.TLS_1_2) 
    .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) 
    .build(); 
OkHttpClient client = ... 
client.setConnectionSpecs(Collections.singletonList(spec)); 
+2

作爲文檔說 - 這隻會在Android 5.0或更高版本 – Shlomi 2015-04-21 08:08:30

+0

它doesn甚至不適用於Android 5.0。我得到SSL HandshakeException。 – 2015-10-22 20:53:09

+0

這不起作用 – 2015-11-26 23:34:52

0

這是基本相同的答案above,但我覺得自己像一個代碼示例將是誰比誰這裏的土地和不加快速度航行的java的SSL景觀有用。

什麼最終結束了我的工作是基於此報告的問題:https://github.com/mattleibow/square-bindings/issues/1
從這個要點https://gist.github.com/mattleibow/c8abfa323db094b820cc

注意這些代碼示例是用C#/ Xamarin但也很容易被轉換爲Java。

internal class CompleteSSLSocketFactory : SSLSocketFactory 
{ 
    private readonly SSLSocketFactory innerFactory; 

    public CompleteSSLSocketFactory (SSLSocketFactory innerFactory) 
    { 
     this.innerFactory = innerFactory; 
    } 

    public override string[] GetDefaultCipherSuites() 
    { 
     return innerFactory.GetDefaultCipherSuites(); 
    } 

    public override string[] GetSupportedCipherSuites() 
    { 
     return innerFactory.GetSupportedCipherSuites(); 
    } 

    public override Socket CreateSocket() 
    { 
     return MakeSocketSafe (innerFactory.CreateSocket()); 
    } 

    public override Socket CreateSocket (Socket s, string host, int port, bool autoClose) 
    { 
     return MakeSocketSafe (innerFactory.CreateSocket (s, host, port, autoClose)); 
    } 

    public override Socket CreateSocket (string host, int port) 
    { 
     return MakeSocketSafe (innerFactory.CreateSocket (host, port)); 
    } 

    public override Socket CreateSocket (string host, int port, InetAddress localHost, int localPort) 
    { 
     return MakeSocketSafe (innerFactory.CreateSocket (host, port, localHost, localPort)); 
    } 

    public override Socket CreateSocket (InetAddress host, int port) 
    { 
     return MakeSocketSafe (innerFactory.CreateSocket (host, port)); 
    } 

    public override Socket CreateSocket (InetAddress address, int port, InetAddress localAddress, int localPort) 
    { 
     return MakeSocketSafe (innerFactory.CreateSocket (address, port, localAddress, localPort)); 
    } 

    private Socket MakeSocketSafe (Socket socket) 
    { 
     var sslSocket = socket as SSLSocket; 
     if (sslSocket != null) { 
      // enable all supported protocols for this socket 
      sslSocket.SetEnabledProtocols (sslSocket.GetSupportedProtocols()); 
      sslSocket.SetEnabledCipherSuites (sslSocket.GetSupportedCipherSuites()); 
     } 
     return socket; 
    } 
} 

,然後調用它像:

// this.client is an OkHttpClient 
if (Android.OS.Build.VERSION.SdkInt < BuildVersionCodes.Lollipop) { 
    this.client.SetSslSocketFactory(new CompleteSSLSocketFactory(HttpsURLConnection.DefaultSSLSocketFactory)); 
} 

這爲我工作,在API測試19

1

原來我的解決方案是非常相似的Ken的(除Java之外)。我發現它here雖然不得不作出一些小的改變,使其工作。希望這個作品'開箱即用'爲他人。

public class TLSSocketFactoryCompat extends SSLSocketFactory { 

private SSLSocketFactory internalSSLSocketFactory; 

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

public TLSSocketFactoryCompat(TrustManager[] tm) throws KeyManagementException, NoSuchAlgorithmException { 
    SSLContext context = SSLContext.getInstance("TLS"); 
    context.init(null, tm, new java.security.SecureRandom()); 
    internalSSLSocketFactory = context.getSocketFactory(); 
} 

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

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

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

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

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

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

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

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

private Socket enableTLSOnSocket(Socket socket) { 
    if(socket != null && (socket instanceof SSLSocket)) { 
     //Create list of supported protocols 
     ArrayList<String> supportedProtocols = new ArrayList<>(); 
     for (String protocol : ((SSLSocket)socket).getEnabledProtocols()) { 

      //Log.d("TLSSocketFactory", "Supported protocol:" + protocol); 
      //Only add TLS protocols (don't want ot support older SSL versions) 
      if (protocol.toUpperCase().contains("TLS")) { 
       supportedProtocols.add(protocol); 
      } 
     } 
     //Force add TLSv1.1 and 1.2 if not already added 
     if (!supportedProtocols.contains("TLSv1.1")) { 
      supportedProtocols.add("TLSv1.1"); 
     } 
     if (!supportedProtocols.contains("TLSv1.2")) { 
      supportedProtocols.add("TLSv1.2"); 
     } 

     String[] protocolArray = supportedProtocols.toArray(new String[supportedProtocols.size()]); 
     /*for (int i = 0; i < protocolArray.length; i++) { 
      Log.d("TLSSocketFactory", "protocolArray[" + i + "]" + protocolArray[i]); 
     }*/ 

     //enable protocols in our list 
     ((SSLSocket)socket).setEnabledProtocols(protocolArray); 
    } 
    return socket; 
} 

}

用法:

OkHttpClient httpClient = new OkHttpClient(); 
    //Add Custom SSL Socket Factory which adds TLS 1.1 and 1.2 support for Android 4.1-4.4 
    try { 
     httpClient.setSslSocketFactory(new TLSSocketFactoryCompat()); 
    } catch (KeyManagementException e) { 
     e.printStackTrace(); 
    } catch (NoSuchAlgorithmException e) { 
     e.printStackTrace(); 
    } 
+0

我對此有很高的期望,但是我看到'啓用TLS 1.2 啓用TLS 1.2 啓用TLS 1.2 啓用TLS 1.2 啓用TLS 1.2 啓用TLS 1.2 啓用TLS 1.2 啓用TLS 1.2 javax.net.ssl.SSLHandshakeException:javax.net.ssl.SSLProtocolException:SSL握手終止:SSL = 0x5ff7f518:失敗在SSL庫,通常一個協議錯誤 錯誤:14094410:SSL例程:SSL3_READ_BYTES:sslv3警報握手失敗(external/openssl/ssl/s3_pkt.c:1256 0x5fe90e28:0x00000003) at com.android.org.conscrypt.OpenSSLSocketImpl.startHandshak e(OpenSSLSocketImpl.java:568)' – 2016-07-11 10:43:06

+0

至少它在放棄之前嘗試enableTLSOnSocket()8次,在幾秒鐘的時間內。 – 2016-07-11 10:43:47

+0

有人在某個地方,我不確定你得到的錯誤實際上是相關的(可能是一個證書問題),但它提醒我,我更新了這個類,以確保只添加了支持的協議列表。我想在它可能只剩下TLS 1.1和1.2啓用之前。希望這有助於。 – aaronmarino 2016-07-11 16:09:17

2

檢查我的代碼!工作完美!

private void checkTls() { 
    if (android.os.Build.VERSION.SDK_INT < 21) { 
     try { 
      ProviderInstaller.installIfNeededAsync(this, new ProviderInstaller.ProviderInstallListener() { 
       @Override 
       public void onProviderInstalled() { 
       } 

       @Override 
       public void onProviderInstallFailed(int i, Intent intent) { 
       } 
      }); 
     } catch (Exception e) { 
      finish(); 
      e.printStackTrace(); 
     } 
    } 
} 
+0

在調用Web服務之前使用它。只需要在您的應用程序中調用一次 – 2016-08-15 20:50:33

+0

此解決方案不適用於所有人。 ProviderInstaller類來自Google Play服務,並且Google Play服務在每個Android設備上都不可用。尤其在中國,GPS不允許使用。 – EJK 2016-11-23 20:11:07