Importar certificado SSL

11 respostas
W

Pessoal, estou com um problema, tenho que fazer minha aplicação se conectar a um determinado site que está rodando com ssl, mas como o certificado não é reconhecido, o sistema lança uma excessão. Sei que posso salvar em arquivo o certificado via internet explorer, e que posso importar pela ferramenta keytool, já fiz alguns testes e ainda continuo obtendo o erro, será que alguém poderia me ajudar?

11 Respostas

T

a) Qual é a exceção?
b) Que versão do Java você está usando? Para algumas versões (como 1.4.2 mas anterior à 1.4.2_08) há problemas ao importar certificados gerados pelo Microsoft Certificate Services.
c) Exceção é com ç porque em inglês exception é com pt - embora esta regra não seja muito rigorosa (por exemplo, analisar em português é com S e em inglês americano é com Z) é fácil de lembrar.

W

a) Exception in thread “main” javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target.

b)1.5

c)Obrigado pela correção, rs…

T

Você precisa incluir no seu arquivo de keystore todos os certificados que fazem parte do caminho de certificação. (Veja no seu browser).

Por exemplo, digamos que você tenha de se conectar ao site https://mustang.dev.java.net. Você terá de incluir o certificado-raiz (GTE Cybertrust Global Root), que provavelmente já está no seu keystore, e o “Comodo Class 3 Security Services CA”.

“Certificate Hierarchy” (Mozilla) ou “Certification Path” (IE)

GTE CyberTrust Global Root
Comodo Class 3 Security Services CA
*.dev.java.net

W

.

T

Você está tentando conectar-se pelo IP. No caso do SSL é muito importante usar o NOME correto, para que a conexão seja efetuada corretamente. Talvez você tenha de modificar /etc/hosts (no Windows C:\windows\system32\drivers\etc\hosts) se você não puder pôr o tal endereço no DNS ou não puder usar o DNS no seu cliente SSL.

Por exemplo:

https://sitenet05.serasa.com.br/...blablabla?wsdl deve fechar a conexão .

em vez de

https://xxx.xxx.xxx.xxx/...blablabla?wsdl não deve fechar.

T

Experimente rodar este programa (salve o certificado “Serasa AC Global” em um arquivo “serasaacglobal.cer”, em formato DER (binário)).

import java.io.*;
import java.net.*;
import java.security.*;
import javax.net.ssl.*;
import sun.misc.BASE64Decoder;
import java.security.cert.*;

public class HTTPSClient
{
    static X509Certificate x509;
    static {
        try {
            CertificateFactory fact = CertificateFactory.getInstance("X.509");
            FileInputStream fis = new FileInputStream ("serasaacglobal.cer");
            x509 = (X509Certificate)fact.generateCertificate(fis);
            fis.close();
        } catch (Exception ex) {
            ex.printStackTrace();
        }    
    }
    
    static TrustManager[] trustAllCerts = new TrustManager[]{
        new X509TrustManager() {
            public java.security.cert.X509Certificate[] getAcceptedIssuers() {
                return new java.security.cert.X509Certificate[]{
                    x509
                };
            }
            public void checkClientTrusted(
                java.security.cert.X509Certificate[] certs, String authType) {
            }
            public void checkServerTrusted(
                java.security.cert.X509Certificate[] certs, String authType) {
            }
        }
    };
    // https://sitenet05.serasa.com.br/wsgestordecisao/wsgestordecisao.asmx?wsdl
    private static int port = 443;                      // The HTTPS Port (usually 443)
    private static String host = "sitenet05.serasa.com.br";   // The server to connect to
    private static String path = "/wsgestordecisao/wsgestordecisao.asmx?wsdl";                   // The file/path to retrieve

    public static void main(String[] args)
    {
        try
        {
            Security.addProvider(new com.sun.net.ssl.internal.ssl.Provider());
            SSLContext sc = SSLContext.getInstance("SSL");
            sc.init(null, trustAllCerts, new java.security.SecureRandom());

            // Connect to the server using an SSL socket
            SSLSocketFactory factory = sc.getSocketFactory(); // (SSLSocketFactory) SSLSocketFactory.getDefault();
            SSLSocket socket = (SSLSocket) factory.createSocket(host, port);

            // Send HTTP GET message
            PrintWriter out = new PrintWriter(new BufferedOutputStream(socket.getOutputStream()));
            out.println("GET "+path+" HTTP/1.1");
            out.println("Host: "+host);
            out.println("Connection: close");
            out.println("User-Agent: Java HTTPS Client");
            out.println("");
            out.flush();

            // Now dump server reply to console
            BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
            int c;
            while ((c = in.read()) != -1)
            {
                System.out.write(c);
            }

            // All done, close io streams and socket
            out.close();
            in.close();
            socket.close();
        }
        catch (Exception e) { e.printStackTrace(); }
    }
}
L

Thingol,

Sem querer ser chato postando nesse tópico antigo, mas queria te fazer uma pergunta. Estou com o mesmo problema que o williammafra. Eu criei um certificado pelo OpenSSL e a sua extenção é .p12. Como faço para usar ele nessa sua classe. Tenho de converter para esse formato DER? Se for, como faço isso. Pelo browser ele tá funcionando legal, mas preciso fazer minha aplicação reconhecer ele fora do browser.

Agradeço se puder me ajudar!

T

Usando o OpenSSL é possível extrair o arquivo X.509 a partir de um arquivo PKCS#12 (que é o que você tem em mãos). O código que mostrei requer um arquivo X.509 em formato binário.
Não sei o comando assim de cor, mas deve ser algo como openssl pkcs12 -in seuarquivo.p12 -clcerts -out seuarquivo.cer ou coisa parecida; por favor, consulte os parâmetros usando openssl pkcs12 -?

L

Obrigado thingol,

Usei o certificado com a extensão .crt gerado pelo OpenSSL e com sua classe funcionou. Mas tenho uma pergunta para você. Em uma aplicação onde muitas pessoas vão utilizar ao mesmo tempo, usar socket (como na sua classe) seria meio complicado não é mesmo? Ou utilizar socket não tem tanta diferença em relação a uma conexão http comum a um servlet?

Obrigado pela atenção!

T

O exemplo (usando sockets) é só um exemplo. O correto é usar o suporte a https (http + ssl) que o Java tem. Se for usar esse suporte, o código é um pouco diferente.

M

tingol, sendo mais chato ainda que o amigo la em cima, em reviver esse post bemmm antigo (rs), eu tambem estou com um problema similar.

O Codigo acima para recuperar o certificado e salvar em um arquivo, eu achei em um outro exemplo por ai. Eu estou usando o HttpClient da apache para realizar conexoes http. Incialmente eu estava recebendo a mesma excessao que o amigo acima esta recebendo, ai consegui resolver recuperando o certificado com a aplicação acima, salvando em um arquivo e colocando ele na pasta java-home/lib/security. Fazendo isso funciona perfeitamente. A questao é que aonde eu estou tentando fazer a conexao, parece que ele altera o certificado toda semana, ou seja, eu teria que gerar um arquivo diferente por semana e colocar la, ocasionando em restartar minha jvm para reconhecer o novo certificado, etc. A minha duvida é como eu poderia fazer para recuperar o certificado (X509Certificate) de forma dinamica, adicionar ele como um certificado reconhecido sem precisar restartar a minha aplicação? Ou seja, fazer tudo de forma dinamica. Vlw amigo

Criado 3 de julho de 2006
Ultima resposta 22 de jun. de 2009
Respostas 11
Participantes 4