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

  1. create self-signed certificate for testing
openssl req -new -newkey rsa:2048 -days 30 -nodes -x509 -keyout test.key -out test.cert
  1. 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();
	}
}
  1. check with curl or openssl
curl https://localhost:8080 -ik --tlsv1.3 --http2
openssl s_client -alpn h2 -connect localhost:8080 -tls1_3
  1. 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)

Most upvoted comments

@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 the SslContextBuilder 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