【发布时间】:2015-11-13 18:16:17
【问题描述】:
我目前正在尝试在一个简单的 testapp 中实现 ssl 连接。
设置: 带有 Tomcat 7 的 Ubuntu 服务器 14.04.3 内网IP:192.168.189.42 Tomcat SSL:
https://192.168.177.42:8443/
通过以下方式创建的 SSL 证书:Tomcat Tutorial 设备:API23 Tablet VM(Hyper-V、Visual Studio) IDE:安卓工作室
首先我通过 AsyncTask 测试了与 Google 的 ssl 连接:
URL url = new URL("https://google.de");
URLConnection urlConnection = url.openConnection();
InputStream in = urlConnection.getInputStream();
in.close();
效果很好。
所以我用这个命令从密钥库中提取了证书:
keytool -export -alias tomcat -file server.cer -keystore .keystore
我将该文件放入:myproject/res/raw/server.cer
在另一个 AsyncTask 中,我使用来自 google 开发人员的 sample code 创建连接:
CertificateFactory cf = CertificateFactory.getInstance("X.509");
InputStream caInput = new BufferedInputStream(context.getResources().openRawResource(R.raw.server));
Certificate ca;
ca = cf.generateCertificate(caInput);
Log.d("CERT: ", "ca=" + ((X509Certificate) ca).getSubjectDN());
caInput.close();
String keyStoreType = KeyStore.getDefaultType();
KeyStore keyStore = KeyStore.getInstance(keyStoreType);
keyStore.load(null, null);
keyStore.setCertificateEntry("ca", ca);
String tmfAlgorithm = TrustManagerFactory.getDefaultAlgorithm();
TrustManagerFactory tmf = TrustManagerFactory.getInstance(tmfAlgorithm);
tmf.init(keyStore);
SSLContext context = SSLContext.getInstance("TLS");
context.init(null, tmf.getTrustManagers(), null);
URL url = new URL("https://192.168.177.42:8443/");
HttpsURLConnection urlConnection = (HttpsURLConnection) url.openConnection();
urlConnection.setSSLSocketFactory(context.getSocketFactory());
InputStream in = urlConnection.getInputStream();
in.close();
如果我尝试执行此代码,我会收到以下异常:
11-13 18:39:02.508 12135-12280/moe.testapp W/System.err﹕ javax.net.ssl.SSLPeerUnverifiedException: Hostname 192.168.177.42 not verified:
11-13 18:39:02.508 12135-12280/moe.testapp W/System.err﹕ certificate: sha1/wFJI0CzwVvJ2MuGvpoJaFO8y4z8=
11-13 18:39:02.508 12135-12280/moe.testapp W/System.err﹕ DN: CN=Alcardis,OU=AL,O=AL,L=test,ST=state,C=XX
11-13 18:39:02.508 12135-12280/moe.testapp W/System.err﹕ subjectAltNames: []
11-13 18:39:02.509 12135-12280/moe.testapp W/System.err﹕ at com.android.okhttp.internal.http.SocketConnector.connectTls(SocketConnector.java:120)
11-13 18:39:02.509 12135-12280/moe.testapp W/System.err﹕ at com.android.okhttp.Connection.connect(Connection.java:143)
11-13 18:39:02.509 12135-12280/moe.testapp W/System.err﹕ at com.android.okhttp.Connection.connectAndSetOwner(Connection.java:185)
11-13 18:39:02.509 12135-12280/moe.testapp W/System.err﹕ at com.android.okhttp.OkHttpClient$1.connectAndSetOwner(OkHttpClient.java:128)
11-13 18:39:02.509 12135-12280/moe.testapp W/System.err﹕ at com.android.okhttp.internal.http.HttpEngine.nextConnection(HttpEngine.java:341)
11-13 18:39:02.509 12135-12280/moe.testapp W/System.err﹕ at com.android.okhttp.internal.http.HttpEngine.connect(HttpEngine.java:330)
11-13 18:39:02.509 12135-12280/moe.testapp W/System.err﹕ at com.android.okhttp.internal.http.HttpEngine.sendRequest(HttpEngine.java:248)
11-13 18:39:02.509 12135-12280/moe.testapp W/System.err﹕ at com.android.okhttp.internal.huc.HttpURLConnectionImpl.execute(HttpURLConnectionImpl.java:433)
11-13 18:39:02.509 12135-12280/moe.testapp W/System.err﹕ at com.android.okhttp.internal.huc.HttpURLConnectionImpl.getResponse(HttpURLConnectionImpl.java:384)
11-13 18:39:02.509 12135-12280/moe.testapp W/System.err﹕ at com.android.okhttp.internal.huc.HttpURLConnectionImpl.getInputStream(HttpURLConnectionImpl.java:231)
11-13 18:39:02.509 12135-12280/moe.testapp W/System.err﹕ at com.android.okhttp.internal.huc.DelegatingHttpsURLConnection.getInputStream(DelegatingHttpsURLConnection.java:210)
11-13 18:39:02.509 12135-12280/moe.testapp W/System.err﹕ at com.android.okhttp.internal.huc.HttpsURLConnectionImpl.getInputStream(HttpsURLConnectionImpl.java)
11-13 18:39:02.509 12135-12280/moe.testapp W/System.err﹕ at moe.testapp.TomcatWebservice.doInBackground(TomcatWebservice.java:64)
11-13 18:39:02.509 12135-12280/moe.testapp W/System.err﹕ at moe.testapp.TomcatWebservice.doInBackground(TomcatWebservice.java:28)
11-13 18:39:02.509 12135-12280/moe.testapp W/System.err﹕ at android.os.AsyncTask$2.call(AsyncTask.java:295)
11-13 18:39:02.509 12135-12280/moe.testapp W/System.err﹕ at java.util.concurrent.FutureTask.run(FutureTask.java:237)
11-13 18:39:02.509 12135-12280/moe.testapp W/System.err﹕ at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:234)
11-13 18:39:02.509 12135-12280/moe.testapp W/System.err﹕ at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1113)
11-13 18:39:02.509 12135-12280/moe.testapp W/System.err﹕ at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:588)
11-13 18:39:02.509 12135-12280/moe.testapp W/System.err﹕ at java.lang.Thread.run(Thread.java:818)
我不明白为什么无法验证主机。证书已正确读取(我至少可以在调试器中使用正确的值访问它),并且 android 应用程序还可以通过标准 Web 浏览器中的 https 访问 tomcat。
好的,从 cmets 的回答中我得到了一些见解并尝试了另一种方法。 服务器没有 FQDN,CN 应该等于 FQND,这就是它在上面的代码中不起作用的原因。
因为服务器没有 FQDN,所以我搜索了另一种使用 IP 地址的方法。我找到了这个howto,并创建了一个没有CN但带有替代名称的证书并将ip放在那里我还必须将keystoreType="PKCS12"行添加到tomcat的server.xml,因为我从默认密钥库更改为PKCS12。
【问题讨论】: