Netty SslHandler不适用于自己的根证书

时间:2018-12-18 11:00:47

标签: java ssl netty

我正在使用Netty 4.1.25。我在代码中从X509Certificate文件创建了pem。使用该证书,我像这样设置SslHandler:

SslContext context = SslContextBuilder.forClient().trustManager( certificate ).build();
pipeline.addLast( "ssl", context.newHandler( socketChannel.alloc() ) );

当证书是服务器上的确切证书(服务器是IoT设备,但可能没有关系)时,这可以正常工作。

但是,当我创建自己的根证书并且:

  • 服务器具有信任根证书的证书
  • 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$5.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();

但是,这也带来了同样的问题。

有趣的是,此IoT设备还具有使用相同证书的Web界面。当我使用相同的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从服务器收到的证书?

1 个答案:

答案 0 :(得分:0)

最后弄清楚出了什么问题。物联网设备将nginx用作Web界面的证书,但将stunnel用作Netty用于通信的证书。

我设法通过openssl CLI看到了这一点:

openssl s_client -showcerts -connect 10.65.101.155:6000

此命令的响应未显示正确的证书链,而使用端口443而不是6000执行同一命令确实显示了良好的信任链。

似乎stunnel要求.pem文件在一个文件中包含“根”证书和“最终实体”证书.pem文件的串联(感谢{ {3}}。

像这样更改IoT设备后,现在也可以进行Netty通信了。