Netty SslHandler не работает для собственного корневого сертификата - PullRequest
0 голосов
/ 18 декабря 2018

Я использую 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 также имеет веб-интерфейс, который использует тот же сертификат.Когда я открываю этот URL, используя тот же TrustManagerFactory, это работает без проблем:

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, но не через Netty, использующий то же самое?TrustManagerFactory?Могу ли я что-нибудь сделать на стороне Netty для дальнейшей отладки этого?Есть ли возможность распечатать сертификат, который Netty получает от сервера?

1 Ответ

0 голосов
/ 03 января 2019

Наконец-то разобрался, что было не так.Устройство IoT использует nginx для сертификата веб-интерфейса, но stunnel для сертификата, который Netty использует для связи.

Мне удалось увидеть это с помощью openssl CLI:

openssl s_client -showcerts -connect 10.65.101.155:6000

В ответе этой команды не показана правильная цепочка сертификатов, хотя при выполнении этой же команды с портом 443 вместо 6000 была показана хорошая цепочка доверия.

Похоже, что stunnel требует, чтобы файл .pem содержал объединение файлов "root" и "end-entity" .pem в одном файле (благодаря https://serverfault.com/a/254804/209813).

После такой смены устройства IoT связь с Netty теперь тоже в порядке.

...