Android HTTPS SSL双向验证(CA根证书)

由于公司项目需要,需要将原来部署的自签名证书切换为CA系统提供商的证书,所以需要对原来的证书生成做相应处理与替换。

想要看自签名证书生成方法可以参考原来的文章Android HTTPS SSL双向验证(自签名证书)

一、相关证书生成

1、从运维那边拿到P12格式的证书文件,后缀一般是.pfx或者.p12的文件

2、生成cer文件
1、从运维那边拿到P12格式的证书文件,后缀一般是.pfx或者.p12的文件,这个文件就是下面需要用到的client.p12文件

2、生成服务器cer证书

openssl pkcs12 -in server.pfx -out server.cer

3、生成客户端信任证书库(由服务端证书生成的证书库),这里生成的文件就是用来校验服务器有效性的文件client.truststore

keytool -import -v -alias server -file server.cer -keystore client.truststore -storepass 123456 -storetype BKS -provider org.bouncycastle.jce.provider.BouncyCastleProvider

通过上面的步骤生成的证书,客户端需要用到的是client.p12(客户端证书,用于请求的时候给服务器来验证身份之用)和client.truststore(客户端证书库,用于验证服务器端身份,防止钓鱼)这两个文件.

其中安卓端的证书类型必须要求是 BKS 类型,这里涉及到这个 JAR bcprov-ext-jdk15on-156.jar文件.这里主要就是把下载的这个 jar 文件放到你 Java 主目录下的 jre/lib/ext目录下,然后修改jre/lib/security/java.security这个文件,在List of providers 注释的地方添加这一行security.provider.11=org.bouncycastle.jce.provider.BouncyCastleProvider其中11个数字可以自己改,按顺序排就行,之后重启终端,再执行应该就不会报找不到类的错误了。一定要注意目录不要放错了,不然一直会报找不到类的。

二、Android端SSL认证请求

1、通过 client.p12client.truststore 这两个文件进行认证的可以参考上篇博客的内容即可

2、不生成 client.truststore 这个文件,自己做服务器校验的代码如下

	public static SSLContext getSslContextByDefaultTrustManager(Context context) {
	        if (sslContext == null) {
	            try {
	                // 服务器端需要验证的客户端证书
	                KeyStore keyStore = KeyStore.getInstance(KEY_STORE_TYPE_P12);
	
	                InputStream ksIn = context.getResources().getAssets().open(KEY_STORE_CLIENT_PATH);
	                try {
	                    keyStore.load(ksIn, KEY_STORE_PASSWORD.toCharArray());
	                } catch (Exception e) {
	                    e.printStackTrace();
	                } finally {
	                    try {
	                        ksIn.close();
	                    } catch (Exception e) {
	                        e.printStackTrace();
	                    }
	                }
	                sslContext = SSLContext.getInstance("TLS");
	                // Create a TrustManager that trusts the CAs in our KeyStore
	                String tmfAlgorithm = TrustManagerFactory.getDefaultAlgorithm();
	                TrustManagerFactory tmf = TrustManagerFactory.getInstance(tmfAlgorithm);
	                tmf.init(keyStore);
	
	                KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance("X509");
	                keyManagerFactory.init(keyStore, KEY_STORE_PASSWORD.toCharArray());
	                sslContext.init(keyManagerFactory.getKeyManagers(), tmf.getTrustManagers(), null);
	            } catch (Exception e) {
	                e.printStackTrace();
	            }
	        }
	        return sslContext;
	    }

3、也可以直接通过运维提供的 crt 证书自己写整个校验逻辑

	public static SSLContext getSslContextByCustomTrustManager(Context context) {
	        if (sslContext == null) {
	            try {
	                CertificateFactory cf = CertificateFactory.getInstance("X.509");
	                InputStream caInput = new BufferedInputStream(context.getResources().getAssets().open(KEY_CRT_CLIENT_PATH));
	                final Certificate ca;
	                try {
	                    ca = cf.generateCertificate(caInput);
	                } finally {
	                    caInput.close();
	                }
	
	                sslContext = SSLContext.getInstance("TLS");
	                sslContext.init(null, new X509TrustManager[]{new X509TrustManager() {
	                    public void checkClientTrusted(X509Certificate[] chain,
	                                                   String authType) throws CertificateException {
	                        Log.d("HttpClientSslHelper", "checkClientTrusted --> authType = " + authType);
	                        //校验客户端证书
	                    }
	
	                    public void checkServerTrusted(X509Certificate[] chain,
	                                                   String authType) throws CertificateException {
	                        Log.d("HttpClientSslHelper", "checkServerTrusted --> authType = " + authType);
	                        //校验服务器证书
	                        for (X509Certificate cert : chain) {
	                            cert.checkValidity();
	                            try {
	                                cert.verify(ca.getPublicKey());
	                                isServerTrusted = true;
	                            } catch (NoSuchAlgorithmException | InvalidKeyException | NoSuchProviderException | SignatureException e) {
	                                e.printStackTrace();
	                                isServerTrusted = false;
	                            }
	                        }
	                    }
	
	                    public X509Certificate[] getAcceptedIssuers() {
	                        return new X509Certificate[0];
	                    }
	                }}, null);
	            } catch (Exception e) {
	                e.printStackTrace();
	            }
	        }
	        return sslContext;
	    }

这里给出全部代码链接–>AndroidHttpsDemo