Sorry for my english. I try using libruary OKhttp, and i use https for post reqest. Now i have error, when i try post my example, this is error:
java.net.UnknownServiceException: Unable to find acceptable protocols. isFallback=false, modes=[ConnectionSpec(cipherSuites=[TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, TLS_DHE_RSA_WITH_AES_128_GCM_SHA256, TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, TLS_ECDHE_ECDSA_WITH_RC4_128_SHA, TLS_ECDHE_RSA_WITH_RC4_128_SHA, TLS_DHE_RSA_WITH_AES_128_CBC_SHA], tlsVersions=[TLS_1_2], supportsTlsExtensions=true)], supported protocols=[SSLv3, TLSv1]
I try fix it, but i cant do this. I dont know what i have this error
And bellow my code:
public class PostOKhttp extends AsyncTask<String, Void, String> {
@Override
protected String doInBackground(String...ulr) {
Response response = null;
OkHttpClient client = new OkHttpClient();
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,
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)
.build();
client.setConnectionSpecs(Collections.singletonList(spec));
RequestBody postForm = new FormEncodingBuilder()
.add("name", "name")
.build();
Request request = new Request.Builder()
.url(ulr[0])
.addHeader("id", "--")
.addHeader("key", "--")
.post(postForm)
.build();
try {
response = client.newCall(request).execute();
Log.e("post", response.body().string());
} catch (Exception e) {
Log.e("error", e.toString());
}
return null;
}
@Override
protected void onPostExecute(String result) {
}
UDP:
Use CertificatePinner
i add this code
String link = "example.net";
CertificatePinner certificatePinner = new CertificatePinner.Builder()
.add(link, "sha1/DmxUShsZuNiqPQsX2Oi9uv2sCnw=")
.add(link, "sha1/SXxoaOSEzPC6BgGmxAt/EAcsajw=")
.add(link, "sha1/blhOM3W9V/bVQhsWAcLYwPU6n24=")
.add(link, "sha1/T5x9IXmcrQ7YuQxXnxoCmeeQ84c=")
.build();
client.setCertificatePinner(certificatePinner);
Now i have this error:
javax.net.ssl.SSLHandshakeException: java.security.cert.CertPathValidatorException: Trust anchor for certification path not found.
Actually the problem is TLSv1.1 and TLSv1.2 not enabled on Android <5 by default and to connect using these latest secure protocol we must have to enable in Android <5 devices.
Because by default android device pick the highest supported protocol to establish the connection but the highest/ newest secure protocol (eg. TLSV1.1 or TLSV1.2) are not enable by default (only enabled are SSLV3.0 or TLSV1.0).
Enabling the TLSV1.1 and TLSV1.2 in android < 5
import java.io.IOException;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.SSLSocketFactory;
/**
* @author Bajrang Hudda
*/
public class MyTLSSocketFactory extends SSLSocketFactory {
private SSLSocketFactory internalSSLSocketFactory;
public MyTLSSocketFactory() 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();
}
@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)) {
((SSLSocket)socket).setEnabledProtocols(new String[] {"TLSv1.1", "TLSv1.2"});
}
return socket;
}
}
And now add it in your Okhttpclient -
protected static OkHttpClient getHttpClient(long timeout){
String hostname = Constants.HOST_NAME_DEBUG;
CertificatePinner certificatePinner = new CertificatePinner.Builder()
.add(hostname, "sha1/mBN/TTGneHe2Hq0yFG+SRt5nMZQ=")
.add(hostname, "sha1/6CgvsAgBlX3PYiYRGedC0NZw7ys=")
.build();
//specifying the specs; this is impotent otherwise android <5 won't work
//And do note to include the android < 5 supported specs.
ConnectionSpec spec = new ConnectionSpec.Builder(ConnectionSpec.MODERN_TLS)
.tlsVersions(TlsVersion.TLS_1_1, 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,
CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256)
.build();
final OkHttpClient okHttpClient = new OkHttpClient();
okHttpClient.setCertificatePinner(certificatePinner);
okHttpClient.setConnectionSpecs(Collections.singletonList(spec));
try
{
// enabling the tlsv1.1 and tlsv.2
okHttpClient.setSslSocketFactory(new MyTLSSocketFactory());
} catch (KeyManagementException e)
{
e.printStackTrace();
} catch (NoSuchAlgorithmException e)
{
e.printStackTrace();
}
return okHttpClient;
}
And now finally add it in your retrofit -
RestAdapter restAdapter = new RestAdapter.Builder()
.setEndpoint(Constants.API_URL)
.setLogLevel(RestAdapter.LogLevel.FULL)
.setErrorHandler(new ErrorHandler())
.setClient(getHttpClient())
.setRequestInterceptor(new SecureHeaderInterceptor(null))
.build();
That's it, Happy Coding :-)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With