HOWTO · Java

Javax.Net.SSL.SSLHandshakeException エラーを修正します。

このチュートリアルでは、Java の javax.net.ssl.SSLHandshakeException エラーについて説明します。

このページの内容

このチュートリアルでは、Java の javax.net.ssl.SSLHandshakeException エラーについて説明します。

Java での SSL ハンドシェイク

SSL ハンドシェークは、クライアントとサーバーがインターネット上の接続を保護するために必要な信頼とロジスティクスを確立するために使用されます。 SSL ハンドシェイク操作には、従う必要のある一般的な手順があります。

  1. まず、クライアントは、可能なすべての暗号スイートと SSL バージョンのリストを提供します。
  2. サーバーは特定の暗号スイートと SSL バージョンに同意し、証明書で応答します。
  3. 次に、クライアントは指定された証明書から公開鍵を抽出し、新しい暗号化されたプリマスター鍵で応答します。
  4. 次に、サーバーは秘密鍵を使用してプリマスター鍵を復号化します。
  5. 次に、クライアントとサーバーは、プリマスター キーを一緒に使用して共有シークレットを計算します。
  6. 最後に、クライアントとサーバーは、共有シークレットの暗号化と復号化が成功したことを確認するメッセージを交換します。

SSL ハンドシェイクには 2つのタイプがあります。 1つ目は、サーバーにすべてのクライアントを信頼させる一方向 SSL であり、2つ目は、クライアントとサーバーが互いの証明書を受け入れる必要がある双方向 SSL です。

SSL ハンドシェイクを理解したら、SSLHandShakeException について詳しく説明できます。 SSLHandShakeException には 2つのシナリオがあり、以下に示します。

サーバー証明書がないため、SSLHandshakeException を修正する

クライアントがサーバーに接続しているときに SSL ハンドシェイク操作で証明書を受信しなかった場合、以下に示すように SSLHandShakeException がスローされます。

Exception in thread "main" javax.net.ssl.SSLHandshakeException:
  Received fatal alert: handshake_failure

この問題を解決するには、上記のすべての手順に従ってください。 この問題は、キーストアまたはシステム プロパティが正しく入力されていない場合に発生します。

キーストアは、当局によって提供される証明書です。または、JDK の keytool 機能を使用してキーストアを作成することもできます。 キーストアの例を次に示します。

$ keytool -genkey -keypass password \
                  -storepass password \
                  -keystore Server_Keystore.jks

上記の keytool コードは Keystore ファイルに記述されています。 これで、keytool を使用して、上記で生成されたキーストア ファイルから公開証明書を抽出できます。

$ keytool -export -storepass password \
                  -file NewServer.cer \
                  -keystore Server_Keystore.jks

上記のコードは、公開証明書をキーストアからファイル NewServer.cer としてエクスポートします。 これで、クライアントのトラストストアに追加できます。

$ keytool -import -v -trustcacerts \
                     -file NewServer.cer \
                     -keypass password \
                     -storepass password \
                     -keystore Client_Truststore.jks

これで、サーバー用のキーストアとクライアント用のトラストストアが生成されました。 次のコマンドを使用して、それらをシステム プロパティとしてサーバーに渡すことができます。

-Djavax.net.ssl.keyStore=Client_Keystore.jks -Djavax.net.ssl.keyStorePassword=password

システムプロパティに必要です。 キーストア ファイル パスは絶対パスにするか、コマンドが呼び出された場所と同じディレクトリにキーストア ファイルを配置する必要があります。

相対パスはサポートされていません。 このプロセスに従うと、証明書の欠落エラーは解決され、SSLHandShakeException はなくなります。

信頼されていないサーバー証明書のため、SSLHandShakeException を修正する

SSLHandShakeException のもう 1つの理由は、信頼されていないサーバー証明書です。 サーバーが当局によって署名されていない自己署名証明書を使用している場合、次のエラーがスローされます。

Exception in thread "main" javax.net.ssl.SSLHandshakeException:
  sun.security.validator.ValidatorException:
  PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException:
  unable to find valid certification path to requested target

この例外は、証明書が既定のストア以外のエンティティによって署名されている場合は常にスローされます。 JDK のデフォルトのトラストストアには、使用中の一般的な証明書に関する情報が含まれています。

この問題は、クライアントがサーバーによって提示された証明書を信頼するように強制することで解決できます。 上で生成した Truststore を使用し、それらをシステム プロパティとしてクライアントに渡す必要があります。

-Djavax.net.ssl.trustStore=Client_Truststore.jks -Djavax.net.ssl.trustStorePassword=password

これで例外は解決されますが、理想的な状況ではありません。 理想的な状況では、認証局 (CA) によって認証される必要がある自己署名証明書を使用でき、クライアントはデフォルトでそれらを信頼できます。

証明書が正しくないため、SSLHandShakeException を修正する

証明書が正しくないためにハンドシェイクが失敗することもあります。 証明書が適切に作成されていない場合、SSLHandShakeException がスローされます。

Exception in thread "main" javax.net.ssl.SSLHandshakeException:
    java.security.cert.CertificateException:
    No name matching localhost found

証明書が正しく作成されているかどうかを確認するには、次のコマンドを実行します。

keytool -v -list -keystore Server_Keystore.jks

上記のコマンドは、キーストアの所有者の詳細を表示します。

...
Owner: CN=localhost, OU=technology, O=delftstack, L=city, ST=state, C=xx
..

所有者の CN はサーバーの CN と一致する必要があり、一致しない場合は、CN が異なるために生成される上記と同じ例外がスローされます。

SSL のバージョンと暗号スイートに互換性がないため、SSLHandShakeException を修正する

SSL ハンドシェーク操作中に、異なるバージョンの SSL、TLS などのさまざまな暗号化プロトコルが存在する可能性があります。クライアントとサーバーはハンドシェークで暗号化プロトコルとバージョンに同意する必要がありますが、SSL は TLS に取って代わられます。 その暗号強度。

たとえば、サーバーがプロトコル SSL3 を使用し、クライアントがプロトコル TLS1.3 を使用している場合、両者は暗号化プロトコルに同意できず、SSLHandShakeException をスローします。

Exception in thread "main" javax.net.ssl.SSLHandshakeException:
  No appropriate protocol (protocol is disabled or cipher suites are inappropriate)

この問題を解決するには、クライアントとサーバーが同じまたは互換性のある暗号化プロトコルを使用していることを確認する必要があります。

同様に、互換性のある暗号スイートも必要です。 ハンドシェイク中に、クライアントは暗号のリストを提供し、サーバーは使用する暗号を選択します。

サーバーが適切な暗号を選択できない場合、コードは次の SSLHandShakeException をスローします。

Exception in thread "main" javax.net.ssl.SSLHandshakeException:
  Received fatal alert: handshake_failure

通常、クライアントとサーバーはさまざまな暗号スイートを使用します。 そのため、このエラーが発生する可能性があります。 このエラーは、サーバーが非常に選択的な暗号を選択したために発生します。

この問題を回避するために、サーバーは選択的な暗号のリストを使用します。これはセキュリティにも適しています。