web-dev-qa-db-ja.com

要求されたターゲットへの有効な証明書パスが見つかりません - 証明書のインポート後もエラー

自己署名証明書を使用してサーバーにアクセスしようとしている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を再起動し、 'post'を引退しました。

私はまだ同じエラーを受けています。

これは私のGlassfishが実際に私が修正したcacertファイルを読んでいるのではなく、おそらく他のファイルを読んでいるからです。

誰かがこの問題を抱えていて、正しい方向に私を推し進めることができますか?

164
TheCoder

残念なことに - それは多くのことが考えられます - そして多くのアプリケーションサーバーや他のJavaの「ラッパー」はプロパティで遊ぶ傾向があり、それら自身がキーチェーンを持っています。それでそれは全く違う何かを見ているかもしれません。

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

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

それが役立つかどうかを確認する。 'all'の代わりに 'ssl'、key managerおよびtrust managerに設定することもできます - これはあなたの場合に役立つかもしれません。 '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 を参照

129

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

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);
    }
    }

}
18
user6258309

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サイトの詳細 を参照してください。

12
Vic

からの私の他の応答 からの再投稿)
インポート(および trust! )に必要な証明書には、Javaソフトウェア配布からcliユーティリティー keytool を使用します。

サンプル:

  1. Cliからdreを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

私はと同じ問題を抱えていた sBT
repo1.maven.org over sslから依存関係を取得しようとしました
しかし、「要求されたターゲットURLへの有効な認証パスを見つけることができない」と述べました。
だから私は この記事 に続き、それでも接続の確認に失敗しました。
それで私はそれについて読み、ポストによって示唆されたようにルート証明書が十分ではないことがわかりました
私にとってうまくいったのは、中間CA証明書をキーストアにインポートすることでした
実際にすべての証明書をチェーンに追加したところ、魅力的に機能しました。

5
Danny Mor

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

JDK 10

[email protected]:/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

[email protected]:/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 Imagesを構築しているので、マルチステージビルドを使用してすぐにそれを実行できます。
    • jlinkname__を/opt/jdk/bin/jlink \ --module-path /opt/jdk/jmods...として使用して最小限のJREを構築しています。

それで、これは異なるパスとコマンドのシーケンスです...

# 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
3

私はREST Webサービスのチュートリアルをwww.udemy.com(REST Java Web Services)で作成しています。チュートリアルの例では、SSLを使用するには、Eclipseの "client"プロジェクトに "trust_store"というフォルダを作成し、その中に "key store"ファイルを含める必要があります(サービスを呼び出す "client"プロジェクトがありました)。また、REST Webサービスを含む "service"プロジェクト - 同じEclipseワークスペース内に2つのプロジェクト(一方はクライアント、もう一方はサービス)。簡単にするために、彼らは私達が使っているglassfishアプリケーションサーバー(glassfish\domains\domain1\config\keystore.jsk)から "keystore.jks"をコピーし、それを私が作ったこの "trust_store"フォルダに入れると言いました。クライアントプロジェクトこれは理にかなっているように思えます:サーバーのkey_storeの自己署名証明書はクライアントのtrust_storeの証明書に対応するでしょう。さて、これをしていると、私は元の記事が述べているエラーを得ていました。私はこれをグーグルしました、そして、エラーがそれが見つけた証明書が自己署名しているという信頼された/署名された証明書を含んでいないクライアントの "keystore.jks"ファイルのせいです。

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

Glassfishには、 "cacerts.jks"ファイルもあります。これは、glassfishのtrust_storeファイルです。 cacerts.jskにはCA証明書が含まれているはずです。そしてどうやら私は少なくとも1つのCA証明書を持つキーストアファイルを含むために私のtrust_storeフォルダが必要です。そこで、私は自分のクライアントプロジェクトで作成した "trust_store"フォルダに "cacerts.jks"ファイルを置き、 "keystore"ではなく "cacerts.jks"を指すようにVMプロパティを変更してみました。 .jks "それはエラーを取り除きました。私が必要としているのは、動作するためのCA証明書だけだったと思います。

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

同様に、私のアプローチはクライアント(クライアントの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
Steve T

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

0
gary69

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

解決策: /本物のcacertsファイルをコピーして( 他のJDKからコピーすることができます /etc/ssl/certs/Java/ディレクトリに移動すれば問題が解決します:)

0
0x7E1