I need to make sure that my client supports SNI and it works. To do that, I want to start some dummy server (Spring boot application with it's embedded Tomcat 9) that requires hostname from client. The question is how to force Spring boot embedded Tomcat to require SNI from client? I've read that to do that, we need to provide to server 2 (or more) certificates.
I tried to follow example from this topic. But it does not work for me.
I generated 2 keystores mycompany1.keystore
and mycompany2.keystore
with 1 certificate in each of them. And 1 truststore mycompany.truststore
that stores both these certificates. Certificates have CN my.hostname.com
and my.another.hostname.com
.
This is the way how I configure embedded tomcat:
@Component
public class MultipleHostsTomcatFactory {
@Value("${abc.com.key-store}")
String abcComKeyStore;
@Value("${xyz.com.key-store}")
String xyzComKeyStore;
@Value("${server.port}")
int serverPort;
@Value("${server.http.port:8080}")
private int httpPort;
@Bean
public ServletWebServerFactory servletContainer() throws Exception {
TomcatServletWebServerFactory factor = new TomcatServletWebServerFactory();
factor.addAdditionalTomcatConnectors(createSSLConnectorForMultipleHosts());
return factor;
}
private Connector createSSLConnectorForMultipleHosts() {
Connector connector = null;
try {
connector = new Connector("org.apache.coyote.http11.Http11NioProtocol");
connector.setScheme("https");
connector.setSecure(true);
connector.setProperty("SSLEnabled", "true");
connector.setProperty("defaultSSLHostConfigName", /*"*.abc.com"*/ "*.hostname.com");
connector.setPort(8444);
// *.abc.com
SSLHostConfig sslHostConfig = new SSLHostConfig();
sslHostConfig.setHostName("*.abc.com");
SSLHostConfigCertificate sslHostConfigCertificate = new SSLHostConfigCertificate(sslHostConfig, SSLHostConfigCertificate.Type.EC);
sslHostConfigCertificate.setCertificateKeystoreFile(abcComKeyStore);
sslHostConfig.addCertificate(sslHostConfigCertificate);
connector.addSslHostConfig(sslHostConfig);
// *.xyz.com
sslHostConfig = new SSLHostConfig();
sslHostConfig.setHostName("*.xyz.com");
sslHostConfigCertificate = new SSLHostConfigCertificate(sslHostConfig, SSLHostConfigCertificate.Type.EC);
sslHostConfigCertificate.setCertificateKeystoreFile(xyzComKeyStore);
sslHostConfig.addCertificate(sslHostConfigCertificate);
connector.addSslHostConfig(sslHostConfig);
} catch (Exception e) {
System.out.println("Catched exception!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
e.printStackTrace();
}
return connector;
}
}
This code is based on this topic. But I have an error:
2022-01-13 16:10:21.301 ERROR 22364 --- [ main] org.apache.catalina.util.LifecycleBase : Failed to initialize component [Connector[HTTP/1.1-8444]]
org.apache.catalina.LifecycleException: Protocol handler initialization failed
...
Caused by: java.lang.IllegalArgumentException: Keystore was tampered with, or password was incorrect
...
Caused by: java.io.IOException: Keystore was tampered with, or password was incorrect
...
Caused by: java.security.UnrecoverableKeyException: Password verification failed
Looks like I miss somethimg.
So, how can I force embedded Tomcat to enable SNI?