2015-09-29 167 views
2

tl; dr:使用自定義CA而不將其添加到永久密鑰庫。在Java中運行時加載CA根證書

我正在編寫一個Java應用程序,該應用程序應該使用HTTPS連接到遠程服務器。該連接的代碼已準備就緒,但服務器的SSL證書由StartSSL簽署,該證書不在Java的CA根證書存儲區中。

使用this code,我從網站的有效證書信息,如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根證書添加到我的應用程序文件中進行分發,然後在運行時將其加載到某個臨時密鑰庫中。通過這種方式,「真正」的密鑰庫保持不變。

從我已閱讀herehere,我將不得不亂用一些類,比如TrustManager。我甚至找到了一種方法來completely turn off the validation,但這不是我想要的,因爲它似乎消除了加密通信的全部目的。

我甚至發現了一些代碼行,似乎做的正是我想要的,但我無法弄清楚如何調用哪些值作爲參數傳遞這種方法即:

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

您將需要創建一個自定義的TrustStore,就像您已經找到的那樣。 除此之外,您還需要創建一個使用您提到的自定義信任管理器的自定義SSL套接字工廠,並使用您正在使用的HTTP框架進行註冊。細節真的取決於你選擇的框架。

使用keytool實用程序將證書添加到默認密鑰存儲區沒有任何問題。您可能會發現需要多個證書。如果出現這種情況,您必須確保整個Java應用程序使用相同的密鑰存儲庫作爲單一事實來源。如果您在同一應用程序中使用多個密鑰存儲區,它可能會變得非常多毛。

希望這會有所幫助。

+0

關於你的答案的'keytool'部分:應用程序將被分發到多個客戶端系統。由於用戶可以更改密碼(默認情況下爲「changeit」,所以有人可能會這樣做),但手動修改系統密鑰庫對於每個單一系統都是不可能的,並且在運行時修改它是很困難的。在這種情況下,連接將不起作用,或者我需要提示輸入不是用戶友好的密碼。不過謝謝你的回答,我很快就會再來一次。 – Hexaholic

+0

您可以創建自定義密鑰存儲運行時(如果其中一個不存在或者可以將密鑰存儲與您的應用程序一起打包)。我不知道你的項目的細節,但應該有更優雅的解決方案。無論如何,祝你好運:) – Boris

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!