reactor-netty: TLSv1.3 not working with HTTP/2 for HttpServer using JDK as SSL Provider
If an HttpServer is configured to use TLSv1.3 and HTTP/2, connections using HTTP/2 and TLSv1.3 can not be established. TLSv1.3 works only without HTTP/2. If TLSv1.2 and TLSv1.3 are configured, only TLSv1.2 can be used. If only TLSv1.3 is configured, no connection can be established at all.
Expected Behavior
Connecting to an HttpServer using HTTP/2 and TLSv1.3 should be possible.
Actual Behavior
HTTP/2 connections with TLSv1.3 can not be established and the following exceptions is thrown.
(reactor-http-nio-3) [id: 0xa7207b9e, L:/127.0.0.1:8080 ! R:/127.0.0.1:50370] onUncaughtException(SimpleConnection{channel=[id: 0xa7207b9e, L:/127.0.0.1:8080 ! R:/127.0.0.1:50370]}) - io.netty.handler.codec.DecoderException: javax.net.ssl.SSLHandshakeException: The client supported protocol versions [TLSv1.3] are not accepted by server preferences [TLS12]
io.netty.handler.codec.DecoderException: javax.net.ssl.SSLHandshakeException: The client supported protocol versions [TLSv1.3] are not accepted by server preferences [TLS12]
at io.netty.handler.codec.ByteToMessageDecoder.callDecode(ByteToMessageDecoder.java:471)
at io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:276)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365)
at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:357)
at io.netty.channel.DefaultChannelPipeline$HeadContext.channelRead(DefaultChannelPipeline.java:1410)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365)
at io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:919)
at io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:163)
at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:714)
at io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:650)
at io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:576)
at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:493)
at io.netty.util.concurrent.SingleThreadEventExecutor$4.run(SingleThreadEventExecutor.java:989)
at io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74)
at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
at java.base/java.lang.Thread.run(Thread.java:832)
Caused by: javax.net.ssl.SSLHandshakeException: The client supported protocol versions [TLSv1.3] are not accepted by server preferences [TLS12]
at java.base/sun.security.ssl.Alert.createSSLException(Alert.java:131)
at java.base/sun.security.ssl.Alert.createSSLException(Alert.java:117)
at java.base/sun.security.ssl.TransportContext.fatal(TransportContext.java:312)
at java.base/sun.security.ssl.TransportContext.fatal(TransportContext.java:268)
at java.base/sun.security.ssl.TransportContext.fatal(TransportContext.java:259)
at java.base/sun.security.ssl.ClientHello$ClientHelloConsumer.negotiateProtocol(ClientHello.java:915)
at java.base/sun.security.ssl.ClientHello$ClientHelloConsumer.onClientHello(ClientHello.java:831)
at java.base/sun.security.ssl.ClientHello$ClientHelloConsumer.consume(ClientHello.java:812)
at java.base/sun.security.ssl.SSLHandshake.consume(SSLHandshake.java:396)
at java.base/sun.security.ssl.HandshakeContext.dispatch(HandshakeContext.java:445)
at java.base/sun.security.ssl.SSLEngineImpl$DelegatedTask$DelegatedAction.run(SSLEngineImpl.java:1260)
at java.base/sun.security.ssl.SSLEngineImpl$DelegatedTask$DelegatedAction.run(SSLEngineImpl.java:1247)
at java.base/java.security.AccessController.doPrivileged(AccessController.java:691)
at java.base/sun.security.ssl.SSLEngineImpl$DelegatedTask.run(SSLEngineImpl.java:1192)
at io.netty.handler.ssl.SslHandler.runAllDelegatedTasks(SslHandler.java:1550)
at io.netty.handler.ssl.SslHandler.runDelegatedTasks(SslHandler.java:1564)
at io.netty.handler.ssl.SslHandler.unwrap(SslHandler.java:1448)
at io.netty.handler.ssl.SslHandler.decodeJdkCompatible(SslHandler.java:1275)
at io.netty.handler.ssl.SslHandler.decode(SslHandler.java:1322)
at io.netty.handler.codec.ByteToMessageDecoder.decodeRemovalReentryProtection(ByteToMessageDecoder.java:501)
at io.netty.handler.codec.ByteToMessageDecoder.callDecode(ByteToMessageDecoder.java:440)
... 17 more
Steps to Reproduce
- create self-signed certificate for testing
openssl req -new -newkey rsa:2048 -days 30 -nodes -x509 -keyout test.key -out test.cert
- simple demo code
import io.netty.handler.ssl.SslContextBuilder;
import java.io.File;
import reactor.core.publisher.Mono;
import reactor.netty.http.HttpProtocol;
import reactor.netty.http.server.HttpServer;
public class Main
{
public static void main(String... args)
{
var key = new File("test.key");
var cert = new File("test.cert");
var server = HttpServer
.create()
.port(8080)
.host("localhost")
.protocol(HttpProtocol.H2) // remove to disable HTTP/2
.secure(spec -> spec.sslContext(SslContextBuilder.forServer(cert, key).protocols("TLSv1.2", "TLSv1.3")))
.handle((request, response) -> response.sendString(Mono.just("hello")))
.bindNow();
server.onDispose().block();
}
}
- check with curl or openssl
curl https://localhost:8080 -ik --tlsv1.3 --http2
openssl s_client -alpn h2 -connect localhost:8080 -tls1_3
- disable H2 and re-check with the commands from step 3.
Your Environment
- Reactor version(s) used: 0.9.10
- Other relevant libraries versions (eg.
netty
, …): - JVM version (
java -version
): 11.0.6, 14.0.1 - OS and version (eg
uname -a
):
About this issue
- Original URL
- State: closed
- Created 4 years ago
- Comments: 22 (22 by maintainers)
@violetagg Netty 4.1.52.Final has been released. I have tested reactor-netty 0.9.10 and 0.9.11 with netty-4.1.52.Final and it works in both combinations.
The issue here is related to
io.netty.handler.ssl.SslProvider.JDK
usage and that by default when theSslContextBuilder
does not provide any HTTP/2 relevant configuration Reactor Netty applies such. The cipher suite is as defined here https://tools.ietf.org/html/rfc7540#section-9.2.2 (specific to TLSv1.2) and here https://github.com/netty/netty/blob/4.1/codec-http2/src/main/java/io/netty/handler/codec/http2/Http2SecurityUtil.java. https://github.com/reactor/reactor-netty/blob/5d5a04c75276a854a766c752e6245150ef84e205/src/main/java/reactor/netty/tcp/SslProvider.java#L311-L323