[java] 요청한 대상에 대한 유효한 인증 경로를 찾을 수 없음-인증서를 가져온 후에도 오류

자체 서명 된 인증서로 서버에 액세스하려고하는 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 파일을 읽지 않고 다른 파일을 읽었 기 때문에 이것이 느낌입니다.

당신 중 누구 에게이 문제가 있고 올바른 방향으로 나를 밀어 줄 수 있습니까?



답변

불행히도 많은 것들이 될 수 있으며 많은 응용 프로그램 서버와 다른 Java ‘래퍼’가 속성을 가지고 노는 경향이 있으며 ‘자체’가 키 체인을 취하는 것과 그렇지 않은 것입니다. 완전히 다른 것을보고있을 수 있습니다.

트러스-링 부족-시도해 볼 것 :

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

그것이 도움이되는지 확인하십시오. ‘all’대신에 키 관리자 및 신뢰 관리자 인 ‘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 참조


답변

해결책은 다음과 같습니다. 아래 링크를 단계별로 따르십시오.

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

자바 파일 : 블로그에서 누락

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

}


답변

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 사이트를 참조하십시오 .


답변

(에서 재 게시 내 다른 응답 )
CLI 유틸리티 사용 키 도구를 가져 오기위한 자바 소프트웨어 배포에서 (그리고 신뢰! )에 필요한 인증서

견본:

  1. cli change 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


답변

sbt 와 같은 문제가있었습니다 . repo1.maven.org 에서 ssl을 통해
종속성을 가져 오려고 시도했지만
“요청한 대상 URL에 대한 유효한 인증 경로를 찾을 수 없습니다”라고 말했습니다.
그래서 나는 이 게시물을 따라
여전히 연결을 확인하지 못했습니다.
그래서 그것에 대해 읽고 게시물에서 제안한 것처럼 루트 인증서가 충분하지 않다는 것을 알았습니다. 그래서 나를 위해 일한 것은 중간 CA 인증서를 키 저장소로 가져 오는 것입니다 .
실제로 체인에 모든 인증서를 추가했으며 매력처럼 작동했습니다.


답변

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 Images를 빌드 중이므로 다단계 빌드를 사용하여 신속하게 수행 할 수 있습니다
    • 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


답변

www.udemy.com (REST Java Web Services)에서 REST 웹 서비스에 대한 자습서를 작성 중입니다. 튜토리얼의 예제에 따르면 SSL을 사용하려면 일식 “클라이언트”프로젝트에 “key store”파일을 포함해야하는 “trust_store”라는 폴더가 있어야합니다 (서비스를 호출 할 “클라이언트”프로젝트가 있음) , 동일한 웹 사이트에있는 2 개의 프로젝트 (하나는 클라이언트이고 다른 하나는 서비스) 인 REST 웹 서비스를 포함하는 “service”프로젝트). 일을 단순하게 유지하기 위해, 우리가 사용하고있는 glassfish 앱 서버 (glassfish \ domains \ domain1 \ config \ keystore.jks)에서 “keystore.jks”를 복사하여이 “trust_store”폴더에 넣습니다. 클라이언트 프로젝트. 서버의 자체 서명 인증서 key_store는 클라이언트 trust_store의 인증서에 해당합니다. 이제이 작업을 수행하면서 원래 게시물에 언급 된 오류가 발생했습니다. 나는 이것을 구글 검색하고 오류가 신뢰할 수있는 / 서명 된 인증서를 포함하지 않는 클라이언트의 “keystore.jks”파일 때문이며 찾은 인증서는 자체 서명되어 있음을 읽었습니다.

이해를 돕기 위해 “keystore.jks”에는 자체 서명 인증서가 포함되어 있고 “cacerts.jks”파일에는 CA 인증서 (CA 서명)가 포함되어 있습니다. “keystore.jks”는 “keystore”이고 “cacerts.jks”는 “trust store”입니다. 주석 작성자 인 “Bruno”는 위에서 “keystore.jks”는 로컬이고 “cacerts.jks”는 원격 클라이언트를위한 것입니다.

글쎄, glassfish에는 glassfish의 trust_store 파일 인 “cacerts.jks”파일도 있습니다. cacerts.jsk에는 CA 인증서가 포함되어 있어야합니다. 그리고 적어도 하나 이상의 CA 인증서가있는 키 저장소 파일을 포함하려면 trust_store 폴더가 필요합니다. 따라서 클라이언트 프로젝트에서 “trust_store”폴더에 “cacerts.jks”파일을 넣고 “keystore.jks”대신 “cacerts.jks”를 가리 키도록 VM 속성을 변경하려고했습니다. 그것은 오류를 제거했습니다. CA 인증서 만 있으면 충분합니다.

이것은 생산에 이상적 일 수도 있고 단순히 일을하는 것 이상의 개발에도 적합하지 않을 수도 있습니다. 예를 들어 “keytool”명령을 사용하여 CA 인증서를 클라이언트의 “keystore.jks”파일에 추가 할 수 있습니다. 그러나 어쨌든 이것이 적어도 오류를 유발하기 위해 여기에서 진행될 수있는 시나리오를 좁히기를 바랍니다.

또한 내 접근 방식은 클라이언트 (클라이언트 trust_store에 추가 된 서버 인증서)에 유용한 것처럼 보였으며 원래 게시물을 해결하는 위의 주석은 서버에 유용합니다 (클라이언트 인증서가 서버 trust_store에 추가됨). 건배.

이클립스 프로젝트 설정 :

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

  });
}