Проблемы с 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());
}
Exception.
03-02 16: 58: 25.234: W/System.err(1868): javax.net.ssl.SSLPeerUnverifiedException: Отсутствует сертификат peer 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): при 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)
Вопрос
Что я делаю неправильно и как я могу решить эту проблему. Почему я получаю исключение < Отсутствие сертификатов peer certificate "
Спасибо.
Edited
Настройки 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>
Ответы
Ответ 1
Наконец, я решил проблему https. Поскольку я воевал, основная проблема была в сервере, конкретно в сертификате.
Android поддерживает только сертификат "BKS", и это было причиной того, что мы не можем получить ответ от
сервер. Чтобы решить эту проблему, я прочитал более 30 статей и, наконец, нашел решение.
Действия, которые я предпринял для решения этой проблемы, вы можете увидеть ниже:
Первое, что я сделал, это генерировать файл .bks keystore из нашего сертификата fidoserver.crt, чтобы сделать это, я прочитал эту статью и делаю следующее:
- Открыть cmd
- Перейдите в папку JDK "cd X:\Programs\Java\Jdk6\bin"
- Вызов следующей команды:
keytool -import -alias tomcat -file X://KeyStore/fidoserver.crt -keypass password - keystore X://KeyStore/keystore.bks -storetype BKS -storepass 222222 -providerClass org.bouncycastle.jce.provider.BouncyCastleProvider -providerpath X://KeyStore/bcprov-jdk16-146.jar
Перед запуском этой команды я загрузил Bouncy Castle.jar и поместил его в папку с сертификатами. После выполнения всех этих шагов я получаю файл keystore.bks, который является правильным файлом сертификата для приложения Android. Я помещаю этот файл в папку Androids 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-соединениями.
Ссылки
Ответ 2
Метод запроса 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());
/* ... */
Ответ 3
Вы пытались открыть страницу в браузере? Если его неправильная конфигурация неправильная.
Обратите внимание, что если вы используете самоподписанный сертификат, у вас могут возникнуть проблемы с подключением. Некоторые версии ядра Android (до 2.6.32.9) не любят Self-Singed-Certificates.