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的时候回报错的哦
keytool -importcert -trustcacerts -keystore E:\newkey\client.bks -file E:\keyhttps\server.cer -storetype BKS -provider org.bouncycastle.jce.provider.BouncyCastleProvider
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(); } } }
HttpsUtil类
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> T getService(Class<T> 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; } }这是配置文件,其他项目类 需要的话 私我