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
neztreh
источник
2
Однажды я получил эту ошибку и связался с нашей службой безопасности, и оказалось, что мне пришлось исправлять JAR, который мы использовали, поскольку наша команда использовала устаревший, предоставленный компанией. Просто к вашему сведению для всех, кто может быть в подобной ситуации.
kayleeFrye_onDeck

Ответы:

215

Проблема появляется, когда ваш сервер имеет самозаверяющий сертификат. Чтобы обойти это, вы можете добавить этот сертификат в список доверенных сертификатов вашей JVM.

В этой статье автор описывает, как получить сертификат из вашего браузера и добавить его в файл cacerts вашей 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
это не сработало для меня. У меня установлен рут и сертификат цепочки, но Tomcat-7 по-прежнему сообщает об исключении validatorException, вызванном «не удается найти действительный путь сертификации к запрошенной цели», каким-либо способом отладить это?
Черувим
Проблема также появляется с сертификатом, подписанным кем-то еще, которому не доверяют.
Маркиз Лорн
Большой! Оно работает! Только не забывайте, что у вас могут быть как jre, так и jdk, и оба они cacertsдолжны быть обновлены
Дима Фомин
В моем случае корневой CA был там, но не следующий CA отключен. Добавление следующего CA сделало свое дело - спасибо.
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:443 -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 при получении сертификата
Patrik Beck
46

У меня была та же проблема с действующим подписанным сертификатом подстановочного знака от Symantec.

Сначала попробуйте запустить ваше Java-приложение с -Djavax.net.debug = SSL, чтобы увидеть, что на самом деле происходит.

Я закончил тем, что импортировал промежуточный сертификат, который вызывал разрыв цепочки сертификатов.

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

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

keytool -import -keystore ../jre/lib/security/cacerts -trustcacerts -alias "VeriSign Class 3 International Server CA - G3" -file /pathto/SVRIntlG3.cer
Стефан Аудмайер
источник
Это было так:
Кисна
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
Кисна
И, конечно же, официальная статья по устранению проблем с SSL: docs.oracle.com/javase/7/docs/technotes/guides/security/jsse/… blogs.oracle.com/java-platform-group/entry/…
Кисна
У меня была такая же проблема, это очень полезно, но в моем случае вам нужно было только добавить сертификат сервера в файл cacerts версии JDK
Pigritia
Пожалуйста, имейте в виду, что существует другой инструмент под названием portecle, который может открыть файл cacert (хранилище сертификатов) и легко импортировать сертификат. Просто не забудьте сохранить файл cacert впоследствии.
24
41
  1. Экспортируйте сертификат SSL с помощью Firefox. Вы можете экспортировать его, нажав URL-адрес в браузере, а затем выберите опцию для экспорта сертификата. Давайте предположим, что имя файла сертификата - your.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 Martin-Dempesy мне помог. И я написал небольшой сценарий, связанный с этим. Использование очень просто.

Установить сертификат с хоста:

> 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;
bhdrk
источник
Работает без нареканий. Прекрасная работа! , Вот как это работает: запустите службу SSL (если она не запущена) и выполните команду, как описано (например ./java-cert-importer.sh example.com 1234). Вот и все.
Лепе
1
Прекрасно работает. Я получал сообщение об ошибке на сервере Jenkins, подключающемся к внешнему API, который изменяет его сертификат и дает сбой при сборке. Это решает мою проблему
user9869932
Во-первых, Oracle должен был предоставить что-то подобное или никогда не создавать свое собственное ужасное решение SSL. Обработка сертификата SSL должна быть задачей операционной системы.
Вольфганг
17

Цитата из Нет больше «невозможно найти действительный путь сертификации для запрашиваемой цели»

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

Проверка сертификата является очень важной частью безопасности SSL, но я не пишу эту запись, чтобы объяснить детали. Если вы заинтересованы, вы можете начать с чтения википедии. Я пишу эту запись, чтобы показать простой способ общения с этим хостом с помощью тестового сертификата, если вы действительно этого хотите.

По сути, вы хотите добавить сертификат сервера в хранилище ключей с вашими доверенными сертификатами

Попробуйте приведенный там код. Это может помочь.

Nishant
источник
5
Часть о «Проверка сертификата является очень важной частью безопасности SSL» не обязательно верна. SSL дает вам две гарантии: (1) что ваше общение является конфиденциальным, и (2) что вы разговариваете с сервером, который известен АНБ. (:-) Иногда вам важна только конфиденциальность разговора, а затем Самоподписанная сертификация в порядке. См. Social-biz.org/2011/10/16/the-anti-ssl-conspiracy
AgilePro
@AgilePro SSL дает вам четыре гарантии: аутентификация, конфиденциальность, целостность и возможность авторизации. Это не дает вам никаких гарантий, что вы разговариваете с сервером, известным АНБ. Забота только о конфиденциальности без аутентификации является противоречием в терминах.
маркиз Лорн
@EJP Согласитесь, что если вы используете клиентский сертификат, вы можете получить аутентификацию, и я предполагаю возможность авторизации ... но большинство случаев использования не с клиентским сертификатом. Как бы вы назвали разницу между «самоподписанным» сертификатом и сертификатом от подписывающего органа? Дает ли подписывающая власть "целостность". Моя шутка о АНБ заключается в том, что все подписывающие органы не могут положительно гарантировать независимость от всего. На самом деле это не параноик, но дело в том, что ваш сертификат является настолько секретным, насколько его могут подписать подписывающие органы. Самоподписанный может быть более секретным.
AgilePro
@AgilePro Использование сертификата сервера аутентифицирует сервер и требуется для обеспечения безопасности SSL, как указано в RFC 2246. Сертификаты вообще не являются секретными: поэтому оставшаяся часть вашего комментария не имеет смысла.
маркиз Лорн
6

Это решило мою проблему,

Нам нужно импортировать сертификат на локальную Java. Если нет, мы могли бы получить следующее исключение.

    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- пароль по умолчанию. и, наконец, приглашение «Доверять этому сертификату? [нет]:», укажите «да», чтобы добавить сертификат в хранилище ключей.

Verfication:

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
Кстати, я использую httpasyncclient: 4.0.1
Йонас Бергстрем
Мне нужно что-то подобное, @ JonasBergström, ваше решение с SSLContext очень поможет.
EnterSB
8
Обратите внимание, что это решение небезопасно.
Маркиз Лорн
Спасибо Джонас, ваше решение решило проблему. Но я обнаружил, что создание первого соединения занимает очень много времени (3-5), после этого каждому соединению требуется всего 300-400 мс.
Двенадцатое
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 на сервере. Как только вы найдете соответствующий сертификат, загрузите его и (если сервер находится под вашим контролем) добавьте его в комплект сертификатов. Кроме того, вы можете импортировать отсутствующий сертификат локально. Размещение этой проблемы на сервере является более общим решением проблемы.

vallismortis
источник
ssllabs.com/ssltest - спаситель, просто сравните его с проверкой действующего сертификата.
Кисна
5

Только для Windows, выполните следующие действия:

  1. В Chrome зайдите в настройки.
  2. В настройках нажмите Показать предварительные настройки.
  3. Под HTTPS / SSL Нажмите на Управление сертификатами.
  4. Экспортируйте ваш сертификат.
  5. В поиске Windows (Нажатие клавиши Windows на клавиатуре) введите Java.
  6. Выберите (настроить Java) параметр, который откроет панель управления Java
  7. Выберите вкладку «Безопасность» в панели управления Java.
  8. Выберите Управление сертификатами
  9. Нажмите Импорт
  10. На вкладке (Пользователь) выбран тип сертификата (Доверенные сертификаты)
  11. Нажмите кнопку импорта и перейдите к загруженному сертификату и импортируйте его.
Praveen
источник
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

Чтобы удалить сертификат:

sudo rm /usr/share/ca-certificates/test/test.loc.crt
sudo rm /etc/ssl/certs/java/cacerts
sudo update-ca-certificates --fresh --verbose
gavenkoa
источник
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

Может быть, Демон Gradle тоже помешал. Возможно, стоит убить всех найденных демонов, ./gradlew --statusесли все начнет выглядеть мрачно.

ОРИГИНАЛЬНАЯ ПУБЛИКАЦИЯ:

Никто не поверит этому, я знаю. Тем не менее, если ничего не помогает, попробуйте: после перезагрузки моего Mac проблема исчезла. Хмм.

Справочная информация: ./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

Как уже упоминалось, это работало только после перезагрузки.

StaticNoiseLog
источник
2

AVG версии 18.1.3044 (с Windows 10) мешает моему локальному приложению Spring.

Решение: войдите в раздел AVG под названием «Интернет и электронная почта» и отключите «Защита электронной почты». AVG блокирует сертификат, если сайт не защищен.

Insoft
источник
2

Убедитесь, что https://176.66.3.69:6443/ имеет действительный сертификат. Вы можете проверить это через браузер, во-первых, https не является безопаснымесли он работает в браузере, он будет работать в Java.

это работает для меня

Амр Ибрагим
источник
А что мне делать, если браузер тоже жалуется?
Крестный отец
попробуйте установить сертификат
Амр Ибрагим
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


Я создал файл хранилища ключей из .crtфайла CA центра сертификации следующим образом:

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

К вашему сведению: 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 (блокировка) был сертифицирован Чарльзом. Потом я понял, что мои чарльзы были включены все время. Пока я это выключил, все работает нормально.

Поэтому я оставил свой опыт, который мог бы помочь вашему делу.

Lalaphoon
источник
0

В моем случае я использую MacOs High Sierra с Java 1.6. Файл cacert находится в другом месте, чем указано в ответе Гейба Мартина-Демпси. Файл cacert также уже был связан с другим местоположением (/ Library / Internet Plug-Ins / JavaAppletPlugin.plugin / Contents / Home / lib / security / 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-сертификат, затем вы можете перейти к своему пути в java bin, выполнив в консоли следующую команду.

C:\java\JDK1.8.0_66-X64\bin>keytool -printcert -file C:\Users\lova\openapi.cer -keystore openapistore
Лова Читтумури
источник
-1

В моем случае у обоих хранилищ ключей и хранилищ доверенных сертификатов был один и тот же сертификат, поэтому удаление хранилища доверенных сертификатов помогло. Иногда цепочка сертификатов может быть проблемой, если у вас есть несколько копий сертификатов.

Умный кодер
источник