it-swarm.com.ru

Проблемы с https (нет сертификата пира) в Android

Проблема

Я хочу отправить https запрос на сайт https://10.2.20.20/fido/EzPay/login.php мой собственный сервер и получить от него ответ и сохранить его, например, в строку. Я нашел несколько примеров кодов в интернете и попробую проверить их на предмет моей проблемы, но они не помогают. Ниже я представляю некоторые части кодов, которые я протестировал.


Пример кода:

Я пробую этот код, но всегда получаю одно и то же исключение "Нет сертификата однорангового узла" Почему?

try
{
    HostnameVerifier hostnameVerifier = org.Apache.http.conn.ssl.SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER;

    DefaultHttpClient client = new DefaultHttpClient();

    SchemeRegistry registry = new SchemeRegistry();
    SSLSocketFactory socketFactory = SSLSocketFactory.getSocketFactory();
    socketFactory.setHostnameVerifier((X509HostnameVerifier) hostnameVerifier);
    registry.register(new Scheme("https", socketFactory, 443));
    SingleClientConnManager mgr = new SingleClientConnManager(client.getParams(), registry);
    DefaultHttpClient httpClient = new DefaultHttpClient(mgr, client.getParams());

    // Set verifier      
    HttpsURLConnection.setDefaultHostnameVerifier(hostnameVerifier);

    // Example send http request
    final String url = "https://10.2.20.20/fido/EzPay/login.php";
    HttpPost httpPost = new HttpPost(url);
    HttpResponse response = httpClient.execute(httpPost);

    BufferedReader rd = new BufferedReader(new InputStreamReader(response.getEntity().getContent()));
    String line = "";
    while ((line = rd.readLine()) != null) {
        Log.i(DownloadImageTask.class.getName(), line);
    }

}
catch(IOException ex)
{
    Log.e(DownloadImageTask.class.getName(), ex.getMessage());
}

Исключение.

03-02 16: 58: 25.234: W/System.err (1868): javax.net.ssl.SSLPeerUnverifiedException: нет сертификата однорангового узла 03-02 16: 58: 25.238: W/System.err (1868): at org.Apache.harmony.xnet.provider.jsse.SSLSessionImpl.getPeerCertificates (SSLSessionImpl.Java:137) 03-02 16: 58: 25.238: W/System.err (1868): at org.Apache.http.conn.ssl.AbstractVerifier.verify (AbstractVerifier.Java:93) 03-02 16: 58: 25.238: W/System.err (1868): at org.Apache.http.conn.ssl.SSLSocketFactory.createSocket (SSLSocketFactory.Java:381) 03-02 16: 58: 25.238: W/System.err (1868): at org.Apache.http.impl.conn.DefaultClientConnectionOperator.openConnection (DefaultClientConnectionOperator.Java:165) 03-02 16: 58: 25.250: W/System.err (1868): at org.Apache.http.impl.conn.AbstractPoolEntry.open (AbstractPoolEntry.Java:164) 03-02 16: 58: 25.250: W/System.err (1868): at org.Apache.http.impl.conn.AbstractPooledConnAdapter.open (AbstractPooledConnAdapter.Java:119) 03-02 16: 58: 25.250: W/System.err (1868): at org.Apache.http.impl.client.DefaultRequestDirector.execute (DefaultRequestDirector.Java:360) 03-02 16: 58: 25.250: W/System.err (1868): at org.Apache.http.impl.client.AbstractHttpClient.execute (AbstractHttpClient.Java:555) 03-02 16: 58: 25.250: W/System.err (1868): at org.Apache.http.impl.client.AbstractHttpClient.execute (AbstractHttpClient.Java:487) 03-02 16: 58: 25.250: W/System.err (1868): at org.Apache.http.impl.client.AbstractHttpClient.execute (AbstractHttpClient.Java:465) 03-02 16: 58: 25.250: W/System.err (1868): at com.https.test.DownloadImageTask.doInBackground (Https_testActivity.Java:78) 03-02 16: 58: 25.250: W/System.err (1868): at com.https.test.DownloadImageTask.doInBackground (Https_testActivity.Java:1) 03-02 16: 58: 25.250: W/System.err (1868): at Android.os.AsyncTask $ 2.call (AsyncTask.Java:264) 03-02 16: 58: 25.253: W/System.err (1868): at Java.util.concurrent.FutureTask $ Sync.innerRun (FutureTask.Java:305) 03-02 16: 58: 25.253: W/System.err (1868): at Java.util.concurrent.FutureTask.run (FutureTask.Java:137) 03-02 16: 58: 25.253: W/System.err (1868): at Android.os.AsyncTask $ SerialExecutor $ 1.run (AsyncTask.Java:208) 03-02 16: 58: 25.257: W/System.err (1868): at Java.util.concurrent.ThreadPoolExecutor.runWorker (ThreadPoolExecutor.Java:1076) 03-02 16: 58: 25.257: W/System.err (1868): at Java.util.concurrent.ThreadPoolExecutor $ Worker.run (ThreadPoolExecutor.Java:569) 03-02 16: 58: 25.257: W/System.err (1868): at Java.lang.Thread.run (Thread.Java:856)


Вопрос

Что я делаю не так и как я могу решить эту проблему. Почему я получаю исключение "Нет сертификата однорангового узла"?

Благодарю.

Отредактированный


Настройки Windows Server.

<VirtualHost *:443>
  ServerName 10.2.20.20

 Alias /fido/EzPay/ "d:/fido/EzPay/" 
Alias /fido/EzPay "d:/fido/EzPay/" 

<Directory "d:/fido/EzPay/">
    Options Indexes FollowSymLinks MultiViews
    AllowOverride all
        Order allow,deny
    Allow from all
</Directory>


  # These are the actual SSL directives needed to get it all working!
  SSLEngine on
  SSLCertificateFile C:/wamp/bin/Apache/apache2.2.17/conf/ssl/fidoserver.crt
  SSLCertificateKeyFile C:/wamp/bin/Apache/apache2.2.17/conf/ssl/fidoserver.pem
</VirtualHost>
19
Viktor Apoyan

Наконец я решил проблему https. Поскольку я боролся, основная проблема была в сервере, конкретно в сертификате . Android поддерживает только сертификат "BKS", и это было причиной, по которой мы не можем получить ответ от сервера Чтобы решить эту проблему, я прочитал более 30 статей и наконец нашел решение. 

Шаги, которые я сделал для решения этой проблемы, вы можете увидеть ниже:

Первым делом я сгенерировал файл хранилища ключей .bks из нашего сертификата fidoserver.crt, для этого я прочитал эту статью и сделаю следующее: 

  1. Открыть cmd 
  2. Перейдите в папку JDK «cd X:\Programs\Java\Jdk6\bin» 
  3. Вызовите следующую команду:

keytool -import -alias Tomcat -file X: //KeyStore/fidoserver.crt - пароль доступа - хранилище ключей X: //KeyStore/keystore.bks - тип магазина BKS -storepass 222222 -providerClass org.bouncycastle.jce.provider.BouncyCastleProvider -providerpath X: //KeyStore/bcprov-jdk16-146.jar

Перед запуском этой команды я скачал файл Bouncy Castle .jar и положил его в папку с сертификатами. После этого я получаю файл keystore.bks, который является подходящим файлом сертификата для приложения Android. Я положил этот файл в папку Android MNC/SDCard. В коде Java я должен написать следующий код, чтобы прочитать этот файл keystore.bbk

KeyStore trustStore  = KeyStore.getInstance( "BKS" /*KeyStore.getDefaultType()*/ );
FileInputStream instream = new FileInputStream(new File("/mnt/sdcard/keystore.bks"));
try {
    trustStore.load(instream, "222222".toCharArray());
} catch (NoSuchAlgorithmException e) {
    e.printStackTrace();
} catch (CertificateException e) {
    e.printStackTrace();
} catch (IOException e) {
    e.printStackTrace();
} finally {
    try { instream.close(); } catch (Exception ignore) {}
}

// Create socket factory with given keystore.
SSLSocketFactory socketFactory = new SSLSocketFactory(trustStore);

SSLSocketFactory socketFactory = new SSLSocketFactory(trustStore);
Scheme sch = new Scheme("https", socketFactory, 443);
httpclient.getConnectionManager().getSchemeRegistry().register(sch);

HttpGet httpget = new HttpGet("https://10.2.20.20/fido/EzPay/login.php");

System.out.println("executing request " + httpget.getRequestLine());

HttpResponse response = httpclient.execute(httpget);
HttpEntity entity = response.getEntity();

System.out.println("----------------------------------------");
System.out.println(response.getStatusLine());
if (entity != null) {
    System.out.println("Response content length:  " + entity.getContentLength());
}

// Print html.
BufferedReader in = new BufferedReader(new InputStreamReader(response.getEntity().getContent()));
String line = "";
while ((line = in.readLine()) != null) {
     System.out.println(line);
}
in.close();

Все это позволяет m загрузить наш сертификат с заданным паролем 222222 (пароль, который мы даем при создании хранилища ключей с помощью keytool).

После этого все мои тестовые приложения начинают работать правильно. Теперь я могу отправить запрос в https и получить от него ответ. Я протестировал приложение С сервером FIDO, все отлично работает! Я думаю, что в понедельник я внесу некоторые изменения в приложение EzPay, и оно Начнет работать с https-соединениями. 

Рекомендации

20
Viktor Apoyan

Метод запроса POST не подходит для URL /. Это все, что мы знаем.

Пример 1 не работает, потому что кажется, что вы не можете отправить запрос POST на эту страницу. Пытаться:

/* ... */
HttpGet httpGet = new HttpGet(url);
HttpResponse response = httpClient.execute(httpGet);
/* ... */

Пример 2 не работает, потому что вы не принимаете сертификат веб-сайта в качестве принятого сертификата, поэтому он также должен выглядеть следующим образом:

/* ... */
HostnameVerifier hostnameVerifier = org.Apache.http.conn.ssl.SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER;
SchemeRegistry registry = new SchemeRegistry();
SSLSocketFactory socketFactory = SSLSocketFactory.getSocketFactory();
socketFactory.setHostnameVerifier((X509HostnameVerifier) hostnameVerifier);
registry.register(new Scheme("https", socketFactory, 443));
SingleClientConnManager mgr = new SingleClientConnManager(client.getParams(), registry);
DefaultHttpClient httpClient = new DefaultHttpClient(mgr, client.getParams());
/* ... */
7
Caner

Вы пытались открыть страницу с помощью браузера? Если он не открывается, ваша Конфигурация неверна.

Обратите внимание, что если вы используете самоподписанный сертификат, у вас могут возникнуть проблемы с подключением. Некоторые версии ядра Android (до 2.6.32.9) не любят Self-Singed-Certificates.

0
outofBounds