Netty SSL: пример клиента чата с настраиваемым хранилищем ключей не может принимать несколько соединенийJAVA

Программисты JAVA общаются здесь
Ответить Пред. темаСлед. тема
Anonymous
 Netty SSL: пример клиента чата с настраиваемым хранилищем ключей не может принимать несколько соединений

Сообщение Anonymous »


Я поигрался с примерами Netty (версия 4.0.24) SecureChatServer и подключил свое собственное хранилище ключей (на основе ответов, найденных в следующих двух сообщениях: post 1 и post2. См. фрагменты кода ниже.

Проблема, которую я вижу, заключается в том, что все работает так, как ожидалось, когда я запускаю один экземпляр клиента, но когда я пытаюсь запустить больше экземпляров клиента, я получаю исключения как на сервере, так и на клиенте (текст исключения см. ниже) и в этот момент сервер перестает отвечать.

Я надеюсь, что кто-нибудь здесь сможет пролить свет на то, что я делаю неправильно.

Это класс, который обрабатывает загрузку моего хранилища ключей и создание экземпляров SSLContext, используемых как клиентом, так и сервером (по очевидным причинам я опустил значения своего хранилища ключей):

пакет com.test.securechat; импортировать java.io.ByteArrayInputStream; импортировать java.security.KeyStore; импортировать javax.net.ssl.KeyManagerFactory; импортировать javax.net.ssl.SSLContext; импортировать javax.net.ssl.TrustManagerFactory; импортировать com.test.util.Key; импортировать com.pragmafs.util.encryption.Base64Coder; /** * Создает экземпляры SSLContext из статического хранилища ключей (строковое представление). * См. http://maxrohde.com/2013/09/07/setting- ... ith-netty/. */ общественный класс SslContextFactory { частная статическая окончательная строка ПРОТОКОЛ = "TLS"; частный статический окончательный SSLContext SERVER_CONTEXT; частный статический окончательный SSLContext CLIENT_CONTEXT; частный статический окончательный TrustManagerFactorytrustManagerFactory; статический { SSLContext serverContext = null; SSLContext clientContext = null; пытаться { KeyStore ks = KeyStore.getInstance("JKS"); ks.load(new ByteArrayInputStream(Base64Coder.decode(Key.SSL.getKey())), Base64Coder.decodeString(Key.SSL.getPwd()).toCharArray()); // Настраиваем фабрику менеджера ключей для использования нашего хранилища ключей KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm()); kmf.init(ks, Base64Coder.decodeString(Key.SSL.getPwd()).toCharArray()); // хранилище доверенных сертификатов KeyStore ts = KeyStore.getInstance("JKS"); ts.load(new ByteArrayInputStream(Base64Coder.decode(Key.SSL.getKey())), Base64Coder.decodeString(Key.SSL.getPwd()).toCharArray()); // настраиваем фабрику доверительных менеджеров для использования нашего хранилища доверенных сертификатов TrustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); TrustManagerFactory.init(ts); // Инициализируем SSLContext для работы с нашими менеджерами ключей. serverContext = SSLContext.getInstance(ПРОТОКОЛ); serverContext.init(kmf.getKeyManagers(),trustManagerFactory.getTrustManagers(), null); clientContext = SSLContext.getInstance(ПРОТОКОЛ); clientContext.init(null,trustManagerFactory.getTrustManagers(), null); } catch (Исключение е) { throw new Error("Не удалось инициализировать SSLContext", e); } SERVER_CONTEXT = Контекст сервера; CLIENT_CONTEXT = clientContext; } публичный статический SSLContext getServerContext() { вернуть SERVER_CONTEXT; } публичный статический SSLContext getClientContext() { вернуть CLIENT_CONTEXT; } public static TrustManagerFactory getTrustManagerFactory() { вернуть довериеManagerFactory; } частный SslContextFactory() { // Не используется } } Это код сервера:

пакет com.test.securechat; импортировать java.net.InetAddress; импортировать javax.net.ssl.SSLEngine; импортировать io.netty.bootstrap.ServerBootstrap; импортировать io.netty.channel.Channel; импортировать io.netty.channel.ChannelHandlerContext; импортировать io.netty.channel.ChannelInitializer; импортировать io.netty.channel.ChannelPipeline; импортировать io.netty.channel.EventLoopGroup; импортировать io.netty.channel.SimpleChannelInboundHandler; импортировать io.netty.channel.group.ChannelGroup; импортировать io.netty.channel.group.DefaultChannelGroup; импортировать io.netty.channel.nio.NioEventLoopGroup; импортировать io.netty.channel.socket.SocketChannel; импортировать io.netty.channel.socket.nio.NioServerSocketChannel; импортировать io.netty.handler.codec.DelimiterBasedFrameDecoder; импортировать io.netty.handler.codec.Delimiters; импортировать io.netty.handler.codec.string.StringDecoder; импортировать io.netty.handler.codec.string.StringEncoder; импортировать io.netty.handler.logging.LogLevel; импортировать io.netty.handler.logging.LoggingHandler; импортировать io.netty.handler.ssl.SslHandler; импортировать io.netty.util.concurrent.Future; импортировать io.netty.util.concurrent.GenericFutureListener; импортировать io.netty.util.concurrent.GlobalEventExecutor; /** * Простой SSL-сервер чата */ публичный финальный класс SecureChatServer { static Final int PORT = Integer.parseInt(System.getProperty("port", "8992")); public static void main(String[] args) выдает исключение { SSLEngine sslEngine = SslContextFactory.getServerContext().createSSLEngine(); sslEngine.setUseClientMode (ложь); EventLoopGroup BossGroup = новый NioEventLoopGroup (1); EventLoopGroup workerGroup = новый NioEventLoopGroup(); пытаться { ServerBootstrap b = новый ServerBootstrap(); b.group(bossGroup, рабочая группа) .channel(NioServerSocketChannel.class) .handler(новый LoggingHandler(LogLevel.INFO)) .childHandler(новый SecureChatServerInitializer(sslEngine)); b.bind(PORT).sync().channel().closeFuture().sync(); } окончательно { BossGroup.shutdownИзящно(); workerGroup.shutdownGraceful(); } } частный статический класс SecureChatServerInitializer расширяет ChannelInitializer { частный окончательный SSLEngine sslCtx; общественный SecureChatServerInitializer (SSLEngine sslCtx) { this.sslCtx = sslCtx; } @Override public void initChannel(SocketChannel ch) выдает исключение { Конвейер ChannelPipeline = ch.pipeline(); конвейер.addLast(новый SslHandler(sslCtx)); конвейер.addLast(новый DelimiterBasedFrameDecoder(8192, Delimiters.lineDelimiter())); конвейер.addLast(новый StringDecoder()); конвейер.addLast(новый StringEncoder()); // а затем бизнес-логика. конвейер.addLast(новый SecureChatServerHandler()); } } частный статический класс SecureChatServerHandler расширяет SimpleChannelInboundHandler { статические конечные каналы ChannelGroup = новая DefaultChannelGroup(GlobalEventExecutor.INSTANCE); @Override public voidchannelActive(final ChannelHandlerContext ctx) { // Как только сеанс будет защищен, отправьте приветствие и зарегистрируйте канал в глобальном канале // список, чтобы канал получал сообщения от других. ctx.pipeline().get(SslHandler.class).handshakeFuture().addListener( новый GenericFutureListener() { @Override public void OperationComplete(Future будущее) выдает исключение { ctx.writeAndFlush( "Добро пожаловать в службу безопасного чата " + InetAddress.getLocalHost().getHostName() + "!\n"); ctx.writeAndFlush( "Ваша сессия защищена" + ctx.pipeline().get(SslHandler.class).engine().getSession().getCipherSuite() + "набор шифров.\n"); каналы.add(ctx.channel()); } }); } @Override public void ChannelRead0 (ChannelHandlerContext ctx, String msg) выдает исключение { // Отправляем полученное сообщение во все каналы, кроме текущего. for (Канал c: каналы) { if (c != ctx.channel()) { c.writeAndFlush("[" + ctx.channel().remoteAddress() + "] " + msg + '\n'); } еще { c.writeAndFlush("[you] " + msg + '\n'); } } // Закрываем соединение, если клиент отправил «пока». if ("пока".equals(msg.toLowerCase())) { ctx.закрыть(); } } @Override public voidExceptionCaught(ChannelHandlerContext ctx, Throwable Cause) { причина.printStackTrace(); ctx.закрыть(); } } } Код клиента:

пакет com.test.securechat; импортировать java.io.BufferedReader; импортировать java.io.InputStreamReader; импортировать javax.net.ssl.SSLEngine; импортировать io.netty.bootstrap.Bootstrap; импортировать io.netty.channel.Channel; импортировать io.netty.channel.ChannelFuture; импортировать io.netty.channel.ChannelHandlerContext; импортировать io.netty.channel.ChannelInitializer; импортировать io.netty.channel.ChannelPipeline; импортировать io.netty.channel.EventLoopGroup; импортировать io.netty.channel.SimpleChannelInboundHandler; импортировать io.netty.channel.nio.NioEventLoopGroup; импортировать io.netty.channel.socket.SocketChannel; импортировать io.netty.channel.socket.nio.NioSocketChannel; импортировать io.netty.handler.codec.DelimiterBasedFrameDecoder; импортировать io.netty.handler.codec.Delimiters; импортировать io.netty.handler.codec.string.StringDecoder; импортировать io.netty.handler.codec.string.StringEncoder; импортировать io.netty.handler.ssl.SslHandler; /** * Простой SSL-клиент чата */ публичный финальный класс SecureChatClient { статическая финальная строка HOST = System.getProperty("хост", "127.0.0.1"); static Final int PORT = Integer.parseInt(System.getProperty("port", "8992")); public static void main(String[] args) выдает исключение { Механизм SSLEngine = SslContextFactory.getClientContext().createSSLEngine(); engine.setUseClientMode(истина); Группа EventLoopGroup = новая NioEventLoopGroup(); пытаться { Bootstrap b = новый Bootstrap(); б.группа(группа) .channel(NioSocketChannel.класс) .handler(новый SecureChatClientInitializer(движок)); // Начинаем попытку подключения. Канал ch = b.connect(HOST, PORT).sync().channel(); // Чтение команд из стандартного ввода. ChannelFuture LastWriteFuture = null; BufferedReader in = новый BufferedReader (новый InputStreamReader (System.in)); для (; ; ) { Строковая строка = in.readLine(); если (строка == ноль) { перерыв; } // Отправляет полученную строку на сервер. LastWriteFuture = ch.writeAndFlush(line + "\r\n"); // Если пользователь ввел команду «пока», подождем, пока сервер закроется // связь. if ("пока".equals(line.toLowerCase())) { ch.closeFuture().sync(); перерыв; } } // Подождите, пока все сообщения не будут удалены, прежде чем закрывать канал. если (lastWriteFuture != ноль) { LastWriteFuture.sync(); } } окончательно { // Соединение закрывается автоматически при завершении работы. group.shutdownGraceful(); } } частный статический класс SecureChatClientInitializer расширяет ChannelInitializer { частный окончательный SSLEngine sslCtx; public SecureChatClientInitializer (SSLEngine sslCtx) { this.sslCtx = sslCtx; } @Override public void initChannel(SocketChannel ch) выдает исключение { Конвейер ChannelPipeline = ch.pipeline(); // Сначала добавьте обработчик SSL, чтобы все зашифровать и расшифровать. // В этом примере мы используем поддельный сертификат на стороне сервера // и принять все недействительные сертификаты на стороне клиента. // Вам понадобится что-то более сложное, чтобы идентифицировать оба // и сервер в реальном мире. //pipeline.addLast(sslCtx.newHandler(ch.alloc(), SecureChatClient.HOST, SecureChatClient.PORT)); конвейер.addLast(новый SslHandler(sslCtx)); // Поверх обработчика SSL добавьте кодек текстовой строки. конвейер.addLast(новый DelimiterBasedFrameDecoder(8192, Delimiters.lineDelimiter())); конвейер.addLast(новый StringDecoder()); конвейер.addLast(новый StringEncoder()); //pipeline.addLast(new LoggingHandler(LogLevel.INFO)); // а затем бизнес-логика. конвейер.addLast(новый SecureChatClientHandler()); } } частный статический класс SecureChatClientHandler расширяет SimpleChannelInboundHandler { @Override public void ChannelRead0 (ChannelHandlerContext ctx, String msg) выдает исключение { System.err.println(msg); } @Override public voidExceptionCaught(ChannelHandlerContext ctx, Throwable Cause) { причина.printStackTrace(); ctx.закрыть(); } } } Исключение сервера:

ИНФОРМАЦИЯ: [id: 0x5eb2ac7a, /0:0:0:0:0:0:0:0:8992] ПОЛУЧЕНО: [id: 0x7d7a7dca, /127.0.0.1:55932 => /127.0. 0,1:8992] io.netty.handler.codec.DecoderException: javax.net.ssl.SSLHandshakeException: проверка работоспособности зашифрованного текста не удалась в io.netty.handler.codec.ByteToMessageDecoder.callDecode(ByteToMessageDecoder.java:278) в io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:147) в io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:333) в io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:319) в io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:787) в io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:130) в io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:511) в io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:468) в io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:382) в io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:354) в io.netty.util.concurrent.SingleThreadEventExecutor$2.run(SingleThreadEventExecutor.java:116) в io.netty.util.concurrent.DefaultThreadFactory$DefaultRunnableDecorator.run(DefaultThreadFactory.java:137) в java.lang.Thread.run(Thread.java:744) Вызвано: javax.net.ssl.SSLHandshakeException: проверка работоспособности зашифрованного текста не удалась. в sun.security.ssl.Alerts.getSSLException(Alerts.java:192) в sun.security.ssl.SSLEngineImpl.fatal(SSLEngineImpl.java:1683) в sun.security.ssl.SSLEngineImpl.readRecord(SSLEngineImpl.java:959) в sun.security.ssl.SSLEngineImpl.readNetRecord(SSLEngineImpl.java:884) в sun.security.ssl.SSLEngineImpl.unwrap(SSLEngineImpl.java:758) в javax.net.ssl.SSLEngine.unwrap(SSLEngine.java:624) в io.netty.handler.ssl.SslHandler.unwrap(SslHandler.java:995) в io.netty.handler.ssl.SslHandler.unwrap(SslHandler.java:921) в io.netty.handler.ssl.SslHandler.decode(SslHandler.java:867) в io.netty.handler.codec.ByteToMessageDecoder.callDecode(ByteToMessageDecoder.java:247) ... еще 12 Вызвано: javax.crypto.BadPaddingException: проверка работоспособности зашифрованного текста не удалась. в sun.security.ssl.InputRecord.decrypt(InputRecord.java:147) в sun.security.ssl.EngineInputRecord.decrypt(EngineInputRecord.java:192) в sun.security.ssl.SSLEngineImpl.readRecord(SSLEngineImpl.java:953) ... еще 19 Исключение клиента:
io.netty.handler.codec.DecoderException: javax.net.ssl.SSLException: получено фатальное предупреждение: в io.netty.handler.codec.ByteToMessageDecoder.callDecode(ByteToMessageDecoder.java:278) в io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:147) в io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:333) в io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:319) в io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:787) в io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:130) в io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:511) в io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:468) в io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:382) в io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:354) в io.netty.util.concurrent.SingleThreadEventExecutor$2.run(SingleThreadEventExecutor.java:116) в io.netty.util.concurrent.DefaultThreadFactory$DefaultRunnableDecorator.run(DefaultThreadFactory.java:137) в java.lang.Thread.run(Thread.java:744) Вызвано: javax.net.ssl.SSLException: получено фатальное предупреждение: в sun.security.ssl.Alerts.getSSLException(Alerts.java:208) в sun.security.ssl.SSLEngineImpl.fatal(SSLEngineImpl.java:1619) в sun.security.ssl.SSLEngineImpl.fatal(SSLEngineImpl.java:1587) в sun.security.ssl.SSLEngineImpl.recvAlert(SSLEngineImpl.java:1756) в sun.security.ssl.SSLEngineImpl.readRecord(SSLEngineImpl.java:1060) в sun.security.ssl.SSLEngineImpl.readNetRecord(SSLEngineImpl.java:884) в sun.security.ssl.SSLEngineImpl.unwrap(SSLEngineImpl.java:758) в javax.net.ssl.SSLEngine.unwrap(SSLEngine.java:624) в io.netty.handler.ssl.SslHandler.unwrap(SslHandler.java:995) в io.netty.handler.ssl.SslHandler.unwrap(SslHandler.java:921) в io.netty.handler.ssl.SslHandler.decode(SslHandler.java:867) в io.netty.handler.codec.ByteToMessageDecoder.callDecode(ByteToMessageDecoder.java:247) ... еще 12
Реклама
Ответить Пред. темаСлед. тема

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

  • Похожие темы
    Ответы
    Просмотры
    Последнее сообщение

Вернуться в «JAVA»