X509证书信任管理器的实现与应用

什么是JSSE?

即Java Secure Socket Extension,JSSE是基于安全算法和握手机制之上的合成体。在计算机中,Java安全套接字扩展(JSSE)提供的包,支持安全的互联网通信。它实现一个Java的所述的技术版本的安全套接字层(SSL)和传输层安全(TLS)协议。它包括数据的功能加密,服务器的身份验证,消息完整性和可选的客户端认证。
JSSE参考指南:http://docs.oracle.com/javase/8/docs/technotes/guides/security/jsse/JSSERefGuide.html

通过实现X509TrustManager接口,实现自己的证书信任管理器

import java.io.FileInputStream;
import java.security.KeyStore;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;

import javax.net.ssl.TrustManager;
import javax.net.ssl.TrustManagerFactory;
import javax.net.ssl.X509TrustManager;
/**
 * 
 * @author jing.ming
 *
 */
public class MyX509TrustManager implements X509TrustManager{

    X509TrustManager pkixTrustManager;
    MyX509TrustManager() throws Exception {
        // create a "default" JSSE X509TrustManager.

        KeyStore ks = KeyStore.getInstance("JKS");
        ks.load(new FileInputStream("trustedCerts"), "passphrase".toCharArray());

        TrustManagerFactory tmf = TrustManagerFactory.getInstance("PKIX");
        tmf.init(ks);

        TrustManager tms [] = tmf.getTrustManagers();

        /*
         * 遍历返回的信任管理器,找到X509TrustManager 的管理器作为默认的信任管理器
         */
        for (int i = 0; i < tms.length; i++) {
            if (tms[i] instanceof X509TrustManager) {
                pkixTrustManager = (X509TrustManager) tms[i];
                return;
            }
        }

        /*
         *没有找到,初始化信任管理器失败
         */
        throw new Exception("Couldn't initialize");
    }

    public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
         try {
             pkixTrustManager.checkClientTrusted(chain, authType);
         } catch (CertificateException excep) {
             // do any special handling here, or rethrow exception.
         }

    }

    public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
         try {
             pkixTrustManager.checkServerTrusted(chain, authType);
         } catch (CertificateException excep) {
             /*
              * Possibly pop up a dialog box asking whether to trust the
              * cert chain.
              */
         }

    }

    public X509Certificate[] getAcceptedIssuers() {
        return pkixTrustManager.getAcceptedIssuers();
    }

}

你创建一个信任管理器之后,就可以通过init()方法指派给SSLContext ,以后从这个SSLContext创建的SocketFactories,就会使用你创建的信任管理器.

TrustManager[] myTMs = new TrustManager[] { new MyX509TrustManager() };
SSLContext ctx = SSLContext.getInstance("TLS");
ctx.init(null, myTMs, null);

应用

自己实现了信任管理器类,如何使用呢?类HttpsURLConnection似乎并没有提供方法设置信任管理器.其实HttpsURLConnection通过SSLSocket来建立与HTTPS的安全连接,SSLSocket对象是由SSLSocketFactory生成的.HttpsURLConnection提供了方法setSSLSocketFactory(SSLSocketFactory)设置它使用的SSLSocketFactory对象.SSLSocketFactory通过SSLContext对象来获得,在初始化SSLContext对象时可指定信任管理器对象。下面用例子简单表示如何应用:

// 创建SSLContext对象,并使用我们指定的信任管理器初始化
TrustManager[] tm = { new MyX509TrustManager() };
SSLContext sslContext = SSLContext.getInstance("SSL", "SunJSSE");
sslContext.init(null, tm, new java.security.SecureRandom());

// 从上述SSLContext对象中得到SSLSocketFactory对象
SSLSocketFactory ssf = sslContext.getSocketFactory();
URL url = new URL(requestUrl);
HttpsURLConnection httpUrlConn = (HttpsURLConnection) url.openConnection();
httpUrlConn.setSSLSocketFactory(ssf);

  这样,HttpsURLConnection对象就可以正常连接HTTPS了,无论其证书是否经权威机构的验证,只要实现了接口X509TrustManager的类MyX509TrustManager信任该证书。

  

小结

  本文主要介绍了在HTTPS的证书未经权威机构认证的情况下,访问HTTPS站点的两种方法,一种方法是把该证书导入到Java的TrustStore文件中,另一种是自己实现并覆盖JSSE缺省的证书信任管理器类。两种方法各有优缺点,第一种方法不会影响JSSE的安全性,但需要手工导入证书;第二种方法虽然不用手工导入证书,但需要小心使用,否则会带来一些安全隐患。

热评文章