網絡(二):簡單易懂的https雙向認證自制安全證書和tomcat配置
網絡(三):簡單易懂的Android平臺Okhttp/Retrofit下的https雙向認證環(huán)境配置
前面的兩篇文章(網絡(一)和網絡(二))已經簡單總結了https的工作原理、證書的生成過程和tomcat的配置以及PC端的證書導入過程牺弄,具體每一個不走都有相應的代碼和截圖雷酪。安卓平臺下現(xiàn)在主流使用網絡框架且官方推薦使用的網絡框架為okhttp,或基于okhttp的retrofit框架卵渴,其實retrofit的配置還是通過okhttp配置垦江。
證書準備
網絡(二)中已經生成了客戶端密鑰client.jks 和包含服務端公鑰證書publickeys.jks姑躲,但是安卓平臺不支持jsk,需要將jsk轉成bks,依然使用工具portecle進行轉換撩鹿。
證書導入工程
放入assets工程下就好了
image.png
讀取密鑰代碼
import android.content.Context;
import java.io.IOException;
import java.io.InputStream;
import java.security.KeyManagementException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.UnrecoverableKeyException;
import java.security.cert.CertificateException;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManagerFactory;
/**
* Created by Zhouds
* Created time 2018/03/26.
* Description:
* Version: V 1.0
*/
public class SSLHelper {
/**
* 存儲客戶端自己的密鑰
*/
private final static String CLIENT_PRI_KEY = "client.bks";
/**
* 存儲服務器的公鑰
*/
private final static String TRUSTSTORE_PUB_KEY = "publickey.bks";
/**
* 讀取密碼
*/
private final static String CLIENT_BKS_PASSWORD = "123321";
/**
* 讀取密碼
*/
private final static String PUCBLICKEY_BKS_PASSWORD = "123321";
private final static String KEYSTORE_TYPE = "BKS";
private final static String PROTOCOL_TYPE = "TLS";
private final static String CERTIFICATE_STANDARD = "X509";
public static SSLSocketFactory getSSLCertifcation(Context context) {
SSLSocketFactory sslSocketFactory = null;
try {
// 服務器端需要驗證的客戶端證書谦炬,其實就是客戶端的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);
//加載證書
keyStore.load(ksIn, CLIENT_BKS_PASSWORD.toCharArray());
trustStore.load(tsIn, PUCBLICKEY_BKS_PASSWORD.toCharArray());
//關閉流
ksIn.close();
tsIn.close();
//初始化SSLContext
SSLContext sslContext = SSLContext.getInstance(PROTOCOL_TYPE);
TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(CERTIFICATE_STANDARD);
KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(CERTIFICATE_STANDARD);
trustManagerFactory.init(trustStore);
keyManagerFactory.init(keyStore, CLIENT_BKS_PASSWORD.toCharArray());
sslContext.init(keyManagerFactory.getKeyManagers(), trustManagerFactory.getTrustManagers(), null);
sslSocketFactory = sslContext.getSocketFactory();
} catch (KeyStoreException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (CertificateException e) {
e.printStackTrace();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (UnrecoverableKeyException e) {
e.printStackTrace();
} catch (KeyManagementException e) {
e.printStackTrace();
}
return sslSocketFactory;
}
}
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.SSLSession;
import itsen.com.bduidemo.lib.tool.LogTool;
/**
* Created by zhoud
* Created time 2018/03/27.
* Description:
* Version: V 1.0
*/
public class UnSafeHostnameVerifier implements HostnameVerifier {
@Override
public boolean verify(String hostname, SSLSession session) {
LogTool.e("hostname:"+hostname);
return true;
}
}
OKHTTP添加SSL
//參數配置
client = new OkHttpClient.Builder()
.sslSocketFactory(SSLHelper.getSSLCertifcation(this))
.hostnameVerifier(new UnSafeHostnameVerifier())
.addInterceptor(loggingInterceptor)
.connectTimeout(mTimeOut, TimeUnit.SECONDS)
.readTimeout(mTimeOut, TimeUnit.SECONDS)
.writeTimeout(mTimeOut, TimeUnit.SECONDS)
.build();
//retrofit 對象初始化
retrofit = new Retrofit.Builder()
.baseUrl(baseUrl + FORADN)
.addConverterFactory(GsonConverterFactory.create())
.client(client)
.build();
驗證
1)tomcat日志,433端口接受了請求并返回請求
image.png
2)retrofit請求日志
image.png
3)手機頁面
image.png
至此整個https雙向認證環(huán)境搭建完畢=诼佟<肌!
如果解決你的問題甫贯,請給個喜歡吼鳞,謝謝!=懈椤赔桌!