Java: sun.security.provider.certpath.SunCertPathBuilderException: не вдалося знайти дійсний шлях сертифікації до потрібної цілі


250

У мене є клас, який завантажить файл із https- сервера. Коли я запускаю його, він повертає багато помилок. Здається, у мене проблема з сертифікатом. Чи можна ігнорувати автентифікацію клієнт-сервер? Якщо так, то як?

package com.da;

import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.CharBuffer;
import java.util.concurrent.Future;

import org.apache.http.HttpResponse;
import org.apache.http.client.utils.URIUtils;
import org.apache.http.impl.nio.client.DefaultHttpAsyncClient;
import org.apache.http.nio.IOControl;
import org.apache.http.nio.client.HttpAsyncClient;
import org.apache.http.nio.client.methods.AsyncCharConsumer;
import org.apache.http.nio.client.methods.HttpAsyncGet;
import org.apache.http.nio.client.methods.HttpAsyncPost;

public class RSDDownloadFile {
    static FileOutputStream fos;

    public void DownloadFile(String URI, String Request) throws Exception
    {
        java.net.URI uri = URIUtils.createURI("https", "176.66.3.69:6443", -1, "download.aspx",
                "Lang=EN&AuthToken=package", null);
        System.out.println("URI Query: " + uri.toString());

        HttpAsyncClient httpclient = new DefaultHttpAsyncClient();
        httpclient.start();
        try {
            Future<Boolean> future = httpclient.execute(
                    new HttpAsyncGet(uri),
                    new ResponseCallback(), null);

            Boolean result = future.get();
            if (result != null && result.booleanValue()) {
                System.out.println("\nRequest successfully executed");
            } else {
                System.out.println("Request failed");
            }              
        } 
        catch(Exception e){
            System.out.println("[DownloadFile] Exception: " + e.getMessage());
        }
        finally {
            System.out.println("Shutting down");
            httpclient.shutdown();
        }
        System.out.println("Done");  

    }

    static class ResponseCallback extends AsyncCharConsumer<Boolean> {

        @Override
        protected void onResponseReceived(final HttpResponse response) {
             System.out.println("Response: " + response.getStatusLine());
             System.out.println("Header: " + response.toString());
             try {   
                 //if(response.getStatusLine().getStatusCode()==200)
                     fos = new FileOutputStream( "Response.html" );
             }catch(Exception e){
                 System.out.println("[onResponseReceived] Exception: " + e.getMessage());
             }
        }

        @Override
        protected void onCharReceived(final CharBuffer buf, final IOControl ioctrl) throws IOException {
            try
            {
                while (buf.hasRemaining()) 
                {
                    //System.out.print(buf.get());
                    fos.write(buf.get());
                }
            }catch(Exception e)
            {
                System.out.println("[onCharReceived] Exception: " + e.getMessage());
            }
        }

        @Override
        protected void onCleanup() {
            try
            {             
                if(fos!=null)
                    fos.close();
            }catch(Exception e){
                System.out.println("[onCleanup] Exception: " + e.getMessage());         
            }
             System.out.println("onCleanup()");
        }

        @Override
        protected Boolean buildResult() {
            return Boolean.TRUE;
        }

    }
}

Помилки:

URI Query: https://176.66.3.69:6443/download.aspx?Lang=EN&AuthToken=package
Aug 2, 2011 3:47:57 PM org.apache.http.impl.nio.client.NHttpClientProtocolHandler exception
SEVERE: I/O error: General SSLEngine problem
javax.net.ssl.SSLHandshakeException: General SSLEngine problem
    at com.sun.net.ssl.internal.ssl.Handshaker.checkThrown(Unknown Source)
    at com.sun.net.ssl.internal.ssl.SSLEngineImpl.checkTaskThrown(Unknown Source)
    at com.sun.net.ssl.internal.ssl.SSLEngineImpl.writeAppRecord(Unknown Source)
    at com.sun.net.ssl.internal.ssl.SSLEngineImpl.wrap(Unknown Source)
    at javax.net.ssl.SSLEngine.wrap(Unknown Source)
    at org.apache.http.impl.nio.reactor.SSLIOSession.doHandshake(SSLIOSession.java:154)
    at org.apache.http.impl.nio.reactor.SSLIOSession.isAppInputReady(SSLIOSession.java:276)
    at org.apache.http.impl.nio.client.InternalClientEventDispatch.inputReady(InternalClientEventDispatch.java:79)
    at org.apache.http.impl.nio.reactor.BaseIOReactor.readable(BaseIOReactor.java:161)
    at org.apache.http.impl.nio.reactor.AbstractIOReactor.processEvent(AbstractIOReactor.java:335)
    at org.apache.http.impl.nio.reactor.AbstractIOReactor.processEvents(AbstractIOReactor.java:315)
    at org.apache.http.impl.nio.reactor.AbstractIOReactor.execute(AbstractIOReactor.java:275)
    at org.apache.http.impl.nio.reactor.BaseIOReactor.execute(BaseIOReactor.java:104)
    at org.apache.http.impl.nio.reactor.AbstractMultiworkerIOReactor$Worker.run(AbstractMultiworkerIOReactor.java:542)
    at java.lang.Thread.run(Unknown Source)
Caused by: javax.net.ssl.SSLHandshakeException: General SSLEngine problem
    at com.sun.net.ssl.internal.ssl.Alerts.getSSLException(Unknown Source)
    at com.sun.net.ssl.internal.ssl.SSLEngineImpl.fatal(Unknown Source)
    at com.sun.net.ssl.internal.ssl.Handshaker.fatalSE(Unknown Source)
    at com.sun.net.ssl.internal.ssl.Handshaker.fatalSE(Unknown Source)
    at com.sun.net.ssl.internal.ssl.ClientHandshaker.serverCertificate(Unknown Source)
    at com.sun.net.ssl.internal.ssl.ClientHandshaker.processMessage(Unknown Source)
    at com.sun.net.ssl.internal.ssl.Handshaker.processLoop(Unknown Source)
    at com.sun.net.ssl.internal.ssl.Handshaker$1.run(Unknown Source)
    at java.security.AccessController.doPrivileged(Native Method)
    at com.sun.net.ssl.internal.ssl.Handshaker$DelegatedTask.run(Unknown Source)
    at org.apache.http.impl.nio.reactor.SSLIOSession.doHandshake(SSLIOSession.java:180)
    ... 9 more
Caused by: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
    at sun.security.validator.PKIXValidator.doBuild(Unknown Source)
    at sun.security.validator.PKIXValidator.engineValidate(Unknown Source)
    at sun.security.validator.Validator.validate(Unknown Source)
    at com.sun.net.ssl.internal.ssl.X509TrustManagerImpl.checkServerTrusted(Unknown Source)
    at com.sun.net.ssl.internal.ssl.JsseX509TrustManager.checkServerTrusted(Unknown Source)
    ... 16 more
Caused by: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
    at sun.security.provider.certpath.SunCertPathBuilder.engineBuild(Unknown Source)
    at java.security.cert.CertPathBuilder.build(Unknown Source)
    ... 21 more
onCleanup()

[DownloadFile] Exception: javax.net.ssl.SSLHandshakeException: General SSLEngine problem
Shutting down
Done

2
Одного разу я отримав цю помилку і зв’язався з нашою командою з безпеки, і виявилося, що мені довелося виправити JAR, який ми використовували, оскільки наша команда використовувала застарілий, наданий компанією. Просто вигадка для всіх, хто може опинитися в подібній ситуації.
kayleeFrye_onDeck

Відповіді:


215

Проблема з'являється, коли ваш сервер має самопідписаний сертифікат. Щоб її вирішити, ви можете додати цей сертифікат до списку надійних сертифікатів вашого JVM.

У цій статті автор описує, як отримати сертифікат у вашому браузері та додати його до файлу кесерів вашого JVM. Ви можете редагувати JAVA_HOME/jre/lib/security/cacertsфайл або запустити додаток із -Djavax.net.ssl.trustStoreпараметром. Перевірте, який саме JDK / JRE ви використовуєте, оскільки це часто є причиною плутанини.

Дивіться також: Як вирішуються імена серверів сертифікатів SSL / Чи можна додати альтернативні імена за допомогою keytool? Якщо ви зіткнулися з java.security.cert.CertificateException: No name matching localhost foundвинятком.


3
це не працювало для мене. У мене встановлений корінь і cert cert, але Tomcat-7 все ще повідомляє validatorException, викликаний "не в змозі знайти дійсний шлях сертифікації до запитуваної цілі" будь-яким способом налагодити це?
Херувим

Проблема також з’являється із сертифікатом, який підписує хтось інший, якому не довіряють.
Маркіз Лорн

Чудово! Це працює! Просто не забувайте, що у вас могли бути і jre, і jdk, і обидва вони cacertsповинні бути оновлені
Діма Фомін,

У моєму випадку кореневий СА був там, але не наступним ЦА вниз. Додавання наступного ЦА зробило трюк - спасибі.
java-addict301

1
У моєму випадку я використовую Netbeans + Apache Tomcat (інтегрований), тому, додаючи .cer до магазину довіри "cacerts" на Jdk / jre (C: \ Program Files \ Java \ jdk1.8.0_152 \ jre \ lib \ безпека) і Jre (C: \ Program Files \ Java \ jre1.8.0_91 \ lib \ security) працює для мене
Jnn

149

Ось що надійно працює для мене на macOS. Переконайтесь, що замініть example.com та 443 фактичним іменем хосту та портом, до якого ви намагаєтесь підключитися, та надайте спеціальний псевдонім. Перша команда завантажує наданий сертифікат з віддаленого сервера і зберігає його локально у форматі x509. Друга команда завантажує збережений сертифікат у сховище SSL Java.

openssl x509 -in <(openssl s_client -connect example.com:443 -prexit 2>/dev/null) -out ~/example.crt
sudo keytool -importcert -file ~/example.crt -alias example -keystore $(/usr/libexec/java_home)/jre/lib/security/cacerts -storepass changeit

3
Для мене працює чому? Потрібно надати пояснення.
Маркіз Лорн

openssl x509 -in <(openssl s_client -connect example.com:243 -prexit 2> / dev / null) -out ~ / example.crt - що таке example.crt у команді я маю сертифікат .pem, який мені потрібно дати що тут ??
Вішну Ранганатан

3
.crt і .pem - зазвичай використовуються розширення файлів для одного формату файлів. Якщо у вас вже є файл, просто запустіть другу команду і передайте її в аргумент -file.
Гейб Мартін-Демпесі

1
Чудові речі. Єдине: мені довелося чомусь використовувати останню openssl 1.0.Xx, старий 9.X.Xx не працював.
zbstof

1
Це не працює з кінцевою точкою SNI. Для цього вам потрібно додати: -servername example.com під час отримання cert
Патрік Бек

46

У мене був такий самий випуск із дійсним підписаним сертифікатом wildcard від symantec.

Спершу спробуйте запустити свою програму java за допомогою -Djavax.net.debug = SSL, щоб побачити, що насправді відбувається.

Я в кінці імпортував проміжний сертифікат, через який ланцюг cert розірвався.

Я завантажив відсутній проміжний серт із symantec (ви можете побачити посилання для завантаження до відсутнього cert в журналі рукостискання ssl: http://svrintl-g3-aia.verisign.com/SVRIntlG3.cer у моєму випадку).

І я імпортував cert у сховище Java. Після імпорту проміжного сертифікату мій підписний знак ssl cert нарешті почав працювати:

keytool -import -keystore ../jre/lib/security/cacerts -trustcacerts -alias "VeriSign Class 3 International Server CA - G3" -file /pathto/SVRIntlG3.cer

Це було так:
kisna

2
Щоб уникнути плутанини, запустіть java (або jcurl) з параметрами налагодження, щоб побачити віддалений "ланцюжок сертифікатів" у журналах, а потім натисніть на "CN" у довіреному магазині, явно переданому (замість за замовчуванням) наступним чином, якщо його немає, вам потрібно додати. ssllabs.com/ssltest/analyze.html покаже, якщо серти на стороні сервера мають неповний ланцюг, і включає проміжні сертифікати шляху сертифікації, які потрібно додати. -Djavax.net.debug=ssl,handshake -Djavax.net.ssl.keyStoreType=PKCS12 -Djavax.net.ssl.keyStore=our-client-certs -Djavax.net.ssl.trustStoreType=jks -Djavax.net.ssl.trustStore=their-server-certs
kisna

І, звичайно, офіційна стаття про налагодження проблем SSL: docs.oracle.com/javase/7/docs/technotes/guides/security/jsse/… blogs.oracle.com/java-platform-group/entry/…
kisna

У мене був той самий випуск, це дуже корисно, але в моєму випадку вам довелося лише додати сертифікат сервера до файлу касертів версії JDK
Pigritia

Майте на увазі, що є ще один інструмент під назвою portecle, який може відкрити файл cacert (сховище сертифікатів) та легко імпортувати сертифікат. Просто пам’ятайте, щоб потім зберегти файл cacert.
will824

41
  1. Експортуйте сертифікат SSL за допомогою Firefox. Ви можете експортувати його, натиснувши URL-адресу в браузері, а потім виберіть опцію для експорту сертифіката. Припустимо, що ім'ям файлу cert є ваше.ssl.server.name.crt
  2. Перейдіть до свого JRE_HOME/binабоJDK/JRE/bin
  3. Введіть команду
  4. keytool -keystore ..\lib\security\cacerts -import -alias your.ssl.server.name -file .\relative-path-to-cert-file\your.ssl.server.name.crt
  5. Перезапустіть процес Java

13
Якщо ввести відповідний пароль, використовуйте cacerts Значення за замовчуванням пароль для сховища ключів changeit( stackoverflow.com/a/22782035/1304830 ). Також не забудьте запустити cmd як адміністратор.
Fr4nz

22

@Gabe Мартін-Демпесі мені допомагає у відповіді. І я написав невеликий сценарій, пов’язаний з цим. Використання дуже просте.

Встановіть сертифікат від хоста:

> sudo ./java-cert-importer.sh example.com

Видаліть сертифікат, який уже встановлений.

> sudo ./java-cert-importer.sh example.com --delete

java-cert-importer.sh

#!/usr/bin/env bash

# Exit on error
set -e

# Ensure script is running as root
if [ "$EUID" -ne 0 ]
  then echo "WARN: Please run as root (sudo)"
  exit 1
fi

# Check required commands
command -v openssl >/dev/null 2>&1 || { echo "Required command 'openssl' not installed. Aborting." >&2; exit 1; }
command -v keytool >/dev/null 2>&1 || { echo "Required command 'keytool' not installed. Aborting." >&2; exit 1; }

# Get command line args
host=$1; port=${2:-443}; deleteCmd=${3:-${2}}

# Check host argument
if [ ! ${host} ]; then
cat << EOF
Please enter required parameter(s)

usage:  ./java-cert-importer.sh <host> [ <port> | default=443 ] [ -d | --delete ]

EOF
exit 1
fi;

if [ "$JAVA_HOME" ]; then
    javahome=${JAVA_HOME}
elif [[ "$OSTYPE" == "linux-gnu" ]]; then # Linux
    javahome=$(readlink -f $(which java) | sed "s:bin/java::")
elif [[ "$OSTYPE" == "darwin"* ]]; then # Mac OS X
    javahome="$(/usr/libexec/java_home)/jre"
fi

if [ ! "$javahome" ]; then
    echo "WARN: Java home cannot be found."
    exit 1
elif [ ! -d "$javahome" ]; then
    echo "WARN: Detected Java home does not exists: $javahome"
    exit 1
fi

echo "Detected Java Home: $javahome"

# Set cacerts file path
cacertspath=${javahome}/lib/security/cacerts
cacertsbackup="${cacertspath}.$$.backup"

if ( [ "$deleteCmd" == "-d" ] || [ "$deleteCmd" == "--delete" ] ); then
    sudo keytool -delete -alias ${host} -keystore ${cacertspath} -storepass changeit
    echo "Certificate is deleted for ${host}"
    exit 0
fi

# Get host info from user
#read -p "Enter server host (E.g. example.com) : " host
#read -p "Enter server port (Default 443) : " port

# create temp file
tmpfile="/tmp/${host}.$$.crt"

# Create java cacerts backup file
cp ${cacertspath} ${cacertsbackup}

echo "Java CaCerts Backup: ${cacertsbackup}"

# Get certificate from speficied host
openssl x509 -in <(openssl s_client -connect ${host}:${port} -prexit 2>/dev/null) -out ${tmpfile}

# Import certificate into java cacerts file
sudo keytool -importcert -file ${tmpfile} -alias ${host} -keystore ${cacertspath} -storepass changeit

# Remove temp certificate file
rm ${tmpfile}

# Check certificate alias name (same with host) that imported successfully
result=$(keytool -list -v -keystore ${cacertspath} -storepass changeit | grep "Alias name: ${host}")

# Show results to user
if [ "$result" ]; then
    echo "Success: Certificate is imported to java cacerts for ${host}";
else
    echo "Error: Something went wrong";
fi;

Працює бездоганно. Чудова робота! . Ось як це працює: запустіть службу SSL (якщо вона не працює) та виконайте команду, як пояснено (наприклад ./java-cert-importer.sh example.com 1234). Це воно.
лепе

1
Чудово працює. Я отримував помилку на сервері Дженкінса при підключенні до зовнішнього API, який змінює його сертифікат і не дає змоги. Це вирішує мою проблему
user9869932

Oracle повинен був забезпечити щось подібне в першу чергу або ніколи не створив своє власне жахливе рішення SSL. Обробка сертифікатів SSL має бути завданням операційної системи.
Вольфганг Фаль

17

Цитуючи з " Більше немає" не в змозі знайти дійсний шлях сертифікації до потрібної цілі "

при спробі відкрити SSL-з'єднання з хостом за допомогою JSSE. Зазвичай це означає, що сервер використовує тестовий сертифікат (можливо, згенерований за допомогою keytool), а не сертифікат від відомого комерційного сертифікаційного органу, такого як Verisign або GoDaddy. У цьому випадку веб-браузери відображають діалогові вікна попередження, але оскільки JSSE не може припустити, що інтерактивний користувач присутній, він за замовчуванням видає виняток.

Перевірка сертифікату є дуже важливою частиною безпеки SSL, але я не пишу цей запис для пояснення деталей. Якщо вас зацікавило, можна почати з читання розмитості у Вікіпедії. Я пишу цей запис, щоб показати простий спосіб поговорити з цим хостом із сертифікатом тесту, якщо ви цього дійсно хочете.

В основному ви хочете додати сертифікат сервера до KeyStore за допомогою ваших надійних сертифікатів

Спробуйте код, наданий там. Це може допомогти.


5
Частина про "Перевірка сертифікату є дуже важливою частиною безпеки SSL" не обов'язково відповідає дійсності. SSL дає вам два запевнення: (1), що ваше спілкування приватне, і (2), що ви спілкуєтесь із сервером, відомим АНБ. (:-) Іноді ви дбаєте лише про конфіденційність розмови, а потім самовільна сертифікація - це добре. Дивіться social-biz.org/2011/10/16/the-anti-ssl-conspiracy
AgilePro

@AgilePro SSL дає чотири гарантії: автентифікацію, конфіденційність, цілісність та можливість авторизації. Це не дає вам впевненості, що ви спілкуєтесь із сервером, відомим NSA. Піклування лише про конфіденційність без автентифікації є суперечливістю.
Маркіз Лорнський

@EJP Погоджуєтесь, що якщо ви користуєтесь клієнтським сертифікатом, ви можете отримати автентифікацію, і я припускаю можливість авторизації ... але більшість застосувань не мають клієнтського сертифіката. Чим би ви назвали різницю між "самопідписаним" сертифікатом і сертифікатом від органу, що підписує? Чи надає орган, що підписує, "цілісність". Мій жарт про АНБ полягає в тому, що всі підписуючі органи не можуть позитивно гарантувати незалежність від усього. Насправді це не параноїк, але справа в тому, що ваш сертифікат ТОЛЬКО таємний, оскільки орган, що підписує, може це зробити. Самопідпис може бути більш секретним.
AgilePro

@AgilePro Використання серверного сертифіката аутентифікує сервер та вимагає зробити SSL захищеним, як зазначено в RFC 2246. Сертифікати взагалі не є секретними: тому залишити коментар не має сенсу.
Маркіз Лорн

6

Це вирішило моє питання,

Нам потрібно імпортувати церт на місцеву яву. Якщо ні, ми могли б отримати нижченаведений виняток.

    javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: Не вдалося побудувати шлях PKIX: sun.security.provider.certpath.SunCertPathBuilderException: не вдалося знайти дійсний шлях сертифікації до потрібної цілі
        at sun.security.ssl.Alerts.getSSLException (Alerts.java:192)
        at sun.security.ssl.SSLSocketImpl.fatal (SSLSocketImpl.java:1949)
        at sun.security.ssl.Handshaker.fatalSE (Handshaker.java:302)

SSLPOKE - це інструмент, за допомогою якого ви можете перевірити https-зв’язок із локальної машини.

Команда для перевірки підключення:

"%JAVA_HOME%/bin/java" SSLPoke <hostname> 443
    sun.security.validator.ValidatorException: Помилка побудови шляху PKIX: 
    sun.security.provider.certpath.SunCertPathBuilderException: не вдалося знайти дійсний шлях сертифікації до потрібної цілі
        at sun.security.validator.PKIXValidator.doBuild (PKIXValidator.java:387)
        at sun.security.validator.PKIXValidator.engineValidate (PKIXValidator.java:292)
        at sun.security.validator.Validator.validate (Validator.java:260)
        at sun.security.ssl.X509TrustManagerImpl.validate (X509TrustManagerImpl.java:324)
        at sun.security.ssl.X509TrustManagerImpl.checkTrusted (X509TrustManagerImpl.java:229)
        at sun.security.ssl.X509TrustManagerImpl.checkServerTrusted (X509TrustManagerImpl.java:124)
        at sun.security.ssl.ClientHandshaker.serverCertificate (ClientHandshaker.java:1496)
        at sun.security.ssl.ClientHandshaker.processMessage (ClientHandshaker.java:216)
        at sun.security.ssl.Handshaker.processLoop (Handshaker.java:1026)
        at sun.security.ssl.Handshaker.process_record (Handshaker.java:961)
        at sun.security.ssl.SSLSocketImpl.readRecord (SSLSocketImpl.java:1062)
        at sun.security.ssl.SSLSocketImpl.performInitialHandshake (SSLSocketImpl.java:1375)
        at sun.security.ssl.SSLSocketImpl.writeRecord (SSLSocketImpl.java:747)
        at sun.security.ssl.AppOutputStream.write (AppOutputStream.java:123)
        at sun.security.ssl.AppOutputStream.write (AppOutputStream.java:138)
        на SSLPoke.main (SSLPoke.java:31)
    Викликано: sun.security.provider.certpath.SunCertPathBuilderException: не вдалося знайти дійсний шлях сертифікації до 
    запитувана ціль
        at sun.security.provider.certpath.SunCertPathBuilder.build (SunCertPathBuilder.java:141)
        at sun.security.provider.certpath.SunCertPathBuilder.engineBuild (SunCertPathBuilder.java:126)
        на java.security.cert.CertPathBuilder.build (CertPathBuilder.java:280)
        at sun.security.validator.PKIXValidator.doBuild (PKIXValidator.java:382)
        ... ще 15
keytool -import -alias <anyname> -keystore "%JAVA_HOME%/jre/lib/security/cacerts" -file <cert path>

спочатку буде запропоновано "Ввести пароль зберігання ключів": changeitце пароль за замовчуванням. і, нарешті, підказка "Довіряти цьому сертифікату? [ні]:", надайте "так", щоб додати сертифікат до зберігання ключів.

Версія:

C:\tools>"%JAVA_HOME%/bin/java" SSLPoke <hostname> 443
Successfully connected    

5

Мені вдалося змусити його працювати лише з кодом, тобто не потрібно використовувати keytool:

import com.netflix.config.DynamicBooleanProperty;
import com.netflix.config.DynamicIntProperty;
import com.netflix.config.DynamicPropertyFactory;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.config.Registry;
import org.apache.http.config.RegistryBuilder;
import org.apache.http.conn.ssl.SSLContexts;
import org.apache.http.conn.ssl.TrustStrategy;
import org.apache.http.conn.ssl.X509HostnameVerifier;
import org.apache.http.impl.nio.client.CloseableHttpAsyncClient;
import org.apache.http.impl.nio.client.HttpAsyncClients;
import org.apache.http.impl.nio.conn.PoolingNHttpClientConnectionManager;
import org.apache.http.impl.nio.reactor.DefaultConnectingIOReactor;
import org.apache.http.impl.nio.reactor.IOReactorConfig;
import org.apache.http.nio.conn.NoopIOSessionStrategy;
import org.apache.http.nio.conn.SchemeIOSessionStrategy;
import org.apache.http.nio.conn.ssl.SSLIOSessionStrategy;

import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLException;
import javax.net.ssl.SSLSession;
import javax.net.ssl.SSLSocket;
import java.io.IOException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;

public class Test
{
    private static final DynamicIntProperty MAX_TOTAL_CONNECTIONS = DynamicPropertyFactory.getInstance().getIntProperty("X.total.connections", 40);
    private static final DynamicIntProperty ROUTE_CONNECTIONS = DynamicPropertyFactory.getInstance().getIntProperty("X.total.connections", 40);
    private static final DynamicIntProperty CONNECT_TIMEOUT = DynamicPropertyFactory.getInstance().getIntProperty("X.connect.timeout", 60000);
    private static final DynamicIntProperty SOCKET_TIMEOUT = DynamicPropertyFactory.getInstance().getIntProperty("X.socket.timeout", -1);
    private static final DynamicIntProperty CONNECTION_REQUEST_TIMEOUT = DynamicPropertyFactory.getInstance().getIntProperty("X.connectionrequest.timeout", 60000);
    private static final DynamicBooleanProperty STALE_CONNECTION_CHECK = DynamicPropertyFactory.getInstance().getBooleanProperty("X.checkconnection", true);

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

        SSLContext sslcontext = SSLContexts.custom()
                .useTLS()
                .loadTrustMaterial(null, new TrustStrategy()
                {
                    @Override
                    public boolean isTrusted(X509Certificate[] chain, String authType) throws CertificateException
                    {
                        return true;
                    }
                })
                .build();
        SSLIOSessionStrategy sslSessionStrategy = new SSLIOSessionStrategy(sslcontext, new AllowAll());

        Registry<SchemeIOSessionStrategy> sessionStrategyRegistry = RegistryBuilder.<SchemeIOSessionStrategy>create()
                .register("http", NoopIOSessionStrategy.INSTANCE)
                .register("https", sslSessionStrategy)
                .build();

        DefaultConnectingIOReactor ioReactor = new DefaultConnectingIOReactor(IOReactorConfig.DEFAULT);
        PoolingNHttpClientConnectionManager connectionManager = new PoolingNHttpClientConnectionManager(ioReactor, sessionStrategyRegistry);
        connectionManager.setMaxTotal(MAX_TOTAL_CONNECTIONS.get());
        connectionManager.setDefaultMaxPerRoute(ROUTE_CONNECTIONS.get());

        RequestConfig requestConfig = RequestConfig.custom()
                .setSocketTimeout(SOCKET_TIMEOUT.get())
                .setConnectTimeout(CONNECT_TIMEOUT.get())
                .setConnectionRequestTimeout(CONNECTION_REQUEST_TIMEOUT.get())
                .setStaleConnectionCheckEnabled(STALE_CONNECTION_CHECK.get())
                .build();

        CloseableHttpAsyncClient httpClient = HttpAsyncClients.custom()
                .setSSLStrategy(sslSessionStrategy)
                .setConnectionManager(connectionManager)
                .setDefaultRequestConfig(requestConfig)
                .build();

        httpClient.start();

        // use httpClient...
    }

    private static class AllowAll implements X509HostnameVerifier
    {
        @Override
        public void verify(String s, SSLSocket sslSocket) throws IOException
        {}

        @Override
        public void verify(String s, X509Certificate x509Certificate) throws SSLException {}

        @Override
        public void verify(String s, String[] strings, String[] strings2) throws SSLException
        {}

        @Override
        public boolean verify(String s, SSLSession sslSession)
        {
            return true;
        }
    }
}

1
Btw, я використовую httpasyncclient: 4.0.1
Jonas Bergström

Мені потрібно було щось подібне, @ JonasBergström, ваше рішення з SSLContext дуже допомагає.
EnterSB

8
Зауважте, що це рішення небезпечно.
Маркіз Лорн

Дякую вам, Йонас, ваше рішення вирішило проблему. Але я виявив, що створити перше з'єднання потрібно дуже тривалий час (3 - 5 с), після цього для кожного з'єднання потрібно лише 300-400 мс.
twcai

5

Джерелом цієї помилки в моєму екземплярі Apache 2.4 (використовуючи сертифікат підстановки Comodo) був неповний шлях до кореневого сертифіката, підписаного SHA-1. У виданому сертифікаті було кілька ланцюгів, і ланцюгу, що веде до кореневого сертифіката SHA-1, відсутній проміжний сертифікат . Сучасні браузери знають, як з цим впоратися, але Java 7 не справляється з цим за замовчуванням (хоча є кілька спрощених способів досягти цього в коді). Результатом є повідомлення про помилку, які виглядають ідентично випадку сертифікатів самопідписаних:

Caused by: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
    at sun.security.provider.certpath.SunCertPathBuilder.engineBuild(SunCertPathBuilder.java:196)
    at java.security.cert.CertPathBuilder.build(CertPathBuilder.java:268)
    at sun.security.validator.PKIXValidator.doBuild(PKIXValidator.java:380)
    ... 22 more

У цьому випадку повідомлення "не в змозі знайти дійсний шлях сертифікації до потрібного цілі" виробляється через відсутній проміжний сертифікат. Ви можете перевірити, який сертифікат відсутній, використовуючи тест SSL Labs проти сервера. Як тільки ви знайдете відповідний сертифікат, завантажте його та (якщо сервер знаходиться під вашим контролем), додайте його в комплект сертифікатів. Можна також імпортувати відсутній сертифікат локально. Розміщення цієї проблеми на сервері - більш загальне рішення проблеми.


ssllabs.com/ssltest - це рятівник, просто порівняйте його з робочою валідацією сертифіката.
kisna

5

Тільки для Windows виконайте наступні дії:

  1. У Chrome перейдіть до налаштувань.
  2. У Налаштуваннях натисніть Показати попередні налаштування.
  3. У розділі HTTPS / SSL натисніть Управління сертифікатами.
  4. Експортуйте свій сертифікат.
  5. У пошуку Windows (натискання клавіші Windows на клавіатурі) введіть java.
  6. Виберіть (Налаштувати Java) Варіант, який відкриє Панель управління Java
  7. Виберіть вкладку Безпека на Панелі керування Java
  8. Виберіть Керувати сертифікатами
  9. Клацніть Імпортувати
  10. На вкладці (Користувач) вибрано та тип сертифікату як (Довірені сертифікати)
  11. Натисніть кнопку імпорту та перегляньте завантажений сертифікат та імпортуйте його.

4

Для тих, хто любить Debian та попередньо упаковану Java:

sudo mkdir /usr/share/ca-certificates/test/  # don't mess with other certs
sudo cp ~/tmp/test.loc.crt /usr/share/ca-certificates/test/
sudo dpkg-reconfigure --force ca-certificates  # check your cert in curses GUI!
sudo update-ca-certificates --fresh --verbose

Не забудьте перевірити /etc/default/cacerts:

# enable/disable updates of the keystore /etc/ssl/certs/java/cacerts
cacerts_updates=yes

Щоб видалити cert:

sudo rm /usr/share/ca-certificates/test/test.loc.crt
sudo rm /etc/ssl/certs/java/cacerts
sudo update-ca-certificates --fresh --verbose

2

Це також може бути спричинено використанням церков GoDaddy з Java 7, які підписані за допомогою SHA2.

Chrome та всі інші веб-переглядачі починають зневажати сертифікати SSL, які підписані за допомогою SHA1, оскільки це не так захищено.

Більше інформації про проблему можна знайти тут , а також способи її вирішення на вашому сервері, якщо вам потрібно.


2

У мене була така ж проблема з помилками сертифікатів і через SNI, і http-клієнт, який я використовував, не реалізував SNI. Тож оновлення версії зробило свою роботу

   <dependency>
        <groupId>org.apache.httpcomponents</groupId>
        <artifactId>httpclient</artifactId>
        <version>4.3.6</version>
    </dependency>

2

ОНОВЛЕННЯ: Те, що перезавантаження допомогло, було випадковим (я сподівався, ура!). Справжня причина проблеми полягала в наступному: Коли Gradle спрямовується на використання конкретного сховища ключів, цей сховище ключів також має містити всі офіційні кореневі сертифікати. В іншому випадку він не може отримати доступ до бібліотек із звичайних сховищ. Що я повинен був зробити:

Імпортуйте самопідписаний сертифікат:

keytool -import -trustcacerts -alias myselfsignedcert -file /Users/me/Desktop/selfsignedcert.crt -keystore ./privateKeystore.jks

Додайте офіційні кореневі сертифікати:

keytool -importkeystore -srckeystore <java-home>/lib/security/cacerts -destkeystore ./privateKeystore.jks

Можливо, демона Градле теж заважав. Можливо, варто вбити всіх знайдених демонів, ./gradlew --statusякщо речі почнуть виглядати похмурими.

ОРИГІНАЛЬНІ ПОСТАВКИ:

Ніхто не повірить у це, я знаю. Однак, якщо все інше не вдалося, спробуйте: Після перезавантаження мого Mac проблеми не було. Grrr

Передумови: ./gradlew jar продовжував давати мені "не в змозі знайти дійсний шлях сертифікації до потрібної цілі"

Я застряг із самопідписаним сертифікатом, збереженим із браузера, імпортованим у privateKeystore.jks. Потім доручив Gradle працювати з privateKeystore.jks:

org.gradle.jvmargs=-Djavax.net.debug=SSL -Djavax.net.ssl.trustStore="/Users/me/IntelliJ/myproject/privateKeystore.jks"  -Djavax.net.ssl.trustStorePassword=changeit

Як вже було сказано, це спрацювало лише після перезавантаження.


2

AVG версія 18.1.3044 (для Windows 10) заважає моїй місцевій програмі Spring.

Рішення: увійдіть у розділ AVG під назвою "Веб та електронна пошта" та відключіть "захист електронної пошти". AVG блокує сертифікат, якщо сайт не захищений.


2

Переконайтесь, що https://176.66.3.69:6443/ має дійсний сертифікат. ви можете перевірити це спочатку через браузер, https не захищеноякщо він працює в браузері, він буде працювати в Java.

що працює на мене


І що робити, якщо браузер також скаржиться?
Хрещений батько

спробуйте встановити сертифікат
Amr Ibrahim

2

Існує багато способів вирішити це ...

Один із способів - встановити сертифікати TrustStore у файл зберігання ключів і поставити його в шлях програми та встановити ці системні властивості в основному методі:

public static void main(String[] args) {
  System.setProperty("javax.net.ssl.trustStore", "trust-store.jks");
  System.setProperty("javax.net.ssl.trustStorePassword", "TrustStore");
  ...
}

Інший спосіб - розмістити сховище клавіш як файл ресурсів всередині файлу банку jar і завантажити його:

public static SSLContext createSSLContext(String resourcePath, String pass) throws NoSuchAlgorithmException, KeyStoreException, IOException, CertificateException, UnrecoverableKeyException, KeyManagementException {
  // initialise the keystore
  final char[] password = pass.toCharArray();
  KeyStore ks = KeyStore.getInstance("JKS");
  ks.load(ThisClass.class.getResourceAsStream(resourcePath
  ), password);

  // Setup the key manager factory.
  KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
  kmf.init(ks, password);

  // Setup the trust manager factory.
  TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509");
  tmf.init(ks);

  SSLContext sslc = SSLContext.getInstance("TLS");
  sslc.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
  return sslc;
}

public static void main(String[] args) {
  SSLContext.setDefault(
    createSSLContext("/trust-store.jks", "TrustStore"));
  ...
}

У Windows також можна спробувати це рішення: https://stackoverflow.com/a/59056537/980442


Я створив файл зберігання ключів з файлу CA сертифіката .crtтаким чином:

keytool -import -alias ca -keystore trust-store.jks -storepass TrustStore -trustcacerts -file ca.crt

FYI: https://docs.oracle.com/javadb/10.8.3.0/adminguide/cadminsslclient.html


1

У вас є два варіанти, імпортуйте самопідписаний сертифікат у сховище ключів Java для кожного jvm, на якому буде запущене програмне забезпечення, або спробуйте недійсну заводську ssl:

jdbc:postgresql://myserver.com:5432/mydatabasename?ssl=true&sslfactory=org.postgresql.ssl.NonValidatingFactory

1

Мав таке питання, як це зображення.

введіть тут опис зображення

Спробував кілька рішень. Але виявив, що навіть якщо це той самий проект, коли він знаходиться на робочому місці інших, це абсолютно добре. Не потрібні додаткові налаштування. Тож ми здогадалися, що це питання навколишнього середовища. Ми спробували змінити версію JDK, IDE, але не вийшло. На розслідування знадобилося близько 4 годин, поки ми не спробували відповідь, що найкраще оцінюється. Я не знайшов помилку, згадану у цій відповіді, але через свій браузер дізнався про HTTP URL (замок), що існувала сертифікація Чарльза. Тоді я зрозумів, що мій шарл був весь час. Поки я це відключив, він працює добре.

Тому я залишив свій досвід, який може бути корисним для вашої справи.


0

У моєму випадку я запускаю MacOs High Sierra з Java 1.6. Файл cacert знаходиться в іншому місці, ніж зазначено вище у відповіді Габе Мартіна-Демпесі. Файл cacert також був пов’язаний з іншим місцем (/ Бібліотека / Інтернет Plug-Ins / JavaAppletPlugin.plugin / Зміст / Головна / lib / безпека / cacerts).

Використовуючи FireFox, я експортував сертифікат із відповідного веб-сайту в локальний файл під назвою "exportedCertFile.crt". Звідти я використовував keytool для переміщення сертифіката у файл cacert. Це вирішило проблему.

bash-3.2# cd /Library/Java/JavaVirtualMachines/1.6.0.jdk/Contents/Home/lib/security/
bash-3.2# keytool -importcert -file ~/exportedCertFile.crt -alias example -keystore cacerts -storepass changeit

0

спочатку скачайте сертифікат ssl, потім ви можете перейти до свого шляху bin java, виконавши команду нижче в консолі.

C:\java\JDK1.8.0_66-X64\bin>keytool -printcert -file C:\Users\lova\openapi.cer -keystore openapistore

-1

У моєму випадку я мав як брелок, так і довірений магазин, який мав однаковий сертифікат, тому видалення довіри допомогло. Іноді ланцюжок сертифікатів може бути проблемою, якщо у вас є кілька копій сертифікатів.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.