以下筆者實測單向驗證可運作(雙向尚未驗證)
安卓指定CA證書步驟:
application中加入設定android:networkSecurityConfig
可排除部分僅用http
可排除第三方使用系統CA證書(他方CA證書)OkHttpClient.Builder給定CA證書sslSocketFactory
可在hostnameVerifier指定信任的域名或地址
步驟一
<application
android:name=".MyApplication"
android:allowBackup="true"
android:icon="@mipmap/ic_launcher_app"
android:label="@string/app_name"
android:largeHeap="true"
android:supportsRtl="true"
android:networkSecurityConfig="@xml/network_security_config"
android:theme="@style/AppTheme">
<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
<base-config cleartextTrafficPermitted="false" >
<trust-anchors>
<certificates src="@raw/mycertificate" />
</trust-anchors>
</base-config>
<!-- for some only support http-->
<domain-config cleartextTrafficPermitted="true">
<domain includeSubdomains="true">my.exclude.com</domain>
<trust-anchors>
<certificates src="@raw/mycertificate" />
</trust-anchors>
</domain-config>
<!--友盟分析採用第三方CA, 設定domain排除-->
<domain-config cleartextTrafficPermitted="true">
<domain includeSubdomains="true">ulogs.umeng.com</domain>
<domain includeSubdomains="true">ulogs.umengcloud.com</domain>
<trust-anchors>
<certificates src="system"/>
</trust-anchors>
</domain-config>
</network-security-config>
步驟二
OkHttpClient.Builder builder = new OkHttpClient.Builder()
.cookieJar(new NovateCookieManger())
.cache(cache)
.addInterceptor(new CacheInterceptor())
.addNetworkInterceptor(new CacheInterceptor())
.addNetworkInterceptor(new HttpLoggingInterceptor().setLevel(HttpLoggingInterceptor.Level.BODY))
.connectTimeout(DEFAULT_TIMEOUT, TimeUnit.SECONDS)
.writeTimeout(DEFAULT_TIMEOUT, TimeUnit.SECONDS)
.readTimeout(DEFAULT_TIMEOUT, TimeUnit.SECONDS)
.connectionPool(new ConnectionPool(8, 15, TimeUnit.SECONDS));
if(SSLCustom){
builder.sslSocketFactory(getSocketFactory(), 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 X509Certificate[0];
}
})
.hostnameVerifier(new HostnameVerifier() {
@Override
public boolean verify(String hostname, SSLSession session) {
return true;
//return hostname.compareTo("192.1.1.1")==0; //you can compare the Hostname of your server
}
});
}
public static SSLSocketFactory getSocketFactory() {
try {
CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");
KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
keyStore.load(null);
String certificateStrs[] = new String[]{
"mycertificate1.cer"
"mycertificate2.cer"
};
for(int i=0;i<certificateStrs.length;i++){
InputStream is = BaseApplication.getInstance().getAssets().open(certificateStrs[i]);
keyStore.setCertificateEntry(i+"", certificateFactory.generateCertificate(is));
if (is!=null){
is.close();
}
}
SSLContext sslContext = SSLContext.getInstance("TLS");
TrustManagerFactory trustManagerFactory =
TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
trustManagerFactory.init(keyStore);
//初始化keystore, 雙向驗證
// KeyStore clientKeyStore = KeyStore.getInstance("BKS");
// clientKeyStore.load(BaseApplication.getInstance().getAssets().open("client.bks"), "quantdo".toCharArray());
// KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
// keyManagerFactory.init(clientKeyStore, "quantdo".toCharArray());
// sslContext.init(keyManagerFactory.getKeyManagers(), trustManagerFactory.getTrustManagers(), new SecureRandom());
//單向驗證
sslContext.init(null, trustManagerFactory.getTrustManagers(), new SecureRandom());
return sslContext.getSocketFactory();
} catch (Exception e) {
e.printStackTrace();
}
return null;
}