Android 6无法使用自签名证书与安全服务器通信

时间:2017-06-08 11:57:27

标签: android ssl android-6.0-marshmallow self-signed

我无法在Android 6应用程序和安全服务器之间建立连接,其中服务器使用由Java(jdk 1.6)keytool命令生成的自签名证书。 Android 6应用程序显示以下错误。

Excepton Log:

javax.net.ssl.SSLHandshakeException: Handshake failed : javax.net.ssl.SSLHandshakeException: Handshake failed
05-23 17:21:03.498 3602-6487/issac.wise.pay I/System.out:     at com.android.org.conscrypt.OpenSSLSocketImpl.startHandshake(OpenSSLSocketImpl.java:429)
05-23 17:21:03.498 3602-6487/issac.wise.pay I/System.out:     at com.android.okhttp.Connection.connectTls(Connection.java:235)
05-23 17:21:03.498 3602-6487/issac.wise.pay I/System.out:     at com.android.okhttp.Connection.connectSocket(Connection.java:199)
05-23 17:21:03.498 3602-6487/issac.wise.pay I/System.out:     at com.android.okhttp.Connection.connect(Connection.java:172)
05-23 17:21:03.498 3602-6487/issac.wise.pay I/System.out:     at com.android.okhttp.Connection.connectAndSetOwner(Connection.java:367)
05-23 17:21:03.498 3602-6487/issac.wise.pay I/System.out:     at com.android.okhttp.OkHttpClient$1.connectAndSetOwner(OkHttpClient.java:130)
05-23 17:21:03.498 3602-6487/issac.wise.pay I/System.out:     at com.android.okhttp.internal.http.HttpEngine.connect(HttpEngine.java:329)
05-23 17:21:03.498 3602-6487/issac.wise.pay I/System.out:     at com.android.okhttp.internal.http.HttpEngine.sendRequest(HttpEngine.java:246)
05-23 17:21:03.498 3602-6487/issac.wise.pay I/System.out:     at com.android.okhttp.internal.huc.HttpURLConnectionImpl.execute(HttpURLConnectionImpl.java:457)
05-23 17:21:03.498 3602-6487/issac.wise.pay I/System.out:     at com.android.okhttp.internal.huc.HttpURLConnectionImpl.connect(HttpURLConnectionImpl.java:126)
05-23 17:21:03.498 3602-6487/issac.wise.pay I/System.out:     at com.android.okhttp.internal.huc.HttpURLConnectionImpl.getOutputStream(HttpURLConnectionImpl.java:257)
05-23 17:21:03.498 3602-6487/issac.wise.pay I/System.out:     at com.android.okhttp.internal.huc.DelegatingHttpsURLConnection.getOutputStream(DelegatingHttpsURLConnection.java:218)
05-23 17:21:03.498 3602-6487/issac.wise.pay I/System.out:     at com.android.okhttp.internal.huc.HttpsURLConnectionImpl.getOutputStream(HttpsURLConnectionImpl.java)

我正在使用下面的代码,它正常工作到Android 5.9但它不能与android 6(marshmallow);以下链接提供了与ssl进行通信的代码 -

https://developer.android.com/training/articles/security-ssl.html

// Load CAs from an InputStream
// (could be from a resource or ByteArrayInputStream or ...)
CertificateFactory cf = CertificateFactory.getInstance("X.509");
// From https://www.washington.edu/itconnect/security/ca/load-der.crt
InputStream caInput = new BufferedInputStream(new FileInputStream("load-der.crt"));
Certificate ca;
try {
    ca = cf.generateCertificate(caInput);
    System.out.println("ca=" + ((X509Certificate) ca).getSubjectDN());
} finally {
    caInput.close();
}

// Create a KeyStore containing our trusted CAs
String keyStoreType = KeyStore.getDefaultType();
KeyStore keyStore = KeyStore.getInstance(keyStoreType);
keyStore.load(null, null);
keyStore.setCertificateEntry("ca", ca);

// Create a TrustManager that trusts the CAs in our KeyStore
String tmfAlgorithm = TrustManagerFactory.getDefaultAlgorithm();
TrustManagerFactory tmf = TrustManagerFactory.getInstance(tmfAlgorithm);
tmf.init(keyStore);

// Create an SSLContext that uses our TrustManager
SSLContext context = SSLContext.getInstance("TLS");
context.init(null, tmf.getTrustManagers(), null);

// Tell the URLConnection to use a SocketFactory from our SSLContext
URL url = new URL("https://certs.cac.washington.edu/CAtest/");
HttpsURLConnection urlConnection =
    (HttpsURLConnection)url.openConnection();
urlConnection.setSSLSocketFactory(context.getSocketFactory());
InputStream in = urlConnection.getInputStream();
copyInputStreamToOutputStream(in, System.out);

有人可以建议如何解决这个问题吗?这是任何证书生成问题还是我需要遵循任何新技术与服务器通信?

1 个答案:

答案 0 :(得分:1)

Android 6不再接受不安全的连接,您应该使用安全证书或通过让应用程序忽略不安全的证书来解决此问题(这会产生严重的安全问题,并且根本不建议)。

来自Android开发者:https://developer.android.com/training/articles/security-ssl.html

  

自签名服务器证书 SSLHandshakeException的第二种情况是由于自签名证书,这意味着   服务器表现为自己的CA.这类似于未知   证书颁发机构,所以你可以使用相同的方法   上一节。

     

您可以创建自己的TrustManager,这次信任服务器   证书直接。这具有前面讨论的所有缺点   将您的应用程序直接绑定到证书,但可以安全地完成。   但是,您应该小心确保自签名   证书有一个相当强大的关键。截至2012年,一个2048位的RSA   指数为65537的签名每年到期是可以接受的。   旋转键时,您应该检查来自的建议   关于什么是可接受的权威(如NIST)