我正在尝试在 Android 应用程序中创建一个SSLSocket
在另一个之上。SSLSocket
下层连接是到安全 Web 代理(SSL 上的 HTTP 代理)的 SSL 安全连接,上层连接是用于 SSL 上的 HTTP (HTTPS)。
为此,我正在使用 SSLSocketFactory 的createSocket()
函数,该函数允许传递一个现有的 Socket 来运行 SSL 连接,如下所示:
private Socket doSSLHandshake(Socket socket, String host, int port) throws IOException {
TrustManager[] trustAllCerts = new TrustManager[]{
new X509TrustManager(){
public X509Certificate[] getAcceptedIssuers(){ return null; }
public void checkClientTrusted(X509Certificate[] certs, String authType) {}
public void checkServerTrusted(X509Certificate[] certs, String authType) {}
}
};
try {
SSLContext sslContext = SSLContext.getInstance("SSL");
sslContext.init(null, trustAllCerts, new SecureRandom());
SSLSocket sslSocket = (SSLSocket) sslContext.getSocketFactory().createSocket(socket, host, port, true);
sslSocket.setEnabledProtocols(sslSocket.getSupportedProtocols());
sslSocket.setEnableSessionCreation(true);
sslSocket.startHandshake();
return sslSocket;
} catch (KeyManagementException | NoSuchAlgorithmException e) {
throw new IOException("Could not do handshake: " + e);
}
}
当底层套接字是普通的 tcp 套接字时,此代码工作正常,但是当我使用之前使用上述代码创建的 SSLSocket 作为底层套接字时,握手失败并出现以下异常:
javax.net.ssl.SSLHandshakeException: Handshake failed
at com.android.org.conscrypt.OpenSSLSocketImpl.startHandshake(OpenSSLSocketImpl.java:429)
at com.myapp.MyThreadClass.doSSLHandshake(MyThreadClass.java:148)
at com.myapp.MyThreadClass.run(MyThreadClass.java:254)
Caused by: javax.net.ssl.SSLProtocolException: SSL handshake aborted: ssl=0x7374d56e80: Failure in SSL library, usually a protocol error
error:100000e3:SSL routines:OPENSSL_internal:UNKNOWN_ALERT_TYPE (external/boringssl/src/ssl/s3_pkt.c:618 0x738418ce7e:0x00000000)
at com.android.org.conscrypt.NativeCrypto.SSL_do_handshake(Native Method)
at com.android.org.conscrypt.OpenSSLSocketImpl.startHandshake(OpenSSLSocketImpl.java:357)
... 2 more
我正在 Android 7.1.1 上进行测试。该应用程序的目标是 SDK 级别 23。
- 我可能做错了什么?
- 我该如何进一步调试该问题?
- 有没有人有一个 SSLSocket 在最近的 Android 版本上通过另一个 SSLSocket 的工作示例?
任何帮助是极大的赞赏!
更新:完全相同的代码在 Mac 上的 JRE 1.8 中有效,但在 Android 上无效。
更新 2:从概念上讲,这些是连接经过的步骤:
- 从 Android 应用程序连接到安全代理服务器(套接字)
- 与代理服务器进行 SSL/TLS 握手(SSLSocket over Socket)
- 通过 SSLSocket 向代理服务器发送 CONNECT 消息
- 代理连接到目标(https)服务器,从现在开始只复制字节
- 与目标 (https) 服务器进行 SSL/TLS 握手(SSLSocket over SSLSocket over Socket)
- 将 GET 消息发送到目标服务器并读取响应
问题出现在第 5 步,即在通过 SSLSocket(通过 Socket)的 SSLSocket 上进行握手时。
更新 3:我现在打开了一个带有示例项目和 tcpdump 的 GitHub 存储库:https ://github.com/FD-/SSLviaSSL
注意:我发现并阅读了一个标题非常相似的问题,但不幸的是它没有包含太多有用的帮助。