实现 tomcat 热加载证书

以前一篇中说了如何 创建 https 通讯的完整流程,其中涉及了java web容器 tomcat,关于它的配置是: java

<Connector port="8443" protocol="org.apache.coyote.http11.Http11NioProtocol"          
		SSLEnabled="true"      
		maxThreads="150" 
		scheme="https" 
		secure="true"
		clientAuth="true" sslProtocol="TLS" 
		keystoreFile="D:\ssl\server.keystore" keystorePass="123456"    
		truststoreFile="D:\ssl\server.keystore" truststorePass="123456"/>

对应的keyStore(包括私钥库和受信任证书库)是在tomcat启动时一次性加载到内存中的。 web

大多数的场景这就够了,可是若是 要构建一个 基于https、受信任证书的 权限验证体系,像上边的那样 一次性加载 keyStore 就算 咱们从键库中删除某个证书,程序是没办法探知的。我急需一种热加载 keyStore的技术。 apache

咱们修改对应的配置为 浏览器

<Connector port="8443" protocol="org.apache.coyote.http11.Http11Protocol" 
   SSLEnabled="true"
   maxThreads="150" scheme="https" secure="true"
   clientAuth="true" sslProtocol="TLS" 
   keystoreFile="d:/ssl/server.keystore" 
   keystorePass="123456" 
   trustManagerClassName="MyTrustManager"/>

这里 本身的私钥键库是不须要也是不能从新加载的,关键在与证书键库,咱们建立了一个在自定义的类叫 tomcat

MyTrustManager 用来管理受信任证书,他须要实现接口 X509TrustManager 并提供一个无参的构造函数。 ide

而后将其打包成jar后,部署到tomcat的lib目录(注意connector是在tomcat启动时构建的,因此代码不能放在你本身的web项目里,由于当时tomcat尚未classLoad你的类呢)下边是参考代码 函数


public class MyTrustManager implements X509TrustManager {

    public MyTrustManager(){}

    @Override
    public void checkClientTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException {
        System.out.println("check");
        if(x509Certificates==null||x509Certificates.length==0||s==null||s.length()==0) throw new IllegalArgumentException();
        KeyStore store=getKeyStore();
        boolean pass=false;
        try {
            for(X509Certificate certificate:x509Certificates){
                certificate.checkValidity();
                String theAlias = store.getCertificateAlias(certificate);
                if(theAlias!=null)pass=true;
            }
        } catch (KeyStoreException e) {
            e.printStackTrace();
        }
        System.out.println("pass "+pass);
        if(!pass)throw new  CertificateException();
    }

    @Override
    public void checkServerTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException {
        if(x509Certificates==null||x509Certificates.length==0||s==null||s.length()==0) throw new IllegalArgumentException();
        for(X509Certificate certificate:x509Certificates){
            certificate.checkValidity();
        }
    }

    @Override
    public X509Certificate[] getAcceptedIssuers() {
        ArrayList<X509Certificate> trusts=new ArrayList<X509Certificate>();
        try {
            KeyStore store=getKeyStore();
            Enumeration<String> alias = store.aliases();
            while (alias.hasMoreElements()){
                String name = alias.nextElement();
                if(store.isCertificateEntry(name)){
                    X509Certificate trust = (X509Certificate) store.getCertificate(name);
                    trusts.add(trust);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        X509Certificate[] trustsArr = trusts.toArray(new X509Certificate[0]);
        System.out.println("return trust array "+trustsArr.length);
        return trustsArr;
    }

    private KeyStore getKeyStore() throws CertificateException {
        try {
            KeyStore store = KeyStore.getInstance(KeyStore.getDefaultType());
            store.load(new FileInputStream("D:/ssl/server.keystore"),"123456".toCharArray());
            return store;
        } catch (Exception e) {
            e.printStackTrace();
            throw new CertificateException();
        }
    }
}



getAcceptedIssuers 返回server端的全部信任的证书,这样client (好比浏览器)才知道应该挑选哪些它所拥有的证书来询问你,证书必须是双方都认识的。


checkClientTrusted  是对client提交过来的证书进行验证,certificate.checkValidity();验证证书是否过时,store.getCertificateAlias(certificate)从本身的键库中寻找对应的证书,不存在返回null,发现验证不经过 就本身手动抛出一个异常CertificateException,这样容器就知道如何处理了。 性能

getKeyStore中是加载键库,因为每次验证时才加载键库,因此就实现了热加载。固然为了性能你能够把keyStore放到某个全局变量里,在须要的时候对其进行reload。 spa


综上所述,你能够实现一个经过添加信任证书的方式来对请求方进行控制的系统了。 .net

注意:https为了性能在创建了SSL-SESSION以后容许再也不进行证书验证,你在浏览器里访问作实验须要关闭浏览器后从新访问才会看到keyStore更新生效,你也能够经过代码设法销毁SSL-SESSION让每次https请求都从新握手验证。参考:http://blog.csdn.net/ibznphone/article/details/7846879

相关文章
相关标签/搜索