我正在编写一个需要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
Run Code Online (Sandbox Code Playgroud)
Vip*_*pul 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);
}
}
}
Run Code Online (Sandbox Code Playgroud)
如何在Activity类中调用上面的代码:
DefaultHttpClient client = new MyHttpClient(getApplicationContext());
HttpResponse response = client.execute(...);
Run Code Online (Sandbox Code Playgroud)
我认为您的问题不在于 BouncyCastle 密钥库;我认为问题在于 Android 中的 javax.net.ssl 包损坏。BouncyCastle 密钥库是一个极大的烦恼,因为 Android 更改了默认的 Java 行为而没有在任何地方记录它 - 并删除了默认的提供程序 - 但它确实有效。
请注意,对于 SSL 身份验证,您可能需要 2 个密钥库。“TrustManager”密钥库,其中包含 CA 证书,以及“KeyManager”密钥库,其中包含您的客户端站点公钥/私钥。(文档对于 KeyManager 密钥库中需要包含的内容有些模糊。)理论上,如果您的所有证书均由“知名”证书颁发机构(例如 Verisign、Thawte、等等。让我知道这对你有用。您的服务器还需要 CA 来对您的客户端进行签名。
我根本无法使用 javax.net.ssl 创建 SSL 连接。我在服务器端禁用了客户端 SSL 身份验证,但仍然无法创建连接。由于我的最终目标是 HTTPS GET,因此我尝试使用与 Android 捆绑在一起的 Apache HTTP 客户端。这确实有效。我可以建立 HTTPS 连接,但仍然无法使用 SSL 身份验证。如果我在服务器上启用客户端 SSL 身份验证,连接将会失败。我还没有检查 Apache HTTP 客户端代码,但我怀疑他们正在使用自己的 SSL 实现,并且不使用 javax.net.ssl。
不确定你是否解决了这个问题,但这就是我的做法,并且它在 Android 上有效:
归档时间: |
|
查看次数: |
99922 次 |
最近记录: |