Android java.sécurité.cert.CertPathValidatorException: Ancre de confiance pour le chemin de certification introuvable


Il y a trois hôtes qu'une application Android fait l'authentification et l'autorisation. L'hôte final est l'API REST. Pour la première fois en utilisant le processus d'authentification et d'autorisation Oauth, il fonctionne sans problème.

Mais si utilisateur tue l'app après la connexion et l'accès aux services fournis par l'API REST, puis ouvrez à nouveau l'application, cette question. Dans ce temps, le processus d'authentification et d'autorisation ne se produit pas, seule l'API REST.{[6] } Il a causé à java.security.cert.CertPathValidatorException mais cela fonctionnait lors de la première utilisation (connectez-vous puis utilisez l'application).

Quelqu'un peut-il expliquer le scénario derrière cette exception et ce qui ne va pas avec l'application. Cela fonctionne si les exceptions de certification sont ignorées comme ci-dessous selon cette réponse SO.

SSLSocketFactory sslSocketFactory = null;

        try {
            TrustManagerFactory tmf = TrustManagerFactory.getInstance(
                    TrustManagerFactory.getDefaultAlgorithm());
            // Initialise the TMF as you normally would, for example:
            try {
                tmf.init((KeyStore)null);
            } catch(KeyStoreException e) {
                e.printStackTrace();
            }
            TrustManager[] trustManagers = tmf.getTrustManagers();

            final X509TrustManager origTrustmanager = (X509TrustManager)trustManagers[0];

            // Create a trust manager that does not validate certificate chains
            TrustManager[] wrappedTrustManagers = new TrustManager[]{
                    new X509TrustManager() {
                        public java.security.cert.X509Certificate[] getAcceptedIssuers() {
                            return origTrustmanager.getAcceptedIssuers();
                        }

                        public void checkClientTrusted(X509Certificate[] certs, String authType) {
                            try {
                                origTrustmanager.checkClientTrusted(certs, authType);
                            } catch(CertificateException e) {
                                e.printStackTrace();
                            }
                        }

                        public void checkServerTrusted(X509Certificate[] certs, String authType) {
                            try {
                                origTrustmanager.checkServerTrusted(certs, authType);
                            } catch(CertificateException e) {
                                e.printStackTrace();
                            }
                        }
                    }
            };
            //TrustManager[] trustAllCerts = TrustManagerFactory.getInstance("SSL").getTrustManagers();

            // Install the all-trusting trust manager
            final SSLContext sslContext = SSLContext.getInstance("TLS");
            sslContext.init(null, wrappedTrustManagers, new java.security.SecureRandom());
            // Create an ssl socket factory with our all-trusting manager
            sslSocketFactory = sslContext.getSocketFactory();
        } catch (NoSuchAlgorithmException | KeyManagementException e) {
            e.printStackTrace();
        }
        return sslSocketFactory;

J'utilise Okhttp 3 pour les requêtes http. Toute suggestion aiderait à résoudre le problème. Et veuillez me faire savoir si j'utilise l'extrait de code ci-dessus, est-ce une violation de la sécurité? sera-ce l'effet de la sécurité de l'application?

Author: Community, 2016-09-01

1 answers

Je réponds à cela pour donner une idée du scénario et de la solution selon le site de développement Android pour les autres. J'ai résolu cela en utilisant custom trust manager.

Le problème était avec le certificat du serveur, il manque l'autorité de certification intermédiaire. Cependant, avec le premier chemin de certificat de flux est terminé en quelque sorte et le résultat a réussi la validation du chemin de certificat.

, Il existe une solution pour ce dans développeur android site. il suggère l'utilisation de gestionnaire de confiance personnalisé qui fait confiance à ce certificat de serveur ou il suggère au serveur d'inclure l'autorité de certification intermédiaire dans la chaîne de serveur.

Gestionnaire de confiance personnalisé. source: https://developer.android.com/training/articles/security-ssl.html#UnknownCa

// Load CAs from an InputStream
// (could be from a resource or ByteArrayInputStream or ...)
CertificateFactory cf = CertificateFactory.getInstance("X.509");
// From https://www.washington.edu/itconnect/security/ca/load-der.crt
InputStream caInput = new BufferedInputStream(new FileInputStream("load-der.crt"));
Certificate ca;
try {
    ca = cf.generateCertificate(caInput);
    System.out.println("ca=" + ((X509Certificate) ca).getSubjectDN());
} finally {
    caInput.close();
}

// Create a KeyStore containing our trusted CAs
String keyStoreType = KeyStore.getDefaultType();
KeyStore keyStore = KeyStore.getInstance(keyStoreType);
keyStore.load(null, null);
keyStore.setCertificateEntry("ca", ca);

// Create a TrustManager that trusts the CAs in our KeyStore
String tmfAlgorithm = TrustManagerFactory.getDefaultAlgorithm();
TrustManagerFactory tmf = TrustManagerFactory.getInstance(tmfAlgorithm);
tmf.init(keyStore);

// Create an SSLContext that uses our TrustManager
SSLContext context = SSLContext.getInstance("TLS");
context.init(null, tmf.getTrustManagers(), null);
// Tell the okhttp to use a SocketFactory from our SSLContext
OkHttpClient okHttpClient client = new OkHttpClient.Builder().sslSocketFactory(context.getSocketFactory()).build();

MISE À JOUR: Mon problème a été résolu après l'ajout d'une autorité de certification intermédiaire à la chaîne de certificats du côté serveur. C'est la meilleure solution, le Regroupement le certificat avec l'application nécessite l'application mise à jour sur l'expiration du certificat ou tout autre problème lié à la gestion des certificats.

MISE À JOUR: 03/09/2017 Le moyen le plus simple de charger le fichier de certificat que j'ai trouvé est l'utilisation de la ressource brute.

InputStream caInput = new BufferedInputStream(context
                .getResources().openRawResource(R.raw.certfilename));

Où certfilename est le fichier de certificat placé dans le dossier resources/raw. Aussi okhttp sslSocketFactory(SSLSocketFactory sslSocketFactory) a été obsolète et l'approche suggérée dans le document de l'api okhttp peut être utilisée.

Aussi lors de l'obtention du certificat du serveur, il est préférable d'utiliser openssl.

openssl s_client -connect {server-address}:{port} -showcerts

Parce que j'avais l'habitude de saisir cela de Firefox et de faire face à une situation où il a été modifié par le virus guard.

 16
Author: Ruwanka Madhushan, 2017-09-03 07:52:14