|
@@ -0,0 +1,222 @@
|
|
|
+package com.cooleshow.base.data.auth;
|
|
|
+
|
|
|
+import android.content.Context;
|
|
|
+import android.webkit.ClientCertRequest;
|
|
|
+
|
|
|
+import com.cooleshow.base.utils.LOG;
|
|
|
+import com.cooleshow.base.utils.Utils;
|
|
|
+
|
|
|
+import java.io.IOException;
|
|
|
+import java.io.InputStream;
|
|
|
+import java.math.BigInteger;
|
|
|
+import java.security.KeyStore;
|
|
|
+import java.security.PrivateKey;
|
|
|
+import java.security.PublicKey;
|
|
|
+import java.security.cert.Certificate;
|
|
|
+import java.security.cert.CertificateException;
|
|
|
+import java.security.cert.X509Certificate;
|
|
|
+import java.util.ArrayList;
|
|
|
+import java.util.Enumeration;
|
|
|
+
|
|
|
+import javax.net.ssl.KeyManagerFactory;
|
|
|
+import javax.net.ssl.SSLContext;
|
|
|
+import javax.net.ssl.SSLSocketFactory;
|
|
|
+import javax.net.ssl.TrustManager;
|
|
|
+import javax.net.ssl.TrustManagerFactory;
|
|
|
+import javax.net.ssl.X509TrustManager;
|
|
|
+
|
|
|
+/**
|
|
|
+ * Author by pq, Date on 2023/12/28.
|
|
|
+ */
|
|
|
+public class Https {
|
|
|
+
|
|
|
+ private final static String CLIENT_PRI_KEY = "auth_client.bks";
|
|
|
+ private final static String TRUSTSTORE_PUB_KEY = "auth_truststore.bks";
|
|
|
+ private final static String CLIENT_BKS_PASSWORD = "dayaedu";
|
|
|
+ private final static String TRUSTSTORE_BKS_PASSWORD = "dayaedu";
|
|
|
+ private final static String KEYSTORE_TYPE = "BKS";
|
|
|
+ private final static String PROTOCOL_TYPE = "TLS";
|
|
|
+ private final static String CERTIFICATE_FORMAT = "X509";
|
|
|
+
|
|
|
+ public static SSLSocketFactory getSSLCertifcation(Context context) {
|
|
|
+ SSLSocketFactory sslSocketFactory = null;
|
|
|
+ LOG.i("pq", "getSSLCertifcation");
|
|
|
+ try {
|
|
|
+ TrustManager[] trustAllCerts = new TrustManager[]{getTrustManager()};
|
|
|
+
|
|
|
+ // 服务器端需要验证的客户端证书,其实就是客户端的keystore
|
|
|
+ KeyStore keyStore = KeyStore.getInstance(KEYSTORE_TYPE);// 客户端信任的服务器端证书
|
|
|
+ KeyStore trustStore = KeyStore.getInstance(KEYSTORE_TYPE);//读取证书
|
|
|
+ InputStream ksIn = context.getAssets().open(CLIENT_PRI_KEY);
|
|
|
+ InputStream tsIn = context.getAssets().open(TRUSTSTORE_PUB_KEY);//加载证书
|
|
|
+ LOG.i("ksIn:" + ksIn);
|
|
|
+ LOG.i("tsIn:" + tsIn);
|
|
|
+ keyStore.load(ksIn, CLIENT_BKS_PASSWORD.toCharArray());
|
|
|
+ trustStore.load(tsIn, TRUSTSTORE_BKS_PASSWORD.toCharArray());
|
|
|
+
|
|
|
+ ksIn.close();
|
|
|
+ tsIn.close();
|
|
|
+ //初始化SSLContext
|
|
|
+ SSLContext sslContext = SSLContext.getInstance(PROTOCOL_TYPE);
|
|
|
+ TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(CERTIFICATE_FORMAT);
|
|
|
+ KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(CERTIFICATE_FORMAT);
|
|
|
+
|
|
|
+ trustManagerFactory.init(trustStore);
|
|
|
+ keyManagerFactory.init(keyStore, CLIENT_BKS_PASSWORD.toCharArray());
|
|
|
+
|
|
|
+ sslContext.init(keyManagerFactory.getKeyManagers(), null, null);
|
|
|
+// sslContext.init(keyManagerFactory.getKeyManagers(), trustAllCerts, null);
|
|
|
+ sslSocketFactory = sslContext.getSocketFactory();
|
|
|
+ } catch (Exception e) {
|
|
|
+ e.printStackTrace();
|
|
|
+ }
|
|
|
+ return sslSocketFactory;
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ public static boolean proceed(Context context, ClientCertRequest request) {
|
|
|
+ try {
|
|
|
+ // 加载证书
|
|
|
+ KeyStore keyStore = KeyStore.getInstance(KEYSTORE_TYPE);
|
|
|
+// KeyStore keyStore2 = KeyStore.getInstance(KEYSTORE_TYPE);
|
|
|
+ InputStream certInputStream = context.getAssets().open(CLIENT_PRI_KEY);
|
|
|
+ keyStore.load(certInputStream, CLIENT_BKS_PASSWORD.toCharArray());
|
|
|
+
|
|
|
+ PrivateKey privateKey = (PrivateKey) keyStore.getKey(keyStore.aliases().nextElement(), CLIENT_BKS_PASSWORD.toCharArray());
|
|
|
+
|
|
|
+ // 获取证书链
|
|
|
+// InputStream tsIn = context.getAssets().open(TRUSTSTORE_PUB_KEY);//加载证书
|
|
|
+// keyStore2.load(tsIn, TRUSTSTORE_BKS_PASSWORD.toCharArray());
|
|
|
+// PrivateKey privateKey = (PrivateKey) keyStore2.getKey(keyStore2.aliases().nextElement(), CLIENT_BKS_PASSWORD.toCharArray());
|
|
|
+ Enumeration<String> aliases = keyStore.aliases();
|
|
|
+ ArrayList<Certificate> list = new ArrayList<>();
|
|
|
+
|
|
|
+ while (aliases.hasMoreElements()) {
|
|
|
+ String alias = aliases.nextElement();
|
|
|
+ LOG.i("alias:" + alias);
|
|
|
+ Certificate certificate = keyStore.getCertificate(alias);
|
|
|
+ list.add(certificate);
|
|
|
+ }
|
|
|
+ LOG.i("list:" + list.size());
|
|
|
+ X509Certificate[] chain = new X509Certificate[list.size()];
|
|
|
+ for (int i = 0; i < list.size(); i++) {
|
|
|
+ Certificate certificate = list.get(i);
|
|
|
+ chain[i] = (X509Certificate) certificate;
|
|
|
+ }
|
|
|
+ LOG.i("chain[0]:" + chain[0]);
|
|
|
+// certInputStream.close();
|
|
|
+ certInputStream.close();
|
|
|
+ LOG.i("chain:" + chain.length);
|
|
|
+ request.proceed(privateKey, chain);
|
|
|
+ return true;
|
|
|
+ } catch (Exception e) {
|
|
|
+ e.printStackTrace();
|
|
|
+ }
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ public static TrustAllCerts getTrustManager() {
|
|
|
+ return new TrustAllCerts();
|
|
|
+ }
|
|
|
+
|
|
|
+ private static class TrustAllCerts implements X509TrustManager {
|
|
|
+ public void checkClientTrusted(X509Certificate[] chain, String authType) {
|
|
|
+ }
|
|
|
+
|
|
|
+ public void checkServerTrusted(X509Certificate[] chain, String authType) {
|
|
|
+ LOG.i("checkServerTrusted");
|
|
|
+ if (chain == null || chain.length == 0) {
|
|
|
+ throw new RuntimeException(new CertificateException("checkServerTrusted: X509Certificate array is null"));
|
|
|
+ }
|
|
|
+ if (!(null != authType && authType.equals("ECDHE_RSA"))) {
|
|
|
+ throw new RuntimeException(new CertificateException("checkServerTrusted: AuthType is not ECDHE_RSA"));
|
|
|
+ }
|
|
|
+// //判断证书是否是本地信任列表里颁发的证书(系统默认的验证)
|
|
|
+// try {
|
|
|
+// LOG.i("判断证书是否是本地信任列表里颁发的证书(系统默认的验证)");
|
|
|
+// TrustManagerFactory factory = TrustManagerFactory.getInstance("X509");
|
|
|
+// factory.init((KeyStore) null);
|
|
|
+// for (TrustManager trustManager : factory.getTrustManagers()) {
|
|
|
+// ((X509TrustManager) trustManager).checkServerTrusted(chain, authType);
|
|
|
+// }
|
|
|
+// return;//用系统的证书验证服务器证书,验证通过就不需要继续验证证书信息;也可以注释掉,继续走自己的服务器证书逻辑
|
|
|
+// } catch (Exception e) {
|
|
|
+// e.printStackTrace();
|
|
|
+// //注意这个地方不能抛异常,用系统的证书验证服务器证书,没通过就用自己的验证规则
|
|
|
+//// throw new CertificateException(e);
|
|
|
+// }
|
|
|
+
|
|
|
+ LOG.i("获取本地证书中的信息");
|
|
|
+ //获取本地证书中的信息
|
|
|
+ String clientEncoded = "";//公钥
|
|
|
+ String clientSubject = "";//颁发给
|
|
|
+ String clientIssUser = "";//颁发机构
|
|
|
+ try (InputStream inputStream = getAssetFileInputStream()) {
|
|
|
+ KeyStore keyStore = KeyStore.getInstance(KEYSTORE_TYPE);
|
|
|
+ keyStore.load(inputStream, TRUSTSTORE_BKS_PASSWORD.toCharArray());
|
|
|
+ Enumeration<String> aliases = keyStore.aliases();
|
|
|
+ ArrayList<Certificate> list = new ArrayList<>();
|
|
|
+
|
|
|
+ while (aliases.hasMoreElements()) {
|
|
|
+ String alias = aliases.nextElement();
|
|
|
+ LOG.i("alias:" + alias);
|
|
|
+ Certificate certificate = keyStore.getCertificate(alias);
|
|
|
+ list.add(certificate);
|
|
|
+ }
|
|
|
+ for (int i = 0; i < list.size(); i++) {
|
|
|
+ X509Certificate certificate = (X509Certificate) list.get(i);
|
|
|
+ clientEncoded = new BigInteger(1, certificate.getPublicKey().getEncoded()).toString(16);
|
|
|
+ clientSubject = certificate.getSubjectDN().getName();
|
|
|
+ clientIssUser = certificate.getIssuerDN().getName();
|
|
|
+ boolean check = check(chain, clientEncoded, clientSubject, clientIssUser);
|
|
|
+ if (check) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ throw new RuntimeException(new CertificateException("server's PublicKey is not equals to client's PublicKey"));
|
|
|
+ } catch (Exception e) {
|
|
|
+ e.printStackTrace();
|
|
|
+ throw new RuntimeException(new CertificateException(e));
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ public X509Certificate[] getAcceptedIssuers() {
|
|
|
+ return new X509Certificate[0];
|
|
|
+ }
|
|
|
+
|
|
|
+ private InputStream getAssetFileInputStream() {
|
|
|
+ try {
|
|
|
+ InputStream ksIn = Utils.getApp().getAssets().open(TRUSTSTORE_PUB_KEY);
|
|
|
+ return ksIn;
|
|
|
+ } catch (IOException e) {
|
|
|
+ throw new RuntimeException(e);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private static boolean check(X509Certificate[] chain, String clientEncoded, String clientSubject, String clientIssUser) {
|
|
|
+ LOG.i("获取网络中的证书信息");
|
|
|
+ //获取网络中的证书信息
|
|
|
+ X509Certificate certificate = chain[0];
|
|
|
+ PublicKey publicKey = certificate.getPublicKey();
|
|
|
+ String serverEncoded = new BigInteger(1, publicKey.getEncoded()).toString(16);
|
|
|
+ LOG.i("server publicKey:" + serverEncoded);
|
|
|
+
|
|
|
+ if (!clientEncoded.equals(serverEncoded)) {
|
|
|
+ return false;
|
|
|
+// throw new RuntimeException(new CertificateException("server's PublicKey is not equals to client's PublicKey"));
|
|
|
+ }
|
|
|
+ String subject = certificate.getSubjectDN().getName();
|
|
|
+ if (!clientSubject.equals(subject)) {
|
|
|
+// throw new RuntimeException(new CertificateException("server's SubjectDN is not equals to client's SubjectDN"));
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ String issuser = certificate.getIssuerDN().getName();
|
|
|
+ if (!clientIssUser.equals(issuser)) {
|
|
|
+ return false;
|
|
|
+// throw new RuntimeException(new CertificateException("server's IssuerDN is not equals to client's IssuerDN"));
|
|
|
+ }
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+}
|