Reputation: 157
I tryed to send a POST request to a remote secure server ( https call). First i used the OkHTTP lib to make the call, as this lib worked to make http calls in a previous app, but with https it does not work anymore, see my previous post : Cannot make HTTPS calls with OKHTTP lib
I decided to try the HttpURLConnection to make the call as explained here : https://developer.android.com/reference/java/net/HttpURLConnection.html The code I am using only works on certain devices.
It does work with a Wiko on android 6.0 equiped with SIM card and wifi and does not work on a Samsung on Android 4.2.2 only linked to internet via Wifi.
Here is a logcat of the problem I encounter :
02-23 12:29:59.893 11026-11951 W/System.err: javax.net.ssl.SSLHandshakeException: com.android.org.bouncycastle.jce.exception.ExtCertPathValidatorException: Could not validate certificate signature.
02-23 12:29:59.923 11026-11951 W/System.err: at org.apache.harmony.xnet.provider.jsse.OpenSSLSocketImpl.startHandshake(OpenSSLSocketImpl.java:382)
02-23 12:29:59.923 11026-11951 W/System.err: at libcore.net.http.HttpConnection.setupSecureSocket(HttpConnection.java:231)
02-23 12:29:59.923 11026-11951 W/System.err: at libcore.net.http.HttpsURLConnectionImpl$HttpsEngine.makeSslConnection(HttpsURLConnectionImpl.java:478)
02-23 12:29:59.923 11026-11951 W/System.err: at libcore.net.http.HttpsURLConnectionImpl$HttpsEngine.connect(HttpsURLConnectionImpl.java:433)
02-23 12:29:59.923 11026-11951 W/System.err: at libcore.net.http.HttpEngine.sendSocketRequest(HttpEngine.java:290)
02-23 12:29:59.923 11026-11951 W/System.err: at libcore.net.http.HttpEngine.sendRequest(HttpEngine.java:240)
02-23 12:29:59.923 11026-11951 W/System.err: at libcore.net.http.HttpURLConnectionImpl.connect(HttpURLConnectionImpl.java:81)
02-23 12:29:59.923 11026-11951 W/System.err: at libcore.net.http.HttpURLConnectionImpl.getOutputStream(HttpURLConnectionImpl.java:197)
02-23 12:29:59.923 11026-11951 W/System.err: at libcore.net.http.HttpsURLConnectionImpl.getOutputStream(HttpsURLConnectionImpl.java:281)
02-23 12:29:59.923 11026-11951 W/System.err: at com.gulplug.gulplugtoolbox.DiagnosisOnline$NetworkAsyncTask.doInBackground(DiagnosisOnline.java:109)
02-23 12:29:59.923 11026-11951 W/System.err: at com.gulplug.gulplugtoolbox.DiagnosisOnline$NetworkAsyncTask.doInBackground(DiagnosisOnline.java:82)
02-23 12:29:59.923 11026-11951 W/System.err: at android.os.AsyncTask$2.call(AsyncTask.java:287)
02-23 12:29:59.923 11026-11951 W/System.err: at java.util.concurrent.FutureTask.run(FutureTask.java:234)
02-23 12:29:59.923 11026-11951 W/System.err: at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:230)
02-23 12:29:59.923 11026-11951 W/System.err: at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1080)
02-23 12:29:59.923 11026-11951 W/System.err: at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:573)
02-23 12:29:59.933 11026-11951 W/System.err: at java.lang.Thread.run(Thread.java:856)
02-23 12:29:59.933 11026-11951 W/System.err: Caused by: java.security.cert.CertificateException: com.android.org.bouncycastle.jce.exception.ExtCertPathValidatorException: Could not validate certificate signature.
02-23 12:29:59.933 11026-11951 W/System.err: at org.apache.harmony.xnet.provider.jsse.TrustManagerImpl.checkTrusted(TrustManagerImpl.java:296)
02-23 12:29:59.933 11026-11951 W/System.err: at org.apache.harmony.xnet.provider.jsse.TrustManagerImpl.checkServerTrusted(TrustManagerImpl.java:197)
02-23 12:29:59.933 11026-11951 W/System.err: at org.apache.harmony.xnet.provider.jsse.OpenSSLSocketImpl.verifyCertificateChain(OpenSSLSocketImpl.java:598)
02-23 12:29:59.933 11026-11951 W/System.err: at org.apache.harmony.xnet.provider.jsse.NativeCrypto.SSL_do_handshake(Native Method)
02-23 12:29:59.933 11026-11951 W/System.err: at org.apache.harmony.xnet.provider.jsse.OpenSSLSocketImpl.startHandshake(OpenSSLSocketImpl.java:379)
02-23 12:29:59.933 11026-11951 W/System.err: ... 16 more
02-23 12:29:59.933 11026-11951 W/System.err: Caused by: com.android.org.bouncycastle.jce.exception.ExtCertPathValidatorException: Could not validate certificate signature.
02-23 12:29:59.943 11026-11951 W/System.err: at com.android.org.bouncycastle.jce.provider.RFC3280CertPathUtilities.processCertA(RFC3280CertPathUtilities.java:1475)
02-23 12:29:59.943 11026-11951 W/System.err: at com.android.org.bouncycastle.jce.provider.PKIXCertPathValidatorSpi.engineValidate(PKIXCertPathValidatorSpi.java:305)
02-23 12:29:59.943 11026-11951 W/System.err: at com.sec.android.security.pkix.SecCertPathValidatorSpi.engineValidate(SecCertPathValidatorSpi.java:99)
02-23 12:29:59.953 11026-11951 W/System.err: at java.security.cert.CertPathValidator.validate(CertPathValidator.java:190)
02-23 12:29:59.953 11026-11951 W/System.err: at org.apache.harmony.xnet.provider.jsse.TrustManagerImpl.checkTrusted(TrustManagerImpl.java:283)
02-23 12:29:59.953 11026-11951 W/System.err: ... 20 more
02-23 12:29:59.953 11026-11951 W/System.err: Caused by: java.security.SignatureException: Signature was not verified
02-23 12:29:59.953 11026-11951 W/System.err: at org.apache.harmony.security.provider.cert.X509CertImpl.verify(X509CertImpl.java:384)
02-23 12:29:59.953 11026-11951 W/System.err: at com.android.org.bouncycastle.jce.provider.CertPathValidatorUtilities.verifyX509Certificate(CertPathValidatorUtilities.java:1428)
02-23 12:29:59.953 11026-11951 W/System.err: at com.android.org.bouncycastle.jce.provider.RFC3280CertPathUtilities.processCertA(RFC3280CertPathUtilities.java:1470)
02-23 12:29:59.953 11026-11951 W/System.err: ... 24 more
and the code attached to this log :
class NetworkAsyncTask extends AsyncTask<Void, Void, Void> {
@Override
protected Void doInBackground(Void... voids) {
Authentification authentification = new Authentification();
authentification.setApplicationToken(applicationtoken);
Gson gson = new Gson();
//String json = gson.toJson(authentification);
String json = "";
Log.d(TAG, json);
JSONObject auth = new JSONObject();
try {
auth.put("application_token",mytoken);
} catch (JSONException e) {
e.printStackTrace();
}
String url = myurl;
try {
URL object = new URL(url);
HttpsURLConnection con = (HttpsURLConnection) object.openConnection();
con.setDoOutput(true);
con.setDoInput(true);
con.setRequestProperty("Content-Type", "application/json");
con.setRequestProperty("Accept", "application/json");
con.setRequestProperty("Content-Lenght", String.valueOf(json.getBytes("UTF-8").length));
con.setRequestMethod("POST");
con.setSSLSocketFactory((SSLSocketFactory) SSLSocketFactory.getDefault());
OutputStreamWriter wr = null;
wr = new OutputStreamWriter(con.getOutputStream());
wr.write(auth.toString());
wr.flush();
StringBuilder sb = new StringBuilder();
int HttpResult = 0;
HttpResult = con.getResponseCode();
if (HttpResult == HttpURLConnection.HTTP_OK) {
BufferedReader br = new BufferedReader(
new InputStreamReader(con.getInputStream(), "utf-8"));
String line = null;
while ((line = br.readLine()) != null) {
sb.append(line + "\n");
}
br.close();
Log.d(TAG, "First log");
Log.d(TAG, "" + sb.toString());
} else {
Log.d(TAG, "response code : " + HttpResult);
Log.d(TAG, "Http not ok");
Log.d(TAG, con.getResponseMessage());
}
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
}
I don't understand why my first device can validate the signature and the other not. I tryed to sync the date and time as explained here: Could not validate certificate signature?
A possible explanation of my problem here but i don't get it https://groups.google.com/forum/#!topic/android-security-discuss/C_cm3k9SdaM
Does someone encountered the same problem and fixed it ?
UPDT : Both of the methods presented by Alex and Anton are not working with my device. Using Google play service says that provider is up to date. And I still get no signature validation when enabling TLS 1.1 and 1.2 with the method described here : https://blog.dev-area.net/2015/08/13/android-4-1-enable-tls-1-1-and-tls-1-2/
UPDT 2: Following this link, the server should use TLS 1.1 : https://www.ssllabs.com
Upvotes: 2
Views: 2409
Reputation: 291
private void updateAndroidSecurityProvider() {
try {
ProviderInstaller.installIfNeeded(this);
} catch (Exception e) {
e.getMessage();
}
}
call above method before calling any HTTP .
and
added below library in gradle:
compile 'com.google.android.gms:play-services-auth:11.8.0'
Upvotes: 2
Reputation: 968
I was able to achieve this using OkHttp with Retrofit2. It's written in Kotlin.
You can add this on start of your app possible in your launcher activity:
try {
SSLContext.getInstance("TLSv1.2")
} catch (e: NoSuchAlgorithmException) {
e.printStackTrace()
}
try {
ProviderInstaller.installIfNeeded(context)
} catch (e: Exception) {
e.printStackTrace()
}
Also add this on your OkHttp Builder:
fun provideSecureClient(): OkHttpClient {
try {
val trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm())
trustManagerFactory.init(null as KeyStore?)
val trustManagers = trustManagerFactory.trustManagers
if (trustManagers.size != 1 || trustManagers[0] !is X509TrustManager) {
throw IllegalStateException("Unexpected default trust managers:" + Arrays.toString(trustManagers))
}
val trustManager = trustManagers[0] as X509TrustManager
val sslContext = SSLContext.getInstance("SSL")
sslContext.init(null, arrayOf<TrustManager>(trustManager), null)
val sslSocketFactory = sslContext.socketFactory
return OkHttpClient.Builder()
.sslSocketFactory(sslSocketFactory, trustManager)
.build()
} catch (e: Exception) {
throw RuntimeException(e)
}
}
Upvotes: 1
Reputation: 8861
Android 4.2.2 on older device simply does not support new TLS version used on server. You need to allow to use at least TLS 1.1 on your server, nothing to do on client side.
UPD: TLS 1.2 support is not enabled by default on Android <5, but you can enable its usage using custom SSLSocketFactory
including the following method:
private Socket enableTLSOnSocket(Socket socket) {
if(socket != null && (socket instanceof SSLSocket)) {
((SSLSocket)socket).setEnabledProtocols(new String[] {"TLSv1.1", "TLSv1.2"});
}
return socket;
}
see the link for reference: https://blog.dev-area.net/2015/08/13/android-4-1-enable-tls-1-1-and-tls-1-2/
Upvotes: 3
Reputation: 3382
As Anton Malyshev said the TLS v1.2 is not supported on Android 4.2.2, matter of fact on devices below Android 5.0, and even if it's supported on some devices you will run into problems with the deprecated certificates.
What you could do is to try to install google ssl provider if the device has play services.
You can read more about on https://developer.android.com/training/articles/security-gms-provider.html
Upvotes: 3