43 votes

Utilisation de certificats client / serveur pour l'authentification bidirectionnelle Socket SSL sur Android

Je suis en train de travailler sur une application Android qui exige à la fois le client et le serveur d'authentification par certificat. J'ai un SSLClient classe que j'ai créé qui fonctionne à merveille sur de bureau ordinaire Java SE 6. J'ai déménagé dans mon projet Android et j'obtiens l'erreur suivante: "KeyStore JKS mise en œuvre n'est pas trouvé".

J'ai regardé en ligne un peu et on dirait qu'il ya une possibilité que Java fichiers de clés ne sont pas pris en charge sur Android (génial!) mais j'ai le sentiment que c'est bien plus que cela parce que aucun de l'exemple de code que j'ai trouvé ressemble à ce que j'essaie de le faire du tout. Tout ce que j'ai trouvé parle à l'aide d'un client http, plutôt que de raw sockets SSL. J'ai besoin de sockets SSL pour cette application.

Ci-dessous le code de mon SSLClient.java fichier. Il lit le fichier de clés et truststore, crée un socket SSL connexion au serveur, puis exécute une boucle lors de l'attente pour les lignes d'entrée à partir du serveur puis les traite comme ils viennent dans par l'appel d'une méthode dans une classe différente. Je suis très intéressé d'entendre toute personne avec toute l'expérience de faire des sockets SSL sur la plate-forme 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 
            {

            }
        }
    }
}

Mise à jour:
Faire quelques bons progrès sur ce problème. Découvert que notre établissement n'est en effet pas pris en charge, ni directement le choix de la SunX509 type. J'ai mis à jour mon code ci-dessus pour tenir compte de ces changements. Je suis toujours avoir un problème avec elle apparemment pas le chargement du fichier de stockage des clés et truststore. Je vais mettre à jour que je figure sur plus.


Update2:
Je faisais mon fichier de clés et truststore chargement d'un fichier dans un bureau de Java façon plutôt que de le corriger Android manière. Les fichiers doivent être placés dans le res/raw dossier et chargé à l'aide de getResources(). Je suis maintenant un nombre de 1 et 1 pour le fichier de clés et truststore taille, ce qui signifie qu'ils sont de chargement. Je suis toujours de s'écraser sur une exception, mais se rapproche! Je vais mettre à jour quand je reçois ce travail.


Update3:
Ressemble tout fonctionne maintenant, à l'exception de mon fichier de clés étant configuré de manière incorrecte. Si je désactive le côté client d'authentification sur le serveur, il se connecte sans problème. Quand je le laisse activé, je reçois un handling exception: javax.net.ssl.SSLHandshakeException: null cert chain d'erreur. Donc il semble que je ne suis pas la configuration de la chaîne de certificats correctement. J'ai posté une autre question me demandant comment créer un client de magasin de clés dans le BKS format avec le bon certificat de la chaîne d': Comment créer un BKS (BouncyCastle) format Java fichier de clés qui contient un certificat du client de la chaîne d'

46voto

peceps Points 7246

Android prend en charge les certificats au format BKS. Utilisez portecle pour convertir vos certificats en .bks.

Vous avez besoin de 2 fichiers dans votre dossier /res/raw :

truststore.bks - certificat de confiance pour le serveur (converti à partir du fichier .cer)

client.bks - le certificat client (converti à partir d'un fichier .p12 contenant le certificat client et la clé client)

 import java.io.*;
import java.security.KeyStore;

import javax.net.ssl.*;

import org.apache.http.*;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.params.HttpClientParams;
import org.apache.http.conn.ClientConnectionManager;
import org.apache.http.conn.params.*;
import org.apache.http.conn.scheme.*;
import org.apache.http.conn.ssl.SSLSocketFactory;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager;
import org.apache.http.params.*;

import android.app.Activity;
import android.os.Bundle;

public class SslTestActivity extends Activity {

  /** Called when the activity is first created. */
  @Override
  public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);

    try {
      // setup truststore to provide trust for the server certificate

      // load truststore certificate
      InputStream clientTruststoreIs = getResources().openRawResource(R.raw.truststore);
      KeyStore trustStore = null;
      trustStore = KeyStore.getInstance("BKS");
      trustStore.load(clientTruststoreIs, "MyPassword".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
      InputStream keyStoreStream = getResources().openRawResource(R.raw.client);
      KeyStore keyStore = null;
      keyStore = KeyStore.getInstance("BKS");
      keyStore.load(keyStoreStream, "MyPassword".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, "MyPassword".toCharArray());


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

      // 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", socketFactory, 443));
      ClientConnectionManager conMgr = new ThreadSafeClientConnManager(params, schReg);
      DefaultHttpClient sClient = new DefaultHttpClient(conMgr, params);

      HttpGet httpGet = new HttpGet("https://server/path/service.wsdl");
      HttpResponse response = sClient.execute(httpGet);
      HttpEntity httpEntity = response.getEntity();

      InputStream is = httpEntity.getContent();
      BufferedReader read = new BufferedReader(new InputStreamReader(is));
      String query = null;
      while ((query = read.readLine()) != null)
        System.out.println(query);

    } catch (Exception e) {
      e.printStackTrace();
    }
  }

}
 

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X