https双向认证,这种一般不会在android遇到,因为这种正常是服务器和服务器之间通信采用,而且是银行金融类用的比较多。用在android端的话,不仅起不到安全作用,反而会让https不安全,因为加密对称秘钥的公私钥需要存放在客户端。具体为什么不安全,这是很基础的知识,这里不讲。
正常需要用到双向认证时,会给我们2个证书:Ca证书和.p12结尾的证书,这种做法比较简单,网上到处都有,不赘述。
这里我们要讨论的是,有的情况,给我们的证书是4个文件:
- ca证书(单向认证时使用),
- 公钥证书
- 私钥(这个是一对)
- 服务器认证客户端的证书
解决方法:
SSLContext sslContext = SSLContext.getInstance("TLS");
CertificateFactory cf = CertificateFactory.getInstance("X.509");
// 客户端认证服务端
InputStream in = BaseUtils.getApp().getAssets().open("puk.crt");
// 这个puk.crt文件可以是16进制的也可以是Base64后的
Certificate ca = cf.generateCertificate(in);
KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType());
trustStore.load(null, null);
trustStore.setCertificateEntry("ca", ca);
TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
trustManagerFactory.init(trustStore);
// 服务端认证客户端
KeyStore keyStore = KeyStore.getInstance("PKCS12");
keyStore.load(null, null);
Certificate secondPuk = cf.generateCertificate(new ByteArrayInputStream(Base64.decode(cert1)));
Certificate secondCert = cf.generateCertificate(new ByteArrayInputStream(Base64.decode(cert2)));
PrivateKey privateKey = Utils.getPrivatekey(pem);
if(privateKey == null){
return null;
}
KeyStore.PrivateKeyEntry secondPri = new KeyStore.PrivateKeyEntry(privateKey, new Certificate[]{secondPuk});
// 加载证书
keyStore.setCertificateEntry("cert", secondCert);
keyStore.setEntry("pri", secondPri, null);
// 初始化KeyManagerFactory
KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance("X509");
//(KeyManagerFactory.getDefaultAlgorithm());
keyManagerFactory.init(keyStore, null);
sslContext.init(null, trustManagerFactory.getTrustManagers(), null);
SSLSocketFactory socketFactory = sslContext.getSocketFactory();
OkHttpClient okHttpClient = new OkHttpClient.Builder()// 构建OKHttp客户端
.sslSocketFactory(socketFactory)
.build();
【android|android https 双向认证--高级】