web-dev-qa-db-fra.com

Comment créer un magasin de clés Java au format BKS (BouncyCastle) contenant une chaîne de certificats client

J'écris une application Android qui nécessite une authentification client SSL. Je sais comment créer un magasin de clés JKS pour une application Java de bureau, mais Android ne prend en charge que le format BKS. Chaque fois que j'ai essayé de créer le magasin de clés, l'erreur suivante est générée:
handling exception: javax.net.ssl.SSLHandshakeException: null cert chain

Il semble donc que le client n'envoie jamais une chaîne de certificats appropriée, probablement parce que je ne crée pas correctement le magasin de clés. Je ne parviens pas à activer le débogage SSL comme je le peux sur le bureau, ce qui rend la tâche beaucoup plus difficile qu'elle ne devrait l'être.

Pour référence, voici la commande que IS travaille pour créer un fichier 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


Voici la commande que j'ai essayée qui ne fonctionne PAS pour créer un client BKS keystore :

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

Instructions détaillées étape par étape que j'ai suivies pour y parvenir

  • Téléchargez le fichier JAR de Bouncycastle à partir de http://repo2.maven.org/maven2/org/bouncycastle/bcprov-ext-jdk15on/1.46/bcprov-ext-jdk15on-1.46.jar ou le prendre dans le dossier "doc".
  • Configurez BouncyCastle pour PC en utilisant l’une des méthodes ci-dessous .
    • Ajout statique du fournisseur de Colombie-Britannique (recommandé)
      • Copiez le fichier bcprov-ext-jdk15on-1.46.jar dans chaque fichier
        • D:\tools\jdk1.5.0_09\jre\lib\ext (JDK (JRE fourni)
        • D:\tools\jre1.5.0_09\lib\ext (JRE)
        • C:\(emplacement à utiliser dans la variable env)
      • Modifiez le fichier Java.security sous
        • D:\tools\jdk1.5.0_09\jre\lib\security
        • D:\tools\jre1.5.0_09\lib\security
        • et ajoutez l'entrée suivante
          • security.provider.7 = org.bouncycastle.jce.provider.BouncyCastleProvider
      • Ajoutez la variable d’environnement suivante dans la section "Variables utilisateur"
        • CLASSPATH =% CLASSPATH%; c:\bcprov-ext-jdk15on-1.46.jar
    • Ajoutez bcprov-ext-jdk15on-1.46.jar à CLASSPATH de votre projet et ajoutez la ligne suivante dans votre code
      • Security.addProvider (new BouncyCastleProvider ());
  • Générez le magasin de clés en utilisant Bouncy Castle
    • Exécutez la commande suivante
      • keytool -genkey -alias monprojet -keystore C: /monprojet.keystore -storepasse monprojet -storetype BKS -provider org.bouncycastle.jce.provider.BouncyCastleProvider
    • Cela génère le fichier C:\myproject.keystore
    • Exécutez la commande suivante pour vérifier si elle est correctement générée ou non
      • keytool -list -keystore C:\myproject.keystore -storetype BKS
  • Configurez BouncyCastle pour Tomcat

    • Ouvrez D:\tools\Apache-Tomcat-6.0.35\conf\server.xml et ajoutez l'entrée suivante

      • <Connector Port = "8443" KeystorePass = "myproject" Alias ​​= "myproject" Keystore = "c: /myproject.keystore" KeystoreType = "BKS" SSLEnabled = "true" ClientAuth = "false" Protocole = "HTTP/1.1" Scheme = "https" Secure = "true" SslProtocol = "TLS" sslImplementationName = "org.bouncycastle.jce.provider.BouncyCastleProvider" />
    • Redémarrez le serveur après ces modifications.

  • Configurez BouncyCastle pour le client Android
    • Pas besoin de configuration puisque Android prend en charge Bouncy Castle Version 1.46 en interne dans le fichier "Android.jar" fourni.
    • Il vous suffit de mettre en œuvre votre version de client HTTP (vous trouverez ci-dessous MonHttpClient.Java) et de définir les éléments suivants dans le code
      • SSLSocketFactory.setHostnameVerifier (SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
    • Si vous ne le faites pas, cela donne une exception comme ci-dessous
      • javax.net.ssl.SSLException: le nom d'hôte dans le certificat ne correspond pas: <192.168.104.66>! = 
    • En mode de production, remplacez le code ci-dessus par
      • 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);
        }
    }
}

Comment appeler le code ci-dessus dans votre classe d'activité:

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

J'utilise Portecle , et cela fonctionne comme un charme.

25
gnclmorais

Je ne pense pas que votre problème concerne le magasin de clés BouncyCastle; Je pense que le problème est avec un paquet javax.net.ssl ​​cassé dans Android. Le magasin de clés BouncyCastle est un désagrément suprême car Android a modifié un comportement Java par défaut sans le documenter nulle part et a supprimé le fournisseur par défaut, mais cela fonctionne.

Notez que pour l'authentification SSL, vous aurez peut-être besoin de 2 magasins de clés. Le magasin de clés "TrustManager", qui contient les certificats CA, et le magasin de clés "KeyManager", qui contient les clés publique/privée de votre site client. (La documentation est quelque peu vague sur ce qui doit être dans le magasin de clés KeyManager.) En théorie, vous ne devriez pas avoir besoin du magasin de clés TrustManager si tous vos certificats sont signés par des autorités de certification "bien connues", telles que Verisign, Thawte, etc. etc. Faites-moi savoir comment cela fonctionne pour vous. Votre serveur aura également besoin de l'autorité de certification pour tout ce qui a été utilisé pour signer votre client.

Je ne pouvais pas créer de connexion SSL avec javax.net.ssl. J'ai désactivé l'authentification SSL du client côté serveur et je ne pouvais toujours pas créer la connexion. Comme mon objectif final était un HTTPS GET, j'ai essayé d'utiliser le client HTTP Apache fourni avec Android. Ce genre de travail. Je pouvais établir la connexion HTTPS, mais je ne pouvais toujours pas utiliser l'authentification SSL. Si j'autorisais l'authentification SSL du client sur mon serveur, la connexion échouerait. Je n'ai pas vérifié le code du client HTTP Apache, mais je pense qu'ils utilisent leur propre implémentation SSL et qu'ils n'utilisent pas javax.net.ssl. 

4
Cthulhu

Je ne suis pas sûr que vous ayez résolu ce problème ou pas, mais voici comment je le fais et cela fonctionne sous Android:

  1. Utilisez openssl pour fusionner le certificat du client (le certificat doit être signé par une autorité de certification acceptée par le serveur) et la clé privée dans une paire de clés au format PCKS12: openssl pkcs12 -export -in clientcert.pem -inkey clientkey.pem -out client.p12
  2. Vous aurez peut-être besoin de corriger votre chiffrement de force JRE en fonction de la force de votre clé: copiez les fichiers jar à partir de fichiers de stratégie de juridiction de force illimitée JCE 5.0 } et remplacez ceux de votre JRE (par exemple, C:\Program Files\Java\jre6\lib\security)
  3. Utilisez l'outil Portecle mentionné ci-dessus et créez un nouveau magasin de clés au format BKS.
  4. Importez la paire de clés PCKS12 générée à l'étape 1 et enregistrez-la en tant que magasin de clés BKS. Ce magasin de clés fonctionne avec l'authentification du client Android.
  5. Si vous devez créer une chaîne de certificats, vous pouvez utiliser cet outil IBM: KeyMan pour fusionner la paire de clés PCKS12 du client avec le certificat d'autorité de certification. Mais il ne génère que le fichier de clés JKS, vous devez donc à nouveau Protecle pour le convertir au format BKS.
4
Fei

ligne de commande:

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

Votre commande de création du magasin de clés BKS me semble correcte.

Comment initialisez-vous le magasin de clés?.

Vous devez créer et transmettre votre propre SSLSocketFactory. Voici un exemple qui utilise le org.Apache.http.conn.ssl.SSLSocketFactory d'Apache

Mais je pense que vous pouvez faire la même chose sur le 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);
    }
}

S'il vous plaît laissez-moi savoir si cela a fonctionné.

0
saxos

Utilisez ce manuel http://blog.antoine.li/2010/10/22/Android-trusting-ssl-certificates/ Ce guide m'a vraiment aidé. Il est important d'observer une séquence de certificats dans le magasin. Par exemple: importez d'abord le certificat de l'autorité de certification intermédiaire le plus bas, puis jusqu'au certificat de l'autorité de certification racine

0
pwb