2

SSLSocket を介して、ハンドシェイクに証明書を使用している離れたホストに接続しています。すべての認証局でデフォルトの JVM トラストストアを使用するわけではないため、リモート ホスト証明書をトラストストアに追加する必要があります。

SSLSocket から信頼すべき証明書を取得するにはどうすればよいですか? ハンドシェイクが必要と思われる SSLSession を使用する必要があるそれらを取得するようです。証明書を取得するためにハンドシェイクを実行する必要があるのはなぜですか?

使用されているリモート ホスト証明書を抽出できるツールはありますか?

4

2 に答える 2

4

実際には、ハンドシェイク中に証明書が提示されるため、サーバーはそれ自体を識別でき、最終的にはクライアントも識別できます。

あなたがするとき:

SSLContext context = SSLContext.getInstance("TLS");
TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
[...]
SavingTrustManager tm = new SavingTrustManager(defaultTrustManager);
SSLSocket socket = (SSLSocket)factory.createSocket(host, port);
try {
    socket.startHandshake();
    socket.close();
} catch (SSLException e) {
    e.printStackTrace(System.out);
}

startHandshake() で例外が発生しない場合は、証明書が何らかの理由で既に信頼されていることを意味します (キーストアに直接存在する、信頼されたエンティティによって署名されている)。

例外が発生したかどうかに関係なく、ダウンロードしたチェーンにアクセスできます。

X509Certificate[] chain = tm.chain;
if (chain == null) {
   // error in downloading certificate chain
   return;
}

// loop through chain
for (int i = 0; i < chain.length; i++) {
    X509Certificate cert = chain[i];
    [....]
}

X509Certificate オブジェクト インスタンスを使用すると、実際に k-ieth キーストアを更新できます。

X509Certificate cert = chain[k];
String alias = host + "-" + (k + 1);
KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
[...]
ks.setCertificateEntry(alias, cert);
OutputStream out = new FileOutputStream("jssecacerts");
ks.store(out, passphrase);
out.close();

完全なサンプルについては、こちらをご覧ください。

または、信頼するサーバーの証明書をダウンロードする別のより安全な方法は、openssl コマンドを使用することです。

# openssl s_client -showcerts -connect $SERVER:$PORT  2>&1 | \
      sed -ne '/-BEGIN CERTIFICATE-/,/-END CERTIFICATE-/p' >/tmp/$SERVERNAME.cert  

次に、通常どおりインポートしkeytoolます。

于 2012-09-24T11:13:29.417 に答える
3

通常、信頼すべき証明書を から取得するのSSLSocketではなく、信頼するものの参照として、独自に取得した構成済みの設定を使用する必要があります。

あなたがしたいことは、その接続が傍受されなかったことを期待して、最初の接続の証明書を取得し、これを後続の接続の参照として使用することです (SSH で一般的に行われることと同様に、最初の接続でサーバーキーのフィンガープリントを知っている必要がありますが、後で同じものを取得することを確認してください)。

セキュリティに関しては、最初の接続が MITM 攻撃者によって傍受される可能性があるため (後続のすべての接続が脆弱になります)、これは理想的ではありませんが、リスクを軽減する方法であることは確かです。理想的には、その証明書を、別の方法で取得した既知の参照と比較する必要があります。

カスタムを使用してハンドシェイク中にリモート証明書にアクセスできますX509TrustManager(または、カスタムを使用して信頼検証を無効にして、後で証明書を取得できます)。これを使用して を初期化しSSLContext、そこから を取得できますSSLSocketFactory。一般に、トラスト マネージャーでトラスト検証を無効にすることはお勧めできません (MITM 攻撃への接続が開かれるため) が、この目的には許容できます。InstallCertあなたはユーティリティに興味があるかもしれません.

サーバー証明書にアクセスする前にハンドシェイクを行う必要があるのはなぜですか?

これはハンドシェイク中に行われます。SSL/TLS ソケット API の目的は、アプリケーション層にソケットを提供することであり、アプリケーション層が安全であると見なし、その段階で多かれ少なかれ通常のソケットとして使用できるためです。通常、JSSE (または通常は他の SSL/TLS スタック) のほとんどの使用では、そのスタックを使用するアプリケーション開発者として、明示的に検証を行う必要はありません。ハンドシェイク中に証明書を確認することも、 TLS 仕様の一部として推奨されています。

サーバーの hello done メッセージを受信すると、クライアントは、必要に応じてサーバーが有効な証明書を提供したことを確認し、サーバーの hello パラメータが受け入れられることを確認する必要があります。

于 2012-09-24T10:58:04.967 に答える