以下是从证书颁发机构获得安全连接所需的主要步骤,这些机构在android平台上不被视为受信任的。
按照许多用户的要求,我在此处镜像了我
博客文章中最重要的部分:
- 获取所有必需的证书(根证书和任何中间CA)
- 使用keytool和BouncyCastle提供程序创建密钥库并导入证书
- 在Android应用程序中加载keystore并将其用于安全连接(我建议使用Apache HttpClient而不是标准的
java.net.ssl.HttpsURLConnection
(易于理解,性能更高)
获取证书
您必须获取从终端证书到根CA构建链的所有证书。 这意味着,任何(如果存在)中间CA证书以及根CA证书。 您不需要获取终端证书。
创建密钥库
下载BouncyCastle Provider并将其存储到已知位置。
还要确保您可以调用keytool命令(通常位于JRE安装的bin文件夹下)。
现在将获得的证书(不导入终端证书)导入BouncyCastle格式的keystore中。
我没有测试过,但我认为导入证书的顺序很重要。 这意味着,首先导入最低的中间CA证书,然后一路上导入根CA证书。
使用以下命令可以创建一个新的keystore(如果尚未存在),密码为mysecret,并导入中间CA证书。 我还定义了BouncyCastle提供程序,在我的文件系统中找到它以及keystore格式。 为链中的每个证书执行此命令。
keytool -importcert -v -trustcacerts -file "path_to_cert/interm_ca.cer" -alias IntermediateCA -keystore "res/raw/mykeystore.bks" -provider org.bouncycastle.jce.provider.BouncyCastleProvider -providerpath "path_to_bouncycastle/bcprov-jdk16-145.jar" -storetype BKS -storepass mysecret
验证证书是否已正确导入密钥库:
keytool -list -keystore "res/raw/mykeystore.bks" -provider org.bouncycastle.jce.provider.BouncyCastleProvider -providerpath "path_to_bouncycastle/bcprov-jdk16-145.jar" -storetype BKS -storepass mysecret
应输出整个链:
RootCA, 22.10.2010, trustedCertEntry, Thumbprint (MD5): 24:77:D9:A8:91:D1:3B:FA:88:2D:C2:FF:F8:CD:33:93
IntermediateCA, 22.10.2010, trustedCertEntry, Thumbprint (MD5): 98:0F:C3:F8:39:F7:D8:05:07:02:0D:E3:14:5B:29:43
现在,您可以将密钥库作为原始资源复制到Android应用程序中的res/raw/
目录下。
在应用程序中使用密钥库
首先,我们必须创建一个自定义的Apache HttpClient,用于HTTPS连接并使用我们的密钥库:
import org.apache.http.*
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));
registry.register(new Scheme("https", newSslSocketFactory(), 443));
return new SingleClientConnManager(getParams(), registry);
}
private SSLSocketFactory newSslSocketFactory() {
try {
KeyStore trusted = KeyStore.getInstance("BKS");
InputStream in = context.getResources().openRawResource(R.raw.mykeystore);
try {
trusted.load(in, "mysecret".toCharArray());
} finally {
in.close();
}
SSLSocketFactory sf = new SSLSocketFactory(trusted);
sf.setHostnameVerifier(SSLSocketFactory.STRICT_HOSTNAME_VERIFIER);
return sf;
} catch (Exception e) {
throw new AssertionError(e);
}
}
}
我们已经创建了自定义的HttpClient,现在我们可以使用它进行安全连接。例如,当我们对REST资源进行GET调用时:
// Instantiate the custom HttpClient
DefaultHttpClient client = new MyHttpClient(getApplicationContext());
HttpGet get = new HttpGet("https://www.mydomain.ch/rest/contacts/23");
// Execute the GET call and obtain the response
HttpResponse getResponse = client.execute(get);
HttpEntity responseEntity = getResponse.getEntity();
就是这样了;)