我正在编写需要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
答案 0 :(得分:62)
我遵循的详细分步说明
为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(...);
答案 1 :(得分:25)
我使用Portecle,它就像一个魅力。
答案 2 :(得分:4)
我认为您的问题不在于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。
答案 3 :(得分:4)
不确定您是否解决了这个问题,但我就是这样做的,它适用于Android:
答案 4 :(得分:2)
命令行:
keytool -genseckey -alias aliasName -keystore truststore.bks -providerclass org.bouncycastle.jce.provider.BouncyCastleProvider -providerpath /path/to/jar/bcprov-jdk16-1.46.jar -storetype BKS
答案 5 :(得分:0)
您创建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);
}
}
如果有效,请告诉我。
答案 6 :(得分:0)
使用本手册http://blog.antoine.li/2010/10/22/android-trusting-ssl-certificates/ 这个指南真的帮助了我。在商店中观察一系列证书非常重要。例如:首先导入最低级别的中级CA证书,然后一直导入根CA证书。