使用Java在运行时加载CA根证书

时间:2015-09-29 18:32:26

标签: java ssl https root-certificate

tl; dr:使用自定义CA而不将其添加到持久性密钥库。

我正在编写一个应该使用HTTPS连接到远程服务器的Java应用程序。连接的代码已准备就绪,但服务器的SSL证书由StartSSL签名,this code不在Java的CA根证书库中。

使用here,我会从https://www.google.com/等网站获取有效的证书信息:

Response Code : 200
Cipher Suite : TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256

Cert Type : X.509
Cert Hash Code : -1643391404
Cert Public Key Algorithm : RSA
Cert Public Key Format : X.509

Cert Type : X.509
Cert Hash Code : 771393018
Cert Public Key Algorithm : RSA
Cert Public Key Format : X.509

Cert Type : X.509
Cert Hash Code : 349192256
Cert Public Key Algorithm : RSA
Cert Public Key Format : X.509

相同的代码会为我的域名引发SSLHandshakeException(让我们称之为https://www.example.com/)。

当然,我可以使用keytool手动将证书添加到密钥库(甚至可以使用Runtime.exec("keytool ...")),但这是脏的方法。我现在计划的是将StartSSL根证书添加到我的应用程序文件中以进行分发,然后在运行时将其加载到某个临时密钥库中。这样“真正的”密钥库保持不变。

根据我的阅读herecompletely turn off the validation,我将不得不混淆像TrustManager这样的课程。我甚至找到了{{3}}的方法,但这不是我想要的,因为它似乎消除了加密通信的全部目的。

我甚至发现了一些似乎完全符合我想要的代码行,但我无法弄清楚如何调用这个方法,即将哪些值作为参数传递:

public class SSLClasspathTrustStoreLoader {
    public static void setTrustStore(String trustStore, String password) throws Exception {
        TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance("X509");
        KeyStore keystore = KeyStore.getInstance(KeyStore.getDefaultType());
        InputStream keystoreStream = SSLClasspathTrustStoreLoader.class.getResourceAsStream(trustStore);
        keystore.load(keystoreStream, password.toCharArray());
        trustManagerFactory.init(keystore);
        TrustManager[] trustManagers = trustManagerFactory.getTrustManagers();
        SSLContext sc = SSLContext.getInstance("SSL");
        sc.init(null, trustManagers, null);
        SSLContext.setDefault(sc);
    }
}

之前有没有人遇到类似的情况?我将不胜感激任何有关如何处理此问题的建议。如果你甚至可以帮助我运行上面的代码,我真的很开心!

2 个答案:

答案 0 :(得分:3)

您需要创建一个已经找到的自定义TrustStore。 除此之外,您还需要创建一个自定义SSL套接字工厂,它使用您提到的自定义信任管理器,并将其注册到您正在使用的HTTP框架。细节实际上取决于您选择的框架。

使用 keytool 实用程序将证书添加到默认密钥存储区没有任何问题。您可能会发现需要多个证书。如果是这种情况,您必须确保整个Java应用程序使用相同的密钥存储区作为单一事实来源。如果在同一个应用程序中使用多个密钥库,它可能会变得很毛茸茸。

希望这有帮助。

答案 1 :(得分:0)

这对我有用!

public static void setTrustStore(String trustStore, String password) throws Exception {
        TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance("X509");
        KeyStore keystore = KeyStore.getInstance(KeyStore.getDefaultType());
        InputStream keystoreStream = SSLClasspathTrustStoreLoader.class.getResourceAsStream(trustStore);
        keystore.load(keystoreStream, password.toCharArray());
        trustManagerFactory.init(keystore);
        TrustManager[] trustManagers = trustManagerFactory.getTrustManagers();
        SSLContext sc = SSLContext.getInstance("SSL");
        sc.init(null, trustManagers, null);
        SSLContext.setDefault(sc);
    }

OR,另一种选择是使用" portecle-1.9"

1.1 – Baixar o programa “portecle-1.9”. 
1.1.1   https://sourceforge.net/projects/portecle

1.2 - Acessar a pasta security do JDK que será utilizado para rodar a aplicação
1.2.1   Exemplo: C:\Program Files\Java\jdk1.7.0_67\jre\lib\security
1.2.2   Fazer backup do arquivo “cacerts” (Só por segurança)

1.3 - Abrir o programa portecle  “portecle.jar”
1.3.1   Acessar o “Menu > File > Open Keystore File..”
1.3.2   Selecione o arquivo “cacerts” mande abrir
1.3.3   Irá pedir senha, a senha padrão quando instala o JDK é “changeit”
1.3.4   O programa irá listar os diversos certificados contidos no “cecerts”
1.3.5   Acessar o “Menu > Tools > Import Trusted Certificate…”
1.3.6   Selecione o arquivo de certificado “.pem“ ou “.cer” ou alguma outra extensão compatível.
1.3.7   Será questionado se realmente o arquivo é “trusted” ou seja “confiável” . Aceita como confiavel.
1.3.8   Também será possível alterar o “alias”, provavelmente não será necessário mudar então apenas aceites todas as opções até que receba a mensagem “Certificado importado”.
1.3.9   Clique em “Salvar”, pois se não salvar as alterações não terão efeito!