TL;DR: How can we configure Tomcat running on Windows with Java 8 to support both TLSv1.3 and HTTP/2?
One of our applications runs on Tomcat 9.0 on Windows with Java 8. The setup works fine for us using HTTP/1.1 and TLSv1.2 but we now want to use HTTP/2 and TLSv1.3. We are able to get HTTP/2 or TLSv1.3 working but not both together.
We are able to get TLSv1.3 working by configuring Tomcat to use Azul's Zulu Java 8 release. With this configuration Tomcat uses TLS via JSSE. However, when we try to add support for HTTP/2 we run into problems. According to Tomcat's documentation,
Because Java 8's TLS implementation does not support ALPN (which is required for HTTP/2 over TLS), you must be using an OpenSSL based TLS implementation to enable HTTP/2 support.
Note: We are not sure if the Zulu release of Java 8 that we are using lacks ALPN or not.
When we switch to OpenSSL based TLS we are able to get HTTP/2 working but we can't figure out how to get TLSv1.3 working. We installed the OpenSSL and APR binaries but when we try to run with only TLSv1.3 configured (instead of TLSv1.2+TLSv1.3) we see the following error in our Tomcat logs:
org.apache.catalina.LifecycleException: Protocol handler initialization failed
at org.apache.catalina.connector.Connector.initInternal(Connector.java:935)
at org.apache.catalina.util.LifecycleBase.init(LifecycleBase.java:136)
at org.apache.catalina.core.StandardService.initInternal(StandardService.java:530)
at org.apache.catalina.util.LifecycleBase.init(LifecycleBase.java:136)
at org.apache.catalina.core.StandardServer.initInternal(StandardServer.java:852)
at org.apache.catalina.util.LifecycleBase.init(LifecycleBase.java:136)
at org.apache.catalina.startup.Catalina.load(Catalina.java:633)
at org.apache.catalina.startup.Catalina.load(Catalina.java:656)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.apache.catalina.startup.Bootstrap.load(Bootstrap.java:306)
at org.apache.catalina.startup.Bootstrap.main(Bootstrap.java:491)
Caused by: java.lang.IllegalArgumentException: None of the [protocols] specified are supported by the SSL engine : [[TLSv1.3]]
at org.apache.tomcat.util.net.SSLUtilBase.getEnabled(SSLUtilBase.java:91)
at org.apache.tomcat.util.net.SSLUtilBase.<init>(SSLUtilBase.java:55)
at org.apache.tomcat.util.net.openssl.OpenSSLUtil.<init>(OpenSSLUtil.java:41)
at org.apache.tomcat.util.net.openssl.OpenSSLImplementation.getSSLUtil(OpenSSLImplementation.java:36)
at org.apache.tomcat.util.net.AbstractJsseEndpoint.createSSLContext(AbstractJsseEndpoint.java:102)
at org.apache.tomcat.util.net.AbstractJsseEndpoint.initialiseSsl(AbstractJsseEndpoint.java:85)
at org.apache.tomcat.util.net.NioEndpoint.bind(NioEndpoint.java:216)
at org.apache.tomcat.util.net.AbstractEndpoint.init(AbstractEndpoint.java:1043)
at org.apache.coyote.AbstractProtocol.init(AbstractProtocol.java:540)
at org.apache.coyote.http11.AbstractHttp11Protocol.init(AbstractHttp11Protocol.java:74)
at org.apache.catalina.connector.Connector.initInternal(Connector.java:932)
... 13 more
Below are the different variations we have tried for our server.xml.
Working HTTP/2 Configuration (without TLSv1.3):
<Connector port="8443" protocol="org.apache.coyote.http11.Http11NioProtocol"
maxThreads="150" SSLEnabled="true" sslImplementationName="org.apache.tomcat.util.net.openssl.OpenSSLImplementation">
<UpgradeProtocol className="org.apache.coyote.http2.Http2Protocol" />
<SSLHostConfig truststoreFile="conf/truststore.jks"
protocols="TLSv1.2+TLSv1.3"
truststorePassword="changeit"
truststoreType="JKS"
certificateVerification="optional">
<Certificate certificateKeystoreFile="conf/keystore.jks" type="RSA"/>
</SSLHostConfig>
</Connector>
Working TLSv1.3 Configuration (without HTTP/2):
<Connector port="8443" protocol="org.apache.coyote.http11.Http11NioProtocol"
maxThreads="150" SSLEnabled="true">
<SSLHostConfig truststoreFile="conf/truststore.jks"
protocols="TLSv1.3"
truststorePassword="changeit"
truststoreType="JKS"
certificateVerification="optional">
<Certificate certificateKeystoreFile="conf/keystore.jks" type="RSA"/>
</SSLHostConfig>
</Connector>
NOT Working HTTP/2 and TLSv1.3 Configuration:
<Connector port="8443" protocol="org.apache.coyote.http11.Http11NioProtocol"
maxThreads="150" SSLEnabled="true" sslImplementationName="org.apache.tomcat.util.net.openssl.OpenSSLImplementation">
<UpgradeProtocol className="org.apache.coyote.http2.Http2Protocol" />
<SSLHostConfig truststoreFile="conf/truststore.jks"
protocols="TLSv1.3"
truststorePassword="changeit"
truststoreType="JKS"
certificateVerification="optional">
<Certificate certificateKeystoreFile="conf/keystore.jks" type="RSA"/>
</SSLHostConfig>
</Connector>
When we dig through the Tomcat code we see:
if (SSL.version() >= 0x1010100f) {
SSL_PROTOCOL_ALL = (SSL_PROTOCOL_TLSV1 | SSL_PROTOCOL_TLSV1_1 | SSL_PROTOCOL_TLSV1_2 |
SSL_PROTOCOL_TLSV1_3);
} else {
SSL_PROTOCOL_ALL = (SSL_PROTOCOL_TLSV1 | SSL_PROTOCOL_TLSV1_1 | SSL_PROTOCOL_TLSV1_2);
}
When we check our OpenSSL version (for the only configured OpenSSL on the box), we see:
C:\>openssl version
OpenSSL 1.1.1g 21 Apr 2020
Based on that, we don't see why our OpenSSL configuration isn't supporting TLSv1.3.
EDIT: We tried another configuration to use APR (i.e., no JSSE) but that also didn't work. Below are the details.
NOT Working HTTP/2 and TLSv1.3 via APR Configuration:
<Connector port="8443" protocol="org.apache.coyote.http11.Http11AprProtocol"
maxThreads="150" scheme="https" secure="true" SSLEnabled="true" >
<UpgradeProtocol className="org.apache.coyote.http2.Http2Protocol" />
<SSLHostConfig protocols="TLSv1.3">
<Certificate certificateKeyFile="conf/privkey"
certificateFile="conf/ssl.cer"
certificateChainFile="conf/certchain.pem"
type="RSA" />
</SSLHostConfig>
</Connector>
Resulting error log (slightly different stack trace than before):
org.apache.catalina.LifecycleException: Protocol handler initialization failed
at org.apache.catalina.connector.Connector.initInternal(Connector.java:935)
at org.apache.catalina.util.LifecycleBase.init(LifecycleBase.java:136)
at org.apache.catalina.core.StandardService.initInternal(StandardService.java:530)
at org.apache.catalina.util.LifecycleBase.init(LifecycleBase.java:136)
at org.apache.catalina.core.StandardServer.initInternal(StandardServer.java:852)
at org.apache.catalina.util.LifecycleBase.init(LifecycleBase.java:136)
at org.apache.catalina.startup.Catalina.load(Catalina.java:633)
at org.apache.catalina.startup.Catalina.load(Catalina.java:656)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.apache.catalina.startup.Bootstrap.load(Bootstrap.java:306)
at org.apache.catalina.startup.Bootstrap.main(Bootstrap.java:491)
Caused by: java.lang.IllegalArgumentException: None of the [protocols] specified are supported by the SSL engine : [[TLSv1.3]]
at org.apache.tomcat.util.net.SSLUtilBase.getEnabled(SSLUtilBase.java:91)
at org.apache.tomcat.util.net.AprEndpoint.createSSLContext(AprEndpoint.java:405)
at org.apache.tomcat.util.net.AprEndpoint.bind(AprEndpoint.java:376)
at org.apache.tomcat.util.net.AbstractEndpoint.init(AbstractEndpoint.java:1043)
at org.apache.coyote.AbstractProtocol.init(AbstractProtocol.java:540)
at org.apache.coyote.http11.AbstractHttp11Protocol.init(AbstractHttp11Protocol.java:74)
at org.apache.catalina.connector.Connector.initInternal(Connector.java:932)
... 13 more
Tomcat Logs from Bootup with APR Config
01-Aug-2020 04:34:59.459 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Server version: Apache Tomcat/9.0.7
01-Aug-2020 04:34:59.484 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Server built: Apr 3 2018 19:53:05 UTC
01-Aug-2020 04:34:59.484 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Server number: 9.0.7.0
01-Aug-2020 04:34:59.484 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log OS Name: Windows Server 2016
01-Aug-2020 04:34:59.487 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log OS Version: 10.0
01-Aug-2020 04:34:59.487 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Architecture: amd64
01-Aug-2020 04:34:59.487 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Java Home: C:\Program Files\Java\JDK_Zulu8_262\jre
01-Aug-2020 04:34:59.487 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log JVM Version: 1.8.0_262-b19
01-Aug-2020 04:34:59.487 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log JVM Vendor: Azul Systems, Inc.
01-Aug-2020 04:34:59.487 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log CATALINA_BASE: C:\Program Files\Apache Software Foundation\Tomcat 9.0
01-Aug-2020 04:34:59.487 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log CATALINA_HOME: C:\Program Files\Apache Software Foundation\Tomcat 9.0
01-Aug-2020 04:34:59.488 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: -Dcatalina.home=C:\Program Files\Apache Software Foundation\Tomcat 9.0
01-Aug-2020 04:34:59.488 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: -Dcatalina.base=C:\Program Files\Apache Software Foundation\Tomcat 9.0
01-Aug-2020 04:34:59.488 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: -Djava.io.tmpdir=C:\Program Files\Apache Software Foundation\Tomcat 9.0\temp
01-Aug-2020 04:34:59.488 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: -Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager
01-Aug-2020 04:34:59.488 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: -Djava.util.logging.config.file=C:\Program Files\Apache Software Foundation\Tomcat 9.0\conf\logging.properties
01-Aug-2020 04:34:59.488 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: exit
01-Aug-2020 04:34:59.488 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: abort
01-Aug-2020 04:34:59.489 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: -Xms128m
01-Aug-2020 04:34:59.489 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: -Xmx256m
01-Aug-2020 04:34:59.489 INFO [main] org.apache.catalina.core.AprLifecycleListener.lifecycleEvent Loaded APR based Apache Tomcat Native library [1.2.24] using APR version [1.7.0].
01-Aug-2020 04:34:59.489 INFO [main] org.apache.catalina.core.AprLifecycleListener.lifecycleEvent APR capabilities: IPv6 [true], sendfile [true], accept filters [false], random [true].
01-Aug-2020 04:34:59.489 INFO [main] org.apache.catalina.core.AprLifecycleListener.lifecycleEvent APR/OpenSSL configuration: useAprConnector [false], useOpenSSL [true]
01-Aug-2020 04:34:59.517 INFO [main] org.apache.catalina.core.AprLifecycleListener.initializeSSL OpenSSL successfully initialized [OpenSSL 1.1.1g 21 Apr 2020]
01-Aug-2020 04:35:00.410 INFO [main] org.apache.coyote.AbstractProtocol.init Initializing ProtocolHandler ["http-nio-8080"]
01-Aug-2020 04:35:00.523 INFO [main] org.apache.tomcat.util.net.NioSelectorPool.getSharedSelector Using a shared selector for servlet write/read
01-Aug-2020 04:35:00.536 INFO [main] org.apache.coyote.http11.AbstractHttp11Protocol.configureUpgradeProtocol The ["https-openssl-apr-8443"] connector has been configured to support negotiation to [h2] via ALPN
01-Aug-2020 04:35:00.536 INFO [main] org.apache.coyote.AbstractProtocol.init Initializing ProtocolHandler ["https-openssl-apr-8443"]
01-Aug-2020 04:35:00.633 SEVERE [main] org.apache.catalina.util.LifecycleBase.handleSubClassException Failed to initialize component [Connector[org.apache.coyote.http11.Http11AprProtocol-8443]]
org.apache.catalina.LifecycleException: Protocol handler initialization failed
at org.apache.catalina.connector.Connector.initInternal(Connector.java:935)
at org.apache.catalina.util.LifecycleBase.init(LifecycleBase.java:136)
at org.apache.catalina.core.StandardService.initInternal(StandardService.java:530)
at org.apache.catalina.util.LifecycleBase.init(LifecycleBase.java:136)
at org.apache.catalina.core.StandardServer.initInternal(StandardServer.java:852)
at org.apache.catalina.util.LifecycleBase.init(LifecycleBase.java:136)
at org.apache.catalina.startup.Catalina.load(Catalina.java:633)
at org.apache.catalina.startup.Catalina.load(Catalina.java:656)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.apache.catalina.startup.Bootstrap.load(Bootstrap.java:306)
at org.apache.catalina.startup.Bootstrap.main(Bootstrap.java:491)
Caused by: java.lang.IllegalArgumentException: None of the [protocols] specified are supported by the SSL engine : [[TLSv1.3]]
at org.apache.tomcat.util.net.SSLUtilBase.getEnabled(SSLUtilBase.java:91)
at org.apache.tomcat.util.net.AprEndpoint.createSSLContext(AprEndpoint.java:405)
at org.apache.tomcat.util.net.AprEndpoint.bind(AprEndpoint.java:376)
at org.apache.tomcat.util.net.AbstractEndpoint.init(AbstractEndpoint.java:1043)
at org.apache.coyote.AbstractProtocol.init(AbstractProtocol.java:540)
at org.apache.coyote.http11.AbstractHttp11Protocol.init(AbstractHttp11Protocol.java:74)
at org.apache.catalina.connector.Connector.initInternal(Connector.java:932)
... 13 more
01-Aug-2020 04:35:00.635 INFO [main] org.apache.coyote.AbstractProtocol.init Initializing ProtocolHandler ["ajp-nio-8009"]
01-Aug-2020 04:35:00.638 INFO [main] org.apache.tomcat.util.net.NioSelectorPool.getSharedSelector Using a shared selector for servlet write/read
01-Aug-2020 04:35:00.638 INFO [main] org.apache.catalina.startup.Catalina.load Initialization processed in 3485 ms
01-Aug-2020 04:35:00.706 INFO [main] org.apache.catalina.core.StandardService.startInternal Starting service [Catalina]
01-Aug-2020 04:35:00.706 INFO [main] org.apache.catalina.core.StandardEngine.startInternal Starting Servlet Engine: Apache Tomcat/9.0.7