|
|
@@ -1,10 +1,15 @@
|
|
|
package com.guiying.common.http;
|
|
|
|
|
|
+import android.annotation.SuppressLint;
|
|
|
import android.content.Context;
|
|
|
+import android.os.Build;
|
|
|
import android.support.annotation.RawRes;
|
|
|
|
|
|
import java.io.IOException;
|
|
|
import java.io.InputStream;
|
|
|
+import java.net.InetAddress;
|
|
|
+import java.net.Socket;
|
|
|
+import java.net.UnknownHostException;
|
|
|
import java.security.KeyManagementException;
|
|
|
import java.security.KeyStore;
|
|
|
import java.security.KeyStoreException;
|
|
|
@@ -20,6 +25,7 @@ import javax.net.ssl.KeyManager;
|
|
|
import javax.net.ssl.KeyManagerFactory;
|
|
|
import javax.net.ssl.SSLContext;
|
|
|
import javax.net.ssl.SSLSession;
|
|
|
+import javax.net.ssl.SSLSocket;
|
|
|
import javax.net.ssl.SSLSocketFactory;
|
|
|
import javax.net.ssl.TrustManager;
|
|
|
import javax.net.ssl.TrustManagerFactory;
|
|
|
@@ -29,14 +35,26 @@ import javax.net.ssl.X509TrustManager;
|
|
|
* HttpsUtils来自于鸿洋的: https://github.com/hongyangAndroid/okhttputils;
|
|
|
* 增加了主机名校验方法getHostnameVerifier();
|
|
|
* 其他参考的文章有:http://android.jobbole.com/83787/;
|
|
|
+ *
|
|
|
+ * Android 4.X 对TLS1.1、TLS1.2的支持参考了http://blog.csdn.net/joye123/article/details/53888252
|
|
|
*/
|
|
|
public class HttpsUtil {
|
|
|
|
|
|
+ /**
|
|
|
+ * 包装的 SSL(Secure Socket Layer)参数类
|
|
|
+ */
|
|
|
public static class SSLParams {
|
|
|
public SSLSocketFactory sSLSocketFactory;
|
|
|
public X509TrustManager trustManager;
|
|
|
}
|
|
|
|
|
|
+ /**
|
|
|
+ * @param context 上下文
|
|
|
+ * @param certificatesId "XXX.cer" 文件 (文件位置res/raw/XXX.cer)
|
|
|
+ * @param bksFileId "XXX.bks"文件(文件位置res/raw/XXX.bks)
|
|
|
+ * @param password The certificate's password.
|
|
|
+ * @return SSLParams
|
|
|
+ */
|
|
|
public static SSLParams getSslSocketFactory(Context context, @RawRes int[] certificatesId, @RawRes int bksFileId, String password) {
|
|
|
if (context == null) {
|
|
|
throw new NullPointerException("context == null");
|
|
|
@@ -44,10 +62,11 @@ public class HttpsUtil {
|
|
|
SSLParams sslParams = new SSLParams();
|
|
|
try {
|
|
|
TrustManager[] trustManagers = prepareTrustManager(context, certificatesId);
|
|
|
+ KeyManager[] keyManagers = prepareKeyManager(context, bksFileId, password);
|
|
|
|
|
|
- KeyManager[] keyManagers = prepareKeyManager(context.getResources().openRawResource(bksFileId), password);
|
|
|
//创建TLS类型的SSLContext对象,that uses our TrustManager
|
|
|
SSLContext sslContext = SSLContext.getInstance("TLS");
|
|
|
+
|
|
|
X509TrustManager x509TrustManager;
|
|
|
if (trustManagers != null) {
|
|
|
x509TrustManager = new MyTrustManager(chooseTrustManager(trustManagers));
|
|
|
@@ -56,7 +75,15 @@ public class HttpsUtil {
|
|
|
}
|
|
|
//用上面得到的trustManagers初始化SSLContext,这样sslContext就会信任keyStore中的证书
|
|
|
sslContext.init(keyManagers, new TrustManager[]{x509TrustManager}, null);
|
|
|
+
|
|
|
//通过sslContext获取SSLSocketFactory对象
|
|
|
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
|
|
|
+ /*Android 4.X 对TLS1.1、TLS1.2的支持*/
|
|
|
+ sslParams.sSLSocketFactory = new Tls12SocketFactory(sslContext.getSocketFactory());
|
|
|
+ sslParams.trustManager = x509TrustManager;
|
|
|
+ return sslParams;
|
|
|
+ }
|
|
|
+
|
|
|
sslParams.sSLSocketFactory = sslContext.getSocketFactory();
|
|
|
sslParams.trustManager = x509TrustManager;
|
|
|
return sslParams;
|
|
|
@@ -65,8 +92,25 @@ public class HttpsUtil {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 主机名校验方法
|
|
|
+ */
|
|
|
+ public static HostnameVerifier getHostnameVerifier() {
|
|
|
+ return new HostnameVerifier() {
|
|
|
+ @Override
|
|
|
+ public boolean verify(String hostname, SSLSession session) {
|
|
|
+ return hostname.equalsIgnoreCase(session.getPeerHost());
|
|
|
+ }
|
|
|
+ };
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
private static TrustManager[] prepareTrustManager(Context context, int[] certificatesId) {
|
|
|
- if (certificatesId == null || certificatesId.length <= 0) return null;
|
|
|
+ if (certificatesId == null || certificatesId.length <= 0) {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
try {
|
|
|
//创建X.509格式的CertificateFactory
|
|
|
CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");
|
|
|
@@ -78,7 +122,9 @@ public class HttpsUtil {
|
|
|
//从本地资源中获取证书的流
|
|
|
InputStream cerInputStream = context.getResources().openRawResource(certificateId);
|
|
|
String certificateAlias = Integer.toString(index++);
|
|
|
+
|
|
|
//certificate是java.security.cert.Certificate,而不是其他Certificate
|
|
|
+ //证书工厂根据证书文件的流生成证书Certificate
|
|
|
Certificate certificate = certificateFactory.generateCertificate(cerInputStream);
|
|
|
//将证书certificate作为信任的证书放入到keyStore中
|
|
|
keyStore.setCertificateEntry(certificateAlias, certificate);
|
|
|
@@ -89,6 +135,7 @@ public class HttpsUtil {
|
|
|
e.printStackTrace();
|
|
|
}
|
|
|
}
|
|
|
+
|
|
|
//TrustManagerFactory是用于生成TrustManager的,这里创建一个默认类型的TrustManagerFactory
|
|
|
TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
|
|
|
//用我们之前的keyStore实例初始化TrustManagerFactory,这样trustManagerFactory就会信任keyStore中的证书
|
|
|
@@ -100,35 +147,46 @@ public class HttpsUtil {
|
|
|
return null;
|
|
|
}
|
|
|
|
|
|
- private static KeyManager[] prepareKeyManager(InputStream bksFile, String password) {
|
|
|
- try {
|
|
|
- if (bksFile == null || password == null) return null;
|
|
|
|
|
|
+ private static KeyManager[] prepareKeyManager(Context context, @RawRes int bksFileId, String password) {
|
|
|
+
|
|
|
+ try {
|
|
|
KeyStore clientKeyStore = KeyStore.getInstance("BKS");
|
|
|
- clientKeyStore.load(bksFile, password.toCharArray());
|
|
|
+ clientKeyStore.load(context.getResources().openRawResource(bksFileId), password.toCharArray());
|
|
|
KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
|
|
|
keyManagerFactory.init(clientKeyStore, password.toCharArray());
|
|
|
return keyManagerFactory.getKeyManagers();
|
|
|
|
|
|
- } catch (KeyStoreException | NoSuchAlgorithmException | UnrecoverableKeyException | CertificateException e) {
|
|
|
- e.printStackTrace();
|
|
|
- } catch (IOException e) {
|
|
|
+ } catch (KeyStoreException | NoSuchAlgorithmException | UnrecoverableKeyException | CertificateException | IOException e) {
|
|
|
e.printStackTrace();
|
|
|
}
|
|
|
return null;
|
|
|
}
|
|
|
|
|
|
|
|
|
+ private static X509TrustManager chooseTrustManager(TrustManager[] trustManagers) {
|
|
|
+ for (TrustManager trustManager : trustManagers) {
|
|
|
+ if (trustManager instanceof X509TrustManager) {
|
|
|
+ return (X509TrustManager) trustManager;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
/**
|
|
|
* 客户端不对证书做任何检查;
|
|
|
* 客户端不对证书做任何验证的做法有很大的安全漏洞。
|
|
|
*/
|
|
|
private static class UnSafeTrustManager implements X509TrustManager {
|
|
|
+
|
|
|
+ @SuppressLint("TrustAllX509TrustManager")
|
|
|
@Override
|
|
|
public void checkClientTrusted(X509Certificate[] chain, String authType)
|
|
|
throws CertificateException {
|
|
|
}
|
|
|
|
|
|
+ @SuppressLint("TrustAllX509TrustManager")
|
|
|
@Override
|
|
|
public void checkServerTrusted(X509Certificate[] chain, String authType)
|
|
|
throws CertificateException {
|
|
|
@@ -154,6 +212,7 @@ public class HttpsUtil {
|
|
|
}
|
|
|
|
|
|
|
|
|
+ @SuppressLint("TrustAllX509TrustManager")
|
|
|
@Override
|
|
|
public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
|
|
|
|
|
|
@@ -176,26 +235,62 @@ public class HttpsUtil {
|
|
|
}
|
|
|
|
|
|
|
|
|
- private static X509TrustManager chooseTrustManager(TrustManager[] trustManagers) {
|
|
|
- for (TrustManager trustManager : trustManagers) {
|
|
|
- if (trustManager instanceof X509TrustManager) {
|
|
|
- return (X509TrustManager) trustManager;
|
|
|
- }
|
|
|
+ /**
|
|
|
+ * 自行实现SSLSocketFactory ,实现Android 4.X 对TLSv1.1、TLSv1.2的支持
|
|
|
+ */
|
|
|
+ private static class Tls12SocketFactory extends SSLSocketFactory {
|
|
|
+
|
|
|
+ private static final String[] TLS_SUPPORT_VERSION = {"TLSv1.1", "TLSv1.2"};
|
|
|
+
|
|
|
+ final SSLSocketFactory delegate;
|
|
|
+
|
|
|
+ private Tls12SocketFactory(SSLSocketFactory base) {
|
|
|
+ this.delegate = base;
|
|
|
}
|
|
|
- return null;
|
|
|
- }
|
|
|
|
|
|
+ @Override
|
|
|
+ public String[] getDefaultCipherSuites() {
|
|
|
+ return delegate.getDefaultCipherSuites();
|
|
|
+ }
|
|
|
|
|
|
- /**
|
|
|
- * 主机名校验方法
|
|
|
- */
|
|
|
- public static HostnameVerifier getHostnameVerifier() {
|
|
|
- return new HostnameVerifier() {
|
|
|
- @Override
|
|
|
- public boolean verify(String hostname, SSLSession session) {
|
|
|
- return hostname.equalsIgnoreCase(session.getPeerHost());
|
|
|
+ @Override
|
|
|
+ public String[] getSupportedCipherSuites() {
|
|
|
+ return delegate.getSupportedCipherSuites();
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public Socket createSocket(Socket s, String host, int port, boolean autoClose) throws IOException {
|
|
|
+ return patch(delegate.createSocket(s, host, port, autoClose));
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public Socket createSocket(String host, int port) throws IOException, UnknownHostException {
|
|
|
+ return patch(delegate.createSocket(host, port));
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public Socket createSocket(String host, int port, InetAddress localHost, int localPort) throws IOException, UnknownHostException {
|
|
|
+ return patch(delegate.createSocket(host, port, localHost, localPort));
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public Socket createSocket(InetAddress host, int port) throws IOException {
|
|
|
+ return patch(delegate.createSocket(host, port));
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public Socket createSocket(InetAddress address, int port, InetAddress localAddress, int localPort) throws IOException {
|
|
|
+ return patch(delegate.createSocket(address, port, localAddress, localPort));
|
|
|
+ }
|
|
|
+
|
|
|
+ private Socket patch(Socket s) {
|
|
|
+ //代理SSLSocketFactory在创建一个Socket连接的时候,会设置Socket的可用的TLS版本。
|
|
|
+ if (s instanceof SSLSocket) {
|
|
|
+ ((SSLSocket) s).setEnabledProtocols(TLS_SUPPORT_VERSION);
|
|
|
}
|
|
|
- };
|
|
|
+ return s;
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
+
|
|
|
}
|