Intenté enviar una solicitud POST a un servidor seguro remoto (llamada https). Primero utilicé la biblioteca OkHTTP para hacer la llamada, ya que esta biblioteca funcionaba para hacer llamadas http en una aplicación anterior, pero con https ya no funciona, vea mi publicación anterior: No se pueden hacer llamadas HTTPS con OKHTTP lib

Decidí probar HttpURLConnection para hacer la llamada como se explica aquí: https: // developer.android.com/reference/java/net/HttpURLConnection.html El código que estoy usando solo funciona en ciertos dispositivos.

Funciona con un Wiko en Android 6.0 equipado con tarjeta SIM y wifi y no funciona en un Samsung con Android 4.2.2 solo conectado a Internet a través de Wifi.

Aquí hay un logcat del problema que encuentro:

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

Y el código adjunto a este registro:

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

No entiendo por qué mi primer dispositivo puede validar la firma y el otro no. Intenté sincronizar la fecha y la hora como se explica aquí: ¿No pudo validar la firma del certificado?

Una posible explicación de mi problema aquí, pero no lo entiendo https://groups.google.com/forum/#!topic/android-security-discuss/C_cm3k9SdaM

¿Alguien encontró el mismo problema y lo solucionó?

UPDT: Los dos métodos presentados por Alex y Anton no funcionan con mi dispositivo. El uso del servicio Google play dice que el proveedor está actualizado. Y todavía no obtengo validación de firma cuando habilito TLS 1.1 y 1.2 con el método descrito aquí: https://blog.dev-area.net/2015/08/13/android-4-1-enable-tls- 1-1-y-tls-1-2 /

UPDT 2: Siguiendo este enlace, el servidor debe usar TLS 1.1: https://www.ssllabs.com TLS enabled

2
Marech 23 feb. 2018 a las 14:43

3 respuestas

Como dijo Anton Malyshev, el TLS v1.2 no es compatible con Android 4.2.2, de hecho en dispositivos por debajo de Android 5.0, e incluso si es compatible con algunos dispositivos, se encontrará con problemas con los certificados en desuso.

Lo que podría hacer es intentar instalar el proveedor de google ssl si el dispositivo tiene servicios de reproducción.

Puedes leer más sobre https://developer.android.com/training/articles/security- gms-provider.html

3
Alex 23 feb. 2018 a las 11:55

Pude lograr esto usando OkHttp con Retrofit2. Está escrito en Kotlin.

Puede agregar esto al inicio de su aplicación posible en su actividad de iniciador:

    try {
           SSLContext.getInstance("TLSv1.2")
        } catch (e: NoSuchAlgorithmException) {
            e.printStackTrace()
        }

        try {
            ProviderInstaller.installIfNeeded(context)
        } catch (e: Exception) {
            e.printStackTrace()
        }

Agregue también esto en su 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)
    }

}
1
Umair Adil 23 feb. 2018 a las 13:06
   private void updateAndroidSecurityProvider() {
    try {
        ProviderInstaller.installIfNeeded(this);
    } catch (Exception e) {
        e.getMessage();
    }
    }

Llame al método anterior antes de llamar a cualquier HTTP.

Y

Agregado debajo de la biblioteca en gradle:

compile 'com.google.android.gms:play-services-auth:11.8.0'
2
Gautam Kushwaha 23 feb. 2018 a las 13:16