web-dev-qa-db-ja.com

Javax.net.ssl.SSLHandshakeException:Sun.security.validator.ValidatorExceptionの解決:PKIXパスの構築に失敗したエラー?

編集: - 私のところでもっと見やすい方法で質問と受け入れられた答えをフォーマットしようとしましたブログ

これが元の問題です。

私はこのエラーを受けています:

詳細メッセージSun.security.validator.ValidatorException:PKIXパスの構築に失敗しました:
Sun.security.provider.certpath.SunCertPathBuilderException:要求されたターゲットへの有効な証明書パスが見つかりません

原因javax.net.ssl.SSLHandshakeException:Sun.security.validator.ValidatorException:PKIXパスの構築に失敗しました:Sun.security.provider.certpath.SunCertPathBuilderException:要求されたターゲットへの有効な証明書パスが見つかりません

WebサーバとしてTomcat 6を使用しています。私は2つのHTTPS Webアプリケーションを異なるポートの異なるTomcatsに同じマシンにインストールしています。 App1(port 8443)App2(port 443)を言います。 App1App2に接続します。 App1App2に接続すると、上記のエラーが発生します。これは非常に一般的なエラーであることを私は知っているので、さまざまなフォーラムやサイトで多くの解決策に出会いました。私は両方のTomcatsのserver.xmlに以下のエントリーを持っています:

keystoreFile="c:/.keystore" 
keystorePass="changeit"

すべてのサイトがapp2によって与えられた証明書がapp1 jvmの信頼できるストアにないという同じ理由を言います。これはIEブラウザで同じURLをヒットしようとしたときにも当てはまるようです、それはうまくいきます(警告と共に、このWebサイトのセキュリティ証明書に問題があります。ここで私はこのWebサイトを続けると言います)。しかし、同じURLがJavaクライアントによってヒットされると(私の場合)、上記のエラーが発生します。それでトラストストアに入れるために、私はこれらの3つのオプションを試しました:

オプション1

System.setProperty("javax.net.ssl.trustStore", "C:/.keystore");
System.setProperty("javax.net.ssl.trustStorePassword", "changeit");

Option2 以下の環境変数に設定

CATALINA_OPTS -- param name
-Djavax.net.ssl.trustStore=C:\.keystore -Djavax.net.ssl.trustStorePassword=changeit ---param value

Option3 以下の環境変数に設定

Java_OPTS -- param name
-Djavax.net.ssl.trustStore=C:\.keystore -Djavax.net.ssl.trustStorePassword=changeit ---param value

しかし何も働かなかった

ついにうまくいった で提案されたJavaアプローチを実行している - Apache HttpClientで無効なSSL証明書を処理する方法 Pascal Thiventによる、すなわちプログラムInstallCertの実行。

しかし、この方法はdevboxの設定には問題ありませんが、実稼働環境では使用できません。

server.xmlサーバーのapp2に同じ値を設定し、truststoreに同じ値を設定して参照した場合、上記の3つの方法がうまくいかなかったのはなぜだろう

System.setProperty("javax.net.ssl.trustStore", "C:/.keystore") and System.setProperty("javax.net.ssl.trustStorePassword", "changeit");

app1プログラムで。

より詳しい情報は、これが私がどのように接続しているかです。

URL url = new URL(urlStr);

URLConnection conn = url.openConnection();

if (conn instanceof HttpsURLConnection) {

  HttpsURLConnection conn1 = (HttpsURLConnection) url.openConnection();

  conn1.setHostnameVerifier(new HostnameVerifier() {
    public boolean verify(String hostname, SSLSession session) {
      return true;
    }
  });

  reply.load(conn1.getInputStream());
349
M Sach

%Java_HOME%\lib\security\cacertsにある使用済みJVMのトラストストアファイルに App2 の証明書を追加する必要があります。

まず、次のコマンドを実行して、証明書がすでにトラストストアにあるかどうかを確認できます。keytool -list -keystore "%Java_HOME%/jre/lib/security/cacerts"(パスワードを入力する必要はありません)

証明書が見つからない場合は、ブラウザで証明書をダウンロードして次のコマンドでトラストストアに追加します。

keytool -import -noprompt -trustcacerts -alias <AliasName> -file <certificate> -keystore <KeystoreFile> -storepass <Password>

インポート後、最初のコマンドをもう一度実行して証明書が追加されたかどうかを確認できます。

Sun/Oracleの情報は ここ にあります。

344
SimonSez

javax.net.ssl.SSLHandshakeException:Sun.security.validator.ValidatorException:PKIXパス構築に失敗しました:Sun.security.provider.certpath.SunCertPathBuilderException:要求されたターゲットへの有効な証明書パスが見つかりません

•エラーが発生したとき、Googleで表現の意味を調べたところ、この問題はサーバーがHTTPS SSL証明書を変更したときに発生し、古いバージョンのJavaではルート認証局(CA)が認識されません。 。

•ブラウザでHTTPS URLにアクセスできる場合は、ルートCAを認識するようにJavaを更新することが可能です。

•ブラウザで、JavaがアクセスできないHTTPS URLにアクセスします。 HTTPS証明書チェーン(Internet Explorerに鍵のアイコンがあります)をクリックし、鍵をクリックして証明書を表示します。

•証明書の「詳細」と「ファイルにコピー」に進みます。 Base64(.cer) の形式でコピーします。それはあなたのデスクトップに保存されます。

•すべての警告を無視して証明書をインストールします。

•これで、アクセスしようとしていたURLの証明書情報を収集しました。

証明書について知っているように私のJavaバージョンを作らなければなりませんでしたそれ以上にそれがURLを認識することを拒否しないように。この点で、ルート証明書情報はデフォルトでJDKの \jre\lib\security にあり、アクセスするデフォルトのパスワードは changeitです。

Cacerts情報を表示するには、以下の手順に従ってください。

•スタートボタンをクリック - >実行

•cmdと入力します。コマンドプロンプトが開きます(管理者として開く必要があるかもしれません)。

Java/jreX/binディレクトリに移動します

次のように入力します。

keytool -list -keystore D:\ Java\jdk1.5.0_12\jre\lib\security\cacerts

キーストア内に含まれている現在の証明書のリストが表示されます。それはこのようになります:

C:¥Documents and Settings¥NeelanjanaG> keytool -list -keystore D:\ Java\jdk1.5.0_12\jre\lib\security\cacerts

キーストアのパスワードを入力してください:changeit

鍵ストアのタイプ:jks

キーストアプロバイダ:Sun

キーストアに44のエントリが含まれています

verisignclass3g2ca、2004年3月26日、trustedCertEntry、

証明書フィンガープリント(MD5):A2:33:9B:4C:74:78:73:D4:6C:E7:C1:F3:8D:CB:5C:E9

entrustclientca、2003年1月9日、trustedCertEntry、

証明書のフィンガープリント(MD5):0C:41:2F:13:5B:A0:54:F5:96:66:2D:7E:CD:0E:03:F4

thawtepersonalbasicca、1999年2月13日、trustedCertEntry、

証明書のフィンガープリント(MD5):E6:0B:D2:C9:CA:2D:88:DB:1A:71:0E:4B:78:EB:02:41

addtrustclass1ca、2006年5月1日、trustedCertEntry、

証明書フィンガープリント(MD5):1E:42:95:02:33:92:6B:B9:5F:C0:7F:DA:D6:B2:4B:FC

verisignclass2g3ca、2004年3月26日、trustedCertEntry、

証明書フィンガープリント(MD5):F8:BE:C4:63:22:C9:A8:46:74:8B:B8:1D:1E:4A:2B:F6

•今、私は以前にインストールした証明書をcacertsに含める必要がありました。

•そのための手順は次のとおりです。

keytool -import -noprompt -trustcacerts -alias ALIASNAME -file FILENAME_OF_THE_INSTALLED_CERTIFICATE -keystore PATH_TO_CACERTS_FILE -storepass PASSWORD

Java 7を使用している場合

keytool –importcert –trustcacerts –alias ALIASNAME - ファイルPATH_TO_FILENAME_OF_THE_INSTALLED_CERTIFICATE - キーストアPATH_TO_CACERTS_FILE - storepass changeit

•証明書情報をcacertファイルに追加します。

それは私が上記の例外のために見つけた解決策です!

159
NDeveloper

Tomcat 7での作業方法

Tomcat Appで自己署名証明書をサポートしたいのですが 次のスニペットが機能しませんでした

import Java.io.DataOutputStream;
import Java.net.HttpURLConnection;
import Java.net.URL;

public class HTTPSPlayground {
    public static void main(String[] args) throws Exception {

        URL url = new URL("https:// ... .com");
        HttpURLConnection httpURLConnection = (HttpURLConnection) url.openConnection();

        httpURLConnection.setRequestMethod("POST");
        httpURLConnection.setRequestProperty("Accept-Language", "en-US,en;q=0.5");
        httpURLConnection.setDoOutput(true);
        DataOutputStream wr = new DataOutputStream(httpURLConnection.getOutputStream());

        String serializedMessage = "{}";
        wr.writeBytes(serializedMessage);
        wr.flush();
        wr.close();

        int responseCode = httpURLConnection.getResponseCode();
        System.out.println(responseCode);
    }
}

これが私の問題を解決したものです。

1).crtファイルをダウンロードする

echo -n | openssl s_client -connect <your domain>:443 | sed -ne '/-BEGIN CERTIFICATE-/,/-END CERTIFICATE-/p' > ~/<your domain>.crt
  • <your domain>をあなたのドメインに置き換えます(例:jossef.com

2)Javaのcacerts証明書ストアにある.crtファイルを適用する

keytool -import -v -trustcacerts -alias <your domain> -file ~/<your domain>.crt -keystore <Java HOME>/jre/lib/security/cacerts -keypass changeit -storepass changeit
  • <your domain>をあなたのドメインに置き換えます(例:jossef.com
  • <Java HOME>をJavaのホームディレクトリに置き換えます。

3)それをハック

Iv'eがJavaのデフォルトの証明書ストアに私の証明書をインストールしたとしても、 Tomcatは を無視します(Javaのデフォルトの証明書ストアを使うようには設定されていないようです)。

これをハックするには、コードのどこかに次のコードを追加します。

String certificatesTrustStorePath = "<Java HOME>/jre/lib/security/cacerts";
System.setProperty("javax.net.ssl.trustStore", certificatesTrustStorePath);

// ...
30
Jossef Harush

私の場合、問題はWebサーバが証明書と中間CAだけを送信し、ルートCAは送信していないことでした。このJVMオプションを追加することで問題が解決しました:-Dcom.Sun.security.enableAIAcaIssuers=true

Authority Information Access拡張のcaIssuersアクセス方法のサポートが利用可能です。互換性のためにデフォルトで無効になっており、システムプロパティcom.Sun.security.enableAIAcaIssuersを値trueに設定することで有効にできます。

Trueに設定されている場合、証明書のldap、http、またはftpのURIであれば、証明書のAIA拡張機能(指定されたCertStoreに加えて)の情報を使用して発行CA証明書を見つけます。

出典

6
Guillaume

私のcacertsファイルは完全に空でした。私はこれを解決するためにcacertsファイルを私のwindowsマシンからコピーし(Oracle Java 7を使用している)、それを私のLinuxマシン(OpenJDK)にscpしました。

cd %Java_HOME%/jre/lib/security/
scp cacerts mylinuxmachin:/tmp

そしてLinuxマシンで

cp /tmp/cacerts /etc/ssl/certs/Java/cacerts

これまでのところうまくいっています。

5

もう1つの理由は、JDKの古いバージョンである可能性があります。私は単に最新版に更新することで証明書の問題を解決しました。

5
Ali Ismayilov

LinuxでTomcat 7を使うと、これでうまくいきました。

String certificatesTrustStorePath = "/etc/alternatives/jre/lib/security/cacerts";
System.setProperty("javax.net.ssl.trustStore", certificatesTrustStorePath);
System.setProperty("javax.net.ssl.trustStorePassword", "changeit");

Linuxでは、$Java_HOMEは常に設定されるとは限りませんが、通常/etc/alternatives/jre$Java_HOME/jreを指します。

4
Cedric Simon

私にとっては、SSLを処理していたNGINXリバースプロキシの背後にあるプロセスに接続しようとしたときにもこのエラーが発生しました。

証明書チェーン全体が連結されていない証明書が問題であることがわかりました。中間証明書を追加したときに、問題は解決しました。

お役に立てれば。

4
YaDa

私は同じ問題に直面したとき私はjdk1.8.0_171を使っていました。私はここでトップ2の解決策を試してみました(keytoolを使った証明書とそれにハックがあるもう一つの解決策を追加する)が、私にはうまくいきませんでした。

私はJDKを1.8.0_181にアップグレードしました、そしてそれは魅力のように働きました。

4
avp

以下のコードは私のために働きます:

import Java.security.cert.CertificateException;
import Java.security.cert.X509Certificate;

import javax.net.ssl.X509TrustManager;

public class TrustAnyTrustManager implements X509TrustManager {

public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
}

public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
}

public X509Certificate[] getAcceptedIssuers() {
return new X509Certificate[] {};
}
}

HttpsURLConnection conn = null;
            URL url = new URL(serviceUrl);
            conn = (HttpsURLConnection) url.openConnection();
             SSLContext sc = SSLContext.getInstance("SSL");  
             sc.init(null, new TrustManager[]{new TrustAnyTrustManager()}, new Java.security.SecureRandom());  

             conn.setSSLSocketFactory(sc.getSocketFactory());
4
Sandip S.

私はプログラムファイル内のすべてのJavaのバージョンを検索し、それらに証明書を追加する小さなwin32(WinXP 32ビットのtestet)愚かなcmd(コマンドライン)スクリプトを書いた。パスワードはデフォルトの "changeit"にするか、スクリプトで自分で変更する必要があります:-)

@echo off

for /F  %%d in ('dir /B %ProgramFiles%\Java') do (
    %ProgramFiles%\Java\%%d\bin\keytool.exe -import -noprompt -trustcacerts -file some-exported-cert-saved-as.crt -keystore %ProgramFiles%\Java\%%d\lib\security\cacerts -storepass changeit
)

pause
2
mons droid

Ubuntuサーバー上で動作しているTomcatの場合、どのJavaが使用されているかを調べるには、 "ps -ef | grep Tomcat"コマンドを使用します。

サンプル:

/home/mcp01$ **ps -ef |grep Tomcat**
Tomcat7  28477     1  0 10:59 ?        00:00:18 **/usr/local/Java/jdk1.7.0_15/bin/Java** -Djava.util.logging.config.file=/var/lib/Tomcat7/conf/logging.properties -Djava.awt.headless=true -Xmx512m -XX:+UseConcMarkSweepGC -Djava.net.preferIPv4Stack=true -Djava.util.logging.manager=org.Apache.juli.ClassLoaderLogManager -Djava.endorsed.dirs=/usr/share/Tomcat7/endorsed -classpath /usr/share/Tomcat7/bin/bootstrap.jar:/usr/share/Tomcat7/bin/Tomcat-juli.jar -Dcatalina.base=/var/lib/Tomcat7 -Dcatalina.home=/usr/share/Tomcat7 -Djava.io.tmpdir=/tmp/Tomcat7-Tomcat7-tmp org.Apache.catalina.startup.Bootstrap start
1005     28567 28131  0 11:34 pts/1    00:00:00 grep --color=auto Tomcat

その後、私たちはに行くことができます: cd /usr/local/Java/jdk1.7.0_15/jre/lib/security

デフォルトの cacerts fileはここにあります。信頼できない証明書を挿入します。

1
oraclesoon

私もこの問題を抱えています。

SSL証明書を.keystoreに追加して、ほとんどすべてのことを試しましたが、Java1_6_xでは機能しませんでした。私にとっては、JVMとして新しいバージョンのJava、Java1_8_xを使い始めるのに役立ちました。

0
Nubian

以下のMacOS Xでは、 'importcert'オプションでダブルハイフンを試してみる必要があったところ、私にとって正確に使えるコマンドは以下のとおりです。

Sudo keytool -–importcert -file /PathTo/YourCertFileDownloadedFromBrowserLockIcon.crt -keystore /Library/Java/JavaVirtualMachines/jdk1.8.0_191.jdk/Contents/Home/jre/lib/security/cacerts -alias "Cert" -storepass changeit
0
apandey846

安全のために、実装に自己署名証明書を使用しないでください。しかし、開発に関しては、自己署名証明書を取得した試用環境を使用する必要があります。私は自分のコードでプログラム的にこの問題を解決しようとしましたが失敗しました。しかし、証明書をjre trust-storeに追加することで問題が解決しました。以下の手順を見つけてください、

  1. サイト証明書をダウンロードしてください。

  2. 証明書(例:cert_file.cer)をディレクトリ$ Java_HOME\Jre\Lib\Securityにコピーします。

  3. AdministratorでCMDを開き、ディレクトリを$ Java_HOME\Jre\Lib\Securityに変更します。

  4. Belowコマンドを使用して証明書をトラストストアにインポートします。

keytool -import -alias ca -file cert_file.cer -keystore cacerts -storepass changeit

keytoolが認識できないというエラーが表示された場合は、 こちらを参照してください。

以下のように yes と入力します。

この証明書を信頼します。 [はい]

  1. それでは、コードを実行するか、Javaを使用してプログラムでURLにアクセスしてみてください。

更新

アプリサーバーがjbossの場合は、以下にシステムプロパティを追加してみてください。

System.setProperty("org.jboss.security.ignoreHttpsHost","true");

お役に立てれば!

0
tk_

AndroidStudioCharles ProxyJUnitRobolectricを使ってこの問題に遭遇しました。ありがとう@SimonSez私は問題を解決することができました。

  1. %Java_HOME% - Androidは別のJavaHomeを使用しています。フルパスはRunUnitTestsウィンドウにあります。私の場合は/Applications/Android Studio.app/Contents/jre/jdk/Contents/Homeです
  2. Charles証明書をDownloadsフォルダーにダウンロードします
  3. コマンドを実行する

    Sudo keytool -import -noprompt -trustcacerts -alias charles -file ~/Downloads/charles-ssl-proxying-certificate.pem -keystore "/Applications/Android Studio.app/Contents/jre/jdk/Contents/Home/jre/lib/security/cacerts" -storepass changeit

公式チャールズ文書

0
yoAlex5