[英]How to create a BKS (BouncyCastle) format Java Keystore that contains a client certificate chain
我正在編寫一個需要SSL客戶端身份驗證的Android應用。 我知道如何為桌面Java應用程序創建JKS密鑰庫,但Android僅支持BKS格式。 我試圖創建密鑰庫的每一種方式都會導致以下錯誤:
handling exception: javax.net.ssl.SSLHandshakeException: null cert chain
所以看起來客戶端永遠不會發送正確的證書鏈,可能是因為我沒有正確創建密鑰庫。 我無法在桌面上啟用SSL調試,因此這使得它比應該更加困難。
作為參考,以下是IS用於創建BKS 信任庫的命令:
keytool -importcert -v -trustcacerts -file "cacert.pem" -alias ca -keystore "mySrvTruststore.bks" -provider org.bouncycastle.jce.provider.BouncyCastleProvider -providerpath "bcprov-jdk16-145.jar" -storetype BKS -storepass testtest
這是我嘗試過的命令,它無法創建BKS客戶端密鑰庫 :
cat clientkey.pem clientcert.pem cacert.pem > client.pem
keytool -import -v -file <(openssl x509 -in client.pem) -alias client -keystore "clientkeystore" -provider org.bouncycastle.jce.provider.BouncyCastleProvider -providerpath "bcprov-jdk16-145.jar" -storetype BKS -storepass testtest
為實現這一目標,我遵循詳細的逐步說明
為TOMCAT配置BouncyCastle
打開D:\\ tools \\ apache-tomcat-6.0.35 \\ conf \\ server.xml並添加以下條目
在這些更改后重新啟動服務器。
MyHttpClient.java
package com.arisglobal.aglite.network;
import java.io.InputStream;
import java.security.KeyStore;
import org.apache.http.conn.ClientConnectionManager;
import org.apache.http.conn.scheme.PlainSocketFactory;
import org.apache.http.conn.scheme.Scheme;
import org.apache.http.conn.scheme.SchemeRegistry;
import org.apache.http.conn.ssl.SSLSocketFactory;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.impl.conn.SingleClientConnManager;
import com.arisglobal.aglite.activity.R;
import android.content.Context;
public class MyHttpClient extends DefaultHttpClient {
final Context context;
public MyHttpClient(Context context) {
this.context = context;
}
@Override
protected ClientConnectionManager createClientConnectionManager() {
SchemeRegistry registry = new SchemeRegistry();
registry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
// Register for port 443 our SSLSocketFactory with our keystore to the ConnectionManager
registry.register(new Scheme("https", newSslSocketFactory(), 443));
return new SingleClientConnManager(getParams(), registry);
}
private SSLSocketFactory newSslSocketFactory() {
try {
// Get an instance of the Bouncy Castle KeyStore format
KeyStore trusted = KeyStore.getInstance("BKS");
// Get the raw resource, which contains the keystore with your trusted certificates (root and any intermediate certs)
InputStream in = context.getResources().openRawResource(R.raw.aglite);
try {
// Initialize the keystore with the provided trusted certificates.
// Also provide the password of the keystore
trusted.load(in, "aglite".toCharArray());
} finally {
in.close();
}
// Pass the keystore to the SSLSocketFactory. The factory is responsible for the verification of the server certificate.
SSLSocketFactory sf = new SSLSocketFactory(trusted);
// Hostname verification from certificate
// http://hc.apache.org/httpcomponents-client-ga/tutorial/html/connmgmt.html#d4e506
sf.setHostnameVerifier(SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
return sf;
} catch (Exception e) {
throw new AssertionError(e);
}
}
}
如何在Activity類中調用上面的代碼:
DefaultHttpClient client = new MyHttpClient(getApplicationContext());
HttpResponse response = client.execute(...);
我使用Portecle ,它就像一個魅力。
我認為您的問題不在於BouncyCastle密鑰庫; 我認為問題在於Android中破壞的javax.net.ssl包。 BouncyCastle密鑰庫是一個至高無上的煩惱,因為Android更改了默認的Java行為,而沒有在任何地方記錄它 - 並刪除了默認提供程序 - 但它確實有效。
請注意,對於SSL身份驗證,您可能需要2個密鑰庫。 “TrustManager”密鑰庫(包含CA證書)和“KeyManager”密鑰庫(包含客戶端站點公鑰/私鑰)。 (文檔對於KeyManager密鑰庫中需要的內容有些模糊。)理論上,如果所有證書都由“眾所周知的”證書頒發機構簽署,例如Verisign,Thawte,則不需要TrustManager密鑰庫。等等。 讓我知道這對你有用。 您的服務器還將要求CA用於簽署客戶端的任何內容。
我根本無法使用javax.net.ssl創建SSL連接。 我在服務器端禁用了客戶端SSL身份驗證,但仍然無法創建連接。 由於我的最終目標是HTTPS GET,因此我嘗試使用與Android捆綁在一起的Apache HTTP客戶端。 那種工作。 我可以進行HTTPS連接,但我仍然無法使用SSL身份驗證。 如果我在服務器上啟用了客戶端SSL身份驗證,則連接將失敗。 我沒有檢查Apache HTTP客戶端代碼,但我懷疑他們正在使用自己的SSL實現,並且不使用javax.net.ssl。
不確定您是否解決了這個問題,但這是我如何做到的,它適用於Android:
命令行:
keytool -genseckey -alias aliasName -keystore truststore.bks -providerclass org.bouncycastle.jce.provider.BouncyCastleProvider -providerpath /path/to/jar/bcprov-jdk16-1.46.jar -storetype BKS
使用本手冊http://blog.antoine.li/2010/10/22/android-trusting-ssl-certificates/本指南對我很有幫助 。 在商店中觀察一系列證書非常重要。 例如:首先導入最低級的中級CA證書,然后一直導入根CA證書 。
您創建BKS密鑰庫的命令對我來說是正確的。
你如何初始化密鑰庫。
你需要創建並傳遞自己的SSLSocketFactory。 這是一個使用Apache的org.apache.http.conn.ssl.SSLSocketFactory
的示例
但我認為你可以在javax.net.ssl.SSLSocketFactory
上做同樣的事情
private SSLSocketFactory newSslSocketFactory() {
try {
// Get an instance of the Bouncy Castle KeyStore format
KeyStore trusted = KeyStore.getInstance("BKS");
// Get the raw resource, which contains the keystore with
// your trusted certificates (root and any intermediate certs)
InputStream in = context.getResources().openRawResource(R.raw.mykeystore);
try {
// Initialize the keystore with the provided trusted certificates
// Also provide the password of the keystore
trusted.load(in, "testtest".toCharArray());
} finally {
in.close();
}
// Pass the keystore to the SSLSocketFactory. The factory is responsible
// for the verification of the server certificate.
SSLSocketFactory sf = new SSLSocketFactory(trusted);
// Hostname verification from certificate
// http://hc.apache.org/httpcomponents-client-ga/tutorial/html/connmgmt.html#d4e506
sf.setHostnameVerifier(SSLSocketFactory.STRICT_HOSTNAME_VERIFIER);
return sf;
} catch (Exception e) {
throw new AssertionError(e);
}
}
如果有效,請告訴我。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.