Tomcat 支持 HTTP/2 和 TLSv1.3

3
TL;DR:我们如何配置在Windows上运行的Java 8的Tomcat以支持TLSv1.3和HTTP/2的两种协议?
我们的一个应用程序在Windows上使用Java 8上的Tomcat 9.0运行。使用HTTP/1.1和TLSv1.2,设置对我们来说很好用,但现在我们想同时使用HTTP/2和TLSv1.3。我们能够使HTTP/2或TLSv1.3工作,但不能同时使用两者。
我们能够通过配置Tomcat使用Azul的Zulu Java 8版本来让TLSv1.3工作。使用此配置,Tomcat通过JSSE使用TLS。然而,当我们尝试添加对HTTP/2的支持时,遇到了问题。根据Tomcat文档
“由于Java 8的TLS实现不支持ALPN(这是HTTP/2 over TLS所需的),因此您必须使用基于OpenSSL的TLS实现来启用HTTP/2支持。”
注意:我们不确定我们正在使用的Zulu版本的Java 8是否缺少ALPN。
当我们切换到基于OpenSSL的TLS时,我们能够使HTTP/2工作,但我们无法弄清如何使TLSv1.3工作。我们安装了OpenSSL和APR二进制文件,但当我们尝试仅配置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代码时,我们发现:
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

启动时带有APR配置的Tomcat日志
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

错误消息显示你在这里使用的是JSSE而不是OpenSSL。 - undefined
@MarquisofLorne,我们对于我们的server.xml文件(或任何其他配置)应该做出哪些改变持开放态度。你有什么建议吗? - undefined
在Windows上,libtcnative 静态链接了 libaprlibssl(OpenSSL)。在启动时,Tomcat应该会提供一系列版本信息。它对于有效的APR和OpenSSL版本有什么说法? - undefined
@ChristopherSchultz 在帖子中添加了更多的日志输出。我看到 "OpenSSL 成功初始化 [OpenSSL 1.1.1g 21 Apr 2020]" 和 "Loaded APR based Apache Tomcat Native library [1.2.24] using APR version [1.7.0]"。我还看到 "useAprConnector [false], useOpenSSL [true]",但这是预期的,因为我们想要使用 NIO 来获得非阻塞的好处。我原本以为我们仍然可以在 NIO 中使用 TLSv1.3 和 HTTP/2。 - undefined
@ChristopherSchultz 看起来问题已经解决了。我会进行更多的测试以确保彻底,但目前看来非常有希望。我还会尝试不同的JDK(OpenJDK、Oracle、Azul)来查看是否有任何差异。如果你愿意建议升级到9.0.37版本,我将非常乐意将其标记为正确答案。非常感谢! - undefined
显示剩余2条评论
1个回答

0

你使用的Tomcat版本(9.0.7)已经非常老了,发布时间比你提问的时间早了2年以上。当前版本是9.0.37。

看起来直到9.0.13版本,Tomcat才添加了对TLSv1.3的支持,相关信息可以在ASF Bugzilla issue 62748中找到。

升级你的Tomcat应该能让你使用TLSv1.3,前提是JVM支持(对于JSSE)或者你的OpenSSL版本支持(通过APR连接器)(或者两者都支持!)。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接