Autenticação de cliente SSL com certificado no Android

Estou escrevendo um aplicativo Android que se conecta a um servidor para chamar alguns serviços da Web. Este servidor usa um certificado autoassinado para SSL e requer um certificado de cliente para autenticação.

Quando eu me conecto ao servidor com o navegador Android Chrome ou com o navegador safari de um Iphone, ele funciona perfeitamente. A conexão SSL está sendo estabelecida e a Autenticação de certificado do cliente está sendo bem-sucedida e redirecionada para meus serviços da Web. Mas quando eu me conecto com outros navegadores, como o navegador android padrão, dolphin etc., isso resulta em um Tempo Limite de Rede.

Além disso, quando me conecto ao meu aplicativo Android, recebo o seguinte erro:

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)

Eu segui o blog de chariotsolutions:http://chariotsolutions.com/blog/post/https-with-client-certificates-on/

Também converti o certificado de cliente para o formato BKS com a GUI do portecle.

Aqui está o meu código:

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;
    ....
    }

Aviso prévio: Também tenho a opção de conectar-me ao servidor sem autenticação de certificado de cliente (resultando em uma URL diferente) para fins de teste. O código acima, neste caso, é o mesmo, mas apenas comcontext.init (nulo, tmf.getTrustManagers (), nulo). Isso está funcionando perfeitamente, estabelecendo uma conexão SSL e me redirecionando para meus serviços da Web.

O que realmente me incomoda é que tudo está funcionando com o Chrome e o Safari no Iphone. Acho que o problema pode estar apenas no meu código Android?

Alguém teve um problema semelhante e tem uma idéia ou talvez uma solução para a dele?

Muito obrigado!

EDITAR:

Esqueci de mencionar que também configurei um Gerenciador de cookies, necessário para a conexão SSL. (Configurado na MainActivity em onCreate ())

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

Sem isso, eu estava recebendo o mesmo erro ao tentar estabelecer uma conexão SSL (sem certificado de cliente), mas, infelizmente, também não está ajudando no certificado de cliente.

ATUALIZAÇÃO # 2

Com muitas informações de segundo plano de nelenkov.blogspot.de/2011/12/using-custom-certificate-trust-store-on.html (Obrigado por este ótimo artigo @ Nikolay) e seu aplicativo Android Connectiontest no Github, encontrei algumas coisas interessantes.

O servidor está configurado para me fornecer um cookie ao conectar. Isso para a conexão "funciona" se eu conectar sem autenticação de cliente em uma etapa anterior, para que na segunda conexão (com autenticação de cliente) ele apenas verifique esse cookie e me deixe passar.

Segunda coisa que finalmente notei, o servidor me dá umaNonce. Eu acho que a conexão deve seguir esse redirecionamento automaticamente retornando esse Nonce. Alguns navegadores, como o Firefox e o navegador padrão, estão parando a conexão (depois de serem redirecionados com o Responsecode 302) e finalmente parando com o 404, resultando em uma URL como ..policy? Nonce = fno3i9Hsfn3uz. Preciso recarregar manualmente esse URL para acessar os serviços da Web. Infelizmente, isso não funciona com o meu aplicativo Android.

Eu acho que esse problema pode ser uma configuração incorreta no servidor, então?

questionAnswers(0)

yourAnswerToTheQuestion