Tomcat 与 HTTP/2 和 TLSv1.3

Tomcat with HTTP/2 and TLSv1.3

TL;DR:我们如何配置 Tomcat 运行ning on Windows with Java 8 以支持 两者 TLSv1.3 HTTP/2?


我们的一个应用程序 运行s 在 Tomcat 上 9.0 在 Windows 上使用 Java 8。使用 HTTP/1.1 的设置对我们来说工作正常和 TLSv1.2,但我们现在想使用 HTTP/2 and TLSv1.3。我们能够让 HTTP/2 TLSv1.3 工作,但不能同时工作。

我们可以通过配置 Tomcat 使用 Azul 的 Zulu Java 8 版本来使 TLSv1.3 正常工作。使用此配置 Tomcat 通过 JSSE 使用 TLS。但是,当我们尝试添加对 HTTP/2 的支持时,我们 运行 陷入了问题。根据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.

注意:我们不确定我们使用的 Java8 Zulu 版本是否缺少 ALPN。

当我们切换到基于 OpenSSL 的 TLS 时,我们能够 HTTP/2 工作,但我们不知道如何让 TLSv1.3 工作。我们安装了 OpenSSL and APR binaries,但是当我们尝试 运行 时仅配置了 TLSv1.3(而不是 TLSv1.2+TLSv1.3),我们在 Tomcat 日志中看到以下错误:

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

以下是我们为 server.xml.

尝试过的不同变体

工作 HTTP/2 配置(无 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>

工作 TLSv1.3 配置(没有 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>

不工作HTTP/2 和 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.3"
        truststorePassword="changeit"
        truststoreType="JKS"
        certificateVerification="optional">
            <Certificate certificateKeystoreFile="conf/keystore.jks" type="RSA"/>
    </SSLHostConfig>
</Connector>

当我们挖掘 Tomcat code 时,我们看到:

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);
}

当我们检查我们的 OpenSSL 版本时(对于盒子上唯一配置的 OpenSSL),我们看到:

C:\>openssl version
OpenSSL 1.1.1g  21 Apr 2020

基于此,我们不明白为什么我们的 OpenSSL 配置不支持 TLSv1.3。


编辑: 我们尝试了另一种配置来使用 APR(即没有 JSSE),但这也没有用。以下是详情。

不工作 HTTP/2 和 TLSv1.3 通过 APR 配置:

<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>

生成的错误日志(堆栈跟踪与之前略有不同):

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 使用 APR 配置启动的日志

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

您的 Tomcat (9.0.7) 版本很旧,在您发布此问题前已经发布了 2 年多。当前版本为 9.0.37.

似乎直到 9.0.13 才将 TLSv1.3 支持添加到 Tomcat,在 ASF Bugzilla issue 62748.

下归档

升级你的 Tomcat 应该允许你使用 TLSv1.3 如果 JVM 支持它(对于 JSSE)或者如果你的 OpenSSL 版本支持它(通过 APR 连接器)(或两者!)。