Search code examples
jetty

Old Embedded Jetty Code (SSL) no longer working


Had this sample for a few years and it worked fine. Attempted to use it again and it now returns a Protocol Error.

Not familiar enough with this API to know if anything has changed which is why this sample was copied a while back. Searched again and found another sample with similar code but that too returned the same error which leads me to believe there is possibly a new requirement with this API.

> cat EmbeddedJettyHTTPS.java
import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.eclipse.jetty.server.Connector;
import org.eclipse.jetty.server.HttpConfiguration;
import org.eclipse.jetty.server.HttpConnectionFactory;
import org.eclipse.jetty.server.SecureRequestCustomizer;
import org.eclipse.jetty.server.Request;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.ServerConnector;
import org.eclipse.jetty.server.SslConnectionFactory;
import org.eclipse.jetty.servlet.ServletHandler;
import org.eclipse.jetty.util.ssl.SslContextFactory;
import org.eclipse.jetty.server.handler.AbstractHandler;

public class EmbeddedJettyHTTPS
{
    public static void main(String[] args) throws Exception {
       Server server = new Server();
       server.setHandler ( new HelloServlet());
       ServerConnector connector = new ServerConnector(server);
       connector.setPort(9999);

        HttpConfiguration https = new HttpConfiguration();
        https.addCustomizer(new SecureRequestCustomizer());

        SslContextFactory sslContextFactory = new SslContextFactory("/myDirecotry/mykeystore");
        sslContextFactory.setKeyStorePassword("myPassword");

        ServerConnector sslConnector = new ServerConnector(server,
                        new SslConnectionFactory(sslContextFactory, "http/1.1"),
                        new HttpConnectionFactory(https));
        sslConnector.setPort(8443);
        sslConnector.setIdleTimeout(50000);

        server.setConnectors(new Connector[]{ sslConnector });

        server.start();
        server.join();

    }

    public static class HelloServlet extends AbstractHandler
    {
            @Override
        public void handle( String target,
                        Request baseRequest,
                        HttpServletRequest request,
                        HttpServletResponse response ) throws IOException,
                                                      ServletException
            {
            // Declare response encoding and types
                response.setContentType("text/html; charset=utf-8");

                // Declare response status code
            response.setStatus(HttpServletResponse.SC_OK);

                // Write back response
                response.getWriter().println("<h1>Hello World</h1>");

            // Inform jetty that this request has now been handled
                baseRequest.setHandled(true);
        }
    }
 }

The following is the error which appears within the client web browser when called via https://MyServer:8443

enter image description here

Since this code has worked fine previously, any recommendation as to what may have changed or what extra call needs to be made?

On a side note, the certificate being used is the same for another application so I would think that indicates it is not a certificate related issue.


Solution

  • First, this block of code ...

    SslContextFactory sslContextFactory = new SslContextFactory("/myDirecotry/mykeystore");
            sslContextFactory.setKeyStorePassword("myPassword");
    

    ... points to a old version of Jetty that is no longer supported. (Upgrade)

    The current stable and supported versions of Jetty have Client/Server specific implementations of SslContextFactory now. (a change that was brought onto Jetty due to JVM behavior changes)

    See SecuredRedirectHandlerExample from the embedded-jetty-cookbook project.

    Next, check the certificates you are using in your keystore, you are likely using some technique with your certificate that is no longer supported by your JVM or your Browser. (eg: key length minimum requirements, crypto minimum requirements, etc)

    See https://www.java.com/en/jre-jdk-cryptoroadmap.html for details about JVM crypto changes.

    You can use the keytool to identify these kinds of certificate issues as well.

    $ keytool -list -keystore src/main/resources/ssl/keystore -storepass storepwd
    Keystore type: JKS
    Keystore provider: SUN
    
    Your keystore contains 1 entry
    
    jetty, Nov 6, 2008, PrivateKeyEntry, 
    Certificate fingerprint (SHA-256): 3D:75:8E:56:77:42:01:C7:D3:C3:E9:DF:8C:1B:21:03:19:70:78:A9:27:9E:F1:E4:78:B9:73:F5:F6:CA:EF:C2
    
    Warning:
    <jetty> uses the MD5withRSA signature algorithm which is considered a security risk and is disabled.
    <jetty> uses a 1024-bit RSA key which is considered a security risk. This key size will be disabled in a future update.
    The JKS keystore uses a proprietary format. It is recommended to migrate to PKCS12 which is an industry standard format using "keytool -importkeystore -srckeystore src/main/resources/ssl/keystore -destkeystore src/main/resources/ssl/keystore -deststoretype pkcs12".
    

    First thing that this certificate is doing right is that it's SHA-256 and not one of the other crypto techniques currently deprecated by the JVM.

    But there are 2 warnings that should be addressed by creating a new certificate + keystore.