Saltar al contenido

java.security.cert.CertPathValidatorException: no se encontró el ancla de confianza para la ruta de certificación. Android 2.3

Este team especializado pasados muchos días de trabajo y de juntar de información, han obtenido la respuesta, deseamos que te sea útil para tu plan.

Solución:

Revisé MUCHOS lugares en SO y en la web para resolver esto. Este es el código que funcionó para mí (Android 21):

ByteArrayInputStream derInputStream = new ByteArrayInputStream(app.certificateString.getBytes());
CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509","BC");
X509Certificate cert = (X509Certificate) certificateFactory.generateCertificate(derInputStream);
String alias = "alias";//cert.getSubjectX500Principal().getName();

KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType());
trustStore.load(null);
trustStore.setCertificateEntry(alias, cert);
KeyManagerFactory kmf = KeyManagerFactory.getInstance("X509");
kmf.init(trustStore, null);
KeyManager[] keyManagers = kmf.getKeyManagers();

TrustManagerFactory tmf = TrustManagerFactory.getInstance("X509");
tmf.init(trustStore);
TrustManager[] trustManagers = tmf.getTrustManagers();

SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(keyManagers, trustManagers, null);
URL url = new URL(someURL);
conn = (HttpsURLConnection) url.openConnection();
conn.setSSLSocketFactory(sslContext.getSocketFactory());

app.certificateString es una cadena que contiene el certificado, por ejemplo:

static public String certificateString=
    "-----BEGIN CERTIFICATE-----n" +
    "MIIGQTCCBSmgAwIBAgIHBcg1dAivUzANBgkqhkiG9w0BAQsFADCBjDELMAkGA1UE" +
    "BhMCSUwxFjAUBgNVBAoTDVN0YXJ0Q29tIEx0ZC4xKzApBgNVBAsTIlNlY3VyZSBE" +
    ... a bunch of characters...
    "5126sfeEJMRV4Fl2E5W1gDHoOd6V==n" +
    "-----END CERTIFICATE-----";

He probado que puedes poner cualquier carácter en el certificado. string, si está autofirmado, siempre que mantenga la estructura exacta anterior. Obtuve el certificado string con la línea de comandos de Terminal de mi computadora portátil. Necesito saber más detalles, avíseme.

Parece que el emisor de su certificado no se encuentra en el almacén de confianza de los dispositivos 2.3.

Eche un vistazo a las ca raíz e intermedia de su certificado GoDaddy y verifique si los certificados están presentes en su dispositivo 2.3.

Consulte http://www.andreabaccega.com/blog/2010/09/23/android-root-certification-authorities-list/ para obtener una lista de los certificados 2.3.

Cuando solo esté disponible la CA raíz, asegúrese de que su servidor web también proporcione los certificados intermedios a pedido.

En caso de que alguien necesite la respuesta, finalmente encontré la respuesta después de 2 días de google. Básicamente, necesitamos usar TrustManager personalizado para confiar en las CA en nuestro KeyStore, esto se debe a que en Android 2.3.x, el almacén de claves no se está utilizando correctamente. Crédito a https://github.com/delgurth por CustomTrustManager.

Consulte: https://github.com/ikust/hello-pinnedcerts/issues/2

KeyPinStore.java

import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.security.KeyManagementException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;

import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
public class KeyPinStore 
    private static final String[] certificates = "certificate1.crt", "certificate2.crt", "certificate3.crt", "certificate4.crt";
    private static KeyPinStore instance = null;
    private SSLContext sslContext = SSLContext.getInstance("TLS");

    public static synchronized KeyPinStore getInstance() throws CertificateException, IOException, KeyStoreException, NoSuchAlgorithmException, KeyManagementException 
        if (instance == null) 
            instance = new KeyPinStore();
        
        return instance;
    

    private KeyPinStore() throws CertificateException, IOException, KeyStoreException, NoSuchAlgorithmException, KeyManagementException 
        String keyStoreType = KeyStore.getDefaultType();
        KeyStore keyStore = KeyStore.getInstance(keyStoreType);
        keyStore.load(null, null);
        for (int i = 0; i < certificates.length; i++) 
            CertificateFactory cf = CertificateFactory.getInstance("X.509");
            InputStream caInput = new BufferedInputStream(Application.context.getAssets().open("certificate/" + certificates[i]));
            Certificate ca;
            try 
                ca = cf.generateCertificate(caInput);
                System.out.println("ca=" + ((X509Certificate) ca).getSubjectDN());
             finally 
                caInput.close();
            

            // Create a KeyStore containing our trusted CAs
            keyStore.setCertificateEntry("ca" + i, ca);
        

        // Use custom trust manager to trusts the CAs in our KeyStore
        TrustManager[] trustManagers = new CustomTrustManager(keyStore);

        // Create an SSLContext that uses our TrustManager
        // SSLContext context = SSLContext.getInstance("TLS");
        sslContext.init(null, trustManagers, null);
    

    public SSLContext getContext() 
        return sslContext;
    

CustomTrustManager.java

import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.Principal;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.Arrays;
import java.util.List;

import javax.net.ssl.TrustManager;
import javax.net.ssl.TrustManagerFactory;
import javax.net.ssl.X509TrustManager;

/**
 * A custom X509TrustManager implementation that trusts a specified server certificate in addition
 * to those that are in the system TrustStore.
 * Also handles an out-of-order certificate chain, as is often produced by Apache's mod_ssl
 */
public class CustomTrustManager implements X509TrustManager 

  private final TrustManager[] originalTrustManagers;
  private final KeyStore trustStore;

  /**
   * @param trustStore A KeyStore containing the server certificate that should be trusted
   * @throws NoSuchAlgorithmException
   * @throws KeyStoreException
   */
  public CustomTrustManager(KeyStore trustStore) throws NoSuchAlgorithmException, KeyStoreException 
    this.trustStore = trustStore;

    final TrustManagerFactory originalTrustManagerFactory = TrustManagerFactory.getInstance("X509");
    originalTrustManagerFactory.init(trustStore);

    originalTrustManagers = originalTrustManagerFactory.getTrustManagers();
  

  /**
   * No-op. Never invoked by client, only used in server-side implementations
   * @return
   */
  public X509Certificate[] getAcceptedIssuers() 
    return new X509Certificate[0];
  

  /**
   * No-op. Never invoked by client, only used in server-side implementations
   * @return
   */
  public void checkClientTrusted(X509Certificate[] chain, String authType) throws java.security.cert.CertificateException 
  


  /**
   * Given the partial or complete certificate chain provided by the peer,
   * build a certificate path to a trusted root and return if it can be validated and is trusted
   * for client SSL authentication based on the authentication type. The authentication type is
   * determined by the actual certificate used. For instance, if RSAPublicKey is used, the authType should be "RSA".
   * Checking is case-sensitive.
   * Defers to the default trust manager first, checks the cert supplied in the ctor if that fails.
   * @param chain the server's certificate chain
   * @param authType the authentication type based on the client certificate
   * @throws java.security.cert.CertificateException
   */
  public void checkServerTrusted(X509Certificate[] chain, String authType) throws java.security.cert.CertificateException 
    try 
      for (TrustManager originalTrustManager : originalTrustManagers) 
        ((X509TrustManager) originalTrustManager).checkServerTrusted(chain, authType);
      
     catch(CertificateException originalException) 
      try 
        // Ordering issue?
        X509Certificate[] reorderedChain = reorderCertificateChain(chain);
        if (! Arrays.equals(chain, reorderedChain)) 
          checkServerTrusted(reorderedChain, authType);
          return;
        
        for (int i = 0; i < chain.length; i++) 
          if (validateCert(reorderedChain[i])) 
            return;
          
        
        throw originalException;
       catch(Exception ex) 
        ex.printStackTrace();
        throw originalException;
      
    

  

  /**
   * Checks if we have added the certificate in the trustStore, if that's the case we trust the certificate
   * @param x509Certificate the certificate to check
   * @return true if we know the certificate, false otherwise
   * @throws KeyStoreException on problems accessing the key store
   */
  private boolean validateCert(final X509Certificate x509Certificate) throws KeyStoreException 
    return trustStore.getCertificateAlias(x509Certificate) != null;
  

  /**
   * Puts the certificate chain in the proper order, to deal with out-of-order
   * certificate chains as are sometimes produced by Apache's mod_ssl
   * @param chain the certificate chain, possibly with bad ordering
   * @return the re-ordered certificate chain
   */
  private X509Certificate[] reorderCertificateChain(X509Certificate[] chain) 

    X509Certificate[] reorderedChain = new X509Certificate[chain.length];
    List certificates = Arrays.asList(chain);

    int position = chain.length - 1;
    X509Certificate rootCert = findRootCert(certificates);
    reorderedChain[position] = rootCert;

    X509Certificate cert = rootCert;
    while((cert = findSignedCert(cert, certificates)) != null && position > 0) 
      reorderedChain[--position] = cert;
    

    return reorderedChain;
  

  /**
   * A helper method for certificate re-ordering.
   * Finds the root certificate in a possibly out-of-order certificate chain.
   * @param certificates the certificate change, possibly out-of-order
   * @return the root certificate, if any, that was found in the list of certificates
   */
  private X509Certificate findRootCert(List certificates) 
    X509Certificate rootCert = null;

    for(X509Certificate cert : certificates)  signer.equals(cert))  // no signer present, or self-signed
        rootCert = cert;
        break;
      
    

    return rootCert;
  

  /**
   * A helper method for certificate re-ordering.
   * Finds the first certificate in the list of certificates that is signed by the sigingCert.
   */
  private X509Certificate findSignedCert(X509Certificate signingCert, List certificates) 
    X509Certificate signed = null;

    for(X509Certificate cert : certificates) 
      Principal signingCertSubjectDN = signingCert.getSubjectDN();
      Principal certIssuerDN = cert.getIssuerDN();
      if(certIssuerDN.equals(signingCertSubjectDN) && !cert.equals(signingCert)) 
        signed = cert;
        break;
      
    

    return signed;
  

  /**
   * A helper method for certificate re-ordering.
   * Finds the certificate in the list of certificates that signed the signedCert.
   */
  private X509Certificate findSigner(X509Certificate signedCert, List certificates) 
    X509Certificate signer = null;

    for(X509Certificate cert : certificates) 
      Principal certSubjectDN = cert.getSubjectDN();
      Principal issuerDN = signedCert.getIssuerDN();
      if(certSubjectDN.equals(issuerDN)) 
        signer = cert;
        break;
      
    

    return signer;
  

Para usarlo, simplemente obtenga SSLSocketFactory y aplíquelo, por ejemplo:

con HttpsURLConnection

KeyPinStore keystore = KeyPinStore.getInstance();
SSLSocketFactory sslSF = keystore.getContext().getSocketFactory();
URL url = new URL("https://certs.cac.washington.edu/CAtest/");
HttpsURLConnection urlConnection = (HttpsURLConnection)url.openConnection();
urlConnection.setSSLSocketFactory(sslSF);
InputStream in = urlConnection.getInputStream();
copyInputStreamToOutputStream(in, System.out);

con Volley

KeyPinStore keystore = KeyPinStore.getInstance();
SSLSocketFactory sslSF = keystore.getContext().getSocketFactory();
RequestQueue mRequestQueue = Volley.newRequestQueue(context, new HurlStack(null, sslSF));

Agradecemos que quieras secundar nuestro cometido ejecutando un comentario o puntuándolo te lo agradecemos.

¡Haz clic para puntuar esta entrada!
(Votos: 0 Promedio: 0)



Utiliza Nuestro Buscador

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *