我在Android设备(Samsung Galaxy和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);
}
`
我检查了什么:
服务器站点有点旧(它是一个SOAP服务),但我认为服务器所服务的并不重要。
请帮助,这是我的第一篇文章。