Android デバイス (Samsung Galaxy with Android 6.0) と com.sun.net.httpserver.HttpsServer を使用する Simple Java App との間の SSL (TSL) を介した通信に問題があります。Android 4.4 を搭載した他のデバイスでは、すべて正常に動作すると言わざるを得ません。
Android 6.0 でハンドシェイクを試みると、サーバー側で通信が終了します。android では、次のスタックトレースを参照してください。
W/System.err: javax.net.ssl.SSLHandshakeException: Connection closed by peer
W/System.err: at com.android.org.conscrypt.NativeCrypto.SSL_do_handshake(Native Method)
W/System.err: at com.android.org.conscrypt.OpenSSLSocketImpl.startHandshake(OpenSSLSocketImpl.java:353)
W/System.err: at com.android.okhttp.internal.http.SocketConnector.connectTls(SocketConnector.java:212)
W/System.err: at com.android.okhttp.Connection.connect(Connection.java:1322)
W/System.err: at com.android.okhttp.Connection.connectAndSetOwner(Connection.java:1410)
W/System.err: at com.android.okhttp.OkHttpClient$1.connectAndSetOwner(OkHttpClient.java:128)
W/System.err: at com.android.okhttp.internal.http.HttpEngine.nextConnection(HttpEngine.java:466)
W/System.err: at com.android.okhttp.internal.http.HttpEngine.connect(HttpEngine.java:447)
W/System.err: at com.android.okhttp.internal.http.HttpEngine.sendRequest(HttpEngine.java:353)
W/System.err: at com.android.okhttp.internal.huc.HttpURLConnectionImpl.execute(HttpURLConnectionImpl.java:468) 08-28 06:47:21.322 3676-5603/pl.com.szb.gateopener W/System.err: at com.android.okhttp.internal.huc.HttpURLConnectionImpl.connect(HttpURLConnectionImpl.java:118) 08-28 06:47:21.322 3676-5603/pl.com.szb.gateopener W/System.err: at com.android.okhttp.internal.huc.HttpURLConnectionImpl.getOutputStream(HttpURLConnectionImpl.java:249)
W/System.err: at com.android.okhttp.internal.huc.DelegatingHttpsURLConnection.getOutputStream(DelegatingHttpsURLConnection.java:218)
W/System.err: at com.android.okhttp.internal.huc.HttpsURLConnectionImpl.getOutputStream(HttpsURLConnectionImpl.java:25)
W/System.err: at org.ksoap2.transport.HttpsServiceConnectionSE.openOutputStream(HttpsServiceConnectionSE.java:127)
W/System.err: at org.ksoap2.transport.HttpTransportSE.sendData(HttpTransportSE.java:292)
W/System.err: at org.ksoap2.transport.HttpTransportSE.call(HttpTransportSE.java:184)
W/System.err: at org.ksoap2.transport.HttpTransportSE.call(HttpTransportSE.java:118)
W/System.err: at pl.com.szb.gateopener.client.PSBGOImplPortBinding.sendRequest(PSBGOImplPortBinding.java:99)
W/System.err: at pl.com.szb.gateopener.client.PSBGOImplPortBinding.execute(PSBGOImplPortBinding.java:284)
W/System.err: at pl.com.szb.gateopener.client.PSBGOImplPortBinding.getGates(PSBGOImplPortBinding.java:142)
W/System.err: at pl.com.szb.gateopener.client.PSBGOImplPortBinding$2.Func(PSBGOImplPortBinding.java:165)
W/System.err: at pl.com.szb.gateopener.client.PSBGOImplPortBinding$2.Func(PSBGOImplPortBinding.java:163)
W/System.err: at pl.com.szb.gateopener.client.PSBGOImplPortBinding$7.doInBackground(PSBGOImplPortBinding.java:318)
W/System.err: at pl.com.szb.gateopener.client.PSBGOImplPortBinding$7.doInBackground(PSBGOImplPortBinding.java:308)
W/System.err: at android.os.AsyncTask$2.call(AsyncTask.java:295)
W/System.err: at java.util.concurrent.FutureTask.run(FutureTask.java:237)
W/System.err: at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:234)
W/System.err: at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1113)
W/System.err: at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:588)
W/System.err: at java.lang.Thread.run(Thread.java:818)
SSL 開始用の Android コード
`private void initSSL() throws Exception {
Log.d(TAG,"initSSL");
TrustManager tm = new CustomX509TrustManager();
SSLContext customSSLContext = SSLContext.getInstance("TLSv1.1");
customSSLContext.init(null , new TrustManager[] { tm } , null);
sslSocketFactory = customSSLContext.getSocketFactory();
HttpsURLConnection.setDefaultSSLSocketFactory(sslSocketFactory);
HostnameVerifier hv = new HostnameVerifier() {
public boolean verify(String hostname, SSLSession session) {
Log.d(TAG, String.format("Verifying %s , sessionId: %s", hostname, Arrays.toString(session.getId())));
return true;
}
};
HttpsURLConnection.setDefaultHostnameVerifier(hv);
}
public class CustomX509TrustManager implements X509TrustManager {
private String TAG = "CustomX509TrustManager";
@Override
public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException
{
Log.d(TAG, "checkClientTrusted");
}
@Override
public void checkServerTrusted(java.security.cert.X509Certificate[] certs, String authType) throws CertificateException
{
Log.d(TAG, "checkServerTrusted");
// Here you can verify the servers certificate. (e.g. against one which is stored on mobile device)
InputStream inStream = null;
try {
inStream = getResources().openRawResource(R.raw.goserver_10y);
CertificateFactory cf = CertificateFactory.getInstance("X.509");
X509Certificate ca = (X509Certificate) cf.generateCertificate(inStream);
inStream.close();
for (X509Certificate cert : certs) {
// Verifing by public key
cert.verify(ca.getPublicKey());
}
} catch (Exception e) {
Log.w(TAG, e.getMessage());
throw new CertificateException(e);
} finally {
try {
inStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
public X509Certificate[] getAcceptedIssuers() {
Log.d(TAG, "getAcceptedIssuers");
return null;
}
}`
そしてサーバーコード:
`private void initServer() throws Exception{
Config config = getContext().system().settings().config();
host = getConfigString("pl.com.szb.GOImpl.host", config, "0.0.0.0");
port = getConfigInt("port", config, 10000);
useSSL = getConfigBoolean("use_ssl", config, true);
endpointLocation = getConfigString("endpointLocation", config, "/go");
String fullURL = String.format("%s://%s:%d%s",(useSSL ? "https" : "http"), host, port, endpointLocation);
log.info(String.format("WSDL : %s?wsdl", fullURL));
if (useSSL) {
keystorePass = getConfigString("keystorePass", config, "secret");
keystoreName = getConfigString("keystoreName", config, "second/server.bks");
char[] pass = keystorePass.toCharArray();
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
InputStream is = classLoader.getResourceAsStream(keystoreName);
KeyStore ks = KeyStore.getInstance("BKS");
ks.load(is, pass);
KeyManagerFactory kmf = KeyManagerFactory.getInstance("PKIX");
kmf.init(ks, pass);
SSLContext sslContext = SSLContext.getInstance("TLSv1.2");
sslContext.init(kmf.getKeyManagers(), null, null);
server = HttpsServer.create(new InetSocketAddress(host, port), 0);
((HttpsServer)server).setHttpsConfigurator(new HttpsConfigurator(sslContext) {
public void configure(HttpsParameters params) {
try {
log.debug(String.format("Got client: %s, wantAuth: %b, needAuth: %b",
params.getClientAddress().toString(),
params.getWantClientAuth(),
params.getNeedClientAuth()
));
params.setWantClientAuth(false);
params.setNeedClientAuth(false);
//what to do more??
} catch (Exception ex) {
log.warn(String.format("Failed to create HTTPS port, cause " + ex.getMessage()));
}
}
});
} else {
server = HttpServer.create(new InetSocketAddress(host, port), 0);
}
server.setExecutor(java.util.concurrent.Executors.newCachedThreadPool());
server.start();
HttpContext httpContext = server.createContext(endpointLocation);
endpoint = Endpoint.create(SOAPBinding.SOAP11HTTP_BINDING,this);
endpoint.publish(httpContext);
}
`
私がチェックしたこと:
- タイトルが入力された後にGoogleとstackoverflowが提案するすべてのリンク(特に、Android 5.0 lollipopのピアによって閉じられたリンクHttps接続-しかし運がない)
- 両方のデバイスの暗号化された場所であり、理論的には両方がハンドシェイクを終了できるはずです。対応するアルゴリズムがあります。
- 私はwiresharkとの両方の通信を確認しました。私は、(Android で) TLSv1.2 バージョン TLS 1.0 が SSL ヘッダーで送信されていることを発見しました ( 添付のwireshark ダンプを参照- 「Decode as」を使用 -> SSL) 140 行目に、Android 6.0 からの通信が表示されます。行 145 Android 4.4 からの通信が機能していることがわかります) 10.0.0.203 は Android 6.0、10.0.0.99 はサーバー、10.0.0.200 は Android 4.4 です。
- 「ピアによって閉じられた接続」について読みましたが、多くのトピックで間違った証明書について話している人がいますが、私の場合、証明書交換中ではなくプロトコルネゴシエーション中に SSL がクラッシュすると思います (これは後で説明します)。
サーバー サイトは少し古いですが (SOAP サービスです)、サーバーが何を提供するかは重要ではないと思います。
助けてください、それは私の最初の投稿です。