Устранение исключения javax.net.ssl.SSLHandshakeException: sun.security.validator.Исключение ValidatorException: ошибка при построении пути PKIX?
Редактировать : Я попытался отформатировать вопрос и принятый ответ более презентабельным образом в своем блоге.
Вот исходная проблема.
Я получаю эту ошибку:
подробное сообщение sun.security.validator.Исключение ValidatorException: ошибка построения пути PKIX:
sun.security.provider.certpath.Исключение SunCertPathBuilderException: не удается найти действительный путь сертификации к запрошенной целипричина исключения javax.net.ssl.SSLHandshakeException: sun.security.validator.Исключение ValidatorException: ошибка построения пути PKIX: sun.security.provider.certpath.Исключение SunCertPathBuilderException: не удается найти действительный путь сертификации к запрошенной цели
Я использую Tomcat 6 в качестве веб-сервера. У меня есть два веб-приложения HTTPS, установленные на разных Tomcats на разных портах, но на одном компьютере. Скажем, App1 (порт 8443) и App2 (порт 443). App1 подключается к App2. Когда App1 подключается к App2, я получаю указанную выше ошибку. Я знаю, что это очень распространенная ошибка, поэтому сталкивался со многими решениями на разных форумах и сайтах. У меня есть приведенная ниже запись в server.xml
обоих Tomcats:
keystoreFile="c:/.keystore"
keystorePass="changeit"
Каждый сайт говорит об одной и той же причине, по которой сертификата, предоставленного app2, нет в доверенном хранилище jvm app1. Похоже, это также верно, когда я пытался перейти по тому же URL-адресу в браузере IE, это работает (при прогреве возникает проблема с сертификатом безопасности этого веб-сайта. Здесь я говорю перейти на этот веб-сайт). Но когда Java-клиент нажимает на тот же URL (в моем случае) Я получаю приведенную выше ошибку. Поэтому, чтобы поместить ее в truststore, я попробовал эти три варианта:
Вариант 1
System.setProperty("javax.net.ssl.trustStore", "C:/.keystore");
System.setProperty("javax.net.ssl.trustStorePassword", "changeit");
Вариант 2
Настройка ниже в переменной окружения
CATALINA_OPTS -- param name
-Djavax.net.ssl.trustStore=C:\.keystore -Djavax.net.ssl.trustStorePassword=changeit ---param value
Вариант 3
Настройка ниже в переменной окружения
JAVA_OPTS -- param name
-Djavax.net.ssl.trustStore=C:\.keystore -Djavax.net.ssl.trustStorePassword=changeit ---param value
Результат
Но ничего не сработало.
Что наконец сработало, так это выполнение подхода Java, предложенного в Как обрабатывать недействительные SSL-сертификаты с помощью Apache HttpClient? с помощью Pascal Thivent, т.е. выполнение программы InstallCert.
Но этот подход хорош для установки devbox, но я не могу использовать его в производственной среде.
Мне интересно, почему три подхода, упомянутые выше, не сработали, когда я упомянул те же значения в server.xml
сервера App2 и те же значения в truststore, установив
System.setProperty("javax.net.ssl.trustStore", "C:/.keystore") and System.setProperty("javax.net.ssl.trustStorePassword", "changeit");
в программе App1.
Для получения дополнительной информации вот как я устанавливаю соединение:
URL url = new URL(urlStr);
URLConnection conn = url.openConnection();
if (conn instanceof HttpsURLConnection) {
HttpsURLConnection conn1 = (HttpsURLConnection) url.openConnection();
conn1.setHostnameVerifier(new HostnameVerifier() {
public boolean verify(String hostname, SSLSession session) {
return true;
}
});
reply.load(conn1.getInputStream());
Переведено автоматически
Ответ 1
Вам необходимо добавить сертификат для App2 в файл truststore используемой JVM, расположенный по адресу $JAVA_HOME\lib\security\cacerts
.
Сначала вы можете проверить, находится ли ваш сертификат уже в truststore, выполнив следующую команду: keytool -list -keystore "$JAVA_HOME/jre/lib/security/cacerts"
(вам не нужно вводить пароль)
Если ваш сертификат отсутствует, вы можете получить его, загрузив в свой браузер и добавив в truststore с помощью следующей команды:
keytool -import -noprompt -trustcacerts -alias <AliasName> -file <certificate> -keystore <KeystoreFile> -storepass <Password>
Пример:
keytool -import -noprompt -trustcacerts -alias myFancyAlias -file /path/to/my/cert/myCert.cer -keystore /path/to/my/jdk/jre/lib/security/cacerts/keystore.jks -storepass changeit
После импорта вы можете снова запустить первую команду, чтобы проверить, был ли добавлен ваш сертификат.
Информацию Sun / Oracle можно найти здесь.
Ответ 2
Исключение javax.net.ssl.SSLHandshakeException: sun.security.validator.Исключение ValidatorException: ошибка построения пути PKIX: sun.security.provider.certpath.Исключение SunCertPathBuilderException: не удается найти действительный путь сертификации к запрошенной цели
• Когда я получил сообщение об ошибке, я попытался найти в Google значение выражения и обнаружил, что эта проблема возникает, когда сервер изменяет свой HTTPS SSL-сертификат, а наша более старая версия java не распознает корневой центр сертификации (CA).
• Если вы можете получить доступ к URL-адресу HTTPS в своем браузере, то можно обновить Java для распознавания корневого центра сертификации.
• В вашем браузере перейдите по URL HTTPS, к которому Java не удалось получить доступ. Щелкните цепочку сертификатов HTTPS (в Internet Explorer есть значок блокировки), нажмите на блокировку, чтобы просмотреть сертификат.
• Перейдите в раздел “Сведения” о сертификате и “Скопируйте в файл". Скопируйте его в формате Base64 (.cer). Он будет сохранен на вашем рабочем столе.
• Установите сертификат, игнорируя все предупреждения.
• Вот как я собрал информацию о сертификате URL-адреса, к которому я пытался получить доступ.
Теперь мне пришлось сделать так, чтобы моя версия java знала о сертификате, чтобы в дальнейшем она не отказывалась распознавать URL. В этой связи я должен упомянуть, что я погуглил, что информация о корневом сертификате по умолчанию хранится в папке JDK \ jre \ lib \ security, а пароль для доступа по умолчанию: changeit.
Для просмотра информации cacerts необходимо выполнить следующие процедуры:
• Нажмите кнопку "Пуск" -> "Выполнить".
• Введите cmd. Откроется командная строка (возможно, вам потребуется открыть ее от имени администратора).
• Перейдите в свой Java/jreX/bin
каталог
• Введите следующее
keytool -list -keystore D:\Java\jdk1.5.0_12\jre\lib\security\cacerts
Он выдает список текущих сертификатов, содержащихся в хранилище ключей. Это выглядит примерно так:
C:\Documents and Settings\NeelanjanaG>keytool -list -keystore D:\Java\jdk1.5.0_12\jre\lib\security\cacerts
Enter keystore password: changeit
Keystore type: jks
Keystore provider: SUN
Your keystore contains 44 entries
verisignclass3g2ca, Mar 26, 2004, trustedCertEntry,
Certificate fingerprint (MD5): A2:33:9B:4C:74:78:73:D4:6C:E7:C1:F3:8D:CB:5C:E9
entrustclientca, Jan 9, 2003, trustedCertEntry,
Certificate fingerprint (MD5): 0C:41:2F:13:5B:A0:54:F5:96:66:2D:7E:CD:0E:03:F4
thawtepersonalbasicca, Feb 13, 1999, trustedCertEntry,
Certificate fingerprint (MD5): E6:0B:D2:C9:CA:2D:88:DB:1A:71:0E:4B:78:EB:02:41
addtrustclass1ca, May 1, 2006, trustedCertEntry,
Certificate fingerprint (MD5): 1E:42:95:02:33:92:6B:B9:5F:C0:7F:DA:D6:B2:4B:FC
verisignclass2g3ca, Mar 26, 2004, trustedCertEntry,
Certificate fingerprint (MD5): F8:BE:C4:63:22:C9:A8:46:74:8B:B8:1D:1E:4A:2B:F6
• Теперь мне пришлось включить ранее установленный сертификат в cacerts.
• Для этого выполняется следующая процедура:
keytool -import -noprompt -trustcacerts -alias ALIASNAME -file FILENAME_OF_THE_INSTALLED_CERTIFICATE -keystore PATH_TO_CACERTS_FILE -storepass PASSWORD
Если вы используете Java 7:
keytool -importcert -trustcacerts -alias ALIASNAME -file PATH_TO_FILENAME_OF_THE_INSTALLED_CERTIFICATE -keystore PATH_TO_CACERTS_FILE -storepass changeit
• Затем он добавит информацию о сертификате в файл cacert.
Это решение, которое я нашел для исключения, упомянутого выше!!
Ответ 3
Как это работает в Tomcat 7
Я хотел поддержать самозаверяющий сертификат в приложении Tomcat, но следующий фрагмент не сработал
import java.io.DataOutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
public class HTTPSPlayground {
public static void main(String[] args) throws Exception {
URL url = new URL("https:// ... .com");
HttpURLConnection httpURLConnection = (HttpURLConnection) url.openConnection();
httpURLConnection.setRequestMethod("POST");
httpURLConnection.setRequestProperty("Accept-Language", "en-US,en;q=0.5");
httpURLConnection.setDoOutput(true);
DataOutputStream wr = new DataOutputStream(httpURLConnection.getOutputStream());
String serializedMessage = "{}";
wr.writeBytes(serializedMessage);
wr.flush();
wr.close();
int responseCode = httpURLConnection.getResponseCode();
System.out.println(responseCode);
}
}
это то, что решило мою проблему:
1) Загрузите .crt
файл
echo -n | openssl s_client -connect <your domain>:443 | sed -ne '/-BEGIN CERTIFICATE-/,/-END CERTIFICATE-/p' > ~/<your domain>.crt
- замените
<your domain>
своим доменом (например,jossef.com
)
2) Примените .crt
файл в cacerts
хранилище сертификатов Java
keytool -import -v -trustcacerts -alias <your domain> -file ~/<your domain>.crt -keystore <JAVA HOME>/jre/lib/security/cacerts -keypass changeit -storepass changeit
- замените
<your domain>
своим доменом (например,jossef.com
) - замените
<JAVA HOME>
на ваш домашний каталог java
3) Взломать его
Несмотря на то, что iv'e установил мой сертификат в Java
хранилища сертификатов по умолчанию, Tomcat игнорирует это (похоже, он не настроен на использование хранилищ сертификатов Java по умолчанию).
Чтобы взломать это, добавьте следующее где-нибудь в свой код:
String certificatesTrustStorePath = "<JAVA HOME>/jre/lib/security/cacerts";
System.setProperty("javax.net.ssl.trustStore", certificatesTrustStorePath);
// ...
Ответ 4
В моем случае проблема заключалась в том, что веб-сервер отправлял только сертификат и промежуточный CA, а не корневой CA. Добавление этой опции JVM решило проблему: -Dcom.sun.security.enableAIAcaIssuers=true
Доступна поддержка метода доступа caIssuers расширения доступа к полномочной информации. По умолчанию оно отключено для обеспечения совместимости и может быть включено путем установки системному свойству
com.sun.security.enableAIAcaIssuers
значения true.Если установлено значение true, реализация Sun PKIX CertPathBuilder использует информацию в расширении AIA сертификата (в дополнение к указанным хранилищам сертификатов) для поиска выдавшего сертификат CA, при условии, что это URI типа ldap, http или ftp.