I have a local HTTP proxy set up for debugging .json request and response data from my Android application. I deploy it to a Nexus One emulator image running Android 4.2.2 with the command line option -http-proxy http://localhost:8888
. I'm using a stock ADT Build: v21.1.0-569685. I can validate that the HTTP proxy can handle HTTPS connections with the following code snippet I run using groovy:
import java.security.KeyStore;
import java.security.cert.Certificate;
import java.security.cert.CertificateFactory;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManagerFactory;
FileInputStream fis =
new FileInputStream( "./.mitmproxy/mitmproxy-ca-cert.pem" );
BufferedInputStream bis = new BufferedInputStream( fis );
CertificateFactory cf = CertificateFactory.getInstance( "X.509" );
KeyStore ks = KeyStore.getInstance( KeyStore.getDefaultType() );
ks.load( null,"".toCharArray() );
while ( bis.available() > 0 )
{
Certificate cert = cf.generateCertificate( bis );
ks.setCertificateEntry( "mitmproxy", cert );
System.out.println( cert.toString() );
}
TrustManagerFactory tmf =
TrustManagerFactory.getInstance(
TrustManagerFactory.getDefaultAlgorithm() );
tmf.init( ks );
SSLContext ctx = SSLContext.getInstance( "TLS" );
ctx.init( null, tmf.getTrustManagers(), null );
SSLSocketFactory sslFactory = ctx.getSocketFactory();
try
{
String url = "https://www.openssl.org/";
Proxy proxy =
new Proxy(
Proxy.Type.HTTP,
new InetSocketAddress( "127.0.0.1", 8888 ) );
HttpsURLConnection conn =
( HttpsURLConnection ) new URL( url ).openConnection( proxy );
conn.setSSLSocketFactory( sslFactory );
String s =
new Scanner(
conn.getInputStream(),
"UTF-8" ).useDelimiter( "\\A" ).next();
System.out.println( s );
}
catch ( Exception e )
{
e.printStackTrace();
}
This snippet fetches the HTTPS resource just fine, logs the request and response unencrypted, and works beautifully. The proxy also works when accessing HTTPS resources from a browser configured to use it as its proxy, so I'm pretty sure the problem is not with the proxy. Based on the certificate, you can tell I'm using the mitmproxy, but this code also works with the OWASP ZAP proxy. But with either proxy, after installing the appropriate CA root certificate on the Android image, HTTPS requests from the image fail with the following events being logged to the mitmproxy event log:
127.0.0.1:56210: connect
127.0.0.1:56210: 400: SSL handshake error: (-1, 'Unexpected EOF')
127.0.0.1:56210: disconnect
-> handled 0 requests
On the Android side, the following exception is thrown:
05-23 16:13:30.109: E/HttpUrlConnectionClient(827): Network error
05-23 16:13:30.109: E/HttpUrlConnectionClient(827): javax.net.ssl.SSLHandshakeException: javax.net.ssl.SSLProtocolException: SSL handshake aborted: ssl=0x2a180890: Failure in SSL library, usually a protocol error
05-23 16:13:30.109: E/HttpUrlConnectionClient(827): error:140770FC:SSL routines:SSL23_GET_SERVER_HELLO:unknown protocol (external/openssl/ssl/s23_clnt.c:766 0x45dc2ba8:0x00000000)
05-23 16:13:30.109: E/HttpUrlConnectionClient(827): at org.apache.harmony.xnet.provider.jsse.OpenSSLSocketImpl.startHandshake(OpenSSLSocketImpl.java:420)
05-23 16:13:30.109: E/HttpUrlConnectionClient(827): at com.integralblue.httpresponsecache.compat.libcore.net.http.HttpConnection.setupSecureSocket(HttpConnection.java:219)
05-23 16:13:30.109: E/HttpUrlConnectionClient(827): at com.integralblue.httpresponsecache.compat.libcore.net.http.HttpsURLConnectionImpl$HttpsEngine.makeSslConnection(HttpsURLConnectionImpl.java:480)
05-23 16:13:30.109: E/HttpUrlConnectionClient(827): at com.integralblue.httpresponsecache.compat.libcore.net.http.HttpsURLConnectionImpl$HttpsEngine.connect(HttpsURLConnectionImpl.java:444)
05-23 16:13:30.109: E/HttpUrlConnectionClient(827): at com.integralblue.httpresponsecache.compat.libcore.net.http.HttpEngine.sendSocketRequest(HttpEngine.java:294)
05-23 16:13:30.109: E/HttpUrlConnectionClient(827): at com.integralblue.httpresponsecache.compat.libcore.net.http.HttpEngine.sendRequest(HttpEngine.java:244)
05-23 16:13:30.109: E/HttpUrlConnectionClient(827): at com.integralblue.httpresponsecache.compat.libcore.net.http.HttpURLConnectionImpl.getResponse(HttpURLConnectionImpl.java:286)
05-23 16:13:30.109: E/HttpUrlConnectionClient(827): at com.integralblue.httpresponsecache.compat.libcore.net.http.HttpURLConnectionImpl.getInputStream(HttpURLConnectionImpl.java:181)
05-23 16:13:30.109: E/HttpUrlConnectionClient(827): at com.integralblue.httpresponsecache.compat.libcore.net.http.HttpsURLConnectionImpl.getInputStream(HttpsURLConnectionImpl.java:273)
05-23 16:13:30.109: E/HttpUrlConnectionClient(827): at com.ehi.national.mobile.network.HttpUrlConnectionClient.send(HttpUrlConnectionClient.java:178)
05-23 16:13:30.109: E/HttpUrlConnectionClient(827): at com.ehi.national.mobile.network.AppClient.send(AppClient.java:212)
05-23 16:13:30.109: E/HttpUrlConnectionClient(827): at com.ehi.national.mobile.network.MsiClient.send(MsiClient.java:87)
05-23 16:13:30.109: E/HttpUrlConnectionClient(827): at com.ehi.national.mobile.services.SimpleService.runService(SimpleService.java:134)
05-23 16:13:30.109: E/HttpUrlConnectionClient(827): at com.ehi.national.mobile.task.InitTask.doInBackground(InitTask.java:84)
05-23 16:13:30.109: E/HttpUrlConnectionClient(827): at com.ehi.national.mobile.task.InitTask.doInBackground(InitTask.java:1)
05-23 16:13:30.109: E/HttpUrlConnectionClient(827): at android.os.AsyncTask$2.call(AsyncTask.java:287)
05-23 16:13:30.109: E/HttpUrlConnectionClient(827): at java.util.concurrent.FutureTask.run(FutureTask.java:234)
05-23 16:13:30.109: E/HttpUrlConnectionClient(827): at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:230)
05-23 16:13:30.109: E/HttpUrlConnectionClient(827): at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1080)
05-23 16:13:30.109: E/HttpUrlConnectionClient(827): at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:573)
05-23 16:13:30.109: E/HttpUrlConnectionClient(827): at java.lang.Thread.run(Thread.java:856)
05-23 16:13:30.109: E/HttpUrlConnectionClient(827): Caused by: javax.net.ssl.SSLProtocolException: SSL handshake aborted: ssl=0x2a180890: Failure in SSL library, usually a protocol error
05-23 16:13:30.109: E/HttpUrlConnectionClient(827): error:140770FC:SSL routines:SSL23_GET_SERVER_HELLO:unknown protocol (external/openssl/ssl/s23_clnt.c:766 0x45dc2ba8:0x00000000)
05-23 16:13:30.109: E/HttpUrlConnectionClient(827): at org.apache.harmony.xnet.provider.jsse.NativeCrypto.SSL_do_handshake(Native Method)
05-23 16:13:30.109: E/HttpUrlConnectionClient(827): at org.apache.harmony.xnet.provider.jsse.OpenSSLSocketImpl.startHandshake(OpenSSLSocketImpl.java:378)
05-23 16:13:30.109: E/HttpUrlConnectionClient(827): ... 20 more
Other HTTP requests get logged and recorded as expected. What am I missing in the SSL setup for the Android image to complete the SSL handshake with the HTTP proxy successfully?