简体   繁体   中英

How to cache and update CRL (certificate revokation list)/OCSP responses in SSL configured tomcat?

I've been trying to setup SSL/TLS handshake in Tomcat 8. I've successfully done all the configurations but there are some problems I'm facing with CRL/OCSP.

I need solution to: this

I've a couple of questions so kindly have some patience. Any help would be really appreciated.

  1. Does tomcat 8 allow us to cache the CRL file obtained from the CRL distribution point ? By cache I mean that if network isn't available and we start the server, I don't want tomcat to allow access to all users by default (which it does) because CRL distribution point wasn't available. I want it to cache the last available list and use that if CRL can't be downloaded now. If it can be downloaded then update the existing cache.

I've below configuration of connector in server.xml.

 <Connector protocol="org.apache.coyote.http11.Http11NioProtocol" port="8443" maxThreads="2000" clientAuth="want" scheme="https" keepAliveTimeout="-1" connectionTimeout="900000" compression="on" noCompressionUserAgents="gozilla, traviata" compressableMimeType="text/html,text/xml,text/css,text/javascript,image/jpg,image/ico,image/png,image/jpeg,image/tiff,image/tif" secure="true" SSLEnabled="true" sslProtocol="TLS" sessionTimeout="30" truststoreFile="D:\\Certs\\server.truststore" truststorePass="123456" keystoreFile="D:\\Certs\\keystore.pkcs12" keystorePass="password" keystoreType="PKCS12" crlFile="http://127.0.0.1:8600/getCRLFile/" maxKeepAliveRequests="200" sslEnabledProtocols= "TLSv1,TLSv1.1,TLSv1.2" maxHttpHeaderSize="65536" maxPostSize="4194304" ciphers="TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256, TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384,TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,TLS_RSA_WITH_AES_128_CBC_SHA256,TLS_RSA_WITH_AES_128_CBC_SHA,TLS_RSA_WITH_AES_256_CBC_SHA256,TLS_RSA_WITH_AES_256_CBC_SHA"/> 

Can I achieve this using any of the tomcat configuration ?

  1. I found a way to achieve the above task my manipulating a Java code found here !

Problem with this is that I'll have to send the certificates of client while handshaking to this java code and accept/reject the certificate based on reply from this code. I don't know how to do that. Any help will be of great use. The second reason is I would prefer to achieve task 1 using tomcat configurations rather than custom code because custom code might miss out on some aspects.

  1. Can I dynamically pick an updated CRL from the CRL distribution URL without restarting the tomcat server ? The current scenario with above configuration picks the CRL file once when server is turned On and then it uses that copy only even if CRL list available on the URL has changed.

  2. Can we have multiple CRL end-points configured in the connector ? Tomcat will check them all and accept/reject a client certificate based on combined list from all the URLs.

    1. If configured, can I cache OCSP responses in a similar way I want to cache CRL lists ?

Thanks in advance. Please feel free to ask any details I might have missed.

Answering my own question.

I could find a way to cache CRL. What I did was to make crlFile of connector in server.xml to point to a CRL file on local machine. I updates this file using a CRON job time to time.

Starting with Tomcat v8.5.24, a new API has been added to refresh the whole SSL config without restarting Tomcat server. I called those APIs time to time too to pick the updated CRL file from the local machine.

They introduced 2 methods named:

  1. reloadSslHostConfig(String hostName) - to reload a specific host
  2. reloadSslHostConfigs() - reload all

They can be called in various ways:

  1. Using jmx
  2. Using manager service
  3. By making custom protocol - I found this way during my research

Details of way 1 and way 2 are easily available online.

Details of how to go about using way 3:

  1. Make a class extending the protocol of your choice for eg. Http11NioProtocol
  2. Override the required methods and just call super in them to keep default behavior
  3. Make a thread in this class to call reloadSslHostConfigs method time to time
  4. Package this class in a jar and put that jar in tomcat's lib folder
  5. Edit protocol in connector in server.xml to use this custom defined protocol

Find sample code below:

Main protocol class:

    package com.myown.connector;

    import java.io.File;
    import java.io.InputStream;
    import java.lang.reflect.Field;
    import java.net.URL;
    import java.net.URLConnection;
    import java.nio.file.StandardCopyOption;
    import java.util.ArrayList;
    import java.util.List;
    import java.util.concurrent.ConcurrentMap;

    import javax.management.MalformedObjectNameException;
    import javax.management.ObjectName;
    import javax.net.ssl.SSLSessionContext;

    import org.apache.coyote.http11.Http11NioProtocol;
    import org.apache.juli.logging.Log;
    import org.apache.juli.logging.LogFactory;
    import org.apache.tomcat.util.modeler.Registry;
    import org.apache.tomcat.util.net.AbstractEndpoint;
    import org.apache.tomcat.util.net.AbstractJsseEndpoint;
    import org.apache.tomcat.util.net.GetSslConfig;
    import org.apache.tomcat.util.net.SSLContext;
    import org.apache.tomcat.util.net.SSLHostConfig;
    import org.apache.tomcat.util.net.SSLHostConfigCertificate;
    import org.apache.tomcat.util.net.SSLImplementation;
    import org.apache.tomcat.util.net.SSLUtil;

    public class ReloadProtocol extends Http11NioProtocol {

        private static final Log log = LogFactory.getLog(Http12ProtocolSSL.class);

        public ReloadProtocol() {
            super();
            RefreshSslConfigThread refresher = new 
                  RefreshSslConfigThread(this.getEndpoint(), this);
            refresher.start();
        }

        @Override
        public void setKeystorePass(String s) {
            super.setKeystorePass(s);
        }

        @Override
        public void setKeyPass(String s) {
            super.setKeyPass(s);
        }

        @Override
        public void setTruststorePass(String p) {
            super.setTruststorePass(p);
        }

        class RefreshSslConfigThread extends Thread {

            AbstractJsseEndpoint<?> abstractJsseEndpoint = null;
            Http11NioProtocol protocol = null;

            public RefreshSslConfigThread(AbstractJsseEndpoint<?> abstractJsseEndpoint, Http11NioProtocol protocol) {
                this.abstractJsseEndpoint = abstractJsseEndpoint;
                this.protocol = protocol;
            }

            public void run() {
                int timeBetweenRefreshesInt = 1000000; // time in milli-seconds
                while (true) {
                    try {
                            abstractJsseEndpoint.reloadSslHostConfigs();
                            System.out.println("Config Updated");
                    } catch (Exception e) {
                        System.out.println("Problem while reloading.");
                    }
                    try {
                        Thread.sleep(timeBetweenRefreshesInt);
                    } catch (InterruptedException e) {
                        System.out.println("Error while sleeping");
                    }
                }
            }
       }
}

Connector in server.xml should mention this as the protocol:

<Connector protocol="com.myown.connector.ReloadProtocol"
 ..........

Hope this helps someone.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM