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

Android 6无法使用自签名证书与安全服务器通信,android,ssl,android-6.0-marshmallow,self-signed,Android,Ssl,Android 6.0 Marshmallow,Self Signed,我无法在Android 6应用程序和安全服务器之间建立连接,服务器使用Java(jdk 1.6)keytool命令生成的自签名证书。Android 6应用程序显示以下错误 例外日志: javax.net.ssl.SSLHandshakeException: Handshake failed : javax.net.ssl.SSLHandshakeException: Handshake failed 05-23 17:21:03.498 3602-6487/issac.wise.pay I/Sy

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

例外日志:

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)

我正在使用下面的代码,它在安卓5.9上运行良好,但在安卓6(棉花糖)上不起作用;下面的链接提供了与ssl通信的代码-


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

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

来自Android开发者:

自签名服务器证书SSLHandshakeException的第二种情况是由于自签名证书引起的,这意味着 服务器作为自己的CA运行。这类似于未知CA 证书颁发机构,因此您可以从 上一节

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


“它在安卓5.9之前运行良好”——没有安卓5.9。“下面的链接提供了与SSL通信的代码”——这不是您的代码,除非您正试图与华盛顿大学CA测试服务器通信。相反,这似乎是您从中复制的代码。除非我们能看到您的代码,否则我们无法帮助您解决您的代码问题。“这是证书生成问题还是我需要采用任何新技术与服务器通信?”--我想不出Android 6.0中有什么变化。Android在这里提供了新的选项,但这对Android 7.0来说是新的。
// 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);