6

概要

JSSE を使用すると、ユーザーは javax.net.ssl.* パラメータを指定して、デフォルトのトラスト ストアとキー ストアを提供できます。ユーザーが通常どおり KeyManager を指定できるようにしながら、アプリケーションにデフォルト以外の TrustManager を提供したいと考えていますが、これを実現する方法はないようです。

詳細

http://docs.oracle.com/javase/7/docs/technotes/guides/security/jsse/JSSERefGuide.html#CustomizingStores

UNIXマシンでは、ユーザーが認証にpkcs12キーストアを使用できるようにしたいのに対し、OS XIではユーザーがシステムキーチェーンを使用できるようにしたいとします。OS X では、アプリケーションは次のように起動できます。

java -Djavax.net.ssl.keyStore=NONE -Djavax.net.ssl.keyStoreType=KeychainStore \
     -Djavax.net.ssl.keyStorePassword=- -jar MyApplication.jar

これは正常に機能します。アプリケーションが相互認証 (クライアント証明書認証) を必要とする https サーバーにアクセスすると、ユーザーはキーチェーンへのアクセスを許可するように求められます。

問題

ここで、自己署名認証局をアプリケーションにバンドルしたいとします。TrustManagerFactory を作成し、証明書 ( javadoc )を含む KeyStore を渡すことで、デフォルトのトラスト マネージャーをオーバーライドできます。ただし、このデフォルト以外のトラスト マネージャーを使用するには、SSLContext を作成して初期化する必要があります。ここに問題があります。

SSLContext は、init(..)を呼び出し、KeyManager と TrustManager の両方を渡すことによって初期化されます。ただし、javax.net.ssl.* パラメータを使用して KeyManager を作成するためのロジックは、デフォルトの SSLContexts の実装に組み込まれています。デフォルト以外の TrustManager または TrustManagerFactory。したがって、たとえば、リモート サーバーを認証するためのルート証明書を提供しながら、適切なオペレーティング システム固有のキーチェーン実装を使用することはできないようです。

4

2 に答える 2

5

この質問と同様の問題に直面しているようですnull.trustmanagerパラメーターを使用SSLContext.init(...)するとデフォルトのトラストマネージャーに戻りますが、キーマネージャーには戻りません.

そうは言っても、デフォルトのシステム プロパティを使用して KeyManager を初期化するのはそれほど難しくありません。このようなものは機能するはずです(コードはこの回答に直接記述されているため、いくつかの小さな修正が必要になる場合があります):

String provider = System.getProperty("javax.net.ssl.keyStoreProvider");
String keystoreType = System.getProperty("javax.net.ssl.keyStoreType", KeyStore.getDefaultType());
KeyStore ks = null;
if (provider != null) {
    ks = KeyStore.getInstance(keystoreType, provider);
} else {
    ks = KeyStore.getInstance(keystoreType);
}
InputStream ksis = null;
String keystorePath = System.getProperty("javax.net.ssl.keyStore");
String keystorePassword = System.getProperty("javax.net.ssl.keyStorePassword");
if (keystorePath != null && !"NONE".equals(keystorePath)) {
    ksis = new FileInputStream(keystorePath);
}
try {
    ks.load(ksis, keystorePassword.toCharArray());
} finally {
     if (ksis != null) { ksis.close(); }
}

KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
kmf.init(ks, keystorePassword.toCharArray());
// Note that there is no property for the key password itself, which may be different.
// We're using the keystore password too.

SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(kmf.getKeyManagers(), ..., null);

(このユーティリティ クラスも、より具体的には興味深いものになる可能性がありますgetKeyStoreDefaultLoader()。)

編集:(追加のコメントに続いて)

の半分だけをカスタマイズしたい場合、Oracle と IBM JSSE の両方にデフォルトの動作がないように思われますSSLContext。Oracle JSSE ドキュメントのリンク先のセクションには、「キーストアが javax.net.ssl.keyStore システム プロパティと適切な javax.net.ssl.keyStorePassword システム プロパティによって指定されている場合、KeyManager はデフォルトの SSLContext によって作成されます。これは、指定されたキーストアを管理するための KeyManager 実装になります。」 これは実際にはここでは当てはまりません。なぜなら、SSLContext(その一部をカスタマイズしている場合でも) デフォルトのものではなくカスタムを使用しているためです。

いずれにせよ、Oracle JSSE リファレンス ガイドと IBM JSSE リファレンス ガイドは、この件に関して異なります。(これがどれだけ「標準」であることを意味しているのか、そして原則として一方が他方に準拠するべきかどうかはわかりませんが、明らかにそうではありません。)

両方の「オブジェクトの作成SSLContext」セクションはほとんど同じですが、異なります。

Oracle JSSEリファレンスガイドには次のように書かれています:

KeyManager[] パラメータが null の場合、空の KeyManager がこのコンテキストに対して定義されます。

IBM JSSE リファレンス ガイドには次のように書かれています。

KeyManager[] パラメータが null の場合、インストールされているセキュリティ プロバイダが検索され、KeyManagerFactory の最も優先度の高い実装が検索され、そこから適切な KeyManager が取得されます。

残念ながら、仕様が異なる実装間で同じ動作が必要な場合は、実装の 1 つが既に行っていることを効果的に複製することになるとしても、少しコードを記述する必要があります。

于 2013-03-07T12:13:03.947 に答える
3

デフォルトの動作を持つKeyManagerを作成するのはそれほど難しくありません。ほんの数行のコードです。SSLContextが、TrustManagerの場合とは異なり、KeyManagerの場合と同じように動作するわけではないのは驚くべきことです。IBMのJSSEはそのように動作します。しかし、自分で合成するのは難しくありません。

SSLContext  context = SSLContext.getInstance("TLS");
String  keyStore = System.getProperty("javax.net.ssl.keyStore");
String  keyStoreType = System.getProperty("javax.net.ssl.keyStoreType", KeyStore.getDefaultType());
String  keyStorePassword = System.getProperty("javax.net.ssl.keyStorePassword","");
KeyManager[]    kms = null;
if (keyStore != null)
{
    KeyManagerFactory   kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
    KeyStore    ks = KeyStore.getInstance(keyStoreType);
    if (keyStore != null && !keyStore.equals("NONE")) {
        fs = new FileInputStream(keyStore);
    ks.load(fs, keyStorePassword.toCharArray());
    if (fs != null)
        fs.close();
    char[]  password = null;
    if (keyStorePassword.length() > 0)
        password = keyStorePassword.toCharArray();
    kmf.init(ks,password);
    kms = kmf.getKeyManagers();
}
context.init(kms,null,null);
于 2013-03-07T12:11:03.723 に答える