web-dev-qa-db-ja.com

androidでのhttps(ピア証明書なし)の問題

問題

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:No peer certificate 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):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.execut e(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):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 And roid.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)


質問

私が間違っていることと、この問題を解決する方法。 「No peer certificate」という例外が発生するのはなぜですか?

ありがとう。

編集済み


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以上の記事を読み、最終的に解決策を見つけました。

この問題を解決するために私が実行した手順は、次のとおりです。

私が最初に行うことは、fidoserver.crt証明書から.bksキーストアファイルを生成することでした。そのために、この記事を読み、次のことを行いました。

  1. コマンドを開く
  2. JDKフォルダー「cd X:\ Programs\Java\Jdk6\bin」に移動します
  3. 次のコマンドを呼び出します。

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ファイルをダウンロードして、証明書のあるフォルダーに配置します。これをすべて実行した後、Androidアプリケーションに適切な証明書ファイルであるkeystore.bksファイルを取得します。このファイルを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接続での作業を開始すると思います。

参考文献

20
Viktor Apoyan

リクエストメソッドPOSTはURLに不適切です/。私たちが知っているのはそれだけです。

例1は、そのページへのPOSTリクエストの送信が許可されていないように思われるため機能しません。試してください:

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

例2は、Webサイト証明書を承認済み証明書として受け入れないため機能しません。したがって、次のようになります。

/* ... */
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より前)は、自己署名証明書が好きではありません。

0
outofBounds