Netty SslHandler 不适用于自己的根证书
Netty SslHandler not working for own root certificate
我正在使用 Netty 4.1.25。我在我的代码中从 pem
文件创建了一个 X509Certificate
。使用该证书,我像这样设置 SslHandler:
SslContext context = SslContextBuilder.forClient().trustManager( certificate ).build();
pipeline.addLast( "ssl", context.newHandler( socketChannel.alloc() ) );
当证书与服务器上的证书完全相同时(服务器是物联网设备,但可能无关紧要),这可以正常工作。
但是,当我创建自己的根证书并且:
- 服务器有一个信任根证书的证书
- Netty 应用程序使用根证书
然后我得到这个异常:
io.netty.handler.codec.DecoderException: javax.net.ssl.SSLHandshakeException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
at io.netty.handler.codec.ByteToMessageDecoder.callDecode(ByteToMessageDecoder.java:459) ~[netty-all-4.1.25.Final.jar:4.1.25.Final]
at io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:265) ~[netty-all-4.1.25.Final.jar:4.1.25.Final]
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:362) ~[netty-all-4.1.25.Final.jar:4.1.25.Final]
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:348) ~[netty-all-4.1.25.Final.jar:4.1.25.Final]
at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:340) ~[netty-all-4.1.25.Final.jar:4.1.25.Final]
at io.netty.channel.DefaultChannelPipeline$HeadContext.channelRead(DefaultChannelPipeline.java:1434) ~[netty-all-4.1.25.Final.jar:4.1.25.Final]
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:362) ~[netty-all-4.1.25.Final.jar:4.1.25.Final]
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:348) ~[netty-all-4.1.25.Final.jar:4.1.25.Final]
at io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:965) ~[netty-all-4.1.25.Final.jar:4.1.25.Final]
at io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:163) ~[netty-all-4.1.25.Final.jar:4.1.25.Final]
at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:647) ~[netty-all-4.1.25.Final.jar:4.1.25.Final]
at io.netty.channel.nio.NioEventLoop.processSelectedKeysPlain(NioEventLoop.java:547) ~[netty-all-4.1.25.Final.jar:4.1.25.Final]
at io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:501) ~[netty-all-4.1.25.Final.jar:4.1.25.Final]
at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:461) ~[netty-all-4.1.25.Final.jar:4.1.25.Final]
at io.netty.util.concurrent.SingleThreadEventExecutor.run(SingleThreadEventExecutor.java:884) ~[netty-all-4.1.25.Final.jar:4.1.25.Final]
at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30) ~[netty-all-4.1.25.Final.jar:4.1.25.Final]
at java.base/java.lang.Thread.run(Thread.java:834) ~[na:na]
Caused by: javax.net.ssl.SSLHandshakeException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
at java.base/sun.security.ssl.Alert.createSSLException(Alert.java:128) ~[na:na]
at java.base/sun.security.ssl.TransportContext.fatal(TransportContext.java:321) ~[na:na]
at java.base/sun.security.ssl.TransportContext.fatal(TransportContext.java:264) ~[na:na]
at java.base/sun.security.ssl.TransportContext.fatal(TransportContext.java:259) ~[na:na]
at java.base/sun.security.ssl.CertificateMessage$T12CertificateConsumer.checkServerCerts(CertificateMessage.java:642) ~[na:na]
at java.base/sun.security.ssl.CertificateMessage$T12CertificateConsumer.onCertificate(CertificateMessage.java:461) ~[na:na]
at java.base/sun.security.ssl.CertificateMessage$T12CertificateConsumer.consume(CertificateMessage.java:361) ~[na:na]
at java.base/sun.security.ssl.SSLHandshake.consume(SSLHandshake.java:392) ~[na:na]
at java.base/sun.security.ssl.HandshakeContext.dispatch(HandshakeContext.java:444) ~[na:na]
at java.base/sun.security.ssl.SSLEngineImpl$DelegatedTask$DelegatedAction.run(SSLEngineImpl.java:1065) ~[na:na]
at java.base/sun.security.ssl.SSLEngineImpl$DelegatedTask$DelegatedAction.run(SSLEngineImpl.java:1052) ~[na:na]
at java.base/java.security.AccessController.doPrivileged(Native Method) ~[na:na]
at java.base/sun.security.ssl.SSLEngineImpl$DelegatedTask.run(SSLEngineImpl.java:999) ~[na:na]
at io.netty.handler.ssl.SslHandler.runDelegatedTasks(SslHandler.java:1435) ~[netty-all-4.1.25.Final.jar:4.1.25.Final]
at io.netty.handler.ssl.SslHandler.unwrap(SslHandler.java:1343) ~[netty-all-4.1.25.Final.jar:4.1.25.Final]
at io.netty.handler.ssl.SslHandler.decodeJdkCompatible(SslHandler.java:1177) ~[netty-all-4.1.25.Final.jar:4.1.25.Final]
at io.netty.handler.ssl.SslHandler.decode(SslHandler.java:1221) ~[netty-all-4.1.25.Final.jar:4.1.25.Final]
at io.netty.handler.codec.ByteToMessageDecoder.decodeRemovalReentryProtection(ByteToMessageDecoder.java:489) ~[netty-all-4.1.25.Final.jar:4.1.25.Final]
at io.netty.handler.codec.ByteToMessageDecoder.callDecode(ByteToMessageDecoder.java:428) ~[netty-all-4.1.25.Final.jar:4.1.25.Final]
... 16 common frames omitted
Caused by: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
at java.base/sun.security.validator.PKIXValidator.doBuild(PKIXValidator.java:385) ~[na:na]
at java.base/sun.security.validator.PKIXValidator.engineValidate(PKIXValidator.java:290) ~[na:na]
at java.base/sun.security.validator.Validator.validate(Validator.java:264) ~[na:na]
at java.base/sun.security.ssl.X509TrustManagerImpl.validate(X509TrustManagerImpl.java:321) ~[na:na]
at java.base/sun.security.ssl.X509TrustManagerImpl.checkTrusted(X509TrustManagerImpl.java:279) ~[na:na]
at java.base/sun.security.ssl.X509TrustManagerImpl.checkServerTrusted(X509TrustManagerImpl.java:141) ~[na:na]
at java.base/sun.security.ssl.CertificateMessage$T12CertificateConsumer.checkServerCerts(CertificateMessage.java:620) ~[na:na]
... 30 common frames omitted
Caused by: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
at java.base/sun.security.provider.certpath.SunCertPathBuilder.build(SunCertPathBuilder.java:141) ~[na:na]
at java.base/sun.security.provider.certpath.SunCertPathBuilder.engineBuild(SunCertPathBuilder.java:126) ~[na:na]
at java.base/java.security.cert.CertPathBuilder.build(CertPathBuilder.java:297) ~[na:na]
at java.base/sun.security.validator.PKIXValidator.doBuild(PKIXValidator.java:380) ~[na:na]
... 36 common frames omitted
为了测试,我还使用了 SslContextBuilder 的选项来使用 TrustManagerFactory
而不是直接使用证书:
TrustManagerFactory factory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
factory.init(certificateService.getKeyStore());
SslContext context = SslContextBuilder.forClient().trustManager(factory).build();
然而,这给出了同样的问题。
有趣的是,这个物联网设备还有一个使用相同证书的网络界面。当我使用相同的 TrustManagerFactory
打开此 URL 时,这没有问题:
SSLContext sc = SSLContext.getInstance("TLSv1.2");
sc.init(null, factory.getTrustManagers(), new SecureRandom());
HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
URL url = new URL("https://10.65.101.155");
HttpsURLConnection urlConnection = (HttpsURLConnection)url.openConnection();
使用urlConnection
我可以打印网页内容和查看证书信息
我已经 运行 和 -Djava.security.debug=all
了,但恐怕我不太明白那似乎是很多信息。
为什么它通过 URL
工作,而不是通过使用相同 TrustManagerFactory
的 Netty 工作?我可以在 Netty 方面做些什么来进一步调试它吗?是否可以选择打印 Netty 从服务器收到的证书?
终于知道哪里出了问题。 IoT 设备使用 nginx for the certificate of the web interface, but stunnel 作为 Netty 用于通信的证书。
我设法使用 openssl
CLI 看到了这个:
openssl s_client -showcerts -connect 10.65.101.155:6000
此命令的响应没有显示正确的证书链,而使用端口 443
而不是 6000
执行相同的命令确实显示了良好的信任链。
似乎 stunnel
要求 .pem
文件在 1 个文件中包含 "root" 和 "end-entity" 证书 .pem
文件的串联(感谢 https://serverfault.com/a/254804/209813)。
这样换了IoT设备后,现在Netty通讯也可以了
我正在使用 Netty 4.1.25。我在我的代码中从 pem
文件创建了一个 X509Certificate
。使用该证书,我像这样设置 SslHandler:
SslContext context = SslContextBuilder.forClient().trustManager( certificate ).build();
pipeline.addLast( "ssl", context.newHandler( socketChannel.alloc() ) );
当证书与服务器上的证书完全相同时(服务器是物联网设备,但可能无关紧要),这可以正常工作。
但是,当我创建自己的根证书并且:
- 服务器有一个信任根证书的证书
- Netty 应用程序使用根证书
然后我得到这个异常:
io.netty.handler.codec.DecoderException: javax.net.ssl.SSLHandshakeException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
at io.netty.handler.codec.ByteToMessageDecoder.callDecode(ByteToMessageDecoder.java:459) ~[netty-all-4.1.25.Final.jar:4.1.25.Final]
at io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:265) ~[netty-all-4.1.25.Final.jar:4.1.25.Final]
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:362) ~[netty-all-4.1.25.Final.jar:4.1.25.Final]
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:348) ~[netty-all-4.1.25.Final.jar:4.1.25.Final]
at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:340) ~[netty-all-4.1.25.Final.jar:4.1.25.Final]
at io.netty.channel.DefaultChannelPipeline$HeadContext.channelRead(DefaultChannelPipeline.java:1434) ~[netty-all-4.1.25.Final.jar:4.1.25.Final]
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:362) ~[netty-all-4.1.25.Final.jar:4.1.25.Final]
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:348) ~[netty-all-4.1.25.Final.jar:4.1.25.Final]
at io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:965) ~[netty-all-4.1.25.Final.jar:4.1.25.Final]
at io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:163) ~[netty-all-4.1.25.Final.jar:4.1.25.Final]
at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:647) ~[netty-all-4.1.25.Final.jar:4.1.25.Final]
at io.netty.channel.nio.NioEventLoop.processSelectedKeysPlain(NioEventLoop.java:547) ~[netty-all-4.1.25.Final.jar:4.1.25.Final]
at io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:501) ~[netty-all-4.1.25.Final.jar:4.1.25.Final]
at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:461) ~[netty-all-4.1.25.Final.jar:4.1.25.Final]
at io.netty.util.concurrent.SingleThreadEventExecutor.run(SingleThreadEventExecutor.java:884) ~[netty-all-4.1.25.Final.jar:4.1.25.Final]
at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30) ~[netty-all-4.1.25.Final.jar:4.1.25.Final]
at java.base/java.lang.Thread.run(Thread.java:834) ~[na:na]
Caused by: javax.net.ssl.SSLHandshakeException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
at java.base/sun.security.ssl.Alert.createSSLException(Alert.java:128) ~[na:na]
at java.base/sun.security.ssl.TransportContext.fatal(TransportContext.java:321) ~[na:na]
at java.base/sun.security.ssl.TransportContext.fatal(TransportContext.java:264) ~[na:na]
at java.base/sun.security.ssl.TransportContext.fatal(TransportContext.java:259) ~[na:na]
at java.base/sun.security.ssl.CertificateMessage$T12CertificateConsumer.checkServerCerts(CertificateMessage.java:642) ~[na:na]
at java.base/sun.security.ssl.CertificateMessage$T12CertificateConsumer.onCertificate(CertificateMessage.java:461) ~[na:na]
at java.base/sun.security.ssl.CertificateMessage$T12CertificateConsumer.consume(CertificateMessage.java:361) ~[na:na]
at java.base/sun.security.ssl.SSLHandshake.consume(SSLHandshake.java:392) ~[na:na]
at java.base/sun.security.ssl.HandshakeContext.dispatch(HandshakeContext.java:444) ~[na:na]
at java.base/sun.security.ssl.SSLEngineImpl$DelegatedTask$DelegatedAction.run(SSLEngineImpl.java:1065) ~[na:na]
at java.base/sun.security.ssl.SSLEngineImpl$DelegatedTask$DelegatedAction.run(SSLEngineImpl.java:1052) ~[na:na]
at java.base/java.security.AccessController.doPrivileged(Native Method) ~[na:na]
at java.base/sun.security.ssl.SSLEngineImpl$DelegatedTask.run(SSLEngineImpl.java:999) ~[na:na]
at io.netty.handler.ssl.SslHandler.runDelegatedTasks(SslHandler.java:1435) ~[netty-all-4.1.25.Final.jar:4.1.25.Final]
at io.netty.handler.ssl.SslHandler.unwrap(SslHandler.java:1343) ~[netty-all-4.1.25.Final.jar:4.1.25.Final]
at io.netty.handler.ssl.SslHandler.decodeJdkCompatible(SslHandler.java:1177) ~[netty-all-4.1.25.Final.jar:4.1.25.Final]
at io.netty.handler.ssl.SslHandler.decode(SslHandler.java:1221) ~[netty-all-4.1.25.Final.jar:4.1.25.Final]
at io.netty.handler.codec.ByteToMessageDecoder.decodeRemovalReentryProtection(ByteToMessageDecoder.java:489) ~[netty-all-4.1.25.Final.jar:4.1.25.Final]
at io.netty.handler.codec.ByteToMessageDecoder.callDecode(ByteToMessageDecoder.java:428) ~[netty-all-4.1.25.Final.jar:4.1.25.Final]
... 16 common frames omitted
Caused by: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
at java.base/sun.security.validator.PKIXValidator.doBuild(PKIXValidator.java:385) ~[na:na]
at java.base/sun.security.validator.PKIXValidator.engineValidate(PKIXValidator.java:290) ~[na:na]
at java.base/sun.security.validator.Validator.validate(Validator.java:264) ~[na:na]
at java.base/sun.security.ssl.X509TrustManagerImpl.validate(X509TrustManagerImpl.java:321) ~[na:na]
at java.base/sun.security.ssl.X509TrustManagerImpl.checkTrusted(X509TrustManagerImpl.java:279) ~[na:na]
at java.base/sun.security.ssl.X509TrustManagerImpl.checkServerTrusted(X509TrustManagerImpl.java:141) ~[na:na]
at java.base/sun.security.ssl.CertificateMessage$T12CertificateConsumer.checkServerCerts(CertificateMessage.java:620) ~[na:na]
... 30 common frames omitted
Caused by: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
at java.base/sun.security.provider.certpath.SunCertPathBuilder.build(SunCertPathBuilder.java:141) ~[na:na]
at java.base/sun.security.provider.certpath.SunCertPathBuilder.engineBuild(SunCertPathBuilder.java:126) ~[na:na]
at java.base/java.security.cert.CertPathBuilder.build(CertPathBuilder.java:297) ~[na:na]
at java.base/sun.security.validator.PKIXValidator.doBuild(PKIXValidator.java:380) ~[na:na]
... 36 common frames omitted
为了测试,我还使用了 SslContextBuilder 的选项来使用 TrustManagerFactory
而不是直接使用证书:
TrustManagerFactory factory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
factory.init(certificateService.getKeyStore());
SslContext context = SslContextBuilder.forClient().trustManager(factory).build();
然而,这给出了同样的问题。
有趣的是,这个物联网设备还有一个使用相同证书的网络界面。当我使用相同的 TrustManagerFactory
打开此 URL 时,这没有问题:
SSLContext sc = SSLContext.getInstance("TLSv1.2");
sc.init(null, factory.getTrustManagers(), new SecureRandom());
HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
URL url = new URL("https://10.65.101.155");
HttpsURLConnection urlConnection = (HttpsURLConnection)url.openConnection();
使用urlConnection
我可以打印网页内容和查看证书信息
我已经 运行 和 -Djava.security.debug=all
了,但恐怕我不太明白那似乎是很多信息。
为什么它通过 URL
工作,而不是通过使用相同 TrustManagerFactory
的 Netty 工作?我可以在 Netty 方面做些什么来进一步调试它吗?是否可以选择打印 Netty 从服务器收到的证书?
终于知道哪里出了问题。 IoT 设备使用 nginx for the certificate of the web interface, but stunnel 作为 Netty 用于通信的证书。
我设法使用 openssl
CLI 看到了这个:
openssl s_client -showcerts -connect 10.65.101.155:6000
此命令的响应没有显示正确的证书链,而使用端口 443
而不是 6000
执行相同的命令确实显示了良好的信任链。
似乎 stunnel
要求 .pem
文件在 1 个文件中包含 "root" 和 "end-entity" 证书 .pem
文件的串联(感谢 https://serverfault.com/a/254804/209813)。
这样换了IoT设备后,现在Netty通讯也可以了