I'm trying to create an SSLSocket
on top of another SSLSocket
in an Android app. The lower connection is an SSL-secured connection to a Secure Web Proxy (HTTP proxy over SSL), the upper connection is for HTTP over SSL (HTTPS).
For this, I'm using SSLSocketFactory's createSocket()
function that allows to pass an existing Socket over which to run the SSL connection like this:
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); } }
This code is working fine when the underlying socket is a normal tcp Socket, but when I use as underlying socket an SSLSocket that has been created using the above code before, the handshake fails with the following exception:
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
I'm testing on Android 7.1.1. The app is targeting SDK level 23.
Any help is greatly appreciated!
Update: The very same code works in JRE 1.8 on a Mac, but not on Android.
Update 2: Conceptually, these are the steps the connection goes through:
- From the Android app, make a connection to the Secure Proxy server (Socket)
- Do an SSL/TLS handshake with the Proxy server (SSLSocket over Socket)
- Via the SSLSocket, send the CONNECT message to the Proxy server
- Proxy connects to destination (https) server and only copies bytes from now on
- Do an SSL/TLS handshake with the destination (https) server (SSLSocket over SSLSocket over Socket)
- Send the GET message to the destination server and read response
The problem arises in step 5, when doing the handshake on an SSLSocket that goes over an SSLSocket (that goes over a Socket).
Update 3: I have now opened a GitHub repo with a sample project and tcpdumps: https://github.com/FD-/SSLviaSSL
Note: I have found and read a question with very similar title, but it did not contain much useful help unfortunately.
SSLSocket class is a subclass of the standard Java™ java. net. Socket class. It supports all of the standard socket methods and adds additional methods specific to secure sockets. Instances of this class encapsulate the SSLContext under which they were created.
SSLContext is an engine class for an implementation of a secure socket protocol. An instance of this class acts as a factory for SSL socket factories and SSL engines. An SSLContext holds all of the state information shared across all objects created under that context.
I don't think you're doing anything wrong. It looks like there's a bug in the protocol negotiation during your second handshake. A good candidate would be failing in an NPN TLS handshake extension.
Take a look at your protocols in this call: sslSocket.setEnabledProtocols(sslSocket.getSupportedProtocols());
You can walk through the listed protocols and try them individually. See if you can lock down what's failing and whether you need that specific protocol or extension supported.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With