Https双向认证啊 做了两遍,第一遍懵懂状态处于 好不容易做好了,换服务器,一下子懵了,使出浑身解数又找了一遍,这下终于好了 快哭啦,必须滴要记录一下,以免以后遇到继续懵,这里用retrofit2+okhttp3为例子来简单说明下
先来说说证书:
服务端提供的证书有四个(我这里四个就够用了,有的上面介绍说有一个p12证书,原来提供过,表示没用到,可能是我用的验证方法不一样吧)
转化步骤:
1)生成客户端证书
keytool -genkeypair -alias client -keyalg RSA -validity 3650 -keypass123456 -storepass 123456 -keystore client.jks
这里要说一下,client.jks后端的同事已经提供给我,这一步我就省啦,如果没提供的话 走一步就行啦
2)生成服务端keystore
keytool -genkeypair -alias server -keyalg RSA -validity 3650 -keypass 123456 -storepass123456 -keystore server.keystore
这个也提供啦,我也省了哈
3)导出客户端证书
keytool -export -alias client -file client.cer -keystore client.jks -storepass 123456
这里根据本人理解是将客户端的jks证书导入到服务端cer证书中
4)导出服务端证书
keytool -export -alias server -file server.cer -keystore server.keystore -storepass 123456
这里本人理解是将cer证书导入到keystore中(这里感觉理解的不是很透彻,勿喷)
5)证书交换
将客户端证书导入服务端keystore中,再将服务端证书导入客户端keystore中, 一个keystore可以导入多个证书,生成证书列表。
生成客户端信任证书库(由服务端证书生成的证书库):
keytool -import -v -alias server -file server.cer -keystore truststore.jks -storepass 123456
将客户端证书导入到服务器证书库(使得服务器信任客户端证书):
keytool -import -v -alias client -file client.cer -keystore server.keystore -storepass 123456
6)转换jks证书为Android能够识别的BKS证书
将client.jks和truststore.jks通过portecle-1.9软件转换为.bks文件
步骤:打开portecle.jar文件(window系统的,直接打开是压缩包哦,要选择打开方式 用java方式打开,或者直接切换到mac系统转换好了再粘贴回来即可)
注意:我这里转换client.jks的时候回报错的哦
import android.app.Application;
import android.os.Environment;
import android.os.Process;
import android.util.Log;
import com.baidu.mapapi.SDKInitializer;
import com.franmontiel.persistentcookiejar.ClearableCookieJar;
import com.franmontiel.persistentcookiejar.PersistentCookieJar;
import com.franmontiel.persistentcookiejar.cache.SetCookieCache;
import com.franmontiel.persistentcookiejar.persistence.SharedPrefsCookiePersistor;
import com.zhy.http.okhttp.OkHttpUtils;
import com.zhy.http.okhttp.https.HttpsUtils;
import com.zhy.http.okhttp.log.LoggerInterceptor;
import org.wlf.filedownloader.FileDownloadConfiguration;
import org.wlf.filedownloader.FileDownloader;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.concurrent.TimeUnit;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.SSLSession;
import okhttp3.OkHttpClient;
import static android.content.ContentValues.TAG;
/**
* Created by Jane on 2017/6/23.
*/
public class HNAPPlication extends Application {
private final static String CLIENT_PRI_KEY = "client.bks";
private final static String TRUSTSTORE_PUB_KEY = "truststore.bks";
private final static String SERVER_KEY = "server.cer";
@Override
public void onCreate() {
super.onCreate();
initOkhttp();
// 在使用 SDK 各组间之前初始化 context 信息,传入 ApplicationContext
checkAppReplacingState();
}
private void checkAppReplacingState() {
if (getResources() == null) {
Log.w(TAG, "app is replacing...kill");
Process.killProcess(Process.myPid());
}
}
private void initOkhttp() {
//InputStream [] inputStreams=null;
ClearableCookieJar cookieJar1 = new PersistentCookieJar(new SetCookieCache(), new SharedPrefsCookiePersistor(getApplicationContext()));
// inputStreams = new InputStream[4];
// try {
//// inputStreams[0] = getClass().getResourceAsStream("/assets/newkey.cer");
// inputStreams[0] = getAssets().open("newkey.cer");
// } catch (IOException e) {
// e.printStackTrace();
// }
//读取证书
try {
InputStream clientkey = getAssets().open(CLIENT_PRI_KEY);
InputStream serverkey = getAssets().open(TRUSTSTORE_PUB_KEY);
InputStream[] inputStreams = new InputStream[4];
// inputStreams[0] = getClass().getResourceAsStream("/assets/" + SERVER_KEY);
inputStreams[0] = getAssets().open(SERVER_KEY);
HttpsUtils.SSLParams sslParams = HttpsUtils.getSslSocketFactory(inputStreams, clientkey, "Eastcom_1");
// CookieJarImpl cookieJar1 = new CookieJarImpl(new MemoryCookieStore());
OkHttpClient okHttpClient = new OkHttpClient.Builder()
.connectTimeout(10000L, TimeUnit.MILLISECONDS)
.readTimeout(10000L, TimeUnit.MILLISECONDS)
.addInterceptor(new LoggerInterceptor("TAG"))
.cookieJar(cookieJar1)
.hostnameVerifier(new HostnameVerifier() {
@Override
public boolean verify(String hostname, SSLSession session) {
return true;
}
})
.sslSocketFactory(sslParams.sSLSocketFactory, sslParams.trustManager)
.build();
OkHttpUtils.initClient(okHttpClient);
} catch (IOException e) {
e.printStackTrace();
}
}
}
public class HttpsUtils
{
public static class SSLParams
{
public SSLSocketFactory sSLSocketFactory;
public X509TrustManager trustManager;
}
public static SSLParams getSslSocketFactory(InputStream[] certificates, InputStream bksFile, String password)
{
SSLParams sslParams = new SSLParams();
try
{
TrustManager[] trustManagers = prepareTrustManager(certificates);
KeyManager[] keyManagers = prepareKeyManager(bksFile, password);
SSLContext sslContext = SSLContext.getInstance("TLS");
X509TrustManager trustManager = null;
if (trustManagers != null)
{
trustManager = new MyTrustManager(chooseTrustManager(trustManagers));
} else
{
trustManager = new UnSafeTrustManager();
}
sslContext.init(keyManagers, new TrustManager[]{trustManager},null);
sslParams.sSLSocketFactory = sslContext.getSocketFactory();
sslParams.trustManager = trustManager;
return sslParams;
} catch (NoSuchAlgorithmException e)
{
throw new AssertionError(e);
} catch (KeyManagementException e)
{
throw new AssertionError(e);
} catch (KeyStoreException e)
{
throw new AssertionError(e);
}
}
private class UnSafeHostnameVerifier implements HostnameVerifier
{
@Override
public boolean verify(String hostname, SSLSession session)
{
return true;
}
}
private static class UnSafeTrustManager implements 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[]{};
}
}
private static TrustManager[] prepareTrustManager(InputStream... certificates)
{
if (certificates == null || certificates.length <= 0) return null;
try
{
CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");
KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
keyStore.load(null);
int index = 0;
for (InputStream certificate : certificates)
{
String certificateAlias = Integer.toString(index++);
keyStore.setCertificateEntry(certificateAlias, certificateFactory.generateCertificate(certificate));
try
{
if (certificate != null)
certificate.close();
} catch (IOException e)
{
}
}
TrustManagerFactory trustManagerFactory = null;
trustManagerFactory = TrustManagerFactory.
getInstance(TrustManagerFactory.getDefaultAlgorithm());
trustManagerFactory.init(keyStore);
TrustManager[] trustManagers = trustManagerFactory.getTrustManagers();
return trustManagers;
} catch (NoSuchAlgorithmException e)
{
e.printStackTrace();
} catch (CertificateException e)
{
e.printStackTrace();
} catch (KeyStoreException e)
{
e.printStackTrace();
} catch (Exception e)
{
e.printStackTrace();
}
return null;
}
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 keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
keyManagerFactory.init(clientKeyStore, password.toCharArray());
return keyManagerFactory.getKeyManagers();
} catch (KeyStoreException e)
{
e.printStackTrace();
} catch (NoSuchAlgorithmException e)
{
e.printStackTrace();
} catch (UnrecoverableKeyException e)
{
e.printStackTrace();
} catch (CertificateException e)
{
e.printStackTrace();
} catch (IOException e)
{
e.printStackTrace();
} catch (Exception 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 MyTrustManager implements X509TrustManager
{
private X509TrustManager defaultTrustManager;
private X509TrustManager localTrustManager;
public MyTrustManager(X509TrustManager localTrustManager) throws NoSuchAlgorithmException, KeyStoreException
{
TrustManagerFactory var4 = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
var4.init((KeyStore) null);
defaultTrustManager = chooseTrustManager(var4.getTrustManagers());
this.localTrustManager = localTrustManager;
}
@Override
public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException
{
}
@Override
public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException
{
try
{
defaultTrustManager.checkServerTrusted(chain, authType);
} catch (CertificateException ce)
{
localTrustManager.checkServerTrusted(chain, authType);
}
}
@Override
public X509Certificate[] getAcceptedIssuers()
{
return new X509Certificate[0];
}
}
}
Net请求配置
/**
* Created by Jane on 2017/6/16.
* 网络请求Api
*/
public class NetHttpApi {
private Retrofit retrofit;
//请求超时时间
private static final int REQUEST_TIME = 10;
private static NetHttpApi instance;
private Context context;
private OkHttpClient okHttpClient;
private InputStream[] inputStreams;
private SSLSocketFactory sslSocketFactory;
/**
* @param urlType url访问地址类型
**/
private NetHttpApi(int urlType, Context context) {
this.context = context;
// //日志显示级别
Gson gson = new GsonBuilder()
.setLenient()
.create();
OkHttpClient client = aa();
if (urlType == Contants.OLD_URL_TYPE) {
retrofit = new Retrofit.Builder().client(client)
.addConverterFactory(GsonConverterFactory.create(gson))
.addCallAdapterFactory(RxJavaCallAdapterFactory.create())
.baseUrl(Contants.APP_OLD_URL).build();
} else if (urlType == Contants.NEW_URL_TYPE) {
retrofit = new Retrofit.Builder().client(client)
.addConverterFactory(GsonConverterFactory.create(gson))
.addCallAdapterFactory(RxJavaCallAdapterFactory.create())
.baseUrl(Contants.APP_URL).build();
}
}
private OkHttpClient aa() {
//日志显示级别
HttpLoggingInterceptor.Level level = HttpLoggingInterceptor.Level.BODY;
//新建log拦截器
HttpLoggingInterceptor loggingInterceptor = new HttpLoggingInterceptor(new HttpLoggingInterceptor.Logger() {
@Override
public void log(String message) {
Log.d("vvvvvvvvv", "OkHttp====Message==:" + message);
}
});
loggingInterceptor.setLevel(level);
OkHttpClient okHttpClient = new OkHttpClient.Builder()
.sslSocketFactory(SSLHelper.getSSLCertifcation(context))
.hostnameVerifier(new UnSafeHostnameVerifier())
.addInterceptor(loggingInterceptor)
.build();
return okHttpClient;
}
/**
* 创建单例模式,避免重复创建对象
**/
public static NetHttpApi getInstance(final int urlType, Context context) {
// if (instance == null) {
// synchronized (NetHttpApi.class) {
// if (instance == null) {
// instance = new NetHttpApi(urlType,context);
// }
// }
// }
NetHttpApi netHttpApi = new NetHttpApi(urlType, context);
return netHttpApi;
}
/**
* 获取一个service对象
*/
public T getService(Class service) {
return retrofit.create(service);
}
}
SSLHelper
public class SSLHelper {
private final static String CLIENT_PRI_KEY = "client.bks";
private final static String TRUSTSTORE_PUB_KEY = "truststore.bks";
private final static String CLIENT_BKS_PASSWORD = "Eastcom_1";
private final static String TRUSTSTORE_BKS_PASSWORD = "Eastcom_1";
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, TRUSTSTORE_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;
}
}
这是配置文件,其他项目类 需要的话 私我