Search code examples
securityjettyembedded-jettyjetty-9

missing checkKeyStore() in jetty 9.4 SSLContextFactory


I am migrating from Jetty 9.0 to 9.4 Apparently, following method from SSLContextFactory is removed from 9.3.0

public void checkKeyStore()

I checked api documentation but did not get any replacement for this nor it was deprecated in 9.2.x and directly got removed in 9.3.0. I am not security expert but here is my code and I am not exactly sure how should I get around this in 9.4.x

private void configureHttps(Server server, int httpsPort, JettyAppConfig config, HttpConfiguration httpConfig)
            throws Exception {

        boolean shouldStartHttpsPort = false;

        SslContextFactory sslContextFactory = createJettySslContextFactory();

        if (sslContextFactory != null) {

            shouldStartHttpsPort = true;

            try {
                sslContextFactory.checkKeyStore(); //NEED REPLACEMENT in 9.4
            } catch (IllegalStateException e) {
                logger.debug("keystore check failed", e);
                shouldStartHttpsPort = false;
            }
        }

        if (shouldStartHttpsPort) {

            HttpConfiguration httpsConfig = new HttpConfiguration(httpConfig);
            httpsConfig.addCustomizer(new SecureRequestCustomizer());

            ServerConnector httpsConnector = new ServerConnector(server,
                    new SslConnectionFactory(sslContextFactory, HttpVersion.HTTP_1_1.asString()),
                    new HttpConnectionFactory(httpsConfig));
            httpsConnector.setPort(httpsPort);
            httpsConnector.setIdleTimeout(config.getConnectionIdleTimeout());

            server.addConnector(httpsConnector);

        } else {
            logger.info("Keystore not configured, not starting HTTPS");
        }
    }

Solution

  • The role of checkKeyStore() in Jetty 9.0.0 thru 9.2.0 was only to attempt to load the keystore from disk, that's it. Any other impact on SslContextFactory would be considered a bug.

    Here's an alternate implementation for you.

    import java.io.ByteArrayOutputStream;
    import java.io.IOException;
    import java.io.InputStream;
    import java.io.OutputStream;
    import java.nio.file.Files;
    import java.nio.file.Path;
    import java.nio.file.Paths;
    
    import org.eclipse.jetty.util.IO;
    import org.eclipse.jetty.util.StringUtil;
    import org.eclipse.jetty.util.ssl.SslContextFactory;
    
    private static void check(SslContextFactory ssl) throws IOException
    {
        if (ssl.getKeyStore() == null) // too late, already loaded?
        {
            if (StringUtil.isNotBlank(ssl.getKeyStorePath())) // no path, no check
            {
                Path keystorePath = Paths.get(ssl.getKeyStorePath());
                try (InputStream inputStream = Files.newInputStream(keystorePath);
                     OutputStream outputStream = new ByteArrayOutputStream())
                {
                    IO.copy(inputStream, outputStream);
                }
            }
        }
    }
    

    The method checkKeyStore() was removed in April 2015 when support for SNI was introduced in Jetty 9.3.0, which introduced the ability to have hierarchies of SslContextFactory implementations.

    The behavior that checkKeyStore() provided was instead moved to the loadKeyStore() method, which is always called during doStart() of the SslContextFactory.

    In short, in Jetty 9.0.0 checkKeyStore() always ran, and now in Jetty 9.4.18, it's behavior always runs still, but in a different place. The new behavior also checks the TrustStore, your SNI setup, your cipher suites selections, your protocols selections, etc. The new techniques do much more then the old one.

    Since you are using embedded-jetty, consider instead of checking the SslContextFactory, just let the lifecycle fail on the server.start() call.

    Note: For WebAppContext specifically make sure you set setThrowUnavailableOnStartupException(true) to allow it to report failures up the lifecycle.