webentwicklung-frage-antwort-db.com.de

So erstellen Sie einen Java-Keystore im BKS-Format (BouncyCastle), der eine Client-Zertifikatkette enthält

Ich schreibe eine Android-App, die eine SSL-Clientauthentifizierung erfordert. Ich weiß, wie man einen JKS-Keystore für eine Desktop-Java-Anwendung erstellt, aber Android unterstützt nur das BKS-Format. Ich habe auf alle Arten versucht, den Keystore zu erstellen, und führt zu folgendem Fehler:
handling exception: javax.net.ssl.SSLHandshakeException: null cert chain

Es sieht also so aus, als würde der Client niemals eine korrekte Zertifikatskette senden, wahrscheinlich weil ich den Keystore nicht ordnungsgemäß erstelle. Ich kann das SSL-Debugging nicht wie auf dem Desktop aktivieren, daher ist das viel schwieriger, als es sein sollte.

Der folgende Befehl ist der Befehl, den IS zum Erstellen eines BKS truststore verwendet:
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


Hier ist der Befehl, den ich ausprobiert habe, der NICHT funktioniert, um einen BKS-Client keystore zu erstellen:

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
51
Ben Baron

Detaillierte Schritt für Schritt Anweisungen, die ich befolgte, um dies zu erreichen

  • Laden Sie bouncycastle JAR von http://repo2.maven.org/maven2/org/bouncycastle/bcprov-ext-jdk15on/1.46/bcprov-ext-jdk15on-1.46.jar oder aus dem Ordner "doc".
  • Konfigurieren Sie BouncyCastle für PC mit einer der folgenden Methoden .
    • BC-Anbieter statisch hinzufügen (empfohlen)
      • Kopieren Sie die Datei "bcprov-ext-jdk15on-1.46.jar" in jede
        • D:\tools\jdk1.5.0_09\jre\lib\ext (JDK (gebündelte JRE)
        • D:\tools\jre1.5.0_09\lib\ext (JRE)
        • C:\(Ort, der in der Umgebungsvariablen verwendet werden soll)
      • Ändern Sie die Java.security-Datei unter
        • D:\tools\jdk1.5.0_09\jre\lib\security
        • D:\tools\jre1.5.0_09\lib\security
        • und fügen Sie den folgenden Eintrag hinzu
          • security.provider.7 = org.bouncycastle.jce.provider.BouncyCastleProvider
      • Fügen Sie im Abschnitt "Benutzervariablen" die folgende Umgebungsvariable hinzu
        • CLASSPATH =% CLASSPATH%; c:\bcprov-ext-jdk15on-1.46.jar
    • Fügen Sie bcprov-ext-jdk15on-1.46.jar zu CLASSPATH Ihres Projekts hinzu und fügen Sie die folgende Zeile in Ihren Code ein
      • Security.addProvider (neuer BouncyCastleProvider ());
  • Generieren Sie den Keystore mit Bouncy Castle
    • Führen Sie den folgenden Befehl aus
      • keytool -genkey -alias myproject -keystore C: /myproject.keystore -storepass meinproject -storetyp BKS -provider org.bouncycastle.jce.provider.BouncyCastleProvider
    • Dadurch wird die Datei C:\meinprojekt.keystore generiert
    • Führen Sie den folgenden Befehl aus, um zu prüfen, ob er ordnungsgemäß generiert wurde oder nicht
      • keytool -list -keystore C:\meinprojekt.keystore -storetyp BKS
  • Konfigurieren Sie BouncyCastle für Tomcat

    • Öffnen Sie D:\tools\Apache-Tomcat-6.0.35\conf\server.xml und fügen Sie den folgenden Eintrag hinzu

      • <Connector Port = "8443" KeystorePass = "meinprojekt" Alias ​​= "meinprojekt" Keystore = "c: /myproject.keystore" KeystoreType = "BKS" SSLEnabled = "true" ClientAuth = "false" Protocol = "HTTP/1.1" Scheme = "https" Secure = "true" SslProtocol = "TLS" sslImplementationName = "org.bouncycastle.jce.provider.BouncyCastleProvider" />
    • Starten Sie den Server nach diesen Änderungen neu.

  • Konfigurieren Sie BouncyCastle für Android-Client
    • Keine Konfiguration erforderlich, da Android Bouncy Castle Version 1.46 intern in der mitgelieferten "Android.jar" unterstützt.
    • Implementieren Sie einfach Ihre Version des HTTP-Clients (MyHttpClient.Java finden Sie weiter unten) und setzen Sie Folgendes in Code
      • SSLSocketFactory.setHostnameVerifier (SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
    • Wenn Sie dies nicht tun, gibt es eine Ausnahme wie unten angegeben
      • javax.net.ssl.SSLException: Hostname im Zertifikat stimmt nicht überein: <192.168.104.66>! = 
    • Ändern Sie im Produktionsmodus den obigen Code 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);
        }
    }
}

So rufen Sie den obigen Code in Ihrer Activity-Klasse auf:

DefaultHttpClient client = new MyHttpClient(getApplicationContext());
HttpResponse response = client.execute(...);
61
Vipul

Ich benutze Portecle und es funktioniert wie ein Zauber.

25
gnclmorais

Ich glaube nicht, dass Ihr Problem beim BouncyCastle-Keystore liegt. Ich denke, das Problem liegt in einem defekten javax.net.ssl-Paket in Android. Der BouncyCastle-Keystore ist ein absolutes Ärgernis, da Android ein Java-Standardverhalten geändert hat, ohne es irgendwo zu dokumentieren - und den Standardanbieter entfernt -, aber es funktioniert.

Beachten Sie, dass Sie für die SSL-Authentifizierung möglicherweise zwei Schlüsselspeicher benötigen. Der Keystore "TrustManager", der die CA-Zertifikate enthält, und der Keystore "KeyManager", die die öffentlichen/privaten Schlüssel Ihrer Client-Site enthalten. (Die Dokumentation ist etwas unklar, was im KeyManager-Keystore enthalten sein muss.) Theoretisch sollten Sie den TrustManager-Keystore nicht benötigen, wenn alle Ihre Zertifikate von "bekannten" Certifcate-Behörden, z. B. Verisign, Thawte, signiert sind. und so weiter. Lass mich wissen, wie das für dich funktioniert. Ihr Server erfordert auch die Zertifizierungsstelle für das, was zum Signieren Ihres Clients verwendet wurde.

Ich konnte keine SSL-Verbindung mit javax.net.ssl ​​erstellen. Ich habe die Client-SSL-Authentifizierung auf der Serverseite deaktiviert und konnte die Verbindung immer noch nicht herstellen. Da mein Endziel ein HTTPS GET war, habe ich versucht, den Apache HTTP-Client zu verwenden, der mit Android gebündelt ist. Diese Art hat funktioniert. Ich konnte die HTTPS-Verbindung herstellen, aber ich konnte immer noch keine SSL-Authentifizierung verwenden. Wenn ich die Client-SSL-Authentifizierung auf meinem Server aktiviert habe, schlägt die Verbindung fehl. Ich habe den Apache HTTP Client-Code nicht überprüft, aber ich vermute, dass sie ihre eigene SSL-Implementierung verwenden und javax.net.ssl ​​nicht verwenden. 

4
Cthulhu

Ich bin mir nicht sicher, ob Sie dieses Problem behoben haben oder nicht, aber so mache ich es und es funktioniert auf Android:

  1. Verwenden Sie openssl, um das Zertifikat des Clients (Zertifikat muss von einer vom Server akzeptierten Zertifizierungsstelle signiert sein) und den privaten Schlüssel in einem Schlüsselpaar im PCKS12-Format zusammenzuführen: openssl pkcs12 -export -in clientcert.pem -inkey clientkey .pem -out client.p12
  2. Möglicherweise müssen Sie Ihre JRE auf eine Verschlüsselung mit unbegrenzter Stärke patchen. Dies hängt von Ihrer Schlüsselstärke ab: Kopieren Sie die JAR-Dateien von JCE 5.0-Dateien mit unbegrenzter Stärke und überschreiben Sie diese in Ihrer JRE (z. B. C:\Programme\Java\jre6\lib\security)
  3. Verwenden Sie das oben erwähnte Portecle-Tool und erstellen Sie einen neuen Keystore im BKS-Format
  4. Importieren Sie das in Schritt 1 generierte PCKS12-Schlüsselpaar und speichern Sie es als BKS-Schlüsselspeicher. Dieser Keystore funktioniert mit der Clientauthentifizierung Android.
  5. Wenn Sie die Zertifikatskette ausführen müssen, können Sie das folgende IBM Tool verwenden: KeyMan , um das PCKS12-Schlüsselpaar des Clients mit CA cert zusammenzuführen. Es wird jedoch nur der JKS-Keystore generiert, sodass Sie Protecle erneut zum Konvertieren in das BKS-Format benötigen.
4
Fei

befehlszeile:

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

Ihr Befehl zum Erstellen des BKS-Keystores sieht für mich richtig aus.

Wie initialisieren Sie den Keystore?.

Sie müssen Ihre eigene SSLSocketFactory erstellen und übergeben. Hier ist ein Beispiel, das Apaches org.Apache.http.conn.ssl.SSLSocketFactory verwendet.

Aber ich denke, Sie können auf dem javax.net.ssl.SSLSocketFactory ziemlich dasselbe tun.

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

Bitte lassen Sie mich wissen, ob es funktioniert hat.

0
saxos

Verwenden Sie dieses Handbuch http://blog.antoine.li/2010/10/22/Android-trusting-ssl-certificates/ Dieses Handbuch hat mir wirklich geholfen. Es ist wichtig, eine Abfolge von Zertifikaten im Geschäft zu beachten. Beispiel: Importieren Sie das unterste Zwischenzertifizierungsstellenzertifikat zuerst und dann bis zum Stammzertifizierungsstellenzertifikat

0
pwb