Usando certificados de cliente / servidor para soquete SSL de autenticação bidirecional no Android

Estou trabalhando em um aplicativo Android que requer autenticação de certificado de cliente e servidor. Eu tenho uma classe SSLClient que criei que funciona perfeitamente no Java SE 6. da área de trabalho normal. Eu a mudei para o meu projeto Android e estou recebendo o seguinte erro: "Implementação do KeyStore JKS não encontrada".

Eu olhei um pouco on-line e parece que há uma possibilidade de que o Java Keystores não seja suportado no Android (incrível!), Mas tenho a sensação de que há mais do que isso, porque nenhum código de exemplo que encontrei se parece com o que eu estou tentando fazer tudo. Tudo o que encontrei fala sobre o uso de um cliente http em vez de soquetes SSL brutos. Preciso de soquetes SSL para este aplicativo.

Abaixo está o código no meu arquivo SSLClient.java. Ele lê o keystore e o armazenamento confiável, cria uma conexão de soquete SSL com o servidor, executa um loop enquanto aguarda as linhas de entrada do servidor e as manipula quando entram chamando um método em uma classe diferente. Estou muito interessado em ouvir qualquer pessoa com experiência em soquetes SSL na plataforma Android.

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.security.AccessControlException;
import java.security.KeyManagementException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.UnrecoverableKeyException;
import java.security.cert.CertificateException;

import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManagerFactory;
import otherpackege.OtherClass;

import android.content.Context;
import android.util.Log;

public class SSLClient 
{
    static SSLContext ssl_ctx;

    public SSLClient(Context context)
    {
        try
        {
            // Setup truststore
            KeyStore trustStore = KeyStore.getInstance("BKS");
            TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
            InputStream trustStoreStream = context.getResources().openRawResource(R.raw.mysrvtruststore);
            trustStore.load(trustStoreStream, "testtest".toCharArray());
            trustManagerFactory.init(trustStore);

            // Setup keystore
            KeyStore keyStore = KeyStore.getInstance("BKS");
            KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
            InputStream keyStoreStream = context.getResources().openRawResource(R.raw.clientkeystore);
keyStore.load(keyStoreStream, "testtest".toCharArray());
            keyManagerFactory.init(keyStore, "testtest".toCharArray());

            Log.d("SSL", "Key " + keyStore.size());
            Log.d("SSL", "Trust " + trustStore.size());

            // Setup the SSL context to use the truststore and keystore
            ssl_ctx = SSLContext.getInstance("TLS");
            ssl_ctx.init(keyManagerFactory.getKeyManagers(), trustManagerFactory.getTrustManagers(), null);

            Log.d("SSL", "keyManagerFactory " + keyManagerFactory.getKeyManagers().length);
            Log.d("SSL", "trustManagerFactory " + trustManagerFactory.getTrustManagers().length);
        }
        catch (NoSuchAlgorithmException nsae)
        {
            Log.d("SSL", nsae.getMessage());
        }
        catch (KeyStoreException kse)
        {
            Log.d("SSL", kse.getMessage());
        }
        catch (IOException ioe)
        {
            Log.d("SSL", ioe.getMessage());
        }
        catch (CertificateException ce)
        {
            Log.d("SSL", ce.getMessage());
        }
        catch (KeyManagementException kme)
        {
            Log.d("SSL", kme.getMessage());
        }
        catch(AccessControlException ace)
        {
            Log.d("SSL", ace.getMessage());
        }
        catch(UnrecoverableKeyException uke)
        {
            Log.d("SSL", uke.getMessage());
        }

        try
        {
            Handler handler = new Handler();
            handler.start();
        }
        catch (IOException ioException) 
        {
            ioException.printStackTrace();
        }
     }  
}

//class Handler implements Runnable 
class Handler extends Thread
{
    private SSLSocket socket;
    private BufferedReader input;
    static public PrintWriter output;

    private String serverUrl = "174.61.103.206";
    private String serverPort = "6000";

    Handler(SSLSocket socket) throws IOException
    {

    }
    Handler() throws IOException
    {

    }

    public void sendMessagameInfoge(String message)
    {
        Handler.output.println(message);
    }

    @Override
    public void run() 
    {
        String line;

        try 
        {
            SSLSocketFactory socketFactory = (SSLSocketFactory) SSLClient.ssl_ctx.getSocketFactory();
            socket = (SSLSocket) socketFactory.createSocket(serverUrl, Integer.parseInt(serverPort));
            this.input = new BufferedReader(new InputStreamReader(socket.getInputStream()));
            Handler.output = new PrintWriter(new OutputStreamWriter(socket.getOutputStream()));
            Log.d("SSL", "Created the socket, input, and output!!");

            do
            {
                line = input.readLine();
                while (line == null)
                {
                    line = input.readLine();
                }

                // Parse the message and do something with it
                // Done in a different class
                OtherClass.parseMessageString(line);
            }
            while ( !line.equals("exit|") );
        }
        catch (IOException ioe)
        {
            System.out.println(ioe);
        }
        finally 
        {
            try 
            {
                input.close();
                output.close();
                socket.close();
            } 
            catch(IOException ioe) 
            {
            } 
            finally 
            {

            }
        }
    }
}

Atualizar:
Fazendo algum bom progresso nesse problema. Descobriu que o JKS realmente não é suportado, nem está escolhendo diretamente o tipo SunX509. Atualizei meu código acima para refletir essas alterações. Ainda estou tendo um problema com ele aparentemente não carregando o keystore e o armazenamento confiável. Vou atualizar à medida que descobrir mais.

Update2:
Eu estava carregando meu keystore e o armazenamento de arquivos confiáveis no modo Java da área de trabalho, e não no Android correto. Os arquivos devem ser colocados na pasta res / raw e carregados usando getResources (). Agora estou obtendo uma contagem de 1 e 1 para o tamanho do keystore e do armazenamento confiável, o que significa que eles estão carregando. Ainda estou travando com uma exceção, mas chegando mais perto! Vou atualizar quando eu conseguir isso funcionando.

Update3:
Parece que tudo está funcionando agora, com exceção do meu armazenamento de chaves estar configurado incorretamente. Se eu desativar a autenticação do lado do cliente no servidor, ela se conectará sem problemas. Quando deixo ativado, recebo umahandling exception: javax.net.ssl.SSLHandshakeException: null cert chain erro. Parece que não estou configurando a cadeia de certificados corretamente. Publiquei outra pergunta perguntando como criar um keystore de cliente no formato BKS com a cadeia de certificados apropriada:Como criar um Keystore Java no formato BKS (BouncyCastle) que contém uma cadeia de certificados do cliente

questionAnswers(1)

yourAnswerToTheQuestion