要求されたターゲットへの有効な証明書パスが見つからない-証明書をインポートした後でもエラー


205

自己署名証明書を使用してサーバーにアクセスしようとしているJavaクライアントがあります。

サーバーに投稿しようとすると、次のエラーが発生します。

リクエストされたターゲットへの有効な証明書パスが見つかりません

この問題についていくつか調査を行った後、私は次のことを行いました。

  1. サーバーのドメイン名をroot.cerファイルとして保存しました。
  2. GlassfishサーバーのJREで、これを実行しました。
    keytool -import -alias example -keystore cacerts -file root.cer
  3. 証明書がcacertに正常に追加されたことを確認するために、これを行いました
    keytool -list -v -keystore cacerts
    。証明書が存在することがわかります。
  4. その後、Glassfishを再起動して「投稿」を廃止しました。

まだ同じエラーが発生します。

Glassfishが、修正したcacertファイルではなく、他のファイルを実際に読み取っているからだと感じています。

この問題があり、私を正しい方向に進めることができる人はいますか?


1
「自己署名証明書でサーバーにアクセスしようとしているJavaクライアントがあります。」を明確にするために、あなたは自己署名されたクライアント証明書の使用について話していますよね?Glassfishのコネクタ設定に特定の構成はありますか(特にトラストストアの設定)?
ブルーノ

「Javaクライアントが自己署名証明書を使ってサーバーにアクセスしようとしています。」:自己署名されたクライアント証明書の使用について話していますよね。- はい。
TheCoder 2012

1
Glassfish JVMで2つの設定を見つけました:-Djavax.net.ssl.keyStore = $ {com.sun.aas.instanceRoot} /config/keystore.jksおよび-Djavax.net.ssl.trustStore = $ {com.sun。 aas.instanceRoot} /config/cacerts.jks。そのうちの1つに証明書を追加する必要があります。追加したキーストアであることを確認できますか?
TheCoder

4
サーバーでは、キーストアはサーバー証明書とその秘密鍵用です(キーストアはローカルパーティに「所属する」もの用です)。トラストストアは、リモートパーティでの信頼を確認するために使用される証明書用です。サーバー証明書ストアにクライアント証明書を追加する必要があります。(GlassfishはJREのデフォルトの場所を使用していないようですが、これも参照してください。)
Bruno

それはブルーノを働いた。Glassfishトラストストアに追加しました。助けてくれてどうもありがとう。あなたもダーク。
TheCoder、2012

回答:


155

残念ながら、それは多くのことになる可能性があり、多くのアプリサーバーやその他のJavaの「ラッパー」は、プロパティを操作する傾向があり、それらの「独自の」キーチェーンはどうでしょうか。ですから、まったく違うものを見ているかもしれません。

トラスの不足-私は試してみます:

java -Djavax.net.debug=all -Djavax.net.ssl.trustStore=trustStore ...

それが役立つかどうかを確認します。「すべて」の代わりに、「ssl」、キーマネージャー、トラストマネージャーに設定することもできます。'help'に設定すると、ほとんどのプラットフォームで以下のようなリストが表示されます。

いずれにせよ-キーストア(自分の身元を証明する秘密鍵と証明書を持っている)とトラストストア(信頼できる人物を決定する)の違いを十分に理解していることと、自分の身元も同じであることルートへの信頼の「チェーン」があります。これは、信頼する「誰」を理解するために必要なルートへのチェーンとは別のものです。

all            turn on all debugging
ssl            turn on ssl debugging

The   following can be used with ssl:
    record       enable per-record tracing
    handshake    print each handshake message
    keygen       print key generation data
    session      print session activity
    defaultctx   print default SSL initialization
    sslctx       print SSLContext tracing
    sessioncache print session cache tracing
    keymanager   print key manager tracing
    trustmanager print trust manager tracing
    pluggability print pluggability tracing

    handshake debugging can be widened with:
    data         hex dump of each handshake message
    verbose      verbose handshake message printing

    record debugging can be widened with:
    plaintext    hex dump of record plaintext
    packet       print raw SSL/TLS packets

ソース:#http ://download.oracle.com/javase/1.5.0/docs/guide/security/jsse/JSSERefGuide.html#Debugを参照


6
どうもありがとう!-Djavax.net.ssl.trustStore = / location_of / trustStoreは私の問題を解決し、デバッグ情報も非常に役に立ちました。
RHE、2016

5
java -Djavax.net.debug = all -Djavax.net.ssl.trustStore = trustStore ...以下のエラーが発生します:エラー:メインクラスが見つからないか、ロードできませんでした...
rohith

1
もちろん、トラストストアのパスワードを-Djavax.net.ssl.trustStorePassword = changeit
user1754036

18

これが解決策です、以下のリンクのステップバイステップに従ってください:

http://www.mkyong.com/webservices/jax-ws/suncertpathbuilderexception-unable-to-find-valid-certification-path-to-requested-target/

JAVA FILE:ブログにありません

/*
 * Copyright 2006 Sun Microsystems, Inc.  All Rights Reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   - Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   - Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in the
 *     documentation and/or other materials provided with the distribution.
 *
 *   - Neither the name of Sun Microsystems nor the names of its
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */



import java.io.*;
import java.net.URL;

import java.security.*;
import java.security.cert.*;

import javax.net.ssl.*;

public class InstallCert {

    public static void main(String[] args) throws Exception {
    String host;
    int port;
    char[] passphrase;
    if ((args.length == 1) || (args.length == 2)) {
        String[] c = args[0].split(":");
        host = c[0];
        port = (c.length == 1) ? 443 : Integer.parseInt(c[1]);
        String p = (args.length == 1) ? "changeit" : args[1];
        passphrase = p.toCharArray();
    } else {
        System.out.println("Usage: java InstallCert <host>[:port] [passphrase]");
        return;
    }

    File file = new File("jssecacerts");
    if (file.isFile() == false) {
        char SEP = File.separatorChar;
        File dir = new File(System.getProperty("java.home") + SEP
            + "lib" + SEP + "security");
        file = new File(dir, "jssecacerts");
        if (file.isFile() == false) {
        file = new File(dir, "cacerts");
        }
    }
    System.out.println("Loading KeyStore " + file + "...");
    InputStream in = new FileInputStream(file);
    KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
    ks.load(in, passphrase);
    in.close();

    SSLContext context = SSLContext.getInstance("TLS");
    TrustManagerFactory tmf =
        TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
    tmf.init(ks);
    X509TrustManager defaultTrustManager = (X509TrustManager)tmf.getTrustManagers()[0];
    SavingTrustManager tm = new SavingTrustManager(defaultTrustManager);
    context.init(null, new TrustManager[] {tm}, null);
    SSLSocketFactory factory = context.getSocketFactory();

    System.out.println("Opening connection to " + host + ":" + port + "...");
    SSLSocket socket = (SSLSocket)factory.createSocket(host, port);
    socket.setSoTimeout(10000);
    try {
        System.out.println("Starting SSL handshake...");
        socket.startHandshake();
        socket.close();
        System.out.println();
        System.out.println("No errors, certificate is already trusted");
    } catch (SSLException e) {
        System.out.println();
        e.printStackTrace(System.out);
    }

    X509Certificate[] chain = tm.chain;
    if (chain == null) {
        System.out.println("Could not obtain server certificate chain");
        return;
    }

    BufferedReader reader =
        new BufferedReader(new InputStreamReader(System.in));

    System.out.println();
    System.out.println("Server sent " + chain.length + " certificate(s):");
    System.out.println();
    MessageDigest sha1 = MessageDigest.getInstance("SHA1");
    MessageDigest md5 = MessageDigest.getInstance("MD5");
    for (int i = 0; i < chain.length; i++) {
        X509Certificate cert = chain[i];
        System.out.println
            (" " + (i + 1) + " Subject " + cert.getSubjectDN());
        System.out.println("   Issuer  " + cert.getIssuerDN());
        sha1.update(cert.getEncoded());
        System.out.println("   sha1    " + toHexString(sha1.digest()));
        md5.update(cert.getEncoded());
        System.out.println("   md5     " + toHexString(md5.digest()));
        System.out.println();
    }

    System.out.println("Enter certificate to add to trusted keystore or 'q' to quit: [1]");
    String line = reader.readLine().trim();
    int k;
    try {
        k = (line.length() == 0) ? 0 : Integer.parseInt(line) - 1;
    } catch (NumberFormatException e) {
        System.out.println("KeyStore not changed");
        return;
    }

    X509Certificate cert = chain[k];
    String alias = host + "-" + (k + 1);
    ks.setCertificateEntry(alias, cert);

    OutputStream out = new FileOutputStream("jssecacerts");
    ks.store(out, passphrase);
    out.close();

    System.out.println();
    System.out.println(cert);
    System.out.println();
    System.out.println
        ("Added certificate to keystore 'jssecacerts' using alias '"
        + alias + "'");
    }

    private static final char[] HEXDIGITS = "0123456789abcdef".toCharArray();

    private static String toHexString(byte[] bytes) {
        StringBuilder sb = new StringBuilder(bytes.length * 3);
        for (int b : bytes) {
            b &= 0xff;
            sb.append(HEXDIGITS[b >> 4]);
            sb.append(HEXDIGITS[b & 15]);
            sb.append(' ');
        }
        return sb.toString();
    }

    private static class SavingTrustManager implements X509TrustManager {

    private final X509TrustManager tm;
    private X509Certificate[] chain;

    SavingTrustManager(X509TrustManager tm) {
        this.tm = tm;
    }

    public X509Certificate[] getAcceptedIssuers() {
        throw new UnsupportedOperationException();
    }

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

    public void checkServerTrusted(X509Certificate[] chain, String authType)
        throws CertificateException {
        this.chain = chain;
        tm.checkServerTrusted(chain, authType);
    }
    }

}

3
このソリューションは私にとってはうまくいきましたが、プライベートクラスSavingTrustManagerに小さな変更が必要です:public X509Certificate[] getAcceptedIssuers() { return new X509Certificate[0];}
Richard

1
@ Richard、@ Paul、@ user6258309スレッド "main"でエラーException java.net.SocketTimeoutException:Read timed out at java.net.SocketInputStream.socketRead0(Native Method)at java.net.SocketInputStream.socketRead(Unknown Source )どうすれば修正できますか
Renjith Krishnan 2017

5
この「解決策」は根本的に安全ではありません。使ってはいけません。
ローン侯爵

9
この答えは主にコードです。それが機能する理由または機能しない理由は説明されていません。

13

JSSEシステムプロパティを設定する必要があります。具体的には、クライアント証明書ストアをポイントする必要があります。

コマンドラインから:

java -Djavax.net.ssl.trustStore=truststores/client.ts com.progress.Client

またはJavaコード経由:

import java.util.Properties;
    ...
    Properties systemProps = System.getProperties();
    systemProps.put("javax.net.ssl.keyStorePassword","passwordForKeystore");
    systemProps.put("javax.net.ssl.keyStore","pathToKeystore.ks");
    systemProps.put("javax.net.ssl.trustStore", "pathToTruststore.ts");
    systemProps.put("javax.net.ssl.trustStorePassword","passwordForTrustStore");
    System.setProperties(systemProps);
    ...

詳細については、RedHatサイトの詳細を参照してください。


Spring Boot、Spring Cloudマイクロサービス、および自己署名SSL証明書で同じ問題がありました。keyStoreとkeyStorePasswordをapplication.propertiesに設定してそのまま動作させることはできましたが、trustStoreとtrustStorePasswordで同じことを行うことはできませんでした。この答えは、トラストストアでうまくいきました。
メイトシモビッチ2017年

7

私の他の応答からの再投稿)インポートにはJavaソフトウェア配布の
cliユーティリティkeytoolを使用してください(そして信頼してください!)必要な証明書

サンプル:

  1. cliからdirをjre \ binに変更します

  2. キーストア(jre \ binディレクトリにあるファイル)を確認します
    keytool -list -keystore .. \ lib \ security \ cacerts
    パスワードはchangeit

  3. 必要なサーバーからチェーン内のすべての証明書をダウンロードして保存します。

  4. 証明書を追加します(ファイル ".. \ lib \ security \ cacerts"の "読み取り専用"属性を削除する前に)を実行します:keytool -alias REPLACE_TO_ANY_UNIQ_NAME -import -keystore .. \ lib \ security \ cacerts -file "r: \ root.crt "

たまたまそのような簡単なヒントを見つけました。その他のソリューションでは、InstallCert.JavaおよびJDKを使用する必要があります

ソース:http : //www.java-samples.com/showtutorial.php?tutorialid=210


6

sbtでも同じ問題がありました。SSL経由でrepo1.maven.org
から依存関係を取得しよう としましたが、「要求されたターゲットURLへの有効な証明書パスが見つからない」と述べました。 したがって、私はこの投稿をフォローしましたが 、それでも接続を確認できませんでした。 私はそれについて読んで、ルート証明書が十分でないことがわかったので、ように、ポストによって示唆された- 私のために働いた事がキーストアに中間CA証明書をインポートしました。 私は実際にチェーン内のすべての証明書を追加しましたが、それは魅力のように機能しました。





4

JDK 8からJDK 10に移行する際の解決策

JDK 10

root@c339504909345:/opt/jdk-minimal/jre/lib/security #  keytool -cacerts -list
Enter keystore password:
Keystore type: JKS
Keystore provider: SUN

Your keystore contains 80 entries

JDK 8

root@c39596768075:/usr/lib/jvm/java-8-openjdk-amd64/jre/lib/security/cacerts #  keytool -cacerts -list
Enter keystore password:
Keystore type: JKS
Keystore provider: SUN

Your keystore contains 151 entries

修正する手順

  • JDK 10証明書を削除し、JDK 8に置き換えました
  • 私はDockerイメージをビルドしているので、マルチステージビルドを使用してすばやくそれを行うことができました
    • jlinkas を使用して最小限のJREを構築しています/opt/jdk/bin/jlink \ --module-path /opt/jdk/jmods...

だから、ここに異なるパスとコマンドのシーケンスがあります...

# Java 8
COPY --from=marcellodesales-springboot-builder-jdk8 /usr/lib/jvm/java-8-openjdk-amd64/jre/lib/security/cacerts /etc/ssl/certs/java/cacerts

# Java 10
RUN rm -f /opt/jdk-minimal/jre/lib/security/cacerts
RUN ln -s /etc/ssl/certs/java/cacerts /opt/jdk-minimal/jre/lib/security/cacerts

2

www.udemy.com(REST Java Webサービス)でREST Webサービスのチュートリアルに取り組んでいます。チュートリアルの例では、SSLを使用するために、「クライアント」プロジェクトに「trust_store」というフォルダーが必要です。このフォルダーには、「キーストア」ファイルを含める必要があります(サービスを呼び出す「クライアント」プロジェクトがありました) 、およびREST Webサービスを含む「サービス」プロジェクト-同じEclipseワークスペースにある2つのプロジェクト(1つはクライアント、もう1つはサービス)。物事を簡単にするために、彼らは、「keystore.jks」を、私たちが使用しているglassfishアプリサーバー(glassfish \ domains \ domain1 \ config \ keystore.jks)からコピーして、私が作成したこの「trust_store」フォルダーに置くと述べましたクライアントプロジェクト。それは理にかなっているようです:サーバーの自己署名証明書 ' ■key_storeは、クライアントのtrust_storeの証明書に対応します。これを行うと、元の投稿に記載されているエラーが発生しました。私はこれをグーグルで調べて、エラーが信頼できる/署名された証明書を含まないクライアント上の「keystore.jks」ファイルによるものであり、見つかった証明書が自己署名されていることを読んだ

わかりやすくするために、私が理解しているように、「keystore.jks」には自己署名証明書が含まれ、「cacerts.jks」ファイルにはCA証明書(CAによって署名された)が含まれているとしましょう。「keystore.jks」は「キーストア」であり、「cacerts.jks」は「トラストストア」です。上記のように、コメンターの「Bruno」が言うように、「keystore.jks」はローカルで、「cacerts.jks」はリモートクライアント用です。

だから、私は自分に言いました、グラスフィッシュには「cacerts.jks」ファイルもあります。これは、グラスフィッシュのtrust_storeファイルです。cacerts.jskにはCA証明書が含まれているはずです。そして、どうやらtrust_storeフォルダーには、少なくとも1つのCA証明書を持つキーストアファイルを含める必要があります。そこで、クライアントプロジェクトで作成した「trust_store」フォルダに「cacerts.jks」ファイルを配置し、VMプロパティを「keystore.jks」ではなく「cacerts.jks」を指すように変更してみました。これでエラーは解消されました。必要なのは、機能するCA証明書だけでした。

これは、本番環境や、何かを動作させるだけの開発には理想的ではない場合があります。たとえば、おそらく "keytool"コマンドを使用して、クライアントの "keystore.jks"ファイルにCA証明書を追加できます。しかしとにかく、うまくいけば、これは少なくともここでエラーを引き起こす可能性のある可能なシナリオを絞り込みます。

また、私のアプローチはクライアント(クライアントのtrust_storeに追加されたサーバー証明書)に役立つようです。元の投稿を解決するための上記のコメントはサーバー(サーバーのtrust_storeに追加されたクライアント証明書)に役立つようです。乾杯。

Eclipseプロジェクトのセットアップ:

  • MyClientProject
  • src
  • テスト
  • JREシステムライブラリ
  • ...
  • trust_store
    --- cacerts.jks --- keystore.jks

MyClientProject.javaファイルのスニペット:

static {
  // Setup the trustStore location and password
  System.setProperty("javax.net.ssl.trustStore","trust_store/cacerts.jks");
  // comment out below line
  System.setProperty("javax.net.ssl.trustStore","trust_store/keystore.jks");
  System.setProperty("javax.net.ssl.trustStorePassword", "changeit");
  //System.setProperty("javax.net.debug", "all");

  // for localhost testing only
  javax.net.ssl.HttpsURLConnection.setDefaultHostnameVerifier(new javax.net.ssl.HostnameVerifier() {
        public boolean verify(String hostname, javax.net.ssl.SSLSession sslSession) {
          return hostname.equals("localhost");
        }

  });
}

1

私の問題は、クラウドアクセスセキュリティブローカーであるNetSkopeが、ソフトウェアの更新を通じて仕事用のラップトップにインストールされたことでした。これにより証明書チェーンが変更され、チェーン全体をcacertsキーストアにインポートした後も、Javaクライアントを介してサーバーに接続できませんでした。NetSkopeを無効にして、正常に接続できました。


1

私の場合、私のtomcatプロセスでは特定のキーストアが

-Djavax.net.ssl.trustStore=/pathtosomeselfsignedstore/truststore.jks

Wheras私は証明書をJRE / lib / securityのcacertにインポートしていましたが、変更が反映されていませんでした。次に、/ tmp / cert1.testにターゲットサーバーの証明書が含まれるコマンドを実行しました

keytool -import -trustcacerts -keystore /pathtosomeselfsignedstore/truststore.jks -storepass password123 -noprompt -alias rapidssl-myserver -file /tmp/cert1.test

証明書のインポートが成功したかどうかを再確認できます

keytool -list -v -keystore /pathtosomeselfsignedstore/truststore.jks

そして、あなたのタゲットサーバーがエイリアスrapidssl-myserverに対して見つかったかどうかを確認します


0

ファイル$JAVA_HOME/lib/security/cacertsが存在するかどうか確認してください!私の場合、それはファイルではなく、へのリンクでした/etc/ssl/certs/java/cacertsあり、これはそれ自体へのリンクでした(WHAT ???)。そのため、JVMはファイルを見つけることができません。

解決策: 実際のcacertsファイル(別のJDKから実行できます)を/etc/ssl/certs/java/ディレクトリにコピーすると、問題が解決します:)


実際、JDKはリンクを維持し、古いAPI、SDKとの互換性のために...同じようにうまく管理できました...私はJDK 8からJDK 10に移動してDockerを使用しているので、cacertsを別の画像...リンクを作成しましたが、まったく同じ方法で作成しました...rm -f /opt/jdk-minimal/jre/lib/security/cacerts ; ln -s /etc/ssl/certs/java/cacerts /opt/jdk-minimal/jre/lib/security/cacerts
Marcello de Sales

-9

pom.xmlで$ {JAVA_HOME}のようなクラスパス変数を使用しているとしましょう。

<target>
                    <property name="compile_classpath" refid="maven.compile.classpath"/>
                    <property name="runtime_classpath" refid="maven.runtime.classpath"/>
                    <property name="test_classpath" refid="maven.test.classpath"/>
                    <property name="plugin_classpath" refid="maven.plugin.classpath"/>
                    <property name="jaxb-api.jar" value="${maven.dependency.javax.xml.bind.jaxb-api.jar.path}"/>
                    <property name="project_home" value="${PROJECT_HOME}"/>
                    <property name="java_home" value="${JAVA_HOME}"/>
                    <property name="ant_home" value="${ANT_HOME}"/>
                    <property name="common_home" value="${COMMON_HOME}"/>
                    <property name="JAXP_HOME" value="${common_home}/lib"/>
                    <property name="ejfw_home" value="${PROJECT_HOME}/lib"/>
                    <property name="weblogic_home" value="${WL_HOME}"/>
                    <property name="fw_home" value="${FW_HOME}"/>
                    <property name="env" value="${BUILDENV}"/>
                    <property name="tokenfile" value="${BUILDENV}${BUILDENV_S2S}.properties"/>

目標に合わせて、クラスパス変数を追加します。つまり、-DANT_HOME、-DJAVA_HOME

clean install -e -DPROJECT_HOME=..... -DANT_HOME=C:\bea1036\modules\org.apache.ant_1.7.1 -DJAVA_HOME=C:\bea1036\jdk160_31

1
クラスパスと証明書は、相互に何の関係もありません。
ローンの侯爵

1
あなたはその質問を誤解していると思います。
Dawood ibnカリーム2017年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.