信任Android应用中的自签名证书

时间:2016-01-25 16:28:40

标签: android node.js ssl https ca

我正在尝试通过我的Android应用程序与我的localhost上的https nodejs服务器(使用自签名证书)进行通信,由于我的问题,它正在抛出SSLHandshakeException自签名证书。

我搜索并找到了许多方法来避免这种错误,例如接受所有CA和许多SO。但是,我在官方文档中发现了一篇文章,只相信您的证书,其中有正当理由:https://developer.android.com/training/articles/security-ssl.html#CommonProblems

在第一个场景中,他们提到代码只接受您的证书以避免错误。

我从该页面复制了该片段,但不知道如何修改以使其适用于我的应用,因为我不太了解详情。

我需要做些什么修改才能让这个代码段适用于我的服务器?

以下是 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);

错误:

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)  

1 个答案:

答案 0 :(得分:-1)

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);
        }
    }
}