[解決済み] SSLHandshakeExceptionを通じて、致命的な警告: handshake_failureを受信しました。
質問
SSL接続の認証に問題があります。Client Authorized SSL証明書を使用して外部サーバーに接続するStrutsアクションを作成しました。このアクションで、銀行のサーバーにデータを送信しようとしているのですが、サーバーから次のようなエラーが表示され、うまくいきません。
error: javax.net.ssl.SSLHandshakeException: Received fatal alert: handshake_failure
サーバーにデータを送信する Action クラスのメソッド
//Getting external IP from host
URL whatismyip = new URL("http://automation.whatismyip.com/n09230945.asp");
BufferedReader inIP = new BufferedReader(new InputStreamReader(whatismyip.openStream()));
String IPStr = inIP.readLine(); //IP as a String
Merchant merchant;
System.out.println("amount: " + amount + ", currency: " + currency + ", clientIp: " + IPStr + ", description: " + description);
try {
merchant = new Merchant(context.getRealPath("/") + "merchant.properties");
} catch (ConfigurationException e) {
Logger.getLogger(HomeAction.class.getName()).log(Level.INFO, "message", e);
System.err.println("error: " + e.getMessage());
return ERROR;
}
String result = merchant.sendTransData(amount, currency, IPStr, description);
System.out.println("result: " + result);
return SUCCESS;
私のmerchant.propertiesファイルです。
bank.server.url=https://-servernameandport-/
https.cipher=-cipher-
keystore.file=-key-.jks
keystore.type=JKS
keystore.password=-password-
ecomm.server.version=2.0
encoding.source=UTF-8
encoding.native=UTF-8
初めてこれは証明書の問題だと思い、.pfxから.jksに変換しましたが、何の変化もなく同じエラーが出ます。
解決方法は?
様々な原因でハンドシェイクに失敗した可能性があります。
- クライアントとサーバーで使用している暗号化方式に互換性がない。この場合、クライアントはサーバーがサポートする暗号スイートを使用する(または有効にする)必要があります。
- 使用しているSSLのバージョンに互換性がない(サーバーはTLS v1しか受け付けないが、クライアントはSSL v3しか使用できない可能性がある)。この場合も、クライアントはSSL/TLSプロトコルの互換性のあるバージョンを使用するようにしなければならないかもしれません。
- サーバー証明書のトラストパスが不完全で、サーバーの証明書がクライアントから信頼されていない可能性があります。これは通常、より冗長なエラーになりますが、十分にあり得ることです。通常は、サーバーのCA証明書をクライアントのトラストストアにインポートすることで修正します。
- 別のドメインで発行された証明書である。この場合も、もっと冗長なメッセージになるはずですが、これが原因である場合に備えて、ここで修正方法を明記しておきます。この場合の解決策は、サーバー(あなたのものではないようです)に正しい証明書を使用させることでしょう。
根本的な故障は特定できないので、このような場合は
-Djavax.net.debug=all
フラグを使用して、確立された SSL 接続のデバッグを有効にします。デバッグをオンにすると、ハンドシェイクのどのアクティビティが失敗したかをピンポイントで特定することができます。
更新情報
現在公開されている情報によると、この問題は、サーバーに発行された証明書とルートCAとの間の証明書信頼パスが不完全であることが原因であるように思われます。多くの場合、ルート認証局の証明書がトラストストアに存在しないため、証明書のトラストパスが存在せず、証明書がクライアントから本質的に信頼されない状況になります。ブラウザは警告を表示してユーザーがこれを無視できるようにすることができますが、同じことはSSLクライアント(たとえば HttpsURLConnection クラス、または Apache のような HTTP クライアントライブラリ HttpComponents クライアント ).
これらのクライアントクラス/ライブラリのほとんどは、証明書の検証のためにJVMによって使用されるトラストストアに依存するでしょう。ほとんどの場合、これは
cacerts
ファイル(JRE_HOME/lib/security ディレクトリ)にあります。もし、トラストストアの場所がJVMシステムプロパティである
javax.net.ssl.trustStore
そのパスのストアは、通常、クライアント・ライブラリで使用されるものです。もし疑問があれば、あなたの
Merchant
クラスが接続に使用しているクラス/ライブラリーを特定します。
このトラストストアにサーバーの証明書発行局を追加することで、問題は解決するはずです。私の 関連する質問で、ツールの入手方法について回答しています。 この目的のために Java キートゥールユーティリティ で十分である。
警告 : トラストストアは、基本的に、あなたが信頼するすべてのCAのリストです。もし、あなたが信頼していないCAに属していない証明書を入れた場合、その実体が発行した証明書を持つサイトへのSSL/TLS接続は、秘密鍵が利用可能であれば復号化することが可能です。
更新その2:JSSEトレースの出力を理解する
JVMが使用するキーストアとトラストストアは、通常、以下のような感じで、一番最初にリストアップされます。
keyStore is :
keyStore type is : jks
keyStore provider is :
init keystore
init keymanager of type SunX509
trustStore is: C:\Java\jdk1.6.0_21\jre\lib\security\cacerts
trustStore type is : jks
trustStore provider is :
間違ったトラストストアが使用されている場合、サーバーの証明書を正しいものに再インポートするか、リストされたものを使用するようにサーバーを再設定する必要があります(複数のJVMがあり、それらのすべてが異なるニーズに使用されている場合は推奨されません)。
信頼する証明書のリストに必要な証明書が含まれているかどうかを確認したい場合、同じセクションがあり、次のように始まります。
adding as trusted cert:
Subject: CN=blah, O=blah, C=blah
Issuer: CN=biggerblah, O=biggerblah, C=biggerblah
Algorithm: RSA; Serial number: yadda
Valid from SomeDate until SomeDate
サーバーのCAが主語かどうかを調べる必要があります。
ハンドシェイクのプロセスには、いくつかの重要なエントリーがあります (それらを詳しく理解するには SSL を知る必要がありますが、今回の問題のデバッグのためには、通常 ServerHello で handshake_failure が報告されることを知っていれば十分でしょう) 。
1. クライアントハロー
接続が初期化される際に、一連のエントリーが報告されます。SSL/TLS 接続のセットアップでクライアントから送られる最初のメッセージは ClientHello メッセージで、通常次のようにログに報告されます。
*** ClientHello, TLSv1
RandomCookie: GMT: 1291302508 bytes = { some byte array }
Session ID: {}
Cipher Suites: [SSL_RSA_WITH_RC4_128_MD5, SSL_RSA_WITH_RC4_128_SHA, TLS_RSA_WITH_AES_128_CBC_SHA, TLS_DHE_RSA_WITH_AES_128_CBC_SHA, TLS_DHE_DSS_WITH_AES_128_CBC_SHA, SSL_RSA_WITH_3DES_EDE_CBC_SHA, SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA, SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA, SSL_RSA_WITH_DES_CBC_SHA, SSL_DHE_RSA_WITH_DES_CBC_SHA, SSL_DHE_DSS_WITH_DES_CBC_SHA, SSL_RSA_EXPORT_WITH_RC4_40_MD5, SSL_RSA_EXPORT_WITH_DES40_CBC_SHA, SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA, SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA]
Compression Methods: { 0 }
***
使用されている暗号スイートに注目。この は同意しなければならないかもしれません 銀行のライブラリでも同じ規約が採用されている可能性があるため、merchant.properties ファイル内のエントリと一致させます。使用されている規約が異なっていても、心配はいりません。暗号スイートに互換性がない場合は、ServerHello にその旨が表示されます。
2. サーバーハロー
サーバーはServerHelloで応答し、接続のセットアップを続行できるかどうかが示されます。ログのエントリーは通常、以下のようなものです。
*** ServerHello, TLSv1
RandomCookie: GMT: 1291302499 bytes = { some byte array}
Cipher Suite: SSL_RSA_WITH_RC4_128_SHA
Compression Method: 0
***
これは、サーバとクライアントの両方が利用できる最良の暗号スイートである。通常、暗号スイートはエラーが発生した場合、指定されない。サーバーの証明書(およびオプションでチェーン全体)はサーバーから送信され、次のようなエントリで見つけることができます。
*** Certificate chain
chain [0] = [
[
Version: V3
Subject: CN=server, O=server's org, L=server's location, ST =Server's state, C=Server's country
Signature Algorithm: SHA1withRSA, OID = some identifer
.... the rest of the certificate
***
証明書の検証が成功した場合、次のようなエントリが表示されます。
Found trusted certificate:
[
[
Version: V1
Subject: OU=Server's CA, O="Server's CA's company name", C=CA's country
Signature Algorithm: SHA1withRSA, OID = some identifier
上記のいずれかのステップが成功しなかったために handshake_failure が発生し、この段階でハンドシェイクは通常完了します (実際には、ハンドシェイクの後続ステージでは通常ハンドシェイクの失敗は発生しません)。どの段階が失敗したかを把握し、適切なメッセージを質問に対する更新として投稿する必要があります(メッセージをすでに理解し、それを解決するために何をすべきかを知っている場合を除く)。
関連
-
[解決済み】Javaの".class期待値"
-
[解決済み】popBackStack()とreplace()の操作はどう違うのですか?
-
[解決済み】Android java.lang.IllegalStateException: Android java.lang.IllegalStateException: Could not execute method of the activity
-
[解決済み】HTTPステータス500 サーブレットクラスのインスタンス化エラー [重複]。
-
[解決済み] 解決済み】Javaが「型をインスタンス化できない」というエラーを返す [重複] [重複]
-
[解決済み】Javaでユーザー入力を待機させる方法
-
[解決済み】文字列中の � を置換する方法
-
[解決済み】Java Error "Exception in thread "main" java.util.InputMismatchException" Array プログラムで発生。
-
[解決済み】Ubuntu: OpenJDK 8 - パッケージを見つけることができません。
-
[解決済み] コレクションを反復処理し、ループ内でオブジェクトを削除する際に ConcurrentModificationException を回避する。
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
[解決済み】リンクリストの負の値の数でnegativeCntrを代入する
-
[解決済み】imageio.IIOException: 入力ファイルが読み込めない
-
[解決済み】Mockitoでモックからチェックされた例外を投げる
-
[解決済み] メソッドがそのスーパークラスのメソッドをオーバーライドしない
-
[解決済み】 JAVA 変数宣言はここではできない
-
[解決済み】JLabelのテキストを中央に配置するには?
-
[解決済み】Javaのswitch文。定数式が必要だが、定数である
-
[解決済み】koch snowflake java recursion
-
[解決済み】Eclipseで「パッケージエクスプローラー」ビューが見つからない
-
[解決済み】接続Java - MySQL : 公開鍵の取得は許可されていません。