AndroidをOpenSSL
オブジェクトを使用して単純なHttpsUrlConnection
サーバーに接続するのに問題があります(StackOverflowと一連のオンラインチュートリアルをくまなく調べました。例にほぼ1行ずつ従いましたが、ローカルのトラストストアを使用したときになぜ私のものが壊れているのかまだわかりません)。
現在、HttpsUrlConnection.connect()
が呼び出されると、単純な_OpenSSL server
_(OpenSSLクライアントを使用してサーバーに接続できます)に接続しようとするAndroidアクティビティがあります。 a "_javax.net.ssl.SSLException: Connection closed by peer" error during the SSL handshake.
_サンプルサーバーを正しく設定していない可能性がありますか?
注意事項:
Android 4.1 API 16
_に設定されています。私がすでに試したこと:
127.0.0.1 and 10.0.2.2
_SecureRandom() with the SSLContext.init()
を使用する'URL u = new URL("https", "10.0.2.2", 443, "/");'
でURLを作成するTrustManagerFactory.getDefaultAlgorithms()
を使用する"Unexpected response code error 503"
_を与えます時間を割いて私の質問を確認していただき、ありがとうございます。
コマンドで開始された単純なサーバー:
_$ Sudo openssl s_server -accept 443 -cert server-cert.pem -key server-key.pem -pass file:passphrase.txt -state -www -verify 0
_
コマンドでテストされたクライアント接続:
_$ openssl s_client -connect 127.0.0.1:443
_
Androidアクティビティコード(簡略化のために実行中の完全なコードを削除するように編集されています-さらにコードが必要な場合はお知らせください)-エラー出力はコードの下にあります。
_ try {
TrustManagerFactory tmf;
// local trust store
tmf = TrustManagerFactory.getInstance("X509");
tmf.init(loadLocalKeyStore(getApplicationContext()));
// default trust store - works for https://www.google.com
// tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
// tmf.init((KeyStore) null);
SSLContext context = SSLContext.getInstance("TLS");
context.init(null, tmf.getTrustManagers(), null);
HostnameVerifier hostnameVerifier = org.Apache.http.conn.ssl.SSLSocketFactory.STRICT_HOSTNAME_VERIFIER;
URL u = new URL("https://10.0.2.2");
HttpsURLConnection urlConnection = (HttpsURLConnection) u.openConnection();
urlConnection.setSSLSocketFactory(context.getSocketFactory());
urlConnection.setHostnameVerifier(hostnameVerifier);
urlConnection.connect();
System.out.println("Response Code: " + urlConnection.getResponseCode());
System.out.println("Response Code: " + urlConnection.getCipherSuite());
}
...
private KeyStore loadLocalKeyStore(Context context) {
InputStream in = context.getResources().openRawResource(R.raw.newserverkeystore);
KeyStore trusted = null;
try {
trusted = KeyStore.getInstance("BKS");
trusted.load(in, "thisisasecret".toCharArray());
} finally {
in.close();
}
return trusted;
}
_
正しく接続すると出力 https://www.google.com :
_09-09 21:58:09.947: I/System.out(669): Response Code: 200
09-09 21:58:09.947: I/System.out(669): Response Code: TLS_ECDHE_RSA_WITH_RC4_128_SHA
_
自己署名証明書を使用してサーバーに接続しようとしたときの出力:
_09-09 22:03:23.377: D/HttpsProxy(717): Https Request error
09-09 22:03:23.377: D/HttpsProxy(717): javax.net.ssl.SSLException: Connection closed by peer
09-09 22:03:23.377: D/HttpsProxy(717): at org.Apache.harmony.xnet.provider.jsse.NativeCrypto.SSL_do_handshake(Native Method)
09-09 22:03:23.377: D/HttpsProxy(717): at org.Apache.harmony.xnet.provider.jsse.OpenSSLSocketImpl.startHandshake(OpenSSLSocketImpl.Java:395)
09-09 22:03:23.377: D/HttpsProxy(717): at libcore.net.http.HttpConnection.setupSecureSocket(HttpConnection.Java:210)
09-09 22:03:23.377: D/HttpsProxy(717): at libcore.net.http.HttpsURLConnectionImpl$HttpsEngine.makeSslConnection(HttpsURLConnectionImpl.Java:478)
09-09 22:03:23.377: D/HttpsProxy(717): at libcore.net.http.HttpsURLConnectionImpl$HttpsEngine.connect(HttpsURLConnectionImpl.Java:442)
09-09 22:03:23.377: D/HttpsProxy(717): at libcore.net.http.HttpEngine.sendSocketRequest(HttpEngine.Java:289)
09-09 22:03:23.377: D/HttpsProxy(717): at libcore.net.http.HttpEngine.sendRequest(HttpEngine.Java:239)
09-09 22:03:23.377: D/HttpsProxy(717): at libcore.net.http.HttpURLConnectionImpl.connect(HttpURLConnectionImpl.Java:80)
09-09 22:03:23.377: D/HttpsProxy(717): at libcore.net.http.HttpsURLConnectionImpl.connect(HttpsURLConnectionImpl.Java:165)
09-09 22:03:23.377: D/HttpsProxy(717): at com.example.myfirstapp.HttpsUrlConnectionActivity$3.doInBackground(HttpsUrlConnectionActivity.Java:257)
09-09 22:03:23.377: D/HttpsProxy(717): at com.example.myfirstapp.HttpsUrlConnectionActivity$3.doInBackground(HttpsUrlConnectionActivity.Java:1)
09-09 22:03:23.377: D/HttpsProxy(717): at Android.os.AsyncTask$2.call(AsyncTask.Java:287)
09-09 22:03:23.377: D/HttpsProxy(717): at Java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.Java:305)
09-09 22:03:23.377: D/HttpsProxy(717): at Java.util.concurrent.FutureTask.run(FutureTask.Java:137)
09-09 22:03:23.377: D/HttpsProxy(717): at Android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.Java:230)
09-09 22:03:23.377: D/HttpsProxy(717): at Java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.Java:1076)
09-09 22:03:23.377: D/HttpsProxy(717): at Java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.Java:569)
09-09 22:03:23.377: D/HttpsProxy(717): at Java.lang.Thread.run(Thread.Java:856)
_
再度、感謝します!!
私は自分の問題を解決しました-共通名(CN)として10.0.2.2の証明書を使用する必要があったため、「localhost」または「127.0」ではなくAndroid localhost ip address 10.0.2.2 .0.1 '。
編集:おそらく、ローカルホストをCNとして、「127.0.0.1」と「10.0.2.2」をサブジェクト代替名(SAN)として使用して証明書を作成できます。
10.0.2.2 certファイルと秘密鍵pemファイルを作成すると、次のコマンドで実行中のサーバーにアクセスできました。
openssl s_server -accept 8888 -cert 10.0.2.2-cert.pem -key 10.0.2.2-key.pem -state -www
クライアントに証明書の提供を強制する場合(チェックはされませんが)、上記のコマンドにフラグ-Verify 1
を追加します。
コマンドラインでサーバーをテストするには、以下を使用できます(opensslは127.0.0.1経由で接続できることに注意してください)。
openssl s_client -connect 127.0.0.1:8888
また、サーバーで必要な場合にクライアント証明書を追加するには、フラグ-cert client-cert.pem -key client-key.pem
を追加します。
私のAndroidクライアントでは、次のコードを使用して接続しました(エラーチェックは削除されました):
// use local trust store (CA)
TrustManagerFactory tmf;
KeyStore trustedStore = null;
InputStream in = context.getResources().openRawResource(R.raw.mycatruststore); // BKS in res/raw
trustedStore = KeyStore.getInstance("BKS");
trustedStore.load(in, "insertBksPasswordHere".toCharArray());
tmf = TrustManagerFactory.getInstance("X509");
tmf.init(trustedStore);
// load client certificate
KeyStore clientKeyStore = loadClientKeyStore(getApplicationContext());
KeyManagerFactory kmf = KeyManagerFactory.getInstance("X509");
kmf.init(clientKeyStore, "insertPasswordHere".toCharArray());
SSLContext context = SSLContext.getInstance("TLS");
// provide client cert - if server requires client cert this will pass
context.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
HostnameVerifier hostnameVerifier = org.Apache.http.conn.ssl.SSLSocketFactory.STRICT_HOSTNAME_VERIFIER;
// connect to url
URL u = new URL("https://10.0.2.2:8888/");
HttpsURLConnection urlConnection = (HttpsURLConnection) u.openConnection();
urlConnection.setSSLSocketFactory(context.getSocketFactory());
urlConnection.setHostnameVerifier(hostnameVerifier);
urlConnection.connect();
System.out.println("Response Code: " + urlConnection.getResponseCode());
200の応答コードを取得する必要があり、そこから応答を分析できます。
クライアント資格情報をロードするコードは次のとおりです。これは、サーバーキーストアのロードと同じですが、リソースのファイル名とパスワードが異なります。
private KeyStore loadClientKeyStore(Context context) {
InputStream in = context.getResources().openRawResource(R.yourKeyStoreFile);
KeyStore trusted = null;
trusted = KeyStore.getInstance("BKS");
trusted.load(in, "yourClientPassword".toCharArray());
in.close();
return trusted;
}
私は6〜7時間を無駄にしてこの問題を修正し、最終的には
public void URLConnection(String webUrl) throws IOException, NoSuchAlgorithmException, KeyManagementException {
//TLSSocketFactory objTlsSocketFactory = new TLSSocketFactory();
URL url = new URL(webUrl);
HttpsURLConnection urlConnection = (HttpsURLConnection)url.openConnection();
urlConnection.setRequestMethod("GET");
//urlConnection.setSSLSocketFactory(objTlsSocketFactory);
int responseCode = urlConnection.getResponseCode();
System.out.println("\nSending 'GET' request to URL : " + url);
System.out.println("Response Code : " + responseCode);
BufferedReader in = new BufferedReader(
new InputStreamReader(urlConnection.getInputStream()));
String inputLine;
StringBuffer response = new StringBuffer();
while ((inputLine = in.readLine()) != null) {
response.append(inputLine);
}
in.close();
//print result
System.out.println(response.toString());
}
そしてそれはうまくいきました!!!!!!