Доверяйте самозаверяющему сертификату в Android-приложении

Я пытаюсь связаться с сервером https nodejs (который использует самоподписанный сертификат) на моем локальном хосте из моего приложения для Android. Он выдает 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)  

person kirtan403    schedule 25.01.2016    source источник
comment
Вам нужно добавить файл .cert в папку с ресурсами, а затем получить его как входной поток.   -  person Raghunandan    schedule 25.01.2016
comment
Я делаю все на самом деле. Запуск сервера на локальном хосте. Я нахожу способ сделать это. Будет ли риск включать файл crt в apk?   -  person kirtan403    schedule 25.01.2016
comment
О каком риске вы говорите? Для тестирования у меня есть это в папке активов. Вы можете разместить это на сервере, если хотите. В рабочей среде вам не о чем беспокоиться, потому что ваш сертификат генерируется доверенным центром сертификации. Я не эксперт в этом.   -  person Raghunandan    schedule 25.01.2016
comment
Я говорю об угрозе безопасности. Как любой может открыть файл apk с помощью проводника. На самом деле я не знаю, какова роль этого файла. Я учусь. Я обнаружил, что .pem и .crt — это файлы одного типа с разными расширениями. (источник: serverfault.com/a/9717)   -  person kirtan403    schedule 25.01.2016
comment
stackoverflow.com/questions/9763092 . Мне нужно найти способ использовать мой собственный сертификат для связи с моей серверной частью через ssl.   -  person kirtan403    schedule 25.01.2016