Https双向认证Android客户端配置

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的时候回报错的哦

java.security.KeyStoreException: java.io.IOException: Error initialising store of key store: java.security.InvalidKeyException: Illegal key size
这个尚未明白什么意思,就换了一个方法生成client.bks文件了
7)生成客户端bks文件
keytool -importcert -trustcacerts -keystore E:\newkey\client.bks -file E:\keyhttps\server.cer -storetype BKS -provider org.bouncycastle.jce.provider.BouncyCastleProvider
这个要在JDK目录下:C:\Program Files\Java\jdk1.7.0_80\jre\lib\ext中添加bcprov-ext-jdk15on-146.jar包文件(这个根据不同的jdk版本找对应的,这个搜一下就行啦)
8)将client.bks,truststore.bks,以及server.cercopy到工程的Assets下完成验证
9)项目中的配置
Application文件
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 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;
    }
}
这是配置文件,其他项目类 需要的话  私我








你可能感兴趣的:(知识条目总结)