2

First of all i know there are plenty of topics on this. Most of them the anwser is trusting all certificates/hosts by default which given the environment and security is completely out of the question.

In 2.3 i've got a fully functional SSL client however when trying to run it on 2.2 i got a Read Error: Failure in SSL Library and then the next line it says (openssl_v3) unkown ca.

The thing is i've followed Crazybob and Antoine's blogs word for word several times to no affect(thats how i got it working on 2.3)

The organisation I work for are our own CA, the server port i'm connecting to has been restricted to only allow authorized client certificates of which i have one in a keystore. The 2.3 version has 2 BKS stores, one with the client cert and the other with that particular server's cert.

I tried putting the RootCA and Trusted Authority certs in the server store as well but it still had the same error,so unless they go in in an exact order i'm stumped.

public class WebService 
{
    Context context;
    InputStream serverin;
    InputStream clientin;
    DefaultHttpClient httpClient;

    public WebService(Context context, InputStream serverin, InputStream clientin)
    {
        this.context = context;
        this.serverin = serverin;
        this.clientin = clientin;
        this.httpClient = newConnection();
    }

         public DefaultHttpClient newConnection() {
        // Set basic data
        HttpParams params = new BasicHttpParams();
        HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1);
        HttpProtocolParams.setContentCharset(params, "UTF-8");
        HttpProtocolParams.setUseExpectContinue(params, true);
        HttpProtocolParams.setUserAgent(params, "Android app/1.0.0");
        // Make pool

        ConnPerRoute connPerRoute = new ConnPerRouteBean(12);
        ConnManagerParams.setMaxConnectionsPerRoute(params, connPerRoute);
        ConnManagerParams.setMaxTotalConnections(params, 20);
        // Set timeout
        HttpConnectionParams.setStaleCheckingEnabled(params, false);
        HttpConnectionParams.setConnectionTimeout(params, 20 * 1000);
        HttpConnectionParams.setSoTimeout(params, 20 * 1000);
        HttpConnectionParams.setSocketBufferSize(params, 8192);

        // Some client params
        HttpClientParams.setRedirecting(params, false);
        // Register http/s shemas!
        SchemeRegistry schReg = new SchemeRegistry();
        schReg.register(new Scheme("http", PlainSocketFactory
                .getSocketFactory(), 80));
        schReg.register(new Scheme("https", newSSLSocketFactory(), 3400));

        ClientConnectionManager conMgr = new ThreadSafeClientConnManager(
                params, schReg);
        DefaultHttpClient sClient = new DefaultHttpClient(conMgr, params);      
        return sClient;
    }

    private SSLSocketFactory newSSLSocketFactory() {
        try {
            // setup truststore to provide trust for the server certificate
            // load truststore certificate

            KeyStore trustStore = null;
            trustStore = KeyStore.getInstance("BKS");
            trustStore.load(serverin, "(not telling)".toCharArray());

            System.out.println("Loaded server certificates: "
                    + trustStore.size());

            // initialize trust manager factory with the read truststore
            TrustManagerFactory trustManagerFactory = null;
            trustManagerFactory = TrustManagerFactory
                    .getInstance(TrustManagerFactory.getDefaultAlgorithm());
            trustManagerFactory.init(trustStore);

            // setup client certificate
            // load client certificate
            KeyStore keyStore = null;
            keyStore = KeyStore.getInstance("BKS");
            keyStore.load(clientin, "(not telling)".toCharArray());
            System.out
                    .println("Loaded client certificates: " + keyStore.size());
            // initialize key manager factory with the read client certificate

            KeyManagerFactory keyManagerFactory = null;
            keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory
                    .getDefaultAlgorithm());
            keyManagerFactory.init(keyStore, "(not telling)".toCharArray());

            // initialize SSLSocketFactory to use the certificates
            SSLSocketFactory socketFactory = null;
            socketFactory = new SSLSocketFactory(SSLSocketFactory.TLS,
                    keyStore, "(not telling)", trustStore, null, null);

            return socketFactory;
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

The Stacktrace looks like the following:

12-06 09:13:47.739: W/System.err(280): java.io.IOException: Read error: Failure in SSL library, usually a protocol error
12-06 09:13:47.799: W/System.err(280):  at org.apache.harmony.xnet.provider.jsse.OpenSSLSocketImpl.nativeread(Native Method)
12-06 09:13:47.810: W/System.err(280):  at org.apache.harmony.xnet.provider.jsse.OpenSSLSocketImpl.access$300(OpenSSLSocketImpl.java:55)
12-06 09:13:47.810: W/System.err(280):  at org.apache.harmony.xnet.provider.jsse.OpenSSLSocketImpl$SSLInputStream.read(OpenSSLSocketImpl.java:542)
12-06 09:13:47.819: W/System.err(280):  at org.apache.http.impl.io.AbstractSessionInputBuffer.fillBuffer(AbstractSessionInputBuffer.java:103)
12-06 09:13:47.819: W/System.err(280):  at org.apache.http.impl.io.AbstractSessionInputBuffer.readLine(AbstractSessionInputBuffer.java:191)
12-06 09:13:47.819: W/System.err(280):  at org.apache.http.impl.conn.DefaultResponseParser.parseHead(DefaultResponseParser.java:82)
12-06 09:13:47.819: W/System.err(280):  at org.apache.http.impl.io.AbstractMessageParser.parse(AbstractMessageParser.java:174)
12-06 09:13:47.829: W/System.err(280):  at org.apache.http.impl.AbstractHttpClientConnection.receiveResponseHeader(AbstractHttpClientConnection.java:179)
12-06 09:13:47.829: W/System.err(280):  at org.apache.http.impl.conn.DefaultClientConnection.receiveResponseHeader(DefaultClientConnection.java:235)
12-06 09:13:47.829: W/System.err(280):  at org.apache.http.impl.conn.AbstractClientConnAdapter.receiveResponseHeader(AbstractClientConnAdapter.java:259)
12-06 09:13:47.829: W/System.err(280):  at org.apache.http.protocol.HttpRequestExecutor.doReceiveResponse(HttpRequestExecutor.java:279)
12-06 09:13:47.829: W/System.err(280):  at org.apache.http.protocol.HttpRequestExecutor.execute(HttpRequestExecutor.java:121)
12-06 09:13:47.829: W/System.err(280):  at org.apache.http.impl.client.DefaultRequestDirector.execute(DefaultRequestDirector.java:410)
12-06 09:13:47.829: W/System.err(280):  at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:555)
12-06 09:13:47.829: W/System.err(280):  at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:487)
12-06 09:13:47.829: W/System.err(280):  at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:465)
12-06 09:13:47.829: W/System.err(280):  at (my package).WebService.webGet(WebService.java:75)
12-06 09:13:47.829: W/System.err(280):  at (my package).HardwareHoundActivity.onCreate(HardwareHoundActivity.java:107)
12-06 09:13:47.829: W/System.err(280):  at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1047)
12-06 09:13:47.829: W/System.err(280):  at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2627)
12-06 09:13:47.829: W/System.err(280):  at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2679)
12-06 09:13:47.829: W/System.err(280):  at android.app.ActivityThread.access$2300(ActivityThread.java:125)
12-06 09:13:47.829: W/System.err(280):  at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2033)
12-06 09:13:47.829: W/System.err(280):  at android.os.Handler.dispatchMessage(Handler.java:99)
12-06 09:13:47.829: W/System.err(280):  at android.os.Looper.loop(Looper.java:123)
12-06 09:13:47.839: W/System.err(280):  at android.app.ActivityThread.main(ActivityThread.java:4627)
12-06 09:13:47.839: W/System.err(280):  at java.lang.reflect.Method.invokeNative(Native Method)
12-06 09:13:47.839: W/System.err(280):  at java.lang.reflect.Method.invoke(Method.java:521)
12-06 09:13:47.839: W/System.err(280):  at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:868)
12-06 09:13:47.839: W/System.err(280):  at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:626)
12-06 09:13:47.839: W/System.err(280):  at dalvik.system.NativeStart.main(Native Method)

The line it references in WebService is:

HttpResponse response = httpClient.execute(httpGet);
IainS
  • 260
  • 3
  • 14
  • I have the same issue... http://stackoverflow.com/questions/9300821/ssl-not-working-on-android-2-2-only-in-2-3 Anybody? – CelinHC Feb 16 '12 at 13:22

1 Answers1

0

Looks like an error at the native OpenSSL level. Can you post the full stack trace? Your code looks correct, I don't think you need the KeyManagerFactory bit, httpclient's SSLSocketFactory takes care of this if you pass the keystore (as you are).

Nikolay Elenkov
  • 52,576
  • 10
  • 84
  • 84
  • Added the stacktrace to the main post. Thanks for answering quickly – IainS Dec 06 '11 at 08:35
  • It looks like 2.2 doesn't support the SSL protocol version or cipher your server is using. I don't have 2.2 source right now, so can't check what exactly it supports. Check server settings and server logs to see what protocols it's using/trying to use. – Nikolay Elenkov Dec 06 '11 at 09:10
  • I've checked and the server is running SSLv3 – IainS Dec 06 '11 at 10:31
  • This can happen if Android tries to connect using TLS, but the server only supports SSLv3 (there was a similar Froyo bug, IIRC). Enable TLS on the server if possible and inspect the server SSL logs. – Nikolay Elenkov Dec 06 '11 at 13:32
  • Checked the errors.log of the server and it says 'unable to get local issuer certificate' – IainS Dec 06 '11 at 13:56
  • That implies a server configuration problem. Are both the server and client certificates issued by the same CA? Does the server has access to it's certificate? Increase the debug level and compare logs from successful connections (GB) and failed ones (Froyo). (This a getting a bit out of scope for SO). – Nikolay Elenkov Dec 06 '11 at 14:18
  • I increased the debug level for the ssl. A colleague and i seriously doubt its a server config issue as the failed 2.2 connections only seem to read 'certificate verifcation depth 0: my cert id and (trusted authority issuer) and thus fail on 'unable to get local issuer certificate'. Where as connections from 2.3 and 4.0 both result in it starting at verification depth 2 with our root ca then depth 1 with our trusted authority cert then depth 0 with my client cert. Is there a way to programmatically specify the depth of chain itself in android? – IainS Dec 06 '11 at 14:50
  • 1
    It seems 2.2 is not sending the full chain, but 2.3 and 4.0 are. This may be a bug or a limitation in 2.2 (that has changed a lot in 2.3). You can try to add the full chain (root, trusted authority, client cert, client key) to the client's key store. On the Apache side, make sure it can find the trusted authority cert (check mod_ssl config options). – Nikolay Elenkov Dec 06 '11 at 15:40