Неможливо знайти дійсний шлях сертифікації до запитуваної цілі - помилка навіть після імпорту cert


205

У мене є клієнт Java, який намагається отримати доступ до сервера з власноручним підписом.

Коли я намагаюся розмістити повідомлення на сервері, я отримую таку помилку:

не вдалося знайти дійсний шлях сертифікації до потрібної цілі

Провівши кілька досліджень з цього питання, я зробив наступне.

  1. Збережено доменне ім’я моїх серверів як root.cerфайл.
  2. У JRE мого сервера Glassfish я запустив це:
    keytool -import -alias example -keystore cacerts -file root.cer
  3. Щоб переконатися, що сертифікат був доданий до мого візитника, я зробив це так:
    keytool -list -v -keystore cacerts
    я можу бачити, як церт присутній.
  4. Потім я перезапустив Glassfish і звільнився з посади.

Я все ще отримую ту саму помилку.

У мене таке відчуття, тому що мій Glassfish насправді не читає файл, який я змінив, але, можливо, якийсь інший.

У когось із вас виникло це питання і чи може мене підштовхнути в правильному напрямку?


1
Просто для уточнення "У мене є клієнт Java, який намагається отримати доступ до сервера з власноручним підписом". Чи є певна конфігурація для налаштувань вашого роз'єму на Glassfish (зокрема, налаштування магазину)?
Бруно

"У мене є клієнт Java, який намагається отримати доступ до сервера з власноручним підписом.": Ви говорите про використання клієнтських сертифікатів, які підписуються самостійно, чи не так? - так.
TheCoder

1
Я знайшов 2 налаштування в JVM Glassfish: -Djavax.net.ssl.keyStore = $ {com.sun.aas.instanceRoot} /config/keystore.jks та -Djavax.net.ssl.trustStore = $ {com.sun. aas.instanRoot} /config/cacerts.jks. Мені зараз потрібно додати через cert до одного з таких. Чи можете ви підтвердити, що це клавіатура, до якої я додаю її?
TheCoder

4
На сервері сховище ключів - це сервер cert та його приватний ключ (keystore - це те, що "належить" місцевій партії). Довірений магазин призначений для сертифіката, який використовується для перевірки довіри до віддаленої сторони. Ви повинні додати клієнтський сертифікат до вашого довіреного магазину сервера. (Дивіться також це , хоча, схоже, Glassfish не використовує місце за замовчуванням JRE.)
Бруно,

Це працювало Бруно. Я додав його до свого довіреного магазину Glassfish. Дякую за допомогу. Ти теж Дірк.
TheCoder

Відповіді:


155

На жаль - це може бути багато речей - і безліч серверів додатків та інших Java-обгортків схильні грати з властивостями, і їх "власні" беруть на брелки, а що ні. Тож може дивитися на щось зовсім інше.

Не вистачає трибуна - я б спробував:

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

щоб побачити, чи це допомагає. Замість "всіх" ви можете також встановити його на "ssl", керуючий ключами та менеджером довіри - що може допомогти у вашому випадку. Якщо встановити його як "help", на більшості платформ перелічено щось подібне нижче.

Незалежно - переконайтеся, що ви повністю розумієте різницю між магазином ключів (у якому у вас є приватний ключ і cert, з яким ви підтверджуєте свою власну ідентичність) і магазином довіри (який визначає, кому ви довіряєте) - і тим, що ваша власна ідентичність також має "ланцюжок" довіри до кореня - який є окремим від будь-якого ланцюга до кореня, вам потрібно з'ясувати, "кому" ви довіряєте.

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

5
java -Djavax.net.debug = all -Djavax.net.ssl.trustStore = trustStore ... видає помилку нижче: Помилка: Не вдалося знайти або завантажити основний клас ...
rohith

1
Звичайно, вам може знадобитися вказати пароль довіреного магазину з -Djavax.net.ssl.trustStorePassword =
changeit

18

Ось рішення, перейдіть за посиланням нижче Крок за кроком:

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

}

3
Це рішення працювало для мене, але воно потребує невеликих змін у приватному класі SavingTrustManager:public X509Certificate[] getAcceptedIssuers() { return new X509Certificate[0];}
Річард

1
@ Richard, @ Paul, @ user6258309 Я отримав помилку Виняток у потоці "main" java.net.SocketTimeoutException: Читання вимкнено на java.net.SocketInputStream.socketRead0 (Native Method) на java.net.SocketInputStream.socketRead (Невідоме джерело ) Як я можу це виправити
Ренжіт Крішнан

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. Ця відповідь працювала для мене в довіреному магазині.
Mate Šimović

7

(Репост з мого іншої відповіді )
Використовуйте утиліту CLI Keytool від розповсюдження програмного забезпечення Java для імпорту (і довіри! ) Необхідних сертифікати

Зразок:

  1. З cli змініть dir на jre \ bin

  2. Перевірте сховище ключів (файл знаходиться в JRE каталозі \ Bin)
    Keytool -list -keystore .. \ Lib \ безпеку \ 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 .
Він намагався знайти залежності від repo1.maven.org через ssl,
але заявив, що "не в змозі знайти дійсний шлях сертифікації до потрібного цільового 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 cert і замінив його на JDK 8
  • Оскільки я будую Docker Images, я міг швидко зробити це за допомогою багатоетапних збірок
    • Я лад мінімального JRE , використовуючи в jlinkякості/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

Я працюю над підручником для веб-служб REST на веб-сайті www.udemy.com (REST Java Web Services). У прикладі підручника сказано, що для того, щоб мати SSL, ми повинні мати папку під назвою "trust_store" в проекті мого затемнення "клієнт", яка повинна містити файл "ключ зберігання" (у нас був проект "клієнт", щоб викликати службу , і "сервісний" проект, який містив веб-службу REST - 2 проекти в одній робочій області затемнення, один - клієнт, інший - сервіс). Щоб зробити все просто, вони сказали скопіювати "keystore.jks" з сервера додатків glassfish (glassfish \ domeins \ domain1 \ config \ keystore.jks), який ми використовуємо, і помістив його в цю папку "trust_store", яку вони мені створили проект клієнта. Це, мабуть, має сенс: самопідписані сертифікати на сервері " s key_store відповідатиме сертифікатам клієнтського trust_store. Тепер, роблячи це, я отримував помилку, про яку згадується в початковій публікації. Я переглянув це і прочитав, що помилка пов'язана з файлом "keystore.jks" на клієнті, що не містить довіреного / підписаного сертифіката, що сертифікат, який він знаходить, підписується самостійно.

Щоб ясність була зрозумілою, дозвольте мені сказати, що, наскільки я це розумію, "keystore.jks" містить самопідписані серти, а файл "cacerts.jks" містить сертифікати CA (підписані CA). "Keystore.jks" - це "keystore", а "cacerts.jks" - "магазин довіри". Як говорить вище коментатор "Бруно", "keystore.jks" є локальним, а "cacerts.jks" - для віддалених клієнтів.

Отже, я сказав собі, ей, у келіха також є файл "cacerts.jks", який є файлом trust_store файлу glassfish. cacerts.jsk повинен містити сертифікати CA. І, мабуть, мені потрібна папка trust_store, щоб містити файл зберігання ключів, який має принаймні один сертифікат CA. Отже, я спробував помістити файл "cacerts.jks" у папку "trust_store", яку я створив, на своєму клієнтському проекті та змінивши властивості VM, щоб вказати на "cacerts.jks" замість "keystore.jks". Це позбулося помилки. Я здогадуюсь, що все, що було потрібно, це CA CA для роботи.

Це може не бути ідеальним для виробництва, або навіть для розвитку, крім того, щоб просто отримати щось для роботи. Наприклад, ви, ймовірно, можете скористатися командою "keytool", щоб додати сертифікати CA у файл "keystore.jks" у клієнті. Але все одно сподіваємось, що це принаймні звужує можливі сценарії, які могли б відбуватися тут, щоб викликати помилку.

ТАКОЖ: мій підхід здавався корисним для клієнта (сервер cert додано до client trust_store), схоже, що коментарі вище для вирішення оригінальної публікації корисні для сервера (клієнт cert доданий до сервера 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

Моєю проблемою було те, що на мій робочий ноутбук через оновлення програмного забезпечення було встановлено Cloud Access Security Broker, NetSkope. Це змінило ланцюжок сертифікатів, і я все ще не зміг підключитися до сервера через мій клієнт Java після імпортування всього ланцюжка до мого магазину ключів. Я відключив NetSkope і зміг успішно підключитися.


1

У моєму випадку я зіткнувся з проблемою, оскільки в моєму процесі tomcat було використано конкретне зберігання ключів

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

Коли я імпортував сертифікат до касети JRE / lib / security, і зміни не відображалися. Потім я зробив команду нижче, де /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 а також це було посилання на себе (ЩО ???), тому через нього JVM не може знайти файл.

Рішення: Скопіюйте файл реальних кесерів ( ви можете зробити це з іншого JDK ) у /etc/ssl/certs/java/каталог, і це вирішить вашу проблему :)


Дійсно, JDK підтримує посилання і, можливо, для сумісності зі старими API, SDK ... Мені вдалося це зробити ... Я переходжу з JDK 8 на JDK 10 і використовую Docker, тому мені просто потрібно було скопіювати кекси з зображення до іншого ... Я створив посилання і таким же чином ...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

Скажімо, якщо ви використовуєте змінні classpath, як $ {JAVA_HOME} у pom.xml.

<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"/>

У цілях додайте змінні classpath. тобто .., -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
Я вважаю, що ви неправильно зрозуміли питання.
Давуд ібн Карім
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.