Sto lavorando a un'app Android che richiede l'autenticazione dei certificati client e server. Ho una classe SSLClient che ho creato che funziona magnificamente sul normale desktop Java SE 6. L'ho spostato nel mio progetto Android e ho ricevuto il seguente errore: "Impossibile trovare l'implementazione di KeyStore JKS".Utilizzo dei certificati client/server per l'autenticazione SSL a due vie Presa SSL su Android
Ho guardato un po 'online e sembra che ci sia una possibilità che i Keystore Java non siano supportati su Android (fantastico!) Ma ho la sensazione che ci sia molto di più perché non c'è nessuno del codice di esempio che ho trovato somiglia a quello che sto cercando di fare. Tutto ciò che ho trovato parla dell'utilizzo di un client http piuttosto che di socket SSL grezzi. Ho bisogno di socket SSL per questa applicazione.
Di seguito è riportato il codice nel mio file SSLClient.java. Legge il keystore e il truststore, crea una connessione socket SSL al server, quindi esegue un ciclo in attesa di linee di input dal server e le gestisce man mano che arrivano chiamando un metodo in una classe diversa. Sono molto interessato a sapere da chiunque abbia esperienza con i socket SSL sulla piattaforma 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
{
}
}
}
}
Aggiornamento:
Fare dei buoni progressi su questo problema. Scoperto che JKS non è supportato, né sta scegliendo direttamente il tipo SunX509. Ho aggiornato il mio codice sopra per riflettere questi cambiamenti. Sto ancora avendo un problema con esso apparentemente non caricare il keystore e truststore. Aggiornerò mentre trovo di più.
Update2:
Stavo facendo il mio chiavi e file truststore carico in un desktop Java modo piuttosto che il modo in cui Android corretto. I file devono essere messi nella cartella res/raw e caricati usando getResources(). Ora sto ottenendo un conteggio di 1 e 1 per il keystore e il truststore che significa che stanno caricando. Sto ancora bloccando un'eccezione, ma mi sto avvicinando! Aggiornerò quando avrò questo lavoro.
Update3:
Sembra che tutto sta funzionando ora con l'eccezione del mio chiavi in fase di realizzazione in modo non corretto. Se disattivo l'autenticazione lato client sul server, si connette senza problemi. Quando lo lascio abilitato, ottengo un errore handling exception: javax.net.ssl.SSLHandshakeException: null cert chain
. Quindi sembra che non stia configurando correttamente la catena di certificati. Ho postato un'altra domanda che chiede come creare un keystore del client nel formato BKS con la catena di certificati corretta: How to create a BKS (BouncyCastle) format Java Keystore that contains a client certificate chain
Non funziona su Android 2.2 (funziona su 2.3) – CelinHC
Sono sicuro che questo codice funzioni su Android 1.6+. È usato nella nostra vecchia app che è sul mercato Android da qualche anno. Forse ho modificato qualcosa, ma in generale dovrebbe funzionare. – peceps
Non sto più lavorando a questo progetto, quindi non ho personalmente confermato questa risposta, ma lo accetto perché contiene informazioni sulla riproduzione dei dettagli, e in base ai voti sembra essere una soluzione funzionante. Grazie. –