Join FlipAndroid.COM Telegram Group: https://t.me/joinchat/F_aqThGkhwcLzmI49vKAiw


Uso de certificados de cliente / servidor para la autenticación de dos vías socket SSL en Android

Estoy trabajando en una aplicación de Android que requiere autenticación de certificado de cliente y servidor. Tengo una clase SSLClient que he creado que funciona maravillosamente en el escritorio regular Java SE 6. Lo he movido en mi proyecto de Android y estoy recibiendo el siguiente error: "KeyStore implementación JKS no se encontró".

He mirado en línea un poco y parece que hay una posibilidad de que Java Keystores no son compatibles con Android (impresionante!), Pero tengo la sensación de que hay más que eso, porque ninguno de los códigos de ejemplo que he encontrado se parece a lo que yo Estoy tratando de hacer en absoluto. Todo lo que he encontrado habla de usar un cliente http en lugar de sockets SSL crudos. Necesito SSL sockets para esta aplicación.

A continuación se muestra el código en mi archivo SSLClient.java. Lee el keystore y el truststore, crea una conexión del zócalo del SSL al servidor, después ejecuta un lazo mientras que espera las líneas de entrada del servidor entonces las maneja mientras que vienen adentro llamando un método en una clase diferente. Estoy muy interesado en saber de cualquier persona con alguna experiencia haciendo sockets SSL en la 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 { } } } } 

Actualizar:
Hacer un buen progreso en este problema. Se encontró que JKS no es apoyado, tampoco está eligiendo directamente el tipo SunX509. He actualizado mi código anterior para reflejar estos cambios. Todavía tengo un problema con él al parecer no cargando el keystore y truststore. Actualizaré a medida que averigüe más.


Actualización2:
Yo estaba haciendo mi keystore y truststore carga de archivos en una forma de Java de escritorio en lugar de la forma correcta de Android. Los archivos deben ser colocados en la carpeta res / raw y cargados usando getResources (). Ahora estoy recibiendo una cuenta de 1 y 1 para el keystore y el tamaño de truststore que significa que están cargando. Todavía me estoy estrellando en una excepción, pero cada vez más cerca! Actualizaré cuando consiga este funcionamiento.


Actualización3:
Parece que todo está funcionando ahora, con la excepción de que mi almacén de claves esté configurado incorrectamente. Si desactivo la autenticación del lado del cliente en el servidor, se conecta sin problema. Cuando lo dejo habilitado, consigo una handling exception: javax.net.ssl.SSLHandshakeException: null cert chain error de la handling exception: javax.net.ssl.SSLHandshakeException: null cert chain . Así que parece que no estoy configurando correctamente la cadena de certificados. He publicado otra pregunta preguntando cómo crear un almacén de claves de cliente en el formato BKS con la cadena de certificados adecuada: Cómo crear un formato BKS (BouncyCastle) Java Keystore que contiene una cadena de certificados de cliente

  • SSLSocket se bloquea en getInputStream cuando el dispositivo android está en wifi
  • La manipulación SSL personalizada dejó de funcionar en Android 2.2 FroYo
  • Javax.net.ssl.SSLHandshakeException: java.security.cert.CertPathValidatorException: Ancla de confianza para la ruta de certificación no encontrada
  • Javax.net.ssl.SSLHandshakeException: El host remoto cerró la conexión durante el apretón de manos al insertar filas en bigquery
  • ¿Qué tan seguros son los certificados SSL de clientes en una aplicación para móviles?
  • Certificado de seguridad https no error de confianza en el móvil a través del servidor openshift
  • Cliente SSL en Android
  • Android: conexión HTTPS (SSL) mediante HttpsURLConnection
  • One Solution collect form web for “Uso de certificados de cliente / servidor para la autenticación de dos vías socket SSL en Android”

    Android soporta certificados en los formatos BKS, P12 y otros.

    Para el formato BKS: Utilice portecle para convertir sus certificados (.p12 y .crt) en .bks.

    Necesita 2 archivos en su carpeta /res/raw : truststore.bks certificado de confianza para el servidor (convertido desde el archivo .cer)

    client.bks/client.p12 – el certificado de cliente (convertido desde un archivo .p12 que contiene el certificado de cliente y la clave de cliente)

     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(); } } } 

    Actualizar:

    También puede cargar archivos .crt para el almacén de confianza directamente sin convertirlos a BKS:

      private static KeyStore loadTrustStore(String[] certificateFilenames) { AssetManager assetsManager = GirdersApp.getInstance().getAssets(); int length = certificateFilenames.length; List<Certificate> certificates = new ArrayList<Certificate>(length); for (String certificateFilename : certificateFilenames) { InputStream is; try { is = assetsManager.open(certificateFilename, AssetManager.ACCESS_BUFFER); Certificate certificate = KeyStoreManager.loadX509Certificate(is); certificates.add(certificate); } catch (Exception e) { throw new RuntimeException(e); } } Certificate[] certificatesArray = certificates.toArray(new Certificate[certificates.size()]); return new generateKeystore(certificatesArray); } /** * Generates keystore congaing the specified certificates. * * @param certificates certificates to add in keystore * @return keystore with the specified certificates * @throws KeyStoreException if keystore can not be generated. */ public KeyStore generateKeystore(Certificate[] certificates) throws RuntimeException { // construct empty keystore KeyStore keyStore = KeyStore.getInstance(keyStoreType); // initialize keystore keyStore.load(null, null); // load certificates into keystore int length = certificates.length; for (int i = 0; i < length; i++) { Certificate certificate = certificates[i]; keyStore.setEntry(String.valueOf(i), new KeyStore.TrustedCertificateEntry(certificate), null); } return keyStore; } 

    Lo mismo ocurre con KeyStore con el certificado de cliente, puede utilizar el archivo .p12 directamente sin convertirlo a BKS.

    FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.