我正在关注安全聊天示例以实现HTTPS服务器。对于单个客户端,这工作正常。有多个客户端我得到netty服务器端异常[1]。我使用SOAP UI和Jmeter作为我的两个客户端。这适用于SOAPUI或JMeter。
我的服务器代码如下。
SSLEngine engine = SSLContextFactory.getServerContext().createSSLEngine();
engine.setUseClientMode(false);
EventLoopGroup bossGroup = new NioEventLoopGroup(1);
EventLoopGroup workerGroup = new NioEventLoopGroup();
try {
ServerBootstrap bootstrap = new ServerBootstrap();
bootstrap.group(bossGroup, workerGroup)
.channel(NioServerSocketChannel.class)
.option(ChannelOption.SO_BACKLOG, 200)
.childOption(ChannelOption.ALLOCATOR,
PooledByteBufAllocator.DEFAULT)
.childHandler(new ServerInitializer(engine));
ChannelFuture future = bootstrap.bind(8002).sync();
future.addListener(new ChannelFutureListener() {
@Override
public void operationComplete(ChannelFuture future) {
System.out.println("#### Bootstrap Bind Future #####");
}
});
ChannelFuture closef = future.channel().closeFuture();
closef.addListener(new ChannelFutureListener() {
@Override
public void operationComplete(ChannelFuture future) {
System.out.println("#### Channel Close Future #####");
}
});
closef.sync();
} catch (Exception e) {
e.printStackTrace();
} finally {
bossGroup.shutdownGracefully();
workerGroup.shutdownGracefully();
try {
bossGroup.terminationFuture().sync();
workerGroup.terminationFuture().sync();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
服务器初始化程序类
public class ServerInitializer extends ChannelInitializer<SocketChannel> {
private SSLEngine sslEngine;
public ServerInitializer(SSLEngine sslEngine) {
this.sslEngine = sslEngine;
}
@Override
public void initChannel(SocketChannel ch) throws Exception {
ChannelPipeline pipeline = ch.pipeline();
pipeline.addLast(new SslHandler(sslEngine));
pipeline.addLast("decoder", new HttpRequestDecoder());
pipeline.addLast("aggregator", new HttpObjectAggregator(Integer.MAX_VALUE));
pipeline.addLast("encoder", new HttpResponseEncoder());
pipeline.addLast(new StreamHttpServerHandler());
}
}
我的SSLCOntext类
public class SSLContextFactory {
private static final String PROTOCOL = "TLS";
private static final String KEY_TYPE = "JKS";
private static final SSLContext SERVER_CONTEXT;
private static final SSLContext CLIENT_CONTEXT;
private static final TrustManagerFactory trustManagerFactory;
static {
SSLContext serverContext = null;
SSLContext clientContext = null;
try {
KeyStore ks = KeyStore.getInstance(KEY_TYPE);
ks.load(new ByteArrayInputStream(Base64.decodeBase64(SSLKey.getKey())), new String(Base64.decodeBase64(SSLKey.getKeyPass())).toCharArray());
KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
kmf.init(ks, new String(Base64.decodeBase64(SSLKey.getKeyPass())).toCharArray());
KeyStore ts = KeyStore.getInstance(KEY_TYPE);
ts.load(new ByteArrayInputStream(Base64.decodeBase64(SSLKey.getKey())), new String(Base64.decodeBase64(SSLKey.getKeyPass())).toCharArray());
trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
trustManagerFactory.init(ts);
serverContext = SSLContext.getInstance(PROTOCOL); serverContext.init(kmf.getKeyManagers(),trustManagerFactory.getTrustManagers(), null);
clientContext = SSLContext.getInstance(PROTOCOL);
clientContext.init(null, trustManagerFactory.getTrustManagers(), null);
} catch (Exception e) {
throw new Error("Failed to initialize the Netty SSLContext", e);
}
SERVER_CONTEXT = serverContext;
CLIENT_CONTEXT = clientContext;
}
public static SSLContext getServerContext() {
return SERVER_CONTEXT;
}
public static SSLContext getClientContext() {
return CLIENT_CONTEXT;
}
public static TrustManagerFactory getTrustManagerFactory() {
return trustManagerFactory;
}
private SSLContextFactory() {
}
[1]
io.netty.handler.codec.DecoderException: javax.net.ssl.SSLHandshakeException: ciphertext sanity check failed
at io.netty.handler.codec.ByteToMessageDecoder.callDecode(ByteToMessageDecoder.java:346)
at io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:229)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:339)
at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:324)
at io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:847)
at io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:131)
at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:511)
at io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:468)
at io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:382)
at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:354)
at io.netty.util.concurrent.SingleThreadEventExecutor$2.run(SingleThreadEventExecutor.java:111)
at io.netty.util.concurrent.DefaultThreadFactory$DefaultRunnableDecorator.run(DefaultThreadFactory.java:137)
at java.lang.Thread.run(Thread.java:745)
Caused by: javax.net.ssl.SSLHandshakeException: ciphertext sanity check failed
at sun.security.ssl.Alerts.getSSLException(Alerts.java:192)
at sun.security.ssl.SSLEngineImpl.fatal(SSLEngineImpl.java:1683)
at sun.security.ssl.SSLEngineImpl.readRecord(SSLEngineImpl.java:959)
at sun.security.ssl.SSLEngineImpl.readNetRecord(SSLEngineImpl.java:884)
at sun.security.ssl.SSLEngineImpl.unwrap(SSLEngineImpl.java:758)
at javax.net.ssl.SSLEngine.unwrap(SSLEngine.java:624)
at io.netty.handler.ssl.SslHandler.unwrap(SslHandler.java:1114)
at io.netty.handler.ssl.SslHandler.unwrap(SslHandler.java:981)
at io.netty.handler.ssl.SslHandler.decode(SslHandler.java:934)
at io.netty.handler.codec.ByteToMessageDecoder.callDecode(ByteToMessageDecoder.java:315)
... 12 more
Caused by: javax.crypto.BadPaddingException: ciphertext sanity check failed
at sun.security.ssl.InputRecord.decrypt(InputRecord.java:147)
at sun.security.ssl.EngineInputRecord.decrypt(EngineInputRecord.java:192)
at sun.security.ssl.SSLEngineImpl.readRecord(SSLEngineImpl.java:953)
... 19 more
答案 0 :(得分:3)
您必须为每个SSLEngine
创建一个新的SslHandler
。不是将SSLEngine
传递给ServerInitializer
,而是通过SslContext
并在SslHandler
中通过SslContext.newHandler()
创建新的ServerInitializer.initChannel()
。有关更多信息,请查看SecureChat示例: