博客
关于我
每天记录学习的新知识 :TLS/SSL证书验证
阅读量:489 次
发布时间:2019-03-07

本文共 7415 字,大约阅读时间需要 24 分钟。

参考地址:

自签名证书的验证:

第一部分:

加载本地证书,准备用于SSL校验

/**     * getSSLSocketFactory     */    public SSLSocketFactory getSSLSocketFactory() {           try {               //本地证书流,实现本地证书的加载            InputStream certificate = AppManager.getContext().getAssets().open("root.cer");            //CertificateFactory 用来证书生成            CertificateFactory certificateFactory = CertificateFactory.getInstance("X509");            //创建一个包含可信ca的密钥存储库            KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());            keyStore.load(null);            String certificateAlias = Integer.toString(1);            //读取本地证书,创建一个包含可信ca的密钥存储库            try {                   keyStore.setCertificateEntry(certificateAlias, certificateFactory.generateCertificate(certificate));                certificate.close();            } catch (IOException e) {                   e.printStackTrace();            }            //创建一个信任管理器,它信任密钥存储库中的ca            TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());            trustManagerFactory.init(keyStore);            //创建一个使用我们的TrustManager的SSLContext            SSLContext sslContext = SSLContext.getInstance("TLS");            sslContext.init(null, new TrustManager[]{   x509TrustManager}, new SecureRandom());            return sslContext.getSocketFactory();        } catch (IOException | CertificateException | NoSuchAlgorithmException | KeyManagementException | KeyStoreException e) {               e.printStackTrace();        }        return null;    }
  1. 获取本地证书流

  2. 获取CertificateFactory,此处目的是: 生成一个实现指定证书类型的 CertificateFactory 对象。

    用途:生成一个证书对象并使用从输入流 inStream 中读取的数据对它进行初始化,如下:

Certificate certificate1 =  certificateFactory.generateCertificate(certificate);
  1. KeyStore,表示密钥和证书的存储设施

    创建一个包含可信ca的密钥存储库

KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
  1. 使用给定 LoadStoreParameter 加载此 keystore

    param - 指定如何存储 keystore 的 LoadStoreParameter,该参数可以为 null

    KeyStore.LoadStoreParameter

    用于 KeyStore load 和 store 参数的标记接口。

keyStore.load(null);
  1. 将给定可信证书分配给给定别名。
setCertificateEntry(String alias, Certificate cert)
  1. TrustManagerFactory,此类充当基于信任材料源的信任管理器的工厂

    生成实现指定的信任管理算法的 TrustManagerFactory 对象。

TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
  1. 用证书授权源和相关的信任材料初始化此工厂。
trustManagerFactory.init(keyStore);
  1. 此类的实例表示安全套接字协议的实现, 它是SSLSocketFactory、SSLServerSocketFactory和SSLEngine的工厂
SSLContext sslContext = SSLContext.getInstance("TLS");
  1. 初始化SSLContext实例 ,并使用我们指定的信任管理器初始化
sslContext.init(null, new TrustManager[]{   x509TrustManager}, new SecureRandom());
  1. 创建SSLSocketFactory
sslContext.getSocketFactory()

第二部分:

证书的校验

private X509TrustManager x509TrustManager = new X509TrustManager() {           @Override        public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {               //do nothing,接受任意客户端证书            LogUtils.i(TAG, "checkClientTrusted");        }        @Override        public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {               //do nothing,接受任意服务端证书            LogUtils.i(TAG, "checkServerTrusted");            //TODO:使用白名单对证书做验证            if (chain == null) {                   throw new IllegalArgumentException("check server X509Certificate is null");            }            if (chain.length < 1) {                   throw new IllegalArgumentException("check server X509Certificate is empty");            }            LogUtils.i(TAG, "chain =====" + chain.length);            int errorNum = 0;            //验证证书            for (X509Certificate cert : chain) {   //                LogUtils.i(TAG, "cert ===" + cert);                // Make sure that it hasn't expired.                cert.checkValidity();                try {                       PublicKey publicKey = getServerCert().getPublicKey();                    // Verify the certificate's public key chain.                    cert.verify(publicKey);                } catch (InvalidKeyException e) {                       LogUtils.e(TAG, "使用 AES 加密时,密钥大于128bit的话会抛出java.security.InvalidKeyException异常。因为密钥长度是受限的,所以长度超过时就会抛出这个异常");                    e.printStackTrace();//                    throw new CertificateException(e);                    errorNum++;                } catch (NoSuchAlgorithmException e) {                       LogUtils.e(TAG, "意思是导入证书有问题,或者是未寻找到证书.");                    e.printStackTrace();//                    throw new CertificateException(e);                    errorNum++;                } catch (NoSuchProviderException e) {                       LogUtils.e(TAG, "NoSuchProviderException.");                    e.printStackTrace();//                    throw new CertificateException(e);                    errorNum++;                } catch (SignatureException e) {                       LogUtils.e(TAG, "签名长度不正确.");                    e.printStackTrace();//                    throw new CertificateException(e);                    errorNum++;                }            }            if (errorNum == chain.length){                   LogUtils.i(TAG, "证书=========== 异常 ");                throw new CertificateException(new SignatureException());            }else {                   LogUtils.i(TAG, "证书=========== 正常 ");            }        }        @Override        public X509Certificate[] getAcceptedIssuers() {               LogUtils.i(TAG, "getAcceptedIssuers");            return new X509Certificate[0];        }    };    private X509Certificate serverCert;    private X509Certificate getServerCert() {           if (serverCert == null) {               try {                   InputStream inputStream = new BufferedInputStream(AppManager.getContext().getAssets().open("root.cer"));                CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");                serverCert = (X509Certificate) certificateFactory.generateCertificate(inputStream);            } catch (IOException | CertificateException e) {                   e.printStackTrace();            }        }        return serverCert;    }

  1. X509TrustManager

    此接口的实例管理可用于对安全套接字的远程端进行身份验证的X509证书。决策可能基于受信任的证书颁发机构、证书撤销列表、在线状态检查或其他方法。

  2. void checkClientTrusted(X509Certificate[] chain,String authType) throws CertificateException

    该方法检查客户端的证书,若不信任该证书则抛出异常。由于我们不需要对客户端进行认证,因此我们只需要执行默认的信任管理器的这个方法。JSSE中,默认的信任管理器类为TrustManager。

  3. void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException

    该方法检查服务器的证书,若不信任该证书同样抛出异常。通过自己实现该方法,可以使之信任我们指定的任何证书。在实现该方法时,也可以简单的不做任何处理,即一个空的函数体,由于不会抛出异常,它就会信任任何证书。

  4. X509Certificate[] getAcceptedIssuers()

    返回受信任的X509证书数组。

  5. 使用

    自己实现了信任管理器类,如何使用呢?

    类HttpsURLConnection似乎并没有提供方法设置信任管理器。其实,HttpsURLConnection通过SSLSocket来建立与HTTPS的安全连接,SSLSocket对象是由SSLSocketFactory生成的。

    HttpsURLConnection提供了方法setSSLSocketFactory(SSLSocketFactory)设置它使用的SSLSocketFactory对象。

    SSLSocketFactory通过SSLContext对象来获得,在初始化SSLContext对象时,可指定信任管理器对象。(第一部分,第9条)

    Okhttp也提供了setSSLSocketFactory(SSLSocketFactory)…

  6. 第二部分代码解析

    没有校验客户端证书,只是校验了服务器证书,解析服务器证书时,如果证书异常,会抛出异常,否则即使校验通过

  7. 检验证书是否有效

    检查证书目前是否有效。即当前的日期和时间是否仍在证书中所给定的有效期内。

    抛出:

    certificateexpiredexception - 如果证书已过期。
    certificatenotyetvalidexception - 如果证书不再有效。

cert.checkValidity();
  1. 使用用户证书验证根证书的公钥,知如果验证通过说明道这个用户证书是这个根证书签发的,验证不过就不是这个根证书签发的。
PublicKey publicKey = getServerCert().getPublicKey();// Verify the certificate's public key chain.cert.verify(publicKey);
  1. 加载预埋的服务器端公钥证书
getServerCert()

转载地址:http://ztvcz.baihongyu.com/

你可能感兴趣的文章
【树形dp】P1273 有线电视网
查看>>
【分层图最短路】P4568 [JLOI2011]飞行路线
查看>>
【最短路】P4408 [NOI2003]逃学的小孩
查看>>
回文自动机
查看>>
2020C证(安全员)模拟考试题及C证(安全员)模拟考试系统
查看>>
2020A证(安全员)模拟考试及A证(安全员)证考试
查看>>
2020电工(初级)考试及电工(初级)考试软件
查看>>
2020建筑电工(建筑特殊工种)实操考试视频及建筑电工(建筑特殊工种)作业模拟考试
查看>>
2020N1叉车司机模拟考试题库及N1叉车司机复审模拟考试
查看>>
2020熔化焊接与热切割考试及熔化焊接与热切割考试题库
查看>>
2020年G3锅炉水处理报名考试及G3锅炉水处理考试申请表
查看>>
2020年R2移动式压力容器充装答案解析及R2移动式压力容器充装免费试题
查看>>
2020年制冷与空调设备运行操作答案解析及制冷与空调设备运行操作考试总结
查看>>
2020年保育员(初级)考试资料及保育员(初级)新版试题
查看>>
2020年加氢工艺复审考试及加氢工艺作业考试题库
查看>>
2020年防爆电气考试题及防爆电气多少分及格
查看>>
2020年茶艺师(高级)考试内容及茶艺师(高级)考试申请表
查看>>
2020年车工(中级)考试内容及车工(中级)答案解析
查看>>
2021年烟花爆竹经营单位安全管理人员考试及烟花爆竹经营单位安全管理人员考试试卷
查看>>
2021年过氧化工艺试题及答案及过氧化工艺考试平台
查看>>