Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

NullPointerException in SSL handshake with customized HttpClient #473

Closed
philsttr opened this issue Oct 23, 2018 · 1 comment
Closed

NullPointerException in SSL handshake with customized HttpClient #473

philsttr opened this issue Oct 23, 2018 · 1 comment
Labels
type/bug A general bug
Milestone

Comments

@philsttr
Copy link
Contributor

When I try to use spring-webflux's ReactorNettyWebSocketClient with a customized HttpClient created like this:

    WebSocketClient client = new ReactorNettyWebSocketClient(
        HttpClient.create(ConnectionProvider.newConnection()).secure());

I get the following error when connecting during the ssl handshake :

java.lang.NullPointerException: null
	at java.base/sun.net.util.IPAddressUtil.textToNumericFormatV4(IPAddressUtil.java:49)
	at java.base/sun.net.util.IPAddressUtil.isIPv4LiteralAddress(IPAddressUtil.java:241)
	at java.base/sun.security.util.HostnameChecker.isIpAddress(HostnameChecker.java:117)
	at java.base/sun.security.util.HostnameChecker.match(HostnameChecker.java:95)
	at java.base/sun.security.ssl.X509TrustManagerImpl.checkIdentity(X509TrustManagerImpl.java:459)
	at java.base/sun.security.ssl.X509TrustManagerImpl.checkIdentity(X509TrustManagerImpl.java:434)
	at java.base/sun.security.ssl.X509TrustManagerImpl.checkTrusted(X509TrustManagerImpl.java:291)
	at java.base/sun.security.ssl.X509TrustManagerImpl.checkServerTrusted(X509TrustManagerImpl.java:141)
	at java.base/sun.security.ssl.CertificateMessage$T12CertificateConsumer.checkServerCerts(CertificateMessage.java:620)
	at java.base/sun.security.ssl.CertificateMessage$T12CertificateConsumer.onCertificate(CertificateMessage.java:461)
	at java.base/sun.security.ssl.CertificateMessage$T12CertificateConsumer.consume(CertificateMessage.java:361)
	at java.base/sun.security.ssl.SSLHandshake.consume(SSLHandshake.java:392)
	at java.base/sun.security.ssl.HandshakeContext.dispatch(HandshakeContext.java:444)
	at java.base/sun.security.ssl.SSLEngineImpl$DelegatedTask$DelegatedAction.run(SSLEngineImpl.java:1065)
	at java.base/sun.security.ssl.SSLEngineImpl$DelegatedTask$DelegatedAction.run(SSLEngineImpl.java:1052)
	at java.base/java.security.AccessController.doPrivileged(Native Method)
	at java.base/sun.security.ssl.SSLEngineImpl$DelegatedTask.run(SSLEngineImpl.java:999)
	at io.netty.handler.ssl.SslHandler.runDelegatedTasks(SslHandler.java:1457)
	at io.netty.handler.ssl.SslHandler.unwrap(SslHandler.java:1365)
	at io.netty.handler.ssl.SslHandler.decodeJdkCompatible(SslHandler.java:1199)
	at io.netty.handler.ssl.SslHandler.decode(SslHandler.java:1243)
	at io.netty.handler.codec.ByteToMessageDecoder.decodeRemovalReentryProtection(ByteToMessageDecoder.java:489)
	at io.netty.handler.codec.ByteToMessageDecoder.callDecode(ByteToMessageDecoder.java:428)
	at io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:265)
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:362)
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:348)
	at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:340)
	at io.netty.channel.DefaultChannelPipeline$HeadContext.channelRead(DefaultChannelPipeline.java:1434)
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:362)
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:348)
	at io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:965)
	at io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:163)
	at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:628)
	at io.netty.channel.nio.NioEventLoop.processSelectedKeysPlain(NioEventLoop.java:528)
	at io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:482)
	at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:442)
	at io.netty.util.concurrent.SingleThreadEventExecutor$5.run(SingleThreadEventExecutor.java:884)
	at java.base/java.lang.Thread.run(Thread.java:834)

However, I do not get an error when I use the default HttpClient like this:

    WebSocketClient client = new ReactorNettyWebSocketClient();

I believe Norman Maurer identified the underlying cause of the NPE in the JDK's ssl engine (see here)

However, that doesn't explain the difference in why the error occurs with the customized HttpClient, but not with the default one.

So, I dug a little deeper into reactor-netty code, and found the following:

The NPE occurs when Netty's sslHandler is created without a remote address here. This is the codepath that executes when using the customized HttpClient The sniInfo is null in this case because the instanceof check in the constructor here. The sniInfo object passed to the constructor is an instance of HttpClientHandler (set here) and passed to the constructor here

When the default HttpClient is used, the sniInfo here is an instanceof InetSocketAddress. Therefore the remoteAddress is passed to netty's SslHandler (and into the jdk's ssl engine), and therefore there is no exception.

So, in summary, yes it appears there is a bug in the jdk ssl engine when the remoteAddress is null. But, it seems like reactor-netty should be able to provide a non-null remoteAddress in all cases (and therefore avoid the bug)

Expected behavior

Able to use customized HttpClient with SSL

Actual behavior

Unable to use customized HttpClient with SSL. Exception during the ssl handshake.

java.lang.NullPointerException: null
	at java.base/sun.net.util.IPAddressUtil.textToNumericFormatV4(IPAddressUtil.java:49)
	at java.base/sun.net.util.IPAddressUtil.isIPv4LiteralAddress(IPAddressUtil.java:241)

Steps to reproduce

Create a ReactorNettyWebSocketClient like this:

		WebSocketClient client = new ReactorNettyWebSocketClient(
				HttpClient.create(ConnectionProvider.newConnection()).secure());

And attempt to connect the client to an https destination.

Reactor Netty version

0.8.1.RELEASE

JVM version (e.g. java -version)

openjdk version "11" 2018-09-25
OpenJDK Runtime Environment 18.9 (build 11+28)
OpenJDK 64-Bit Server VM 18.9 (build 11+28, mixed mode)

OS version (e.g. uname -a)

Windows 10 Build 1709

@violetagg violetagg added the type/bug A general bug label Oct 23, 2018
@violetagg violetagg added this to the 0.8.2.RELEASE milestone Oct 23, 2018
@philsttr
Copy link
Contributor Author

Thanks @violetagg !

I somewhat confirmed your fix by manually executing convertLazyRemoteAddress(bootstrap) in a debugger at the same location in which you added it. Doing so does indeed fix the problem I'm seeing.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
type/bug A general bug
Projects
None yet
Development

No branches or pull requests

2 participants