简体   繁体   English

信任Android App中的自签名证书

[英]Trust self-signed certificate in Android App

I am trying to communicate to a https nodejs server (which is using self-signed certificate) on my localhost from my Android app, It is throwing an SSLHandshakeException because of my self signed certificate. 我试图从我的Android应用程序与本地主机上的https nodejs服务器(正在使用自签名证书)进行SSLHandshakeException由于自签名证书,它抛出SSLHandshakeException

I searched and found many ways to avoid this error like accepting all CAs and many in SO. 我进行了搜索,发现了许多避免此错误的方法,例如接受所有CA和许多SO。 But, I found a article here on official documentation to trust only your certificate with a valid reason here : https://developer.android.com/training/articles/security-ssl.html#CommonProblems 但是,我在官方文档中找到了一篇文章,可以在这里基于有效的理由仅信任您的证书: https : //developer.android.com/training/articles/security-ssl.html#CommonProblems

In the first scenario they mentioned the code to accept only your Certificate to avoid the error. 在第一种情况下,他们提到了仅接受证书以避免错误的代码。

I copied that snippet from that page but don't know how can I modify to let it work for my app as I don't know much details. 我从该页面复制了该代码段,但由于我不了解很多细节,因此我不知道如何修改以使其适用于我的应用程序。

What are the modification do I need to do to get this snippet work for my server? 我需要做些什么修改才能使我的服务器运行此代码片段?

Here is the snippet mentioned on developer.android.com : 这是developer.android.com上提到的代码段

// 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 URLConnection to use a SocketFactory from our SSLContext
URL url = new URL("https://certs.cac.washington.edu/CAtest/");
HttpsURLConnection urlConnection =
    (HttpsURLConnection)url.openConnection();
urlConnection.setSSLSocketFactory(context.getSocketFactory());
InputStream in = urlConnection.getInputStream();
copyInputStreamToOutputStream(in, System.out);

Error: 错误:

javax.net.ssl.SSLHandshakeException: java.security.cert.CertPathValidatorException: Trust anchor for certification path not found.
   at com.android.org.conscrypt.OpenSSLSocketImpl.startHandshake(OpenSSLSocketImpl.java:328)
   at org.apache.http.conn.ssl.SSLSocketFactory.createSocket(SSLSocketFactory.java:406)
   at org.apache.http.impl.conn.DefaultClientConnectionOperator.openConnection(DefaultClientConnectionOperator.java:170)
   at org.apache.http.impl.conn.AbstractPoolEntry.open(AbstractPoolEntry.java:169)
   at org.apache.http.impl.conn.AbstractPooledConnAdapter.open(AbstractPooledConnAdapter.java:124)
   at org.apache.http.impl.client.DefaultRequestDirector.execute(DefaultRequestDirector.java:366)
   at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:560)
   at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:492)
   at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:470)
   at com.exampleapp.LoginActivity$2.doInBackground(LoginActivity.java:126)
   at com.exampleapp.LoginActivity$2.doInBackground(LoginActivity.java:116)
   at android.os.AsyncTask$2.call(AsyncTask.java:295)
   at java.util.concurrent.FutureTask.run(FutureTask.java:237)
   at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:234)
   at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1113)
   at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:588)
   at java.lang.Thread.run(Thread.java:818)
Caused by: java.security.cert.CertificateException: java.security.cert.CertPathValidatorException: Trust anchor for certification path not found.
   at com.android.org.conscrypt.TrustManagerImpl.checkTrusted(TrustManagerImpl.java:318)
   at com.android.org.conscrypt.TrustManagerImpl.checkServerTrusted(TrustManagerImpl.java:219)
   at com.android.org.conscrypt.Platform.checkServerTrusted(Platform.java:115)
   at com.android.org.conscrypt.OpenSSLSocketImpl.verifyCertificateChain(OpenSSLSocketImpl.java:556)
   at com.android.org.conscrypt.NativeCrypto.SSL_do_handshake(Native Method)
   at com.android.org.conscrypt.OpenSSLSocketImpl.startHandshake(OpenSSLSocketImpl.java:324)
   at org.apache.http.conn.ssl.SSLSocketFactory.createSocket(SSLSocketFactory.java:406) 
   at org.apache.http.impl.conn.DefaultClientConnectionOperator.openConnection(DefaultClientConnectionOperator.java:170) 
   at org.apache.http.impl.conn.AbstractPoolEntry.open(AbstractPoolEntry.java:169) 
   at org.apache.http.impl.conn.AbstractPooledConnAdapter.open(AbstractPooledConnAdapter.java:124) 
   at org.apache.http.impl.client.DefaultRequestDirector.execute(DefaultRequestDirector.java:366) 
   at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:560) 
   at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:492) 
   at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:470) 
   at com.exampleapp.LoginActivity$2.doInBackground(LoginActivity.java:126) 
   at com.exampleapp.LoginActivity$2.doInBackground(LoginActivity.java:116) 
   at android.os.AsyncTask$2.call(AsyncTask.java:295) 
   at java.util.concurrent.FutureTask.run(FutureTask.java:237) 
   at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:234) 
   at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1113) 
   at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:588) 
   at java.lang.Thread.run(Thread.java:818) 
Caused by: java.security.cert.CertPathValidatorException: Trust anchor for certification path not found.
   at com.android.org.conscrypt.TrustManagerImpl.checkTrusted(TrustManagerImpl.java:318) 
   at com.android.org.conscrypt.TrustManagerImpl.checkServerTrusted(TrustManagerImpl.java:219) 
   at com.android.org.conscrypt.Platform.checkServerTrusted(Platform.java:115) 
   at com.android.org.conscrypt.OpenSSLSocketImpl.verifyCertificateChain(OpenSSLSocketImpl.java:556) 
   at com.android.org.conscrypt.NativeCrypto.SSL_do_handshake(Native Method) 
   at com.android.org.conscrypt.OpenSSLSocketImpl.startHandshake(OpenSSLSocketImpl.java:324) 
   at org.apache.http.conn.ssl.SSLSocketFactory.createSocket(SSLSocketFactory.java:406) 
   at org.apache.http.impl.conn.DefaultClientConnectionOperator.openConnection(DefaultClientConnectionOperator.java:170) 
   at org.apache.http.impl.conn.AbstractPoolEntry.open(AbstractPoolEntry.java:169) 
   at org.apache.http.impl.conn.AbstractPooledConnAdapter.open(AbstractPooledConnAdapter.java:124) 
   at org.apache.http.impl.client.DefaultRequestDirector.execute(DefaultRequestDirector.java:366) 
   at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:560) 
   at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:492) 
   at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:470) 
   at com.exampleapp.LoginActivity$2.doInBackground(LoginActivity.java:126) 
   at com.exampleapp.LoginActivity$2.doInBackground(LoginActivity.java:116) 
   at android.os.AsyncTask$2.call(AsyncTask.java:295) 
   at java.util.concurrent.FutureTask.run(FutureTask.java:237) 
   at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:234) 
   at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1113) 
   at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:588) 
   at java.lang.Thread.run(Thread.java:818)  
package com.interviewpreparation.myapplication;

import android.os.AsyncTask;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.Button;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.URL;
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.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManagerFactory;

public class MainActivity extends AppCompatActivity {
    Button test;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        test = (Button) findViewById(R.id.test);
        test.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                DownloadWebPageTask task = new DownloadWebPageTask();
                task.execute();
            }
        });
    }

    public String call_google_certificate() throws CertificateException, IOException, KeyStoreException, NoSuchAlgorithmException, KeyManagementException {
        //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 = getResources().openRawResource(R.raw.loadder);
        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 URLConnection to use a SocketFactory from our SSLContext
        URL url = new URL("https://certs.cac.washington.edu/CAtest/");
        HttpsURLConnection urlConnection =
                (HttpsURLConnection) url.openConnection();
        urlConnection.setSSLSocketFactory(context.getSocketFactory());
        InputStream in = urlConnection.getInputStream();
        return getStringFromInputStream(in);
    }

    private static String getStringFromInputStream(InputStream is) {
        BufferedReader br = null;
        StringBuilder sb = new StringBuilder();
        String line;
        try {
            br = new BufferedReader(new InputStreamReader(is));
            while ((line = br.readLine()) != null) {
                sb.append(line);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (br != null) {
                try {
                    br.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return sb.toString();
    }

    private class DownloadWebPageTask extends AsyncTask<String, Void, String> {
        @Override
        protected String doInBackground(String... urls) {
            String mresult = null;
            try {
                mresult = call_google_certificate();
            } catch (CertificateException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            } catch (KeyStoreException e) {
                e.printStackTrace();
            } catch (NoSuchAlgorithmException e) {
                e.printStackTrace();
            } catch (KeyManagementException e) {
                e.printStackTrace();
            }
            return mresult;
        }

        @Override
        protected void onPostExecute(String result) {
            System.out.println(result);
        }
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM