'HTTP ERROR 400 Invalid SNI - Jetty HTTPS servlet

I am trying to solve an issue with my Jetty servlet running over HTTPS.

It is showing this error page in the browser:

enter image description here

What I did:

  1. I created my Keystore and Truststore as is described here: How to generate keystore and truststore

  2. Both files were placed in the directory of my project and code was written up to load these files.

package sk.cood.metahost.server;

import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.eclipse.jetty.server.*;
import org.eclipse.jetty.servlet.ServletContextHandler;
import org.eclipse.jetty.servlet.ServletHolder;
import org.eclipse.jetty.util.ssl.SslContextFactory;

import java.io.*;

@WebServlet(displayName = "MetaHostServlet", urlPatterns = { "/*" })
public class MetaHostServlet extends HttpServlet {
    private static File keyStoreFile;
    private static File trustStoreFile;

    public static void main(String[] args) throws Exception {
        loadKeyStores();

        Server server = new Server(8080);
        ServerConnector connector = createSSLConnector(server, "password", "password", false);
        server.addConnector(connector);

        ServletContextHandler context = new ServletContextHandler(ServletContextHandler.SESSIONS);
        context.addServlet(new ServletHolder(new MetaHostServlet()),"/*");
        context.setContextPath("/");
        server.setHandler(context);

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

    private static void loadKeyStores() {
        keyStoreFile = new File("keystore.jks");
        trustStoreFile = new File("truststore.jks");
        if (!keyStoreFile.exists()) {
            throw new RuntimeException("Key store file does not exist on path '"+keyStoreFile.getAbsolutePath()+"'");
        }
        if (!trustStoreFile.exists()) {
            throw new RuntimeException("Trust store file does not exist on path '"+trustStoreFile.getAbsolutePath()+"'");
        }
    }

    private static ServerConnector createSSLConnector(Server server, String keyStorePassword, String trustStorePassword, boolean isClientAuthNeeded) {
        SslContextFactory.Server sslContextFactory = new SslContextFactory.Server();
        sslContextFactory.setKeyStorePath(keyStoreFile.getAbsolutePath());
        sslContextFactory.setKeyStorePassword(keyStorePassword);
        sslContextFactory.setTrustStorePath(trustStoreFile.getAbsolutePath());
        sslContextFactory.setTrustStorePassword(trustStorePassword);
        sslContextFactory.setNeedClientAuth(isClientAuthNeeded);

        HttpConfiguration https_config = new HttpConfiguration();
        https_config.setSendServerVersion(false);
        https_config.setRequestHeaderSize(512 * 1024);
        https_config.setResponseHeaderSize(512 * 1024);

        SecureRequestCustomizer src = new SecureRequestCustomizer();
        https_config.addCustomizer(src);

        return new ServerConnector(server, sslContextFactory, new HttpConnectionFactory(https_config));
    }

    @Override
    public void doGet(HttpServletRequest req, HttpServletResponse res) throws IOException, ServletException {
        res.setContentType("text/html");
        res.setStatus(HttpServletResponse.SC_OK);
        res.getWriter().println("<h1>Hello World!</h1>");
        res.getWriter().println("session=" + req.getSession(true).getId());
    }
}
  1. I started my servlet with jetty and tried to connect to localhost:8080 and mentioned error appears.

Then I tried to create other Keystores and Truststores by other guides, for example, I added DNS alternative names to my new Keystore as is described here: https://serverfault.com/questions/488003/keytool-subjectalternativename but nothing helped me.

I don't know what is wrong in my case, maybe someone more experienced with jetty and certificates will help.

Thank you so much!



Solution 1:[1]

I was also facing same issue when I was running my application from local. As localhost is not allowed for SNI, I disabled the SNI check temporarily in my code. Below is the code I modified for running my application locally :

SecureRequestCustomizer src = new SecureRequestCustomizer();
src.setSniHostCheck(false);
https_config.addCustomizer(src);

Note: For PROD version, SniHostCheck is still set to true for us. And I don't recommend anyone to set it to false.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Nitin Singhal