Resolvendo javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: o caminho do PKIX falhou Erro?

Edit: – Tentei formatar a pergunta e aceito a resposta de forma mais apresentável no meu Blog

Aqui está a edição original:

Estou recebendo este erro

mensagem detalhada sun.security.validator.ValidatorException: falha na construção do caminho PKIX:
sun.security.provider.certpath.SunCertPathBuilderException: não foi possível encontrar o caminho de certificação válido para o destino solicitado

cause javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: Falha na criação do caminho PKIX: sun.security.provider.certpath.SunCertPathBuilderException: não foi possível encontrar o caminho de certificação válido para o destino solicitado

Eu estou usando o tomcat 6 como servidor web. Eu tenho dois https webbapplication instalado no tomcat diferente na porta diferente, mas na mesma máquina. Diga App1(port 8443) e App2(port 443) . App1 conecta ao App2 . Quando o App1 conecta ao App2 i obtenho o erro acima. Eu sei que isso é um erro muito comum, então deparei com muitas soluções em diferentes fóruns e sites. Eu tenho abaixo input em server.xml de ambos tomcat ou seja

 keystoreFile="c:/.keystore" keystorePass="changeit" 

Todo site diz o mesmo motivo pelo qual o certificado fornecido pelo app2 não está no armazenamento confiável do app1 jvm. Isso parece ser verdade também quando eu cansado de acertar a mesma URL no navegador IE, ele funciona (com o aquecimento, Há um problema com o certificado de segurança deste site. Aqui eu digo continuar a este site) Mas quando o mesmo URL é atingido por cliente java (no meu caso). Então eu recebo o erro acima. Então, para colocá-lo em trustore eu tentei essas opções de trees ou seja

Opção 1

 System.setProperty("javax.net.ssl.trustStore", "C:/.keystore"); System.setProperty("javax.net.ssl.trustStorePassword", "changeit"); 

Opção2 Definindo abaixo na variável de ambiente

 CATALINA_OPTS -- param name -Djavax.net.ssl.trustStore=C:\.keystore -Djavax.net.ssl.trustStorePassword=changeit ---param value 

Opção3 Definindo abaixo na variável de ambiente

 JAVA_OPTS -- param name -Djavax.net.ssl.trustStore=C:\.keystore -Djavax.net.ssl.trustStorePassword=changeit ---param value 

Mas nada funcionou .

O que finalmente funcionou está executando a abordagem Java sugerida em Como lidar com certificados SSL inválidos com o Apache HttpClient? por Pascal Thivent, ou seja, executando o programa InstallCert.

Mas esta abordagem é boa para a configuração do devbox, mas eu não posso usá-lo no ambiente de produção.

Eu estou querendo saber por que três abordagens mencionadas acima não funcionaram quando eu mencionei os mesmos valores em server.xml do servidor app2 e os mesmos valores no server.xml app2 , definindo

System.setProperty("javax.net.ssl.trustStore", "C:/.keystore") and System.setProperty("javax.net.ssl.trustStorePassword", "changeit");

no programa app1 .

Para mais informações, é assim que estou fazendo a conexão

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

É necessário include o certificado para App2 no arquivo de armazenamento confiável da JVM usada, localizado em %JAVA_HOME%\lib\security\cacerts .

Primeiro, você pode verificar se seu certificado já está no truststore executando o seguinte comando: keytool -list -keystore "%JAVA_HOME%/jre/lib/security/cacerts" (não é necessário fornecer uma senha)

Se o seu certificado estiver faltando, você pode obtê-lo fazendo o download com seu navegador e adicioná-lo ao armazenamento confiável com o seguinte comando:

keytool -import -noprompt -trustcacerts -alias -file -keystore -storepass

Depois de importar você pode executar o primeiro comando novamente para verificar se seu certificado foi adicionado.

As informações da Sun / Oracle podem ser encontradas aqui .

javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: falha na criação do caminho PKIX: sun.security.provider.certpath.SunCertPathBuilderException: não foi possível encontrar o caminho de certificação válido para o destino solicitado

• Quando recebi o erro, tentei descobrir o significado da expressão no Google e descobri que esse problema ocorre quando um servidor altera seu certificado HTTPS SSL e nossa versão mais antiga do java não reconhece a autoridade de certificação raiz (CA). .

• Se você puder acessar o URL HTTPS em seu navegador, será possível atualizar o Java para reconhecer a CA raiz.

• No seu navegador, vá para o URL HTTPS que o Java não pôde acessar. Clique na cadeia de certificados HTTPS (há um ícone de cadeado no Internet Explorer), clique no cadeado para visualizar o certificado.

• Vá para “Detalhes” do certificado e “Copiar para arquivo”. Copie-o no formato Base64 (.cer) . Ele será salvo na sua área de trabalho.

• Instale o certificado ignorando todos os alertas.

• Foi assim que reuni as informações do certificado da URL que eu estava tentando acessar.

Agora eu tive que fazer minha versão de java para saber sobre o certificado para que, além disso, não se recuse a reconhecer o URL. A esse respeito, devo mencionar que eu pesquisei que as informações do certificado raiz permaneçam, por padrão, no local de \ jre \ lib \ security do JDK, e a senha padrão para access é: changeit.

Para visualizar as informações do cacerts, os procedimentos a seguir são os seguintes:

• Clique no botão Iniciar -> Executar

• Digite cmd. O prompt de comando é aberto (talvez seja necessário abri-lo como administrador).

• Vá para o diretório Java/jreX/bin

• Digite o seguinte

keytool -list -keystore D: \ Java \ jdk1.5.0_12 \ jre \ lib \ security \ cacerts

Fornece a lista dos certificados atuais contidos no keystore. Parece algo como isto:

C: \ Documentos e configurações \ NeelanjanaG> keytool -list -keystore D: \ Java \ jdk1.5.0_12 \ jre \ lib \ security \ cacerts

Digite a senha do keystore: changeit

Tipo de armazenamento de chaves: jks

Fornecedor de keystore: SUN

Seu keystore contém 44 inputs

verisignclass3g2ca, 26 de março de 2004, trustedCertEntry,

Impressão digital do certificado (MD5): A2: 33: 9B: 4C: 74: 78: 73: D4: 6C: E7: C1: F3: 8D: CB: 5C: E9

entrustclientca, 9 de janeiro de 2003, trustedCertEntry,

Impressão digital do certificado (MD5): 0C: 41: 2F: 13: 5B: A0: 54: F5: 96: 66: 2D: 7E: CD: 0E: 03: F4

thawtepersonalbasicca, 13 de fevereiro de 1999, trustedCertEntry,

Impressão digital do certificado (MD5): E6: 0B: D2: C9: CA: 2D: 88: DB: 1A: 71: 0E: 4B: 78: EB: 02: 41

addtrustclass1ca, 1 de maio de 2006, trustedCertEntry,

Impressão digital do certificado (MD5): 1E: 42: 95: 02: 33: 92: 6B: B9: 5F: C0: 7F: DA: D6: B2: 4B: FC

verisignclass2g3ca, 26 de março de 2004, trustedCertEntry,

Impressão digital do certificado (MD5): F8: BE: C4: 63: 22: C9: A8: 46: 74: 8B: B8: 1D: 1E: 4A: 2B: F6

• Agora eu tinha que include o certificado previamente instalado nos cacerts.

• Para isto, segue o procedimento:

keytool –import –noprompt –trustcacerts –alias ALIASNAME -arquivo FILENAME_OF_THE_INSTALLED_CERTIFICATE -keystore PATH_TO_CACERTS_FILE -storepass PASSWORD

Se você estiver usando o Java 7:

keytool –importcert –trustcacerts –alias ALIASNAME -arquivo PATH_TO_FILENAME_OF_THE_INSTALLED_CERTIFICATE -keystore PATH_TO_CACERTS_FILE -storepass changeit

• Ele adicionará as informações do certificado no arquivo cacert.

É a solução que encontrei para a exceção mencionada acima !!

Como trabalhar no Tomcat 7

Eu queria oferecer suporte a um certificado autoassinado em um aplicativo Tomcat, mas o snippet a seguir não funcionou

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

foi isso que resolveu meu problema:

1) Faça o download do arquivo .crt

 echo -n | openssl s_client -connect :443 | sed -ne '/-BEGIN CERTIFICATE-/,/-END CERTIFICATE-/p' > ~/.crt 
  • substitua pelo seu domínio (por exemplo, jossef.com )

2) Aplique o arquivo .crt no armazenamento de certificados cacerts do Java

 keytool -import -v -trustcacerts -alias  -file ~/.crt -keystore /jre/lib/security/cacerts -keypass changeit -storepass changeit 
  • substitua pelo seu domínio (por exemplo, jossef.com )
  • substitua pelo seu diretório home java

3) Hackeá-lo

Apesar de ter instalado meu certificado nos armazenamentos de certificados padrão do Java , o Tomcat o ignora (parece que não está configurado para usar os armazenamentos de certificados padrão do Java).

Para hackear isso, adicione o seguinte em algum lugar em seu código:

 String certificatesTrustStorePath = "/jre/lib/security/cacerts"; System.setProperty("javax.net.ssl.trustStore", certificatesTrustStorePath); // ... 

Meu arquivo cacerts estava totalmente vazio. Eu resolvi isso copiando o arquivo cacerts da minha máquina windows (que está usando o Oracle Java 7) e scp’d para minha checkbox de Linux (OpenJDK).

 cd %JAVA_HOME%/jre/lib/security/ scp cacerts mylinuxmachin:/tmp 

e depois na máquina linux

 cp /tmp/cacerts /etc/ssl/certs/java/cacerts 

Funcionou muito bem até agora.

Para mim, esse erro apareceu também ao tentar se conectar a um processo por trás de um proxy reverso NGINX que estava manipulando o SSL.

Descobriu-se que o problema era um certificado sem toda a cadeia de certificados concatenada. Quando adicionei certificados intermediários, o problema foi resolvido.

Espero que isto ajude.

Usando o Tomcat 7 no Linux, isso funcionou.

 String certificatesTrustStorePath = "/etc/alternatives/jre/lib/security/cacerts"; System.setProperty("javax.net.ssl.trustStore", certificatesTrustStorePath); System.setProperty("javax.net.ssl.trustStorePassword", "changeit"); 

No Linux, $JAVA_HOME nem sempre é configurado, mas geralmente /etc/alternatives/jre aponta para $JAVA_HOME/jre

Eu escrevi um pequeno script de cmd (linha de comando) win32 (WinXP 32bit testet) estúpido que procura por todas as versões de java em arquivos de programas e adiciona um certificado a eles. A senha precisa ser o padrão “changeit” ou mude você mesmo no script 🙂

 @echo off for /F %%d in ('dir /B %ProgramFiles%\java') do ( %ProgramFiles%\Java\%%d\bin\keytool.exe -import -noprompt -trustcacerts -file some-exported-cert-saved-as.crt -keystore %ProgramFiles%\Java\%%d\lib\security\cacerts -storepass changeit ) pause 

Para o Tomcat rodando no servidor Ubuntu, para descobrir qual Java está sendo usado, use o comando “ps -ef | grep tomcat”:

Amostra:

 /home/mcp01$ **ps -ef |grep tomcat** tomcat7 28477 1 0 10:59 ? 00:00:18 **/usr/local/java/jdk1.7.0_15/bin/java** -Djava.util.logging.config.file=/var/lib/tomcat7/conf/logging.properties -Djava.awt.headless=true -Xmx512m -XX:+UseConcMarkSweepGC -Djava.net.preferIPv4Stack=true -Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager -Djava.endorsed.dirs=/usr/share/tomcat7/endorsed -classpath /usr/share/tomcat7/bin/bootstrap.jar:/usr/share/tomcat7/bin/tomcat-juli.jar -Dcatalina.base=/var/lib/tomcat7 -Dcatalina.home=/usr/share/tomcat7 -Djava.io.tmpdir=/tmp/tomcat7-tomcat7-tmp org.apache.catalina.startup.Bootstrap start 1005 28567 28131 0 11:34 pts/1 00:00:00 grep --color=auto tomcat 

Então, podemos ir para: cd /usr/local/java/jdk1.7.0_15/jre/lib/security

O arquivo cacerts padrão está localizado aqui. Insira o certificado não confiável nele.

Eu tenho esse problema tambem.

Eu tentei quase tudo, adicionando o certificado SSL para .keystore, mas, não estava funcionando com Java1_6_x. Para mim, ajudou se começarmos a usar a versão mais recente do Java, Java1_8_x como JVM.

Outro motivo pode ser uma versão desatualizada do JDK. Eu estava usando o jdk versão 1.8.0_60, simplesmente atualizando para a última versão resolveu o problema do certificado.

Abaixo código funciona para mim:

 import java.security.cert.CertificateException; import java.security.cert.X509Certificate; import javax.net.ssl.X509TrustManager; public class TrustAnyTrustManager implements X509TrustManager { public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException { } public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException { } public X509Certificate[] getAcceptedIssuers() { return new X509Certificate[] {}; } } 

 HttpsURLConnection conn = null; URL url = new URL(serviceUrl); conn = (HttpsURLConnection) url.openConnection(); SSLContext sc = SSLContext.getInstance("SSL"); sc.init(null, new TrustManager[]{new TrustAnyTrustManager()}, new java.security.SecureRandom()); conn.setSSLSocketFactory(sc.getSocketFactory()); 

É uma falha do Java não usar o keystore do sistema operacional padrão como no MacOS X. Eu arquivei uma solicitação de alteração hoje em http://bugs.java.com/bugdatabase/view_bug.do?bug_id=JDK-8185892

Eu estava usando o jdk1.8.0_171 quando enfrentei o mesmo problema. Eu tentei top 2 soluções aqui (adicionando um certificado usando keytool e outra solução que tem um truque nele), mas eles não funcionam para mim.

Eu atualizei meu JDK para 1.8.0_181 e funcionou como um encanto.