Android SSLSocket handshake failure in Android 6 and above
我已经编写了一个基于 Java SSLServerSocket 的服务器,它接受连接并通过自定义二进制协议与 android 应用程序通信:
1
2 3 4 5 |
ServerSocket serverSocket = SSLServerSocketFactory.getDefault().createServerSocket(1234);
while (true) { Socket socket = serverSocket.accept(); … } |
我使用以下参数运行服务器:
1
2 |
–Djavax.net.ssl.keyStore=keystore.jks
–Djavax.net.ssl.keyStorePassword=<PASSWORD> |
证书是使用以下构建公钥和私钥集的教程生成的:http://judebert.com/progress/archives/425-Using-SSL-in-Java,-Part-2.html:
1
2 3 |
keytool –genkeypair –keystore keystore.jks –alias keyname
keytool –export –alias keyname –file keyname.crt –keystore keystore.jks keytool –importcert –file keyname.crt –keystore truststore.jks |
另外,我通过使用 bouncycastle 构建信任库来使其与 android 兼容:
1
|
keytool –importkeystore –srckeystore truststore.jks –srcstoretype JKS –srcstorepass <PASSWORD> –destkeystore truststore.bks –deststoretype BKS –deststorepass <PASSWORD> –provider org.bouncycastle.jce.provider.BouncyCastleProvider –providerpath bcprov–ext–jdk15on–1.58.jar
|
在此处下载 bouncycastle 提供程序:https://www.bouncycastle.org/latest_releases.html
并将生成的 truststore.bks 移动到原始资源文件夹中。
在 Android 上,我使用以下代码构建一个
1
2 3 4 5 6 7 8 9 10 11 12 |
KeyStore trustStore = KeyStore.getInstance("BKS"); InputStream trustStoreStream = context.getResources().openRawResource(R.raw.truststore); trustStore.load(trustStoreStream,"<PASSWORD>".toCharArray()); TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm()); SSLContext sslContext = SSLContext.getInstance("TLS"); Socket socket = sslContext.getSocketFactory().createSocket("ip", 1234); |
这适用于低于 6 的 Android 版本。我的问题是在版本 6 及更高版本上尝试使用套接字时出现异常:
1
2 3 4 5 6 7 8 9 10 11 12 13 14 |
Shutting down connection Socket[address=/ip,port=1234,localPort=321321] due to exception Handshake failed
javax.net.ssl.SSLHandshakeException: Handshake failed at com.android.org.conscrypt.OpenSSLSocketImpl.startHandshake(OpenSSLSocketImpl.java:429) at com.example.Client.connect(Client.java:97) at com.example.Client.start(Client.java:60) at com.example.BackendServiceFactory$2.call(BackendServiceFactory.java:136) at com.example.BackendServiceFactory$2.call(BackendServiceFactory.java:130) … Caused by: javax.net.ssl.SSLProtocolException: SSL handshake terminated: ssl=0xe69ec900: Failure in SSL library, usually a protocol error error:10000410:SSL routines:OPENSSL_internal:SSLV3_ALERT_HANDSHAKE_FAILURE (external/boringssl/src/ssl/s3_pkt.c:641 0xe2d10880:0x00000001) error:1000009a:SSL routines:OPENSSL_internal:HANDSHAKE_FAILURE_ON_CLIENT_HELLO (external/boringssl/src/ssl/s3_clnt.c:800 0xe6ea5af3:0x00000000) at com.android.org.conscrypt.NativeCrypto.SSL_do_handshake(Native Method) at com.android.org.conscrypt.OpenSSLSocketImpl.startHandshake(OpenSSLSocketImpl.java:357) … 24 more |
我不确定这里发生了什么。在处理客户端证书的过程中似乎有一个失误,这可能是密码套件不匹配吗?
我已经用 Java 服务器、Java 客户端和 Android 客户端组合了一个最小示例来帮助诊断此问题:
https://github.com/johncarl81/androidCA
我认为这将是一个简单的修复。似乎我需要在第一个 keytool 命令中指定密钥算法:
1
|
keytool –genkeypair –keystore keystore.jks –alias keyname –keyalg RSA
|
这会生成一个 2048 位 RSA 密钥,它与 android < 6 和 >= 6 的版本兼容。
原创文章,作者:ItWorker,如若转载,请注明出处:https://blog.ytso.com/268987.html