Аутентификация клиента SSL с помощью сертификата в Android

Я пишу приложение для Android, которое подключается к серверу для вызова некоторых веб-сервисов. Этот сервер использует самозаверяющий сертификат для SSL и требует клиентский сертификат для аутентификации.

Когда я подключаюсь к серверу с помощью браузера Android Chrome или браузера Safari с Iphone, он работает отлично. Соединение SSL устанавливается, и аутентификация сертификата клиента успешно выполняется и перенаправляется на мои веб-сервисы. Но когда я подключаюсь к другим браузерам, таким как стандартный Android-браузер, Dolphin и т. Д., Это приводит к тайм-ауту сети.

Также, когда я соединяюсь с моим приложением для Android, я получаю следующую ошибку:

javax.net.ssl.SSLException: Read error: ssl=0x12746b8: I/O error during system call, Connection reset by peer
at org.apache.harmony.xnet.provider.jsse.NativeCrypto.SSL_read(Native Method)
at org.apache.harmony.xnet.provider.jsse.OpenSSLSocketImpl$SSLInputStream.read(OpenSSLSocketImpl.java:671)
at libcore.io.Streams.readSingleByte(Streams.java:41)
at org.apache.harmony.xnet.provider.jsse.OpenSSLSocketImpl$SSLInputStream.read(OpenSSLSocketImpl.java:655)
at libcore.io.Streams.readAsciiLine(Streams.java:201)
at libcore.net.http.HttpEngine.readResponseHeaders(HttpEngine.java:544)

Я следил за блогом chariotsolutions:http://chariotsolutions.com/blog/post/https-with-client-certificates-on/

Я также преобразовал сертификат клиента в формат BKS с графическим интерфейсом Portecle.

Вот мой код:

private static final String USER_AGENT = "Mozilla/5.0 (Linux; U; Android 4.0.3; et-ee; GT-P5100 Build/IML74K) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Safari/534.30";

....

@Override
protected Object doInBackground(String... urlString) {
    ....
    URL url = new URL(urlString[0]);
    HttpsURLConnection urlConnection =(HttpsURLConnection)url.openConnection();
    urlConnection.setSSLSocketFactory(getSSLContext().getSocketFactory());
    urlConnection.addRequestProperty("User-Agent", USER_AGENT);
    urlConnection.setDoInput(true);   
    urlConnection.connect();
    ....
}

private SSLContext getSSLContext() throws CertificateException,IOException, KeyStoreException, NoSuchAlgorithmException,KeyManagementException, java.security.cert.CertificateException {
    CertificateFactory cf = CertificateFactory.getInstance("X.509");
    InputStream caRootInput = context.getAssets().open("MySSLCertificate_here.crt");
    InputStream caClientAuth = context.getAssets().open("MyCientCertificate_here");
    ....
    Certificate caRoot;
    caRoot = cf.generateCertificate(caRootInput);

    // KeyStore and KeyManager for Client Certificate
    KeyStore keystore_client = KeyStore.getInstance("BKS");
    keystore_client.load(caClientAuth, "My_passWord_here".toCharArray());
    KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
    kmf.init(keystore_client, "My_passWord_here".toCharArray());
    KeyManager[] keyManagers = kmf.getKeyManagers();

    // KeyStore and Trustmanager for SSL Certificate
    KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
    keyStore.load(null, null);
    keyStore.setCertificateEntry("caRoot", caRoot);
    TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
    tmf.init(keyStore);

    SSLContext context = SSLContext.getInstance("TLSv1");
    context.init(keyManagers, tmf.getTrustManagers(), null);
    return context;
    ....
    }

уведомлениеУ меня также есть возможность подключения к серверу без проверки подлинности сертификата клиента (в результате чего другой URL) для тестирования. Код выше в этом случае тот же, но только сcontext.init (null, tmf.getTrustManagers (), null), Это работает отлично, устанавливает соединение SSL и перенаправляет меня на мои веб-сервисы.

Что меня действительно беспокоит, так это то, что все работает с Chrome и Safari на Iphone. Итак, я думаю, что проблема может быть только в моем коде Android?

У кого-нибудь была похожая проблема и есть идея или, может быть, решение его?

Большое спасибо!

РЕДАКТИРОВАТЬ:

Я забыл упомянуть, что я также установил Cookie Manager, который был необходим для SSL-соединения. (Устанавливается в MainActivity в onCreate ())

// Required for SSL connection
CookieHandler.setDefault(new CookieManager());

Без этого я получал ту же ошибку при попытке установить SSL-соединение (без сертификата клиента), но, к сожалению, это не помогает и с Client Cert.

ОБНОВЛЕНИЕ № 2

Имея много дополнительной информации от nelenkov.blogspot.de/2011/12/using-custom-certificate-trust-store-on.html (спасибо за эту великолепную статью @ Николай) и его приложения Android Connectiontest на Github, я нашел несколько интересных вещей.

Сервер настроен на выдачу мне куки при подключении. Это для Conncetion «работает», если я подключаюсь без Client Authentication на предыдущем шаге, так что при втором подключении (с Client Auth) он только проверяет этот Cookie и пропускает меня.

Второе, что я наконец заметил, Сервер дает мнеданное время, Я предполагаю, что Соединение должно следовать за Перенаправлением автоматически, возвращая этот Nonce. Некоторые браузеры, такие как Firefox и стандартный браузер, останавливают соединение (после перенаправления с кодом ответа 302) и, наконец, останавливаются с 404, в результате чего URL-адрес выглядит как ..policy? Nonce = fno3i9Hsfn3uz. Затем я должен вручную перезагрузить этот URL, чтобы добраться до веб-сервисов. К сожалению, это не работает с моим приложением для Android.

Я думаю, эта проблема может быть неправильной конфигурацией на стороне сервера тогда?