20

クライアント証明書認証を必要とする Web サービスを呼び出しています。

単一の証明書 (サービスが期待するクライアント証明書) を含む Java キーストアを指定すると、すべて正常に機能します。ただし、複数の証明書を含むキーストアを使用すると、クライアントが取得する必要がある証明書を指定できないようです。クライアントは最初に利用可能な証明書を取得するようです (アルファベット順)。

次のプロパティを試しましたが、期待どおりの結果が得られませんでした:

System.setProperty("com.sun.enterprise.security.httpsOutboundKeyAlias", "my-client-certificate alias");

使用するクライアント証明書エイリアスを指定するにはどうすればよいですか?

4

4 に答える 4

16

Jakubが応答で提供するリンクから答えが得られますが、最終的に何かが機能するようになるまでかなり長い間この問題に苦労したため、ここではより簡単な応答を投稿したいと思いました。

使用できる証明書が複数あり、接続を実行するために特定のエイリアスを持つ証明書を使用する必要がある場合があります。これは、ほとんどの機能をデフォルトの X509KeyManager に渡す独自の KeyManager 実装を作成することで実現しましたが、接続が実行されるときに使用する正しいエイリアスを正確に選択する機能を備えています。

最初に作成したキー マネージャー:

public class FilteredKeyManager implements X509KeyManager {

private final X509KeyManager originatingKeyManager;
private final X509Certificate[] x509Certificates;

public FilteredKeyManager(X509KeyManager originatingKeyManager, X509Certificate[] x509Certificates) {
    this.originatingKeyManager = originatingKeyManager;
    this.x509Certificates = x509Certificates;
}

public X509Certificate[] getCertificateChain(String alias) {
    return x509Certificates;
}

public String[] getClientAliases(String keyType, Principal[] issuers) {
    return new String[] {"DesiredClientCertAlias"};
}

実装に必要な他のすべてのメソッドは、 へのパススルーoriginatingKeyManagerです。

次に、実際にコンテキストを設定すると、次のようになります。

SSLContext context = SSLContext.getInstance("TLSv1");
context.init(new KeyManager[] { new FilteredKeyManager((X509KeyManager)originalKeyManagers[0], desiredCertsForConnection) },
    trustManagerFactory.getTrustManagers(), new SecureRandom());

それが明確になり、この問題を解決しようとしている他の人に役立つことを願っています。

于 2011-12-29T18:04:30.543 に答える
10

簡単な答え: デフォルトの Java ssl 実装では実行できません。

長い回答: で SSL ハンドシェイクがどのように実装されているかを調べましたsun.security.ssl.ClientHandshaker。そのメソッドserverHelloDoneでは が呼び出されX509ExtendedKeyManager.chooseClientAliasます。その実装は、最初のエイリアスを返すような方法で実際に行われます。そのエントリは、指定されたキー アルゴリズムと他のいくつかのものに一致します。エイリアスの選択を微調整する方法はありません。

コードを変更できる人にとって、これは有望な回避策のように見えます: http://www.44342.com/java-f392-t785-p1.htm

于 2011-06-07T15:04:16.073 に答える
7

Heresは、動作する完全なコードを切り取ったものです。

これを使用して、標準のフィルタリング基準に一致する複数の証明書を含むスマートカードのキーストアを使用して、Android で SSL 接続を作成します。

クレジットは zarniwoop に送られます。

/**
 * filters the SSLCertificate we want to use for SSL
 * <code>
 * KeyManagerFactory kmf = KeyManagerFactory.getInstance("X509");
 * kmf.init(keyStore, null);
 * String SSLCertificateKeyStoreAlias = keyStore.getCertificateAlias(sslCertificate);
 * KeyManager[] keyManagers = new KeyManager[] { new FilteredKeyManager((X509KeyManager)kmf.getKeyManagers()[0], sslCertificate, SSLCertificateKeyStoreAlias) };
 * </code>
 */
private class FilteredKeyManager implements X509KeyManager {

    private final X509KeyManager originatingKeyManager;
    private final X509Certificate sslCertificate;
    private final String SSLCertificateKeyStoreAlias;

    /**
     * @param originatingKeyManager,       original X509KeyManager
     * @param sslCertificate,              X509Certificate to use
     * @param SSLCertificateKeyStoreAlias, Alias of the certificate in the provided keystore
     */
    public FilteredKeyManager(X509KeyManager originatingKeyManager, X509Certificate sslCertificate, String SSLCertificateKeyStoreAlias) {
        this.originatingKeyManager = originatingKeyManager;
        this.sslCertificate = sslCertificate;
        this.SSLCertificateKeyStoreAlias = SSLCertificateKeyStoreAlias;
    }

    @Override
    public String chooseClientAlias(String[] keyType, Principal[] issuers, Socket socket) {
        return SSLCertificateKeyStoreAlias;
    }

    @Override
    public String chooseServerAlias(String keyType, Principal[] issuers, Socket socket) {
        return originatingKeyManager.chooseServerAlias(keyType, issuers, socket);
    }

    @Override
    public X509Certificate[] getCertificateChain(String alias) {
        return new X509Certificate[]{ sslCertificate };
    }

    @Override
    public String[] getClientAliases(String keyType, Principal[] issuers) {
        return originatingKeyManager.getClientAliases(keyType, issuers);
    }

    @Override
    public String[] getServerAliases(String keyType, Principal[] issuers) {
        return originatingKeyManager.getServerAliases(keyType, issuers);
    }

    @Override
    public PrivateKey getPrivateKey(String alias) {
        return originatingKeyManager.getPrivateKey(alias);
    }
}
于 2014-09-19T14:19:18.523 に答える
1

KeyManager についての私の印象は、キーストアで初期化されると、秘密鍵エントリのエイリアスを使用して、関連する証明書と証明書チェーンを見つけるというものです。
それ以外の場合は、ホストが認識するキーの種類と認証局に基づいてチェーンを選択すると思います。
したがって、あなたの場合、説明にはキーストア内のプライベート エントリについて言及されていないため、キー マネージャーが最も適切な証明書を選択すると推測します。
あなたが言及したシステムプロパティのすべてを認識していません。
-秘密鍵と関連するチェーンを持つようにキーストアを変更してみてください -
または(これが機能するかどうかはわかりません)、サーバーに送信する証明書のエイリアスを変更して、証明書のサブジェクト名と一致させます

于 2011-03-13T22:04:59.530 に答える