Проблемы с https (нет сертификата пира) в Android - PullRequest
19 голосов
/ 02 марта 2012

Задача

Я хочу отправить 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): в org.apache.harmony.xnet.provider.jsse.SSLSessionImpl.getPeerCertificates (SSLSessionImpl.java:137) 03-02 16: 58: 25.238: W / System.err (1868): в org.apache.http.conn.ssl.AbstractVerifier.verify (AbstractVerifier.java:93) 03-02 16: 58: 25.238: W / System.err (1868): в org.apache.http.conn.ssl.SSLSocketFactory.createSocket (SSLSocketFactory.java:381) 03-02 16: 58: 25.238: W / System.err (1868): в org.apache.http.impl.conn.DefaultClientConnectionOperator.openConnection (DefaultClientConnectionOperator.java:165) 03-02 16: 58: 25.250: W / System.err (1868): в org.apache.http.impl.conn.AbstractPoolEntry.open (AbstractPoolEntry.java:164) 03-02 16: 58: 25.250: W / System.err (1868): в org.apache.http.impl.conn.AbstractPooledConnAdapter.open (AbstractPooledConnAdapter.java:119) 03-02 16: 58: 25.250: W / System.err (1868): в org.apache.http.impl.client.DefaultRequestDirector.execute (DefaultRequestDirector.java:360) 03-02 16: 58: 25.250: W / System.err (1868): в org.apache.http.impl.client.AbstractHttpClient.execute (AbstractHttpClient.java:555) 03-02 16: 58: 25.250: W / System.err (1868): в org.apache.http.impl.client.AbstractHttpClient.execute (AbstractHttpClient.java:487) 03-02 16: 58: 25.250: W / System.err (1868): в org.apache.http.impl.client.AbstractHttpClient.execute (AbstractHttpClient.java:465) 03-02 16: 58: 25.250: W / System.err (1868): в com.https.test.DownloadImageTask.doInBackground (Https_testActivity.java:78) 03-02 16: 58: 25.250: W / System.err (1868): в com.https.test.DownloadImageTask.doInBackground (Https_testActivity.java:1) 03-02 16: 58: 25.250: W / System.err (1868): в android.os.AsyncTask $ 2.call (AsyncTask.java:264) 03-02 16: 58: 25.253: W / System.err (1868): в java.util.concurrent.FutureTask $ Sync.innerRun (FutureTask.java:305) 03-02 16: 58: 25.253: W / System.err (1868): в 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): в java.util.concurrent.ThreadPoolExecutor.runWorker (ThreadPoolExecutor.java:1076) 03-02 16: 58: 25.257: W / System.err (1868): в java.util.concurrent.ThreadPoolExecutor $ Worker.run (ThreadPoolExecutor.java:569) 03-02 16: 58: 25.257: W / System.err (1868): в 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>

Ответы [ 3 ]

20 голосов
/ 06 марта 2012

Наконец-то я решил проблему 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-соединениями.

Ссылки

7 голосов
/ 02 марта 2012

Метод запроса 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());
/* ... */
0 голосов
/ 02 марта 2012

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...