Hi there,

I think I found a bug in the TLSv1.3 session cache implementation which 
sometimes can cause failures during session resumption. 
The cause of this sometimes show up as NPE:

javax.net.ssl.SSLException: Session has no PSK
        at java.base/sun.security.ssl.Alert.createSSLException(Alert.java:133)
        at java.base/sun.security.ssl.Alert.createSSLException(Alert.java:117)
        at 
java.base/sun.security.ssl.TransportContext.fatal(TransportContext.java:336)
        at 
java.base/sun.security.ssl.TransportContext.fatal(TransportContext.java:292)
        at 
java.base/sun.security.ssl.TransportContext.fatal(TransportContext.java:283)
        at 
java.base/sun.security.ssl.PreSharedKeyExtension.checkBinder(PreSharedKeyExtension.java:537)
        at 
java.base/sun.security.ssl.PreSharedKeyExtension$CHPreSharedKeyUpdate.consume(PreSharedKeyExtension.java:528)
        at 
java.base/sun.security.ssl.SSLExtension.consumeOnTrade(SSLExtension.java:583)
        at 
java.base/sun.security.ssl.SSLExtensions.consumeOnTrade(SSLExtensions.java:222)
        at 
java.base/sun.security.ssl.ServerHello$T13ServerHelloProducer.produce(ServerHello.java:539)
        at 
java.base/sun.security.ssl.SSLHandshake.produce(SSLHandshake.java:436)
        at 
java.base/sun.security.ssl.ClientHello$T13ClientHelloConsumer.goServerHello(ClientHello.java:1234)
        at 
java.base/sun.security.ssl.ClientHello$T13ClientHelloConsumer.consume(ClientHello.java:1170)
        at 
java.base/sun.security.ssl.ClientHello$ClientHelloConsumer.onClientHello(ClientHello.java:852)
        at 
java.base/sun.security.ssl.ClientHello$ClientHelloConsumer.consume(ClientHello.java:813)
        at 
java.base/sun.security.ssl.SSLHandshake.consume(SSLHandshake.java:392)
        at 
java.base/sun.security.ssl.HandshakeContext.dispatch(HandshakeContext.java:443)
        at 
java.base/sun.security.ssl.SSLEngineImpl$DelegatedTask$DelegatedAction.run(SSLEngineImpl.java:1074)
        at 
java.base/sun.security.ssl.SSLEngineImpl$DelegatedTask$DelegatedAction.run(SSLEngineImpl.java:1061)
        at java.base/java.security.AccessController.doPrivileged(Native Method)
        at 
java.base/sun.security.ssl.SSLEngineImpl$DelegatedTask.run(SSLEngineImpl.java:1008)
        at 
io.netty.handler.ssl.SslHandler.runAllDelegatedTasks(SslHandler.java:1557)
        at 
io.netty.handler.ssl.SslHandler.runDelegatedTasks(SslHandler.java:1571)
        at io.netty.handler.ssl.SslHandler.unwrap(SslHandler.java:1455)
        at 
io.netty.handler.ssl.SslHandler.decodeJdkCompatible(SslHandler.java:1282)
        at io.netty.handler.ssl.SslHandler.decode(SslHandler.java:1329)
        at 
io.netty.handler.codec.ByteToMessageDecoder.decodeRemovalReentryProtection(ByteToMessageDecoder.java:508)
        at 
io.netty.handler.codec.ByteToMessageDecoder.callDecode(ByteToMessageDecoder.java:447)
        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:166)
        at 
io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:719)
        at 
io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:655)
        at 
io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:581)
        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:834)
java.lang.NullPointerException
        at java.base/sun.security.ssl.HKDF.extract(HKDF.java:93)
        at java.base/sun.security.ssl.HKDF.extract(HKDF.java:119)
        at 
java.base/sun.security.ssl.ServerHello.setUpPskKD(ServerHello.java:1169)
        at 
java.base/sun.security.ssl.ServerHello$T13ServerHelloProducer.produce(ServerHello.java:547)
        at 
java.base/sun.security.ssl.SSLHandshake.produce(SSLHandshake.java:436)
        at 
java.base/sun.security.ssl.ClientHello$T13ClientHelloConsumer.goServerHello(ClientHello.java:1234)
        at 
java.base/sun.security.ssl.ClientHello$T13ClientHelloConsumer.consume(ClientHello.java:1170)
        at 
java.base/sun.security.ssl.ClientHello$ClientHelloConsumer.onClientHello(ClientHello.java:852)
        at 
java.base/sun.security.ssl.ClientHello$ClientHelloConsumer.consume(ClientHello.java:813)
        at 
java.base/sun.security.ssl.SSLHandshake.consume(SSLHandshake.java:392)
        at 
java.base/sun.security.ssl.HandshakeContext.dispatch(HandshakeContext.java:443)
        at 
java.base/sun.security.ssl.SSLEngineImpl$DelegatedTask$DelegatedAction.run(SSLEngineImpl.java:1074)
        at 
java.base/sun.security.ssl.SSLEngineImpl$DelegatedTask$DelegatedAction.run(SSLEngineImpl.java:1061)
        at java.base/java.security.AccessController.doPrivileged(Native Method)
        at 
java.base/sun.security.ssl.SSLEngineImpl$DelegatedTask.run(SSLEngineImpl.java:1008)
        at 
io.netty.handler.ssl.SslHandler.runAllDelegatedTasks(SslHandler.java:1557)
        at 
io.netty.handler.ssl.SslHandler.runDelegatedTasks(SslHandler.java:1571)
        at io.netty.handler.ssl.SslHandler.unwrap(SslHandler.java:1455)
        at 
io.netty.handler.ssl.SslHandler.decodeJdkCompatible(SslHandler.java:1282)
        at io.netty.handler.ssl.SslHandler.decode(SslHandler.java:1329)
        at 
io.netty.handler.codec.ByteToMessageDecoder.decodeRemovalReentryProtection(ByteToMessageDecoder.java:508)
        at 
io.netty.handler.codec.ByteToMessageDecoder.callDecode(ByteToMessageDecoder.java:447)
        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:166)
        at 
io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:719)
        at 
io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:655)
        at 
io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:581)
        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:834)


Other times the NPE is not included but it still fails with something like:

Caused by: javax.net.ssl.SSLException: Session has no PSK
        at java.base/sun.security.ssl.Alert.createSSLException(Alert.java:133)
        at java.base/sun.security.ssl.Alert.createSSLException(Alert.java:117)
        at 
java.base/sun.security.ssl.TransportContext.fatal(TransportContext.java:336)
        at 
java.base/sun.security.ssl.TransportContext.fatal(TransportContext.java:292)
        at 
java.base/sun.security.ssl.TransportContext.fatal(TransportContext.java:283)
        at 
java.base/sun.security.ssl.PreSharedKeyExtension.checkBinder(PreSharedKeyExtension.java:537)
        at 
java.base/sun.security.ssl.PreSharedKeyExtension$CHPreSharedKeyUpdate.consume(PreSharedKeyExtension.java:528)
        at 
java.base/sun.security.ssl.SSLExtension.consumeOnTrade(SSLExtension.java:583)
        at 
java.base/sun.security.ssl.SSLExtensions.consumeOnTrade(SSLExtensions.java:222)
        at 
java.base/sun.security.ssl.ServerHello$T13ServerHelloProducer.produce(ServerHello.java:539)
        at 
java.base/sun.security.ssl.SSLHandshake.produce(SSLHandshake.java:436)
        at 
java.base/sun.security.ssl.ClientHello$T13ClientHelloConsumer.goServerHello(ClientHello.java:1234)
        at 
java.base/sun.security.ssl.ClientHello$T13ClientHelloConsumer.consume(ClientHello.java:1170)
        at 
java.base/sun.security.ssl.ClientHello$ClientHelloConsumer.onClientHello(ClientHello.java:852)
        at 
java.base/sun.security.ssl.ClientHello$ClientHelloConsumer.consume(ClientHello.java:813)
        at 
java.base/sun.security.ssl.SSLHandshake.consume(SSLHandshake.java:392)
        at 
java.base/sun.security.ssl.HandshakeContext.dispatch(HandshakeContext.java:443)
        at 
java.base/sun.security.ssl.SSLEngineImpl$DelegatedTask$DelegatedAction.run(SSLEngineImpl.java:1074)
        at 
java.base/sun.security.ssl.SSLEngineImpl$DelegatedTask$DelegatedAction.run(SSLEngineImpl.java:1061)
        at java.base/java.security.AccessController.doPrivileged(Native Method)
        at 
java.base/sun.security.ssl.SSLEngineImpl$DelegatedTask.run(SSLEngineImpl.java:1008)
        at 
io.netty.handler.ssl.SslHandler.runAllDelegatedTasks(SslHandler.java:1557)
        at 
io.netty.handler.ssl.SslHandler.runDelegatedTasks(SslHandler.java:1571)
        at io.netty.handler.ssl.SslHandler.unwrap(SslHandler.java:1455)
        at 
io.netty.handler.ssl.SslHandler.decodeJdkCompatible(SslHandler.java:1282)
        at io.netty.handler.ssl.SslHandler.decode(SslHandler.java:1329)
        at 
io.netty.handler.codec.ByteToMessageDecoder.decodeRemovalReentryProtection(ByteToMessageDecoder.java:508)
        at 
io.netty.handler.codec.ByteToMessageDecoder.callDecode(ByteToMessageDecoder.java:447)
        ... 17 common frames omitted

Looking at the first stacktrace this seems to be related to:

https://bugs.openjdk.java.net/browse/JDK-8241248 
<https://bugs.openjdk.java.net/browse/JDK-8241248>


Unfortunately I don’t have a reproducer which uses the JDK only here but I can 
reproduce this with Netty that uses OpenSSL on the client side and the JDK 
SSLEngine on the server side.
I can reproduce this with the latest JDK11 release but can't with JDK15. Also 
what makes me believe it may be a concurrency bug is that only some handshakes 
fail. Like 70 out of 2600 fail.

While the reproducer also involves netty I am wondering if you would still be 
interested in it ? It should be quite straight forward to run locally for you.

The code that can reproduce it is here:
https://github.com/netty/netty/pull/10994#issuecomment-787976965 
<https://github.com/netty/netty/pull/10994#issuecomment-787976965>

Also you will need to use this branch:
https://github.com/netty/netty/tree/ssl_cache_revamp 
<https://github.com/netty/netty/tree/ssl_cache_revamp>


Please don’t hesitate if you have questions,
Norman



Reply via email to