AndroidHttps
安卓端使用双向认证请求服务器的完整示例
前言
众所周知,Http请求包含了地址、端口、请求头、请求体等等。
与服务器的通信交由SocketFactory,而Https请求需要用SSLSocketFactory。
创建SSLSocketFactory需要一个两个KeyStore:
一个是keyStore,里面放着服务器信任的客户端证书和客户端私钥;
一个是trustStore,里面放着客户端信任的服务器证书。
在Java中默认的KeyStore类型是JKS,安卓中默认为BKS。
生成keyStore和trustStore示例
方式一(加载P12和BKS文件,通过以下方法得到两个KeyStore)
// 把客户端证书和私钥用openssl导出为P12格式
String p12File = "client.p12";
// 你需要知道P12的密码
String p12Pwd = "123456";
// 生成KeyStore,密码为P12的密码
KeyStore keyStore1 = KeyStoreManager.getKeyStoreByP12(ctx, p12File, p12Pwd);
// 把服务器证书用keytool工具生成KeyStore并导入其中
String bksFile = "client.bks";
// 你需要知道bks的密码
String bksPwd = "123456";
// 生成TrustStore
KeyStore trustStore1 = KeyStoreManager.getTrustStoreByBks(ctx, bksFile, bksPwd);
方式二(加载client.pem、client.crt和server.crt,通过以下方法得到两个KeyStore)
// 生成你的私钥文件,内容是...BEGIN RSA PRIVATE KEY...
String clientPem = "client.pem";
// 根据你的私钥生成客户端证书
String clientCrt = "client.crt";
// 为KeyStore设置一个密码
String keyStorePwd = "123456";
// 生成KeyStore
KeyStore keyStore2 = KeyStoreManager.getKeyStoreByCrtPem(ctx, clientCrt, clientPem, keyStorePwd);
// 服务器证书
String serverCrt = "server.crt";
// 生成TrustStore
KeyStore trustStore2 = KeyStoreManager.getTrustStoreByCrt(ctx, serverCrt);
使用你的keyStore和trustStore初始化SSLSocketFactory
方式一(初始化HttpsUrlConnection的SSLSocketFactory)
// -------------使用HTTPS工具类---------------
// 初始化方法只需要调用一次,如果你信任所有服务器,trustStore传入null即可!
HTTPS.init(keyStore, keyStorePwd, trustStore);
// 发起请求
new HTTPS().doGET(HTTPS_URL, params);
方式二(初始化HttpClient的SSLSocketFactory)
// ----------使用HttpClientTool工具类----------
// 初始化方法只需要调用一次,如果你信任所有服务器,trustStore传入null即可!
HttpClientTool.init(keyStore, keyStorePwd, trustStore);
// 发起请求
HttpClientTool.doGET(HTTPS_URL, params);
重要提示
关于私钥的转换,着实是费了几天时间。
网上有大量资料说明在安卓中如何使用P12和BKS的方式生成keyStore和trustStore。
在项目中,我试图把client.pem读出来转换成与P12相同的PrivateKey,即PKCS8类型的私钥。
我们知道,使用openssl生成的私钥是如下形式,例如项目中的client.pem:
-----BEGIN RSA PRIVATE KEY-----
使用openssl很容易完成PKCS8转换:
openssl pkcs8 -topk8 -inform PEM -in client.pem -outform PEM -nocrypt -out client_pkcs8.pem
转换后内容如下:
-----BEGIN PRIVATE KEY-----
完成上述转换的代码其实相当简单,使用bcprov-jdk1***.jar中的PemReader类,可以直接把pem读为KeyPair,
然后从KeyPair中取出私钥,这个私钥就是我们要的!!!
InputStream pem = ctx.getResources().getAssets().open(pemFile);
InputStreamReader inReader = new InputStreamReader(pem);
PEMReader pemReader = new PEMReader(inReader);
KeyPair keyPair = (KeyPair) pemReader.readObject();
PrivateKey privateKey = keyPair.getPrivate();
使用PemWriter可以打印一个密钥,包括BEGIN和END字符串:
PemObject obj = new PemObject(keyName, keyBytes);
PrintWriter pw = new PrintWriter(System.out);
PemWriter pemw = new PemWriter(pw);
pemw.writeObject(obj);
pw.close();
pemw.close();
更多
想了解更多关于证书方面的内容,欢迎访问我的另外一个项目 KS