Android java.security.cert.CertPathValidatorException:找不到证书路径的信任锚 [英] Android java.security.cert.CertPathValidatorException: Trust anchor for certification path not found

查看:182
本文介绍了Android java.security.cert.CertPathValidatorException:找不到证书路径的信任锚的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

android应用有三台主机进行身份验证和授权.最终主机是REST API.首次使用Oauth身份验证和授权过程,它可以正常工作.

There are three hosts that an android app do the authentication and authorization. Final host is the REST API. For the first time using Oauth authentication and authorization process it works without issue.

但是,如果用户在登录并访问REST API提供的服务后杀死了该应用,则会出现此问题. 这次没有进行身份验证和授权过程,只有REST API.它导致java.security.cert.CertPathValidatorException ,但在首次使用(登录后再使用该应用程序)期间一直有效.

But if user kills the app after login and accessing the services provided by REST API and then again open the app, this issue arise. In this time authentication and authorization process is not happening, only the REST API. It caused to java.security.cert.CertPathValidatorException but it was working during the first use (login and then use the app).

有人可以解释此异常背后的情况以及该应用程序有什么问题.如果根据此SO答案,在以下情况下忽略了认证例外,则此方法有效.

Can someone explains the scenario behind this exception and whats wrong with the app. This works if certification exceptions are ignored as bellow according to this SO answer.

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;

我正在将Okhttp 3用于http请求.任何建议都将有助于解决该问题.并且,如果我使用上述代码段,请告诉我,是否违反安全规定?对应用程序的安全性有影响吗?

I am using Okhttp 3 for the http requests. Any suggestion would help to solve the issue. And please let me know if I use above code snippet, is it a security violation? will it effect to the security of the app?

推荐答案

我正在回答这个问题,目的是根据android开发人员网站提供有关方案和解决方案的想法,以使他人受益.我已经使用自定义信任管理器解决了这个问题.

I am answering to this to give an idea about the scenario and solution as per the android developer site for others benefit. I have solved this using custom trust manager.

问题出在服务器证书上,它缺少中间证书颁发机构.但是,第一条证书路径以某种方式完成,结果是证书路径验证成功.

The problem was with the server certificate, it misses intermediate certificate authority. However with the first flow certificate path is completed somehow and result was successful certificate path validation.

Android开发者网站中,有一个解决方案.建议使用信任此服务器证书的自定义信任管理器,或者建议服务器在服务器链中包括中间CA.

There is a solution for this in android developer site. it suggest to use custom trust manager that trusts this server certificate or it suggest to server to include the intermediate CA in the server chain.

自定义信任管理器.来源: https://developer.android.com/training/articles/security -ssl.html#UnknownCa

custom trust manager. 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();

更新:将中间证书颁发机构从服务器端添加到证书链后,我的问题得到解决.这是最好的解决方案,将证书与应用程序捆绑在一起需要在证书到期或与证书管理相关的任何其他问题时更新应用程序.

UPDATE: My problem was solved after intermediate certificate authority added to the certificate chain from the server side. It is the best solution, Bundling the certificate with the app requires app to be updated on certificate expiring or any other issues related with certificate management.

更新:03/09/2017 加载证书文件最简单的方法是使用原始资源.

UPDATE:03/09/2017 Easiest way to load certificate file I found is use of raw resource.

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

其中certfilename是放置在resources/raw文件夹中的证书文件.也是okhttp的 sslSocketFactory(SSLSocketFactory sslSocketFactory) 已被弃用,可以使用okhttp api文档中建议的方法.

where certfilename is the certificate file placed in resources/raw folder. Also okhttp's sslSocketFactory(SSLSocketFactory sslSocketFactory) has been deprecated and suggested approach in the okhttp api doc can be used.

另外,从服务器获取证书时,最好使用openssl.

Also when getting the certificate from the server it is better to use openssl.

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

因为我以前是从firefox那里获取它的,所以遇到了病毒防护人员对其进行更改的情况.

Because I used to grab that from firefox and faced situation where it was altered by the virus guard.

这篇关于Android java.security.cert.CertPathValidatorException:找不到证书路径的信任锚的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆