https自签名证书验证相关代码

https://www.jianshu.com/p/64172ccfb73b

一.单向认证:

    Https在建立Socket连接之前,需要进行握手。
    (1)客户端向服务端发送SSL协议版本号、加密算法种类、随机数等信息。
    (2)服务端给客户端返回SSL协议版本号、加密算法种类、随机数等信息,同时也返回服务器端的证书,即公钥证书
    (3)客户端使用服务端返回的信息验证服务器的合法性,包括:证书是否过期,发型服务器证书的CA是否可靠,返回的公钥是否能正确解开返回证书中的数字签名  ,服务器证书上的域名是否和服务器的实际域名相匹配,验证通过后,将继续进行通信,否则,终止通信
        (4)客户端向服务端发送自己所能支持的对称加密方案,供服务器端进行选择。
    (5)服务器端在客户端提供的加密方案中选择加密程度最高的加密方式。
     (6)服务器将选择好的加密方案通过明文方式返回给客户端,
    (7)客户端接收到服务端返回的加密方式后,使用该加密方式生成产生随机码,用作通信过程中对称加密的密钥,
  使用服务端返回的公钥进行加密,将加密后的随机码发送至服务器。
    (8)服务器收到客户端返回的加密信息后,使用自己的私钥进行解密,获取对称加密密钥。 
    在接下来的会话中,服务器和客户端将会使用该密码进行对称加密,保证通信过程中信息的安全。
二.双向认证
   双向认证和单向认证原理基本差不多,只是除了客户端需要认证服务端以外,增加了服务端对客户端的认证。
   (1)客户端向服务端发送SSL协议版本号、加密算法种类、随机数等信息。
   (2)服务端给客户端返回SSL协议版本号、加密算法种类、随机数等信息,同时也返回服务器端的证书,即公钥证书。
   (3)客户端使用服务端返回的信息验证服务器的合法性,包括:
         证书是否过期
         发型服务器证书的CA是否可靠
         返回的公钥是否能正确解开返回证书中的数字签名
         服务器证书上的域名是否和服务器的实际域名相匹配
         验证通过后,将继续进行通信,否则,终止通信
   (4)服务端要求客户端发送客户端的证书,客户端会将自己的证书发送至服务端
   (5)验证客户端的证书,通过验证后,会获得客户端的公钥
     (6)客户端向服务端发送自己所能支持的对称加密方案,供服务器端进行选择
    (7)服务器端在客户端提供的加密方案中选择加密程度最高的加密方式
    (8)将加密方案通过使用之前获取到的公钥进行加密,返回给客户端
    (9)客户端收到服务端返回的加密方案密文后,使用自己的私钥进行解密,获取具体加密方式,而后,产生该加密方式的随机码,用作加密过程中的密钥,
使用之前从服务端证书中获取到的公钥进行加密后,发送给服务端
    (10)服务端收到客户端发送的消息后,使用自己的私钥进行解密,获取对称加密的密钥,在接下来的会话中,
服务器和客户端将会使用该密码进行对称加密,保证通信过程中信息的安全。
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.security.KeyStore;
import java.security.SecureRandom;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import javax.net.ssl.TrustManagerFactory;
import javax.net.ssl.X509TrustManager;
import okhttp3.OkHttpClient;

public class SafeOkHttp {
    /**
     * 访问在认证机构有认证的https访问
     * @param hostHome 需要访问的地址
     * @return OkHttpClient
     */
    public static OkHttpClient getUnsafeOkHttpClient(final String hostHome) {
        try {
            // Create a trust manager that does not validate certificate chains
            final TrustManager[] trustAllCerts = new TrustManager[]{new X509TrustManager() {
                @Override
                public void checkClientTrusted(java.security.cert.X509Certificate[] chain, String authType) throws CertificateException {
                }
                @Override
                public void checkServerTrusted(java.security.cert.X509Certificate[] chain, String authType) throws CertificateException {
                }
                @Override
                public java.security.cert.X509Certificate[] getAcceptedIssuers() {
                    return null;
                }
            }};
            // Install the all-trusting trust manager
            final SSLContext sslContext = SSLContext.getInstance("SSL");
            sslContext.init(null, trustAllCerts, new java.security.SecureRandom());
            // Create an ssl socket factory with our all-trusting manager
            final SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory();
            OkHttpClient okHttpClient = new OkHttpClient.Builder().sslSocketFactory(sslSocketFactory).hostnameVerifier(new HostnameVerifier() {
                @Override
                public boolean verify(String hostname, SSLSession session) {
                    if (hostname.equals(hostHome))
                        return true;
                    else
                        return false;
                }
            }).build();
            return okHttpClient;
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 获取带有制定输入流的认证证书的 OkHttpClient
     * 构造CertificateFactory对象,通过它的generateCertificate(is)方法得到Certificate。
     * 然后讲得到的Certificate放入到keyStore中。
     * 接下来利用keyStore去初始化我们的TrustManagerFactory
     * 由trustManagerFactory.getTrustManagers获得TrustManager[]初始化我们的SSLContext
     * 最后,设置我们mOkHttpClient.setSslSocketFactory即可。
     * @param certificates 证书输入流
     * @return OkHttpClient
     * @throws Exception
     */
    public static OkHttpClient setCertificates(final URL url,InputStream... certificates) throws Exception {
        CertificateFactory factory = CertificateFactory.getInstance("X.509");
        KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
        keyStore.load(null);
        int index = 0;
        for (InputStream is : certificates) {
            String certificateAlias = Integer.toString(index++);
            keyStore.setCertificateEntry(certificateAlias, factory.generateCertificate(is));
            try {
                if (is != null) {
                    is.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        SSLContext sslContent = SSLContext.getInstance("TLS");
        TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
        trustManagerFactory.init(keyStore);
        sslContent.init(null, trustManagerFactory.getTrustManagers(), new SecureRandom());
        OkHttpClient client = new OkHttpClient.Builder().sslSocketFactory(sslContent.getSocketFactory()).hostnameVerifier(new HostnameVerifier() {
            @Override
            public boolean verify(String hostname, SSLSession session) {
                if (hostname.equals(url.getHost())){
                    return true;
                }
                return false;
            }
        }).build();
        return client;
    }

    /**
     * 双向证书验证
     * 详见:Https的证书生成和相关代码
     * 获取带有制定输入流的认证证书的 OkHttpClient
     * @param certificates 证书输入流
     * @return OkHttpClient
     * @throws Exception
     */
    public static OkHttpClient setCertificatesTwo(final URL url,InputStream keyClient,String password,InputStream... certificates) throws Exception {
        //初始化公钥
        CertificateFactory factory = CertificateFactory.getInstance("X.509");
        KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
        keyStore.load(null);
        int index = 0;
        for (InputStream is : certificates) {
            String certificateAlias = Integer.toString(index++);
            keyStore.setCertificateEntry(certificateAlias, factory.generateCertificate(is));
            try {
                if (is != null) {
                    is.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
        trustManagerFactory.init(keyStore);

        //初始化Android端的密钥
        KeyStore keyClientStore = KeyStore.getInstance("PKCS12");
        keyClientStore.load(keyClient, password.toCharArray());
        KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
        keyManagerFactory.init(keyClientStore,password.toCharArray());
//        KeyManager keyManager = new MyX509KeyManager(keyClientStore,password,keyManagerFactory.getKeyManagers());
//        KeyManager[] keyManagerArray = keyManagerFactory.getKeyManagers();
//        keyManagerArray[0] = keyManager;

        SSLContext sslContent = SSLContext.getInstance("TLS");
        sslContent.init(keyManagerFactory.getKeyManagers(), trustManagerFactory.getTrustManagers(), new SecureRandom());
        OkHttpClient client = new OkHttpClient.Builder().sslSocketFactory(sslContent.getSocketFactory()).hostnameVerifier(new HostnameVerifier() {
            @Override
            public boolean verify(String hostname, SSLSession session) {
                if (hostname.equals(url.getHost())){
                    return true;
                }
                return false;
            }
        }).build();
        return client;
    }
}


Java平台默认识别jks格式的证书文件,但是android平台只识别bks格式的证书文件

Portecle下载Download portecle-1.9.zip (3.4 MB)

解压后,里面包含 bcprov.jar文件,使用jave -jar bcprov.jar即可打开GUI界面

张鸿洋https详解,包含如何生成自签名证书

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值