Trust Anchor no encontrado para la conexión SSL de Android

16 minutos de lectura

Trust Anchor no encontrado para la conexion SSL de Android
Crispix

Estoy tratando de conectarme a un cuadro IIS6 que ejecuta un certificado SSL de 256 bits de Godaddy, y recibo el error:

java.security.cert.CertPathValidatorException: Trust anchor for certification path not found.

He estado tratando de determinar qué podría estar causando eso, pero ahora mismo estoy en blanco.

Así es como me estoy conectando:

HttpsURLConnection conn;              
conn = (HttpsURLConnection) (new URL(mURL)).openConnection();
conn.setConnectTimeout(20000);
conn.setDoInput(true);
conn.setDoOutput(true);
conn.connect();
String tempString = toString(conn.getInputStream());

Contrariamente a la respuesta aceptada que no necesita un administrador de confianza personalizado, ¡necesita arreglar la configuración de su servidor!

Me encontré con el mismo problema al conectarme a un servidor Apache con un certificado dynadot/alphassl instalado incorrectamente. Me estoy conectando usando HttpsUrlConnection (Java/Android), que lanzaba:

javax.net.ssl.SSLHandshakeException: 
  java.security.cert.CertPathValidatorException: 
    Trust anchor for certification path not found.

El problema real es una configuración incorrecta del servidor: pruébelo con http://www.digicert.com/help/ o similar, e incluso te dirá la solución:

“El certificado no está firmado por una autoridad de confianza (comprobando con el almacén raíz de Mozilla). Si compró el certificado de una autoridad de confianza, probablemente solo necesite instalar uno o más certificados intermedios. Comuníquese con su proveedor de certificados para obtener ayuda para hacer esto para su plataforma de servidor”.

También puede verificar el certificado con openssl:

openssl s_client -debug -connect www.thedomaintocheck.com:443

Probablemente verás:

Verify return code: 21 (unable to verify the first certificate)

y, anteriormente en la salida:

depth=0 OU = Domain Control Validated, CN = www.thedomaintocheck.com
verify error:num=20:unable to get local issuer certificate
verify return:1
depth=0 OU = Domain Control Validated, CN = www.thedomaintocheck.com
verify error:num=27:certificate not trusted
verify return:1
depth=0 OU = Domain Control Validated, CN = www.thedomaintocheck.com
verify error:num=21:unable to verify the first certificate`

La cadena de certificados solo contendrá 1 elemento (su certificado):

Certificate chain
 0 s:/OU=Domain Control Validated/CN=www.thedomaintocheck.com
  i:/O=AlphaSSL/CN=AlphaSSL CA - G2

… pero debe hacer referencia a las autoridades de firma en una cadena de regreso a una en la que Android confíe (Verisign, GlobalSign, etc.):

Certificate chain
 0 s:/OU=Domain Control Validated/CN=www.thedomaintocheck.com
   i:/O=AlphaSSL/CN=AlphaSSL CA - G2
 1 s:/O=AlphaSSL/CN=AlphaSSL CA - G2
   i:/C=BE/O=GlobalSign nv-sa/OU=Root CA/CN=GlobalSign Root CA
 2 s:/C=BE/O=GlobalSign nv-sa/OU=Root CA/CN=GlobalSign Root CA
   i:/C=BE/O=GlobalSign nv-sa/OU=Root CA/CN=GlobalSign Root CA

Las instrucciones (y los certificados intermedios) para configurar su servidor generalmente las proporciona la autoridad que emitió su certificado, por ejemplo: http://www.alphassl.com/support/install-root-certificate.html

Después de instalar los certificados intermedios proporcionados por el emisor de mi certificado, ahora no tengo errores al conectarme mediante HttpsUrlConnection.

  • En caso de que el OP tenga acceso a la configuración SSL de los servidores a los que se está conectando, esta podría ser una solución. Pero si él no es el que aloja el servicio al que se está conectando, tiene que solucionar el problema por su parte, lo que significa implementar un administrador de confianza personalizado.

    – Matías B.

    30 de abril de 2013 a las 15:24

  • Su solución funciona, sin duda, pero ¿no está de acuerdo en que es una solución alternativa en lugar de una solución para la causa raíz? Si tengo que conectarme a un servidor desde 3 clientes (Android, iOS, Windows Mobile), entonces tengo que aplicar la solución en los 3, mientras que puedo arreglar el servidor una vez y todos “simplemente funcionarán”.

    – Stevie

    30 de abril de 2013 a las 16:18

  • Gracias Stevie, tuve mi servidor mal configurado durante 3 meses, ¡y recién ahora lo detecté! Ahora mi aplicación de Android funciona al 100%

    – jpros

    5 sep 2013 a las 20:01

  • @Stevie Hago muchas llamadas a diferentes API que comparten el mismo dominio, pero solo una de ellas falla con (javax.net.ssl.SSLHandshakeException) … ¿alguna idea de por qué sucedería tal cosa? y por cierto, el Certificado SSL no es de confianza. Entonces, pensé que todas las llamadas deberían fallar con la misma excepción.

    – un jugador justo

    3 de marzo de 2014 a las 6:39

  • @dvaey póngase en contacto con quien sea el propietario del servidor y dígales que su configuración está rota y que su https no funciona correctamente; déles este enlace para probarlo digicert.com/ayuda … Me imagino que estarían agradecidos y rápidos para resolver. De lo contrario, tendrá que seguir uno de los pasos de solución en las otras respuestas, pero luego tendrá que no aceptar seguridad (ignorar certificados) o volver a implementar sus aplicaciones cuando el certificado caduque y su almacén de confianza personalizado ya no coincida con el nuevo certificado

    – Stevie

    20 noviembre 2015 a las 10:00

1646965454 611 Trust Anchor no encontrado para la conexion SSL de Android
Matías B.

¡La solución de @Chrispix es peligrosa! Confiar en todos los certificados le permite a cualquiera hacer un ataque de hombre en el medio. ¡Simplemente envíe CUALQUIER certificado al cliente y lo aceptará!

Agregue su(s) certificado(s) a un administrador de confianza personalizado como se describe en esta publicación: Confiar en todos los certificados usando HttpClient sobre HTTPS

Aunque es un poco más complejo establecer una conexión segura con un certificado personalizado, le brindará la seguridad de cifrado SSL deseada sin el peligro de un ataque de hombre en el medio.

  • Esto está bien para trabajar con un certificado autogenerado, pero para uno (como el OP) que tiene una cadena válida de regreso a la CA raíz, es solo una solución para un servidor mal configurado; vea mi respuesta.

    – Stevie

    30 de abril de 2013 a las 14:43

  • @Stevie Aceptar CADA certificado es solo una opción para una prueba de concepto, donde la conexión SSL no es la parte que desea probar. De lo contrario, no tiene que usar SSL, si acepta todos los certificados, ¡ya que la conexión no es segura!

    – Matías B.

    30 de abril de 2013 a las 15:26

  • Ah, lo siento, creo que hay un malentendido. ¡Estoy completamente de acuerdo en que nadie debería aceptar todos los certificados! 🙂 Mi comentario fue con respecto a su segundo párrafo, la sugerencia de usar un administrador de confianza personalizado, que en mi humilde opinión debería ser una solución de último recurso en lugar de una solución recomendada.

    – Stevie

    30 de abril de 2013 a las 16:25

  • Solo un aviso… Eliminé la ‘solución’ que pegué como solución alternativa para no causar más problemas, ya que las personas no la vieron como una ‘solución temporal’.

    – Crispix

    28/01/2016 a las 20:41

  • @Chrispix, no debería haber eliminado la solución parcial, es buena solo para fines de prueba

    –Hugo Allexis Cardona

    19 de septiembre de 2017 a las 3:27

Puede confiar en un certificado particular en tiempo de ejecución.
Simplemente descárguelo del servidor, coloque activos y cárguelo así usando ssl-utils-android:

OkHttpClient client = new OkHttpClient();
SSLContext sslContext = SslUtils.getSslContextForCertificateFile(context, "BPClass2RootCA-sha2.cer");
client.setSslSocketFactory(sslContext.getSocketFactory());

En el ejemplo anterior usé OkHttpClient pero SSLContext se puede utilizar con cualquier cliente en Java.

Si usted tiene alguna pregunta no dude en preguntar. Soy el autor de esta pequeña biblioteca.

  • ¿Qué pasa con .pfx?

    – Choletsky

    27/10/2018 a las 21:02

  • ¿No es esto inseguro ya que cualquier usuario puede acceder a la carpeta de activos de una aplicación una vez que tiene el apk?

    – Patrice Ándala

    4 oct 2019 a las 13:57

  • @PatriceAndala, las CA raíz están disponibles públicamente, así que está bien

    – BekaBot

    15 de junio de 2020 a las 7:07

  • Gracias, si ssl se renueva cada 2 meses, ¿tenemos que reemplazar el nuevo archivo cer en la aplicación cada 2 meses?

    – Reza

    14 oct 2021 a las 16:56

1646965455 919 Trust Anchor no encontrado para la conexion SSL de Android
usuario1506104

Actualización basada en la última documentación de Android (marzo de 2017):

Cuando obtiene este tipo de error:

javax.net.ssl.SSLHandshakeException: java.security.cert.CertPathValidatorException: Trust anchor for certification path not found.
        at org.apache.harmony.xnet.provider.jsse.OpenSSLSocketImpl.startHandshake(OpenSSLSocketImpl.java:374)
        at libcore.net.http.HttpConnection.setupSecureSocket(HttpConnection.java:209)
        at libcore.net.http.HttpsURLConnectionImpl$HttpsEngine.makeSslConnection(HttpsURLConnectionImpl.java:478)
        at libcore.net.http.HttpsURLConnectionImpl$HttpsEngine.connect(HttpsURLConnectionImpl.java:433)
        at libcore.net.http.HttpEngine.sendSocketRequest(HttpEngine.java:290)
        at libcore.net.http.HttpEngine.sendRequest(HttpEngine.java:240)
        at libcore.net.http.HttpURLConnectionImpl.getResponse(HttpURLConnectionImpl.java:282)
        at libcore.net.http.HttpURLConnectionImpl.getInputStream(HttpURLConnectionImpl.java:177)
        at libcore.net.http.HttpsURLConnectionImpl.getInputStream(HttpsURLConnectionImpl.java:271)

el problema podría ser uno de los siguientes:

  1. Se desconocía la CA que emitió el certificado del servidor
  2. El certificado del servidor no fue firmado por una CA, pero fue autofirmado
  3. A la configuración del servidor le falta una CA intermedia

La solución es enseñar. HttpsURLConnection para confiar en un conjunto específico de CA. ¿Cómo? por favor, compruebe https://developer.android.com/training/articles/security-ssl.html#CommonProblems

Otros que están usando AsyncHTTPClient desde com.loopj.android:android-async-http biblioteca, verifique Configurar AsyncHttpClient para usar HTTPS.

1646965455 891 Trust Anchor no encontrado para la conexion SSL de Android
Shihab Udin

Si usa la actualización, necesita personalizar su OkHttpClient.

retrofit = new Retrofit.Builder()
    .baseUrl(ApplicationData.FINAL_URL)
    .client(getUnsafeOkHttpClient().build())
    .addConverterFactory(GsonConverterFactory.create())
    .build();

El código completo es el siguiente.

public class RestAdapter {

    private static Retrofit retrofit = null;
    private static ApiInterface apiInterface;

    public static OkHttpClient.Builder getUnsafeOkHttpClient() {
        try {
            // Create a trust manager that does not validate certificate chains
            final TrustManager[] trustAllCerts = new TrustManager[]{
                new X509TrustManager() {
                    @Override
                    public void checkClientTrusted(java.security.cert.X509Certificate[] chain, String authType) throws CertificateException {
                    }

                    @Override
                    public void checkServerTrusted(java.security.cert.X509Certificate[] chain, String authType) throws CertificateException {
                    }

                    @Override
                    public java.security.cert.X509Certificate[] getAcceptedIssuers() {
                        return new java.security.cert.X509Certificate[]{};
                    }
                }
            };
    
                // Install the all-trusting trust manager
                final SSLContext sslContext = SSLContext.getInstance("SSL");
                sslContext.init(null, trustAllCerts, new java.security.SecureRandom());
    
                // Create an ssl socket factory with our all-trusting manager
                final SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory();
    
                OkHttpClient.Builder builder = new OkHttpClient.Builder();
                builder.sslSocketFactory(sslSocketFactory, (X509TrustManager) trustAllCerts[0]);
                builder.hostnameVerifier(new HostnameVerifier() {
                    @Override
                    public boolean verify(String hostname, SSLSession session) {
                        return true;
                    }
                });
                return builder;
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }
        
        public static ApiInterface getApiClient() {
            if (apiInterface == null) {
    
                try {
                    retrofit = new Retrofit.Builder()
                            .baseUrl(ApplicationData.FINAL_URL)
                            .client(getUnsafeOkHttpClient().build())
                            .addConverterFactory(GsonConverterFactory.create())
                            .build();
    
                } catch (Exception e) {
    
                    e.printStackTrace();
                }
    
    
                apiInterface = retrofit.create(ApiInterface.class);
            }
            return apiInterface;
        }
        
    }

  • Intento usar el código, pero recibo el siguiente error nuevamente. puedes ayudar en esto

    –Vishwa Pratap

    28 de febrero de 2019 a las 17:39

  • Esto es radicalmente inseguro. No utilice.

    – usuario207421

    7 de noviembre de 2019 a las 1:24


  • ¡Gracias! Reescribió el método getUnsafeOkHttpClient() en Kotlin: stackoverflow.com/a/60507560/2914140.

    – CoolMind

    3 de marzo de 2020 a las 12:46

1646965456 621 Trust Anchor no encontrado para la conexion SSL de Android
usuario28434’mstep

Respondiendo a un mensaje muy antiguo. Pero tal vez ayude a algunos novatos y si nada de lo anterior funciona.

Explicación: Sé que nadie quiere una mierda de explicación; más bien la solución. Pero en una línea, está intentando acceder a un servicio desde su máquina local a una máquina remota que no confía en su máquina. Su solicitud necesita ganarse la confianza del servidor remoto.

Solución: La siguiente solución asume que se cumplen las siguientes condiciones

  1. Intentando acceder a una API remota desde su máquina local.
  2. Estás construyendo para la aplicación de Android
  3. Su servidor remoto está bajo filtración de proxy (usted usa proxy en la configuración de su navegador para acceder al servicio de API remoto, generalmente un servidor de prueba o de desarrollo)
  4. Estás probando en un dispositivo real

Pasos:

Necesita un archivo de extensión .keystore para registrar su aplicación. Si no sabe cómo crear un archivo .keystore; luego sigue junto con lo siguiente sección Crear archivo .keystore o salte a la siguiente sección Firmar archivo apk

Crear archivo .keystore

Abra Android Studio. Haz clic en el menú superior Generar > Generar APK firmado. En la siguiente ventana, haga clic en el Crear nuevo… botón. En la nueva ventana, ingrese los datos en todos los campos. Recuerde que los dos campos de Contraseña que recomiendo deben tener la misma contraseña; no use una contraseña diferente; y también recuerde la ruta de guardado en la parte superior del campo Ruta del almacén de claves:. Después de ingresar todo el campo, haga clic en el botón Aceptar.

Firmar archivo apk

Ahora necesita crear una aplicación firmada con el archivo .keystore que acaba de crear. Sigue estos pasos

  1. Build > Clean Project, espere hasta que termine de limpiar
  2. Generar > Generar APK firmado
  3. Hacer clic Choose existing... botón
  4. Seleccione el archivo .keystore que acabamos de crear en el Crear archivo .keystore sección
  5. Ingrese la misma contraseña que creó al crear en Crear archivo .keystore sección. Usar la misma contraseña para Key store password y Key password campos. Introduzca también el alias
  6. Haga clic en el botón Siguiente
  7. En la siguiente pantalla; que podría ser diferente en función de su configuración en build.gradle archivos, debe seleccionar Build Types y Flavors.
  8. Para el Build Types escoger release del menú desplegable
  9. Para Flavors sin embargo, dependerá de su configuración en build.gradle expediente. Escoger staging de este campo. Utilicé la siguiente configuración en el build.gradlepuedes usar el mismo que el mío, pero asegúrate de cambiar el applicationId a su nombre de paquete

    productFlavors {
        staging {
            applicationId "com.yourapplication.package"
            manifestPlaceholders = [icon: "@drawable/ic_launcher"]
            buildConfigField "boolean", "CATALYST_DEBUG", "true"
            buildConfigField "boolean", "ALLOW_INVALID_CERTIFICATE", "true"
        }
        production {
            buildConfigField "boolean", "CATALYST_DEBUG", "false"
            buildConfigField "boolean", "ALLOW_INVALID_CERTIFICATE", "false"
        }
    }
    
  10. Haga clic en los dos inferiores Signature Versions casillas de verificación y haga clic en Finish botón.

Casi llegamos:

Todo el trabajo duro está hecho, ahora el movimiento de la verdad. Para acceder al servidor de prueba respaldado por proxy, debe realizar alguna configuración en sus dispositivos Android de prueba reales.

Configuración de proxy en el dispositivo Android:

  1. Haga clic en Configuración dentro del teléfono Android y luego wi-fi
  2. Mantenga presionado el wifi conectado y seleccione Modify network
  3. Haga clic en el Advanced options si no puedes ver el Proxy Hostname campo
  4. En el Proxy Hostname ingrese la IP del host o el nombre que desea conectar. Un servidor de ensayo típico se denominará como stg.api.mygoodcompany.com
  5. Para el puerto, ingrese el número de puerto de cuatro dígitos, por ejemplo 9502
  6. Golpea el Save botón

Una última parada:

Recuerde que generamos el archivo apk firmado en Firmar archivo APK sección. Ahora es el momento de instalar ese archivo APK.

  1. Abra una terminal y cambie a la carpeta de archivos apk firmada
  2. Conecte su dispositivo Android a su máquina
  3. Elimine cualquier archivo apk instalado anteriormente del dispositivo Android
  4. Correr adb install name of the apk file
  5. Si por alguna razón el comando anterior regresa con adb command not found. Introduzca la ruta completa como C:\Users\shah\AppData\Local\Android\sdk\platform-tools\adb.exe install name of the apk file

Espero que se pueda solucionar el problema. Si no, déjame un comentario.

¡Salam!

  • Intento usar el código, pero recibo el siguiente error nuevamente. puedes ayudar en esto

    –Vishwa Pratap

    28 de febrero de 2019 a las 17:39

  • Esto es radicalmente inseguro. No utilice.

    – usuario207421

    7 de noviembre de 2019 a las 1:24


  • ¡Gracias! Reescribió el método getUnsafeOkHttpClient() en Kotlin: stackoverflow.com/a/60507560/2914140.

    – CoolMind

    3 de marzo de 2020 a las 12:46

Utilizar https://www.ssllabs.com/ssltest/ para probar un dominio.

La solución de Shihab Uddin en Kotlin.

import java.security.SecureRandom
import java.security.cert.X509Certificate
import javax.net.ssl.*
import javax.security.cert.CertificateException

object {

    val okHttpClient: OkHttpClient
    val gson: Gson
    val retrofit: Retrofit

    init {

        okHttpClient = getOkHttpBuilder()
            // Other parameters like connectTimeout(15, TimeUnit.SECONDS)
            .build()

        gson = GsonBuilder().setLenient().create()

        retrofit = Retrofit.Builder()
            .baseUrl(BASE_URL)
            .client(okHttpClient)
            .addConverterFactory(GsonConverterFactory.create(gson))
            .build()
    }

    fun getOkHttpBuilder(): OkHttpClient.Builder =
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            OkHttpClient().newBuilder()
        } else {
            // Workaround for the error "Caused by: com.android.org.bouncycastle.jce.exception.ExtCertPathValidatorException: Could not validate certificate: Certificate expired at".
            getUnsafeOkHttpClient()
        }

    private fun getUnsafeOkHttpClient(): OkHttpClient.Builder =
        try {
            // Create a trust manager that does not validate certificate chains
            val trustAllCerts: Array<TrustManager> = arrayOf(
                object : X509TrustManager {
                    @Throws(CertificateException::class)
                    override fun checkClientTrusted(chain: Array<X509Certificate?>?,
                                                    authType: String?) = Unit

                    @Throws(CertificateException::class)
                    override fun checkServerTrusted(chain: Array<X509Certificate?>?,
                                                    authType: String?) = Unit

                    override fun getAcceptedIssuers(): Array<X509Certificate> = arrayOf()
                }
            )
            // Install the all-trusting trust manager
            val sslContext: SSLContext = SSLContext.getInstance("SSL")
            sslContext.init(null, trustAllCerts, SecureRandom())
            // Create an ssl socket factory with our all-trusting manager
            val sslSocketFactory: SSLSocketFactory = sslContext.socketFactory
            val builder = OkHttpClient.Builder()
            builder.sslSocketFactory(sslSocketFactory,
                trustAllCerts[0] as X509TrustManager)
            builder.hostnameVerifier { _, _ -> true }
            builder
        } catch (e: Exception) {
            throw RuntimeException(e)
        }
}

El mismo error también aparecerá si usa Glide, las imágenes no se mostrarán. Para superarlo, consulte Glide – javax.net.ssl.SSLHandshakeException: java.security.cert.CertPathValidatorException: Anclaje de confianza para la ruta de certificación no encontrada y Cómo configurar OkHttpClient para Glide.

@GlideModule
class MyAppGlideModule : AppGlideModule() {

    val okHttpClient = Api.getOkHttpBuilder().build() // Api is the class written above.
    // It is better to create okHttpClient here and not use Api.okHttpClient,
    // because their settings may differ. For instance, it can use its own
    // `addInterceptor` and `addNetworkInterceptor` that can affect on a read JSON.


    override fun registerComponents(context: Context, glide: Glide, registry: Registry) {
        registry.replace(GlideUrl::class.java, InputStream::class.java,
            OkHttpUrlLoader.Factory(okHttpClient))
    }
}

construir.gradle:

// Glide.
implementation 'com.github.bumptech.glide:glide:4.11.0'
implementation 'com.github.bumptech.glide:okhttp3-integration:4.11.0'
kapt 'com.github.bumptech.glide:compiler:4.11.0'

ACTUALIZAR

También recibí otro error en el emulador API 16:

rutinas:SSL23_GET_SERVER_HELLO:versión del protocolo de alerta tlsv1 (external/openssl/ssl/s23_clnt.c:741′.

Leer 1 y 2, cambié el código así que:

okHttpClient = getOkHttpBuilder().build()

private fun getOkHttpBuilder(): OkHttpClient.Builder {
    if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
        Security.insertProviderAt(Conscrypt.newProvider(), 1)
    }
    return OkHttpClient().newBuilder()
}

// build.gradle:
implementation 'org.conscrypt:conscrypt-android:2.5.1'

También eliminé estas líneas de MyApplication:

try {
    ProviderInstaller.installIfNeeded(applicationContext)
    val sslContext = SSLContext.getInstance("TLSv1.2")
    sslContext.init(null, null, null)
    sslContext.createSSLEngine()
} catch (e: GooglePlayServicesRepairableException) {
    Timber.e(e.stackTraceToString())
    // Prompt the user to install/update/enable Google Play services.
    GoogleApiAvailability.getInstance().showErrorNotification(this, e.connectionStatusCode)
} catch (e: GooglePlayServicesNotAvailableException) {
    Timber.e(e.stackTraceToString())
    // Prompt the user to install/update/enable Google Play services.
    // GoogleApiAvailability.getInstance().showErrorNotification(this, e.errorCode)
} catch (e: NoSuchAlgorithmException) {
    Timber.e(e.stackTraceToString())
} catch (e: KeyManagementException) {
    Timber.e(e.stackTraceToString())
}

Pero el Biblioteca agrega 3.4 Mb a apk.

  • Muchas gracias, esto funcionó muy bien para mí.

    – Manú

    20 de enero de 2021 a las 0:56

¿Ha sido útil esta solución?

Esta web utiliza cookies propias y de terceros para su correcto funcionamiento y para fines analíticos y para mostrarte publicidad relacionada con sus preferencias en base a un perfil elaborado a partir de tus hábitos de navegación. Al hacer clic en el botón Aceptar, acepta el uso de estas tecnologías y el procesamiento de tus datos para estos propósitos. Configurar y más información
Privacidad