web-dev-qa-db-ja.com

BKS(BouncyCastle)形式を作成する方法Javaクライアント証明書チェーンを含むキーストア

SSLクライアント認証を必要とするAndroidアプリを作成しています。デスクトップ用のJKSキーストアを作成する方法を知っていますJava application、but AndroidはBKS形式のみをサポートします。キーストアを作成しようとすると、次のエラーが発生します。
handling exception: javax.net.ssl.SSLHandshakeException: null cert chain

そのため、おそらくキーストアを適切に作成していないため、クライアントが適切な証明書チェーンを送信していないようです。デスクトップでできるようにSSLデバッグを有効にできないので、これが必要以上に難しくなっています。

参考のために、以下はIS 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


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

これを達成するために従った詳細な手順説明

  • http://repo2.maven.org/maven2/org/bouncycastle/bcprov-ext-jdk15on/1.46/bcprov-ext-jdk15on-1.46.jar からbouncycastle JARをダウンロードするか、「 doc」フォルダ。
  • 以下のいずれかの方法を使用して、PC用のBouncyCastleを構成します。
    • BCプロバイダーの静的な追加(推奨)
      • Bcprov-ext-jdk15on-1.46.jarをそれぞれにコピーします
        • D:\ tools\jdk1.5.0_09\jre\lib\ext(JDK(バンドルされたJRE)
        • D:\ tools\jre1.5.0_09\lib\ext(JRE)
        • C:\(環境変数で使用される場所)
      • の下のJava.securityファイルを変更します。
        • D:\ tools\jdk1.5.0_09\jre\lib\security
        • D:\ tools\jre1.5.0_09\lib\security
        • 次のエントリを追加します
          • security.provider.7 = org.bouncycastle.jce.provider.BouncyCastleProvider
      • 「ユーザー変数」セクションに次の環境変数を追加します
        • CLASSPATH =%CLASSPATH%; c:\ bcprov-ext-jdk15on-1.46.jar
    • Bcprov-ext-jdk15on-1.46.jarをプロジェクトのCLASSPATHに追加し、コードに次の行を追加します
      • Security.addProvider(new BouncyCastleProvider());
  • Bouncy Castle を使用してキーストアを生成します
    • 次のコマンドを実行します
      • keytool -genkey -alias myproject -keystore C:/myproject.keystore -storepass myproject -storetype BKS -provider org.bouncycastle.jce.provider.BouncyCastleProvider
    • これにより、ファイルC:\ myproject.keystoreが生成されます
    • 次のコマンドを実行して、適切に生成されているかどうかを確認します
      • keytool -list -keystore C:\ myproject.keystore -storetype BKS
  • Tomcat用のBouncyCastleの構成

    • D:\ tools\Apache-Tomcat-6.0.35\conf\server.xmlを開き、次のエントリを追加します

      • <Connector port = "8443" keystorePass = "myproject" alias = "myproject" keystore = "c:/myproject.keystore" keystoreType = "BKS" SSLEnabled = "true" clientAuth = "false" protocol = "HTTP/1.1"スキーム= "https" secure = "true" sslProtocol = "TLS" sslImplementationName = "org.bouncycastle.jce.provider.BouncyCastleProvider" />
    • これらの変更後、サーバーを再起動します。

  • Android Client のBouncyCastleを設定します
    • Androidは提供された「Android.jar」でBouncy Castleバージョン1.46を内部的にサポートするため、設定する必要はありません。
    • HTTPクライアントのバージョン(MyHttpClient.Javaは以下にあります)を実装し、コードで以下を設定するだけです。
      • SSLSocketFactory.setHostnameVerifier(SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
    • これを行わないと、以下のような例外が発生します
      • javax.net.ssl.SSLException:証明書のホスト名が一致しませんでした:<192.168.104.66>!=
    • 本番モードでは、上記のコードをに変更します
      • 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);
        }
    }
}

Activityクラスで上記のコードを呼び出す方法:

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

Portecle を使用しますが、これは魅力のように機能します。

26
gnclmorais

BouncyCastleキーストアに問題があるとは思いません。問題はAndroidの壊れたjavax.net.sslパッケージにあると思います。 BouncyCastleキーストアは、Androidデフォルトを変更しましたJava動作をドキュメント化せずに、そしてデフォルトプロバイダーを削除しましたが、動作します。

SSL認証には、2つのキーストアが必要な場合があることに注意してください。 CA証明書を含む「TrustManager」キーストア、およびクライアントサイトの公開/秘密キーを含む「KeyManager」キーストア。 (ドキュメンテーションは、KeyManagerキーストアに必要なものについて多少曖昧です。)理論的には、すべての証明書が「よく知られた」認証機関(Verisign、Thawteなど)によって署名されている場合、TrustManagerキーストアは必要ありません。等々。それがあなたのためにどのように機能するか教えてください。サーバーは、クライアントへの署名に使用されたものすべてに対してCAも必要とします。

Javax.net.sslを使用してSSL接続を作成できませんでした。サーバー側でクライアントSSL認証を無効にしましたが、それでも接続を作成できませんでした。私の最終目標はHTTPS GETであったため、AndroidにバンドルされているApache HTTPクライアントを使用して試しました。その種のは働いた。 HTTPS接続を確立できましたが、それでもSSL認証を使用できませんでした。サーバーでクライアントSSL認証を有効にした場合、接続は失敗します。 Apache HTTPクライアントのコードはチェックしていませんが、独自のSSL実装を使用していると思われ、javax.net.sslは使用していません。

4
Cthulhu

この問題を解決したかどうかはわかりませんが、これは私がそれを行う方法であり、Androidで動作します:

  1. Opensslを使用して、クライアントの証明書(サーバーが受け入れるCAによって署名されている必要があります)と秘密キーをPCKS12形式のキーペアにマージします:openssl pkcs12 -export -in clientcert.pem -inkey clientkey .pem -out client.p12
  2. JREにパッチを適用して、キーの強度に応じて、無制限の強度の暗号化を行う必要がある場合があります: JCE 5.0無制限の強度の管轄ポリシーファイル からjarファイルをコピーし、JREのファイルをオーバーライドします(例:C :\ Program Files\Java\jre6\lib\security)
  3. 上記のPortecleツールを使用して、BKS形式の新しいキーストアを作成します
  4. 手順1で生成されたPCKS12キーペアをインポートし、BKSキーストアとして保存します。このキーストアは、Androidクライアント認証で機能します。
  5. 証明書チェーンを行う必要がある場合は、このIBMツール: KeyMan を使用して、クライアントのPCKS12キーペアをCA証明書とマージできます。ただし、JKSキーストアのみが生成されるため、Protecleを使用してBKS形式に変換する必要があります。
4
Fei

コマンドライン:

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

BKSキーストアを作成するためのコマンドは私にとって正しいようです。

キーストアを初期化する方法。

独自のSSLSocketFactoryを作成して渡す必要があります。 Apacheのorg.Apache.http.conn.ssl.SSLSocketFactoryを使用する例を次に示します

しかし、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);
    }
}

うまくいったかどうか教えてください。

0
saxos

このマニュアルを使用してください http://blog.antoine.li/2010/10/22/Android-trusting-ssl-certificates/ このガイドは本当に役に立ちました。ストア内の証明書のシーケンスを観察することが重要です。たとえば、最下位の中間CA証明書を最初にインポートし、次にルートCA証明書までインポートします

0
pwb