2010-10-31 17 views
49

Sto scrivendo un'app Android che richiede l'autenticazione client SSL. So come creare un keystore JKS per un'applicazione Java desktop, ma Android supporta solo il formato BKS. Ogni modo in cui ho cercato di creare i risultati keystore il seguente errore:
handling exception: javax.net.ssl.SSLHandshakeException: null cert chainCome creare un keystore Java in formato BKS (BouncyCastle) contenente una catena di certificati client

Quindi sembra che il cliente non è mai l'invio di una catena di certificati corretta, probabilmente perché non sto creando il keystore correttamente. Non riesco ad abilitare il debug SSL come posso sul dekstop, quindi è molto più difficile di quanto dovrebbe essere.

Per riferimento il seguente è il comando che sta lavorando per creare un BKS truststore:
keytool -importcert -v -trustcacerts -file "cacert.pem" -alias ca -keystore "mySrvTruststore.bks" -provider org.bouncycastle.jce.provider.BouncyCastleProvider -providerpath "bcprov-jdk16-145.jar" -storetype BKS -storepass testtest


Ecco il comando che ho provato che non funziona per creare un client BKS chiavi:

cat clientkey.pem clientcert.pem cacert.pem > client.pem 

keytool -import -v -file <(openssl x509 -in client.pem) -alias client -keystore "clientkeystore" -provider org.bouncycastle.jce.provider.BouncyCastleProvider -providerpath "bcprov-jdk16-145.jar" -storetype BKS -storepass testtest 
+17

Seriamente nessuno ha esperienza con il formato BKS? Argh, perché Android non poteva usare solo il formato standard di JKS, o almeno documentare questo formato dal momento che è tutto ciò che supporta? Questo dovrebbe essere semplice ... –

risposta

58

Passo dettagliata per passo le istruzioni ho seguito per raggiungere questo

  • Scarica BouncyCastle JAR da http://repo2.maven.org/maven2/org/bouncycastle/bcprov-ext-jdk15on/1.46/bcprov-ext-jdk15on-1.46.jar o prendere dalla cartella "doc".
  • Configura BouncyCastle per PC utilizzando uno dei seguenti metodi.
    • Aggiungendo il provider aC modo statico (consigliato)
      • Copiare il bcprov-ext-jdk15on-1.46.jar ad ogni
        • D: \ Tools \ jdk1.5.0_09 \ jre \ lib \ ext (JDK (bundle JRE)
        • D: \ tools \ jre1.5.0_09 \ lib \ ext (JRE)
        • C: \ (percorso da utilizzare in variabile ENV)
      • Modificare il file java.security sotto
        • D: \ Tools \ jdk1.5.0_09 \ jre \ lib \ security
        • D: \ Tools \ jre1.5.0_09 \ lib \ security
        • e aggiungere la seguente voce
          • security.provider 0,7 = org.bouncycastle.jce.provider.BouncyCastleProvider
      • Aggiungere la seguente variabile d'ambiente in "variabili utente" sezione
        • CL ASSPATH =% CLASSPATH%; c: \ bcprov-ext-jdk15on-1.46.jar
    • Aggiungi bcprov-ext-jdk15on-1.46.jar a CLASSPATH del tuo progetto e Aggiungi la riga seguente nel tuo codice
      • Security.addProvider (new BouncyCastleProvider());
  • Generare l'archivio di chiavi utilizzando Bouncy Castle
    • Eseguire il comando seguente
      • keytool -genkey -alias myproject -keystore C: /myproject.keystore -storepass myproject -storetype BKS dal provider org .bouncycastle.jce.provider.BouncyCastleProvider
    • Questo genera il file C: \ myproject.keystore
    • Eseguire il seguente comando per verificare se è corretto o no generato
      • keytool -list -keystore C: \ myproject.keystore -storetype BKS
  • Configurare BouncyCastle per Tomcat

    • Aprire D: \ tools \ apache-tomcat-6.0.35 \ conf \ server.xml e aggiungere la seguente voce

      • < connettore port = "8443" keystorePass = "myproject" alias = "myproject" keystore = "c: /myproject.keystore" keystoreType = "BKS" SSLEnabled = "true" clientAuth =" false" protocollo = "HTTP/1.1" schema = "https" sicuro = "true" sslProtocol = "TLS" sslImplementationName = "org.bouncycastle.jce.provider.BouncyCastleProvider"/ >
    • Riavvia il server dopo queste modifiche.

  • Configurare BouncyCastle per Android client
    • Non c'è bisogno di configurare in quanto Android supporta Bouncy Castle Versione 1.46 internamente nel fornito "android.jar".
    • Basta implementare la versione del client HTTP (MyHttpClient.java può essere trovato qui sotto) e impostare il seguente nel codice
      • SSLSocketFactory.setHostnameVerifier (SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
    • Se non si esegue questa operazione, si dà un'eccezione, come di seguito
      • javax.net.ssl.SSLException: nome host nel certificato non corrisponde: < 192.168.104.66> =
    • Nella modalità di produzione, modificare il codice sopra riportato in
      • SSLSocketFactory.setHostnameVerifier (SSLSocketFactory.STRICT_HOSTNAME_VERIFIER);

MyHttpClient.java

package com.arisglobal.aglite.network; 

import java.io.InputStream; 
import java.security.KeyStore; 

import org.apache.http.conn.ClientConnectionManager; 
import org.apache.http.conn.scheme.PlainSocketFactory; 
import org.apache.http.conn.scheme.Scheme; 
import org.apache.http.conn.scheme.SchemeRegistry; 
import org.apache.http.conn.ssl.SSLSocketFactory; 
import org.apache.http.impl.client.DefaultHttpClient; 
import org.apache.http.impl.conn.SingleClientConnManager; 

import com.arisglobal.aglite.activity.R; 

import android.content.Context; 

public class MyHttpClient extends DefaultHttpClient { 

    final Context context; 

    public MyHttpClient(Context context) { 
     this.context = context; 
    } 

    @Override 
    protected ClientConnectionManager createClientConnectionManager() { 
     SchemeRegistry registry = new SchemeRegistry(); 

     registry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80)); 

     // Register for port 443 our SSLSocketFactory with our keystore to the ConnectionManager 
     registry.register(new Scheme("https", newSslSocketFactory(), 443)); 
     return new SingleClientConnManager(getParams(), registry); 
    } 

    private SSLSocketFactory newSslSocketFactory() { 
     try { 
      // Get an instance of the Bouncy Castle KeyStore format 
      KeyStore trusted = KeyStore.getInstance("BKS"); 

      // Get the raw resource, which contains the keystore with your trusted certificates (root and any intermediate certs) 
      InputStream in = context.getResources().openRawResource(R.raw.aglite); 
      try { 
       // Initialize the keystore with the provided trusted certificates. 
       // Also provide the password of the keystore 
       trusted.load(in, "aglite".toCharArray()); 
      } finally { 
       in.close(); 
      } 

      // Pass the keystore to the SSLSocketFactory. The factory is responsible for the verification of the server certificate. 
      SSLSocketFactory sf = new SSLSocketFactory(trusted); 

      // Hostname verification from certificate 
      // http://hc.apache.org/httpcomponents-client-ga/tutorial/html/connmgmt.html#d4e506 
      sf.setHostnameVerifier(SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER); 
      return sf; 
     } catch (Exception e) { 
      throw new AssertionError(e); 
     } 
    } 
} 

come richiamare il codice di cui sopra nella classe di attività:

DefaultHttpClient client = new MyHttpClient(getApplicationContext()); 
HttpResponse response = client.execute(...); 
+0

Sto seguendo la procedura precedente, l'ho fatto bene al passaggio "Genera il Keystore usando Bouncy Castle", qui quando si esegue il comando keytool, il suo errore di assegnazione, errore keytool: java.lang.ClassNotFoundException: org.bouncycastle.jce. provider.BouncyCastleProvider, per favore suggerire – candy

+0

Ho fatto questo passo, specificando il percorso della libreria BouncyCastle anche nel comando keytool, grazie – candy

+0

Non sto più lavorando su questo progetto quindi non l'ho verificato da solo, ma sto accettando questo come risposta perché ti meriti alcuni punti per una risposta così dettagliata e come per le caramelle e le tue esperienze, sembra essere una soluzione funzionante. Grazie per aver contribuito. –

0

vostro comando per creare l'archivio di chiavi BKS sembra corretto per m e.

Come si inizializza il keystore.

È necessario aggirare e passare il proprio SSLSocketFactory. Ecco un esempio che utilizza Apache org.apache.http.conn.ssl.SSLSocketFactory

Ma penso che si può fare praticamente la stessa cosa sul javax.net.ssl.SSLSocketFactory

private SSLSocketFactory newSslSocketFactory() { 
    try { 
     // Get an instance of the Bouncy Castle KeyStore format 
     KeyStore trusted = KeyStore.getInstance("BKS"); 
     // Get the raw resource, which contains the keystore with 
     // your trusted certificates (root and any intermediate certs) 
     InputStream in = context.getResources().openRawResource(R.raw.mykeystore); 
     try { 
      // Initialize the keystore with the provided trusted certificates 
      // Also provide the password of the keystore 
      trusted.load(in, "testtest".toCharArray()); 
     } finally { 
      in.close(); 
     } 
     // Pass the keystore to the SSLSocketFactory. The factory is responsible 
     // for the verification of the server certificate. 
     SSLSocketFactory sf = new SSLSocketFactory(trusted); 
     // Hostname verification from certificate 
     // http://hc.apache.org/httpcomponents-client-ga/tutorial/html/connmgmt.html#d4e506 
     sf.setHostnameVerifier(SSLSocketFactory.STRICT_HOSTNAME_VERIFIER); 
     return sf; 
    } catch (Exception e) { 
     throw new AssertionError(e); 
    } 
} 

Per favore fatemi sapere se ha funzionato.

+0

Il comando che ho postato è corretto per creare un trust store. E sta lavorando per quello scopo. Sto cercando di creare un keystore per utilizzare l'autenticazione client che non funziona. Ho aggiornato la mia domanda per includere il comando che ho provato che non funziona. –

4

Non penso che il tuo problema riguardi il keystore BouncyCastle; Penso che il problema sia con un pacchetto javax.net.ssl ​​rotto in Android. Il keystore BouncyCastle è un fastidio estremo perché Android ha modificato un comportamento predefinito di Java senza documentarlo ovunque e rimosso il provider predefinito, ma funziona.

Nota che per l'autenticazione SSL potrebbero essere necessari 2 keystore. Il keystore "TrustManager", che contiene i certificati CA e il keystore "KeyManager", che contiene le chiavi pubbliche/private del tuo sito client. (La documentazione è piuttosto vaga su ciò che deve essere nel keystore di KeyManager.) In teoria, non è necessario il keystore di TrustManager se tutti i certificati sono firmati da "ben note" autorità di certificazione, ad esempio, Verisign, Thawte, e così via. Fammi sapere come funziona per te. Il tuo server richiederà anche la CA per tutto ciò che è stato usato per firmare il tuo cliente.

Non è stato possibile creare una connessione SSL utilizzando javax.net.ssl. Ho disabilitato l'autenticazione SSL del client sul lato server, e non ho ancora potuto creare la connessione. Dal momento che il mio obiettivo finale era un HTTPS GET, ho puntato e provato a utilizzare il client HTTP Apache incluso in Android. Questo tipo di ha funzionato. Potrei creare la connessione HTTPS, ma non potrei ancora utilizzare l'autenticazione SSL. Se avessi abilitato l'autenticazione SSL del client sul mio server, la connessione sarebbe fallita. Non ho controllato il codice del client HTTP Apache, ma ho il sospetto che stiano usando la loro implementazione SSL e non usano javax.net.ssl.

+0

Sì Sto usando un truststore separato (creato usando il comando nella mia domanda) e un keystore che ho creato usando il secondo comando nella mia domanda (ho anche provato a crearlo in altri modi senza successo). Non mi sono reso conto che il pacchetto ssl in Android potrebbe essere il colpevole. Vedrò se riesco a ottenere qualsiasi risposta dagli utenti di Android. –

22

Io uso Portecle e funziona come un fascino.

+0

Lo sto usando, visto che sto lavorando anche con KeyStores, e funziona. Ok, non è perfetto, ma aiuta molto. – gnclmorais

+2

Ho usato anche Portecle e ho confermato che ha risolto il mio problema !!! Dovevo usare HTTPSUrlConnection nel mio progetto Android e scherzare un po 'con TrustManagerFactory. – Exegesis

+1

Voglio solo notare che Portecle 1.7 che, al momento della scrittura, è l'ultimo, ha un bouncycastle obsoleto che non è in grado di aprire nuovi keystore di bks. – Chris

4

Non certo risolto questo problema o no, ma questo è come lo faccio e funziona su Android:

  1. Utilizzare OpenSSL per unire cert del cliente (cert deve essere firmato da una CA che accettata dal server di) e la chiave privata in un formato PCKS12 coppia di chiavi: openssl pkcs12 -export -in clientcert.pem -inkey clientkey.pem -out client.p12
  2. potrebbe essere necessario applicare la patch al JRE per umlimited crittografia forza dipende dalla vostra chiave forza: copia i file jar da JCE 5.0 unlimited strength Jurisdiction Policy FIles e ignora quelli nel tuo JRE (ad es. C: \ Programmi \ Java \ jre6 \ lib \ securi ty)
  3. Utilizzare lo strumento Portecle menzionato sopra e creare un nuovo keystore con il formato BKS
  4. Importare la coppia di chiavi PCKS12 generata nel passaggio 1 e salvarla come archivio chiavi BKS. Questo keystore funziona con l'autenticazione del client Android.
  5. Se è necessario eseguire la catena di certificati, è possibile utilizzare questo strumento IBM: KeyMan per unire la coppia di chiavi PCKS12 del client con CA cert. Ma genera solo il keystore JKS, quindi hai bisogno di Protecle per convertirlo in formato BKS.
2

riga di comando:

keytool -genseckey -alias aliasName -keystore truststore.bks -providerclass org.bouncycastle.jce.provider.BouncyCastleProvider -providerpath /path/to/jar/bcprov-jdk16-1.46.jar -storetype BKS 
Problemi correlati