Reputation: 2878
i am using OKHttp for my project. i want to enable TLSv1.2 for my service call. can any body tell me how to enable it.
Upvotes: 22
Views: 37437
Reputation: 42615
As far as I know OKHttp does not include own SSL/TLS libraries, therefore it just uses the standard SSLSocket provided by Android.
What TLS versions are supported (and enabled) depends on the used Android version.
On some phones TLS 1.2 is supported but not enabled by default (as far as I remember this affects phones with Android 4.1/4.2/4.4). In such cases you could enable it by implementing a custom wrapper SSLSocketFactory that uses internally the default SSLSocketFactory and calls setEnabledProtocols(new String[]{"TLS1.2"})
on every Socket that is created.
On device with Google Services installed the preferred way to enable TLS 1.2 on old Android 4.x device is using ProviderInstaller.
Upvotes: 10
Reputation: 4002
Turns out my solution is very similar to Ken's (except in Java). I found it here although had to make a couple of small changes to get it to work. Hopefully this works 'out of the box' for others.
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;
}
}
Usage:
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();
}
Upvotes: 1
Reputation: 225
Check My Code!!Working perfect!
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();
}
}
}
Upvotes: 6
Reputation: 1174
This is basically the same as the answer above but I feel like a code sample would be useful for anyone else who lands here and isn't up to speed on navigating the java ssl landscape.
What ultimately ended up working for me was based on the issue reported here: https://github.com/mattleibow/square-bindings/issues/1
from this gist https://gist.github.com/mattleibow/c8abfa323db094b820cc
Note these code samples are in C# / Xamarin but can be translated to java fairly easily.
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;
}
}
And then calling it like:
// this.client is an OkHttpClient
if (Android.OS.Build.VERSION.SdkInt < BuildVersionCodes.Lollipop) {
this.client.SetSslSocketFactory(new CompleteSSLSocketFactory(HttpsURLConnection.DefaultSSLSocketFactory));
}
This worked for me, tested on API 19.
Upvotes: 0
Reputation: 40593
See OkHttp’s 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));
Upvotes: 13