【问题标题】:Android SSL - CertPathValidatorExceptionAndroid SSL - CertPathValidatorException
【发布时间】:2017-07-23 12:10:10
【问题描述】:

我的 HTTPS 服务托管在 TomCat 中(使用 JDK bin 中的 keytool 创建的.keystore)。

服务器证书是自签名的,并通过将其安装在 Trusted Root Authorities 中使其成为受信任的。

我可以从浏览器访问该服务,但无法从 Android 访问该服务。我是 J2EE 的初学者。

host.cert(放置在 assets 目录中)是使用 OpenSSL 创建的。

我正在使用来自 Android 开发者网站的代码 sn-p

        try {
            // 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 inn=getAssets().open("host.cert");

            Certificate ca;
            try {
                ca = cf.generateCertificate(inn);
                Log.i("TEST","ca=" + ((X509Certificate) ca).getSubjectDN());
            } finally {
                inn.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 URLConnection to use a SocketFactory from our SSLContext
            URL url = new URL("https://192.168.56.1:8443/RestHTTPS/JavaCodeGeeks/AuthorService/authors/");
            HttpsURLConnection urlConnection =
                    (HttpsURLConnection)url.openConnection();
            urlConnection.setSSLSocketFactory(context.getSocketFactory());
            InputStream in = urlConnection.getInputStream();

            byte arr[]=new byte[in.available()];
            in.read(arr);

            String str=new String(arr);
            Log.i("TEST",str);

        }catch (Exception e){
            Log.e("TEST",e.toString());
            e.printStackTrace();
        }

我知道这已经是一个问题,但我找不到解决方案。

【问题讨论】:

    标签: android ssl tomcat7


    【解决方案1】:

    我将发布解决方案,供仍然面临问题的人使用。

    主要注意3点(这在Android developer site已经说明)

    • 创建自定义信任管理器以绕过默认信任管理器。
    • 手动验证主机名是否可接受。
    • 切勿将“localhost”或“127.0.0.1”用于测试目的,而应使用您 PC 的 IP 地址。

    这是完整的代码

    try {
    
                // Things to Note 1 : Bypass default Trust Managers
                TrustManager[] byPassTrustManagers = new TrustManager[]{new X509TrustManager() {
                    public X509Certificate[] getAcceptedIssuers() {
                        return new X509Certificate[0];
                    }
    
                    public void checkClientTrusted(X509Certificate[] chain, String authType) {
                    }
    
                    public void checkServerTrusted(X509Certificate[] chain, String authType) {
                    }
                }};
    
                CertificateFactory cf = CertificateFactory.getInstance("X.509");
                InputStream inn = getAssets().open("keystore.cer");
                Certificate ca;
                try {
                    ca = cf.generateCertificate(inn);
                    Log.i("TEST", "ca=" + ((X509Certificate) ca).getSubjectDN());
                } finally {
                    inn.close();
                }
    
    
                String keyStoreType = "BKS";
                KeyStore.getDefaultType();
                KeyStore keyStore = KeyStore.getInstance(keyStoreType);
                keyStore.load(null, null);
                keyStore.setCertificateEntry("ca", ca);
    
                String tmfAlgorithm = TrustManagerFactory.getDefaultAlgorithm();
                TrustManagerFactory tmf = TrustManagerFactory.getInstance(tmfAlgorithm);
                tmf.init(keyStore);
    
                SSLContext context = SSLContext.getInstance("TLS");
                context.init(null, byPassTrustManagers, null);
    
                // Things to Note 2 : Don't use "localhost" ,instead use IP
                URL url = new URL("https://192.168.56.1:8443/RestHTTPS/JavaCodeGeeks/AuthorService/authors");
                HttpsURLConnection urlConnection =
                        (HttpsURLConnection) url.openConnection();
    
                urlConnection.setSSLSocketFactory(context.getSocketFactory());
    
                // Things to Note 3 : Allow all host
                urlConnection.setHostnameVerifier(new HostnameVerifier() {
                    @Override
                    public boolean verify(String hostname, SSLSession session) {
                        return true;
                    }
                });
    
                Log.i("TEST", urlConnection.getResponseMessage() + "");
    
                InputStream in = urlConnection.getInputStream();
    
                InputStreamReader isw = new InputStreamReader(in);
    
                int data = isw.read();
                String str = "";
                while (data != -1) {
                    char current = (char) data;
                    data = isw.read();
                    str += current;
                }
    
                Log.i("TEST", "" + str);
    
            } catch (Exception e) {
                Log.e("TEST", e.toString());
                e.printStackTrace();
            }
    

    【讨论】:

      猜你喜欢
      • 2023-03-05
      • 1970-01-01
      • 1970-01-01
      • 2014-05-22
      • 2011-05-06
      • 2016-11-21
      • 2015-05-30
      • 2017-10-21
      • 1970-01-01
      相关资源
      最近更新 更多