forked from yoyiyi/bilisoleil
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
1 changed file
with
194 additions
and
0 deletions.
There are no files selected for viewing
194 changes: 194 additions & 0 deletions
194
app/src/main/java/com/yoyiyi/soleil/network/helper/HttpUtils.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,194 @@ | ||
package com.yoyiyi.soleil.network.helper; | ||
|
||
import android.util.Log; | ||
|
||
import java.io.IOException; | ||
import java.io.InputStream; | ||
import java.security.KeyManagementException; | ||
import java.security.KeyStore; | ||
import java.security.NoSuchAlgorithmException; | ||
import java.security.cert.Certificate; | ||
import java.security.cert.CertificateException; | ||
import java.security.cert.CertificateFactory; | ||
import java.security.cert.X509Certificate; | ||
|
||
import javax.net.ssl.HostnameVerifier; | ||
import javax.net.ssl.KeyManager; | ||
import javax.net.ssl.KeyManagerFactory; | ||
import javax.net.ssl.SSLContext; | ||
import javax.net.ssl.SSLSession; | ||
import javax.net.ssl.SSLSocketFactory; | ||
import javax.net.ssl.TrustManager; | ||
import javax.net.ssl.TrustManagerFactory; | ||
import javax.net.ssl.X509TrustManager; | ||
|
||
/** | ||
* @author zzq 作者 E-mail: [email protected] | ||
* @date 创建时间:2017/7/12 17:04 | ||
* 描述:证书验证 | ||
*/ | ||
|
||
public class HttpUtils { | ||
private static final String TAG = "HttpUtils"; | ||
|
||
public static class SSLParams { | ||
public SSLSocketFactory sSLSocketFactory; | ||
public X509TrustManager trustManager; | ||
} | ||
|
||
public static SSLParams getSslSocketFactory() { | ||
return getSslSocketFactoryBase(null, null, null); | ||
} | ||
|
||
/** | ||
* https单向认证 | ||
* 可以额外配置信任服务端的证书策略,否则默认是按CA证书去验证的,若不是CA可信任的证书,则无法通过验证 | ||
*/ | ||
public static SSLParams getSslSocketFactory(X509TrustManager trustManager) { | ||
return getSslSocketFactoryBase(trustManager, null, null); | ||
} | ||
|
||
/** | ||
* https单向认证 | ||
* 用含有服务端公钥的证书校验服务端证书 | ||
*/ | ||
public static SSLParams getSslSocketFactory(InputStream... certificates) { | ||
return getSslSocketFactoryBase(null, null, null, certificates); | ||
} | ||
|
||
/** | ||
* https双向认证 | ||
* bksFile 和 password -> 客户端使用bks证书校验服务端证书 | ||
* certificates -> 用含有服务端公钥的证书校验服务端证书 | ||
*/ | ||
public static SSLParams getSslSocketFactory(InputStream bksFile, String password, InputStream... certificates) { | ||
return getSslSocketFactoryBase(null, bksFile, password, certificates); | ||
} | ||
|
||
/** | ||
* https双向认证 | ||
* bksFile 和 password -> 客户端使用bks证书校验服务端证书 | ||
* X509TrustManager -> 如果需要自己校验,那么可以自己实现相关校验,如果不需要自己校验,那么传null即可 | ||
*/ | ||
public static SSLParams getSslSocketFactory(InputStream bksFile, String password, X509TrustManager trustManager) { | ||
return getSslSocketFactoryBase(trustManager, bksFile, password); | ||
} | ||
|
||
private static SSLParams getSslSocketFactoryBase(X509TrustManager trustManager, InputStream bksFile, String password, InputStream... certificates) { | ||
SSLParams sslParams = new SSLParams(); | ||
try { | ||
KeyManager[] keyManagers = prepareKeyManager(bksFile, password); | ||
TrustManager[] trustManagers = prepareTrustManager(certificates); | ||
X509TrustManager manager; | ||
if (trustManager != null) { | ||
//优先使用用户自定义的TrustManager | ||
manager = trustManager; | ||
} else if (trustManagers != null) { | ||
//然后使用默认的TrustManager | ||
manager = chooseTrustManager(trustManagers); | ||
} else { | ||
//否则使用不安全的TrustManager | ||
manager = UnSafeTrustManager; | ||
} | ||
// 创建TLS类型的SSLContext对象, that uses our TrustManager | ||
SSLContext sslContext = SSLContext.getInstance("TLS"); | ||
// 用上面得到的trustManagers初始化SSLContext,这样sslContext就会信任keyStore中的证书 | ||
// 第一个参数是授权的密钥管理器,用来授权验证,比如授权自签名的证书验证。第二个是被授权的证书管理器,用来验证服务器端的证书 | ||
sslContext.init(keyManagers, new TrustManager[]{manager}, null); | ||
// 通过sslContext获取SSLSocketFactory对象 | ||
sslParams.sSLSocketFactory = sslContext.getSocketFactory(); | ||
sslParams.trustManager = manager; | ||
return sslParams; | ||
} catch (NoSuchAlgorithmException e) { | ||
throw new AssertionError(e); | ||
} catch (KeyManagementException e) { | ||
throw new AssertionError(e); | ||
} | ||
} | ||
|
||
private static KeyManager[] prepareKeyManager(InputStream bksFile, String password) { | ||
try { | ||
if (bksFile == null || password == null) return null; | ||
KeyStore clientKeyStore = KeyStore.getInstance("BKS"); | ||
clientKeyStore.load(bksFile, password.toCharArray()); | ||
KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm()); | ||
kmf.init(clientKeyStore, password.toCharArray()); | ||
return kmf.getKeyManagers(); | ||
} catch (Exception e) { | ||
Log.d(TAG, e.toString()); | ||
} | ||
return null; | ||
} | ||
|
||
private static TrustManager[] prepareTrustManager(InputStream... certificates) { | ||
if (certificates == null || certificates.length <= 0) return null; | ||
try { | ||
CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509"); | ||
// 创建一个默认类型的KeyStore,存储我们信任的证书 | ||
KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType()); | ||
keyStore.load(null); | ||
int index = 0; | ||
for (InputStream certStream : certificates) { | ||
String certificateAlias = Integer.toString(index++); | ||
// 证书工厂根据证书文件的流生成证书 cert | ||
Certificate cert = certificateFactory.generateCertificate(certStream); | ||
// 将 cert 作为可信证书放入到keyStore中 | ||
keyStore.setCertificateEntry(certificateAlias, cert); | ||
try { | ||
if (certStream != null) certStream.close(); | ||
} catch (IOException e) { | ||
Log.d(TAG, e.toString()); | ||
} | ||
} | ||
//我们创建一个默认类型的TrustManagerFactory | ||
TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); | ||
//用我们之前的keyStore实例初始化TrustManagerFactory,这样tmf就会信任keyStore中的证书 | ||
tmf.init(keyStore); | ||
//通过tmf获取TrustManager数组,TrustManager也会信任keyStore中的证书 | ||
return tmf.getTrustManagers(); | ||
} catch (Exception e) { | ||
Log.d(TAG, e.toString()); | ||
} | ||
return null; | ||
} | ||
|
||
private static X509TrustManager chooseTrustManager(TrustManager[] trustManagers) { | ||
for (TrustManager trustManager : trustManagers) { | ||
if (trustManager instanceof X509TrustManager) { | ||
return (X509TrustManager) trustManager; | ||
} | ||
} | ||
return null; | ||
} | ||
|
||
/** | ||
* 为了解决客户端不信任服务器数字证书的问题,网络上大部分的解决方案都是让客户端不对证书做任何检查, | ||
* 这是一种有很大安全漏洞的办法 | ||
*/ | ||
public static X509TrustManager UnSafeTrustManager = new X509TrustManager() { | ||
@Override | ||
public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException { | ||
} | ||
|
||
@Override | ||
public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException { | ||
} | ||
|
||
@Override | ||
public X509Certificate[] getAcceptedIssuers() { | ||
return new java.security.cert.X509Certificate[]{}; | ||
} | ||
}; | ||
|
||
/** | ||
* 此类是用于主机名验证的基接口。 在握手期间,如果 URL 的主机名和服务器的标识主机名不匹配, | ||
* 则验证机制可以回调此接口的实现程序来确定是否应该允许此连接。策略可以是基于证书的或依赖于其他验证方案。 | ||
* 当验证 URL 主机名使用的默认规则失败时使用这些回调。如果主机名是可接受的,则返回 true | ||
*/ | ||
public static HostnameVerifier UnSafeHostnameVerifier = new HostnameVerifier() { | ||
@Override | ||
public boolean verify(String hostname, SSLSession session) { | ||
return true; | ||
} | ||
}; | ||
} |