Netty 4.0.27 HTTP over SSL(如安全聊天示例中)因多个客户端而失败

时间:2015-04-15 19:19:49

标签: java ssl https netty

我正在关注安全聊天示例以实现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

1 个答案:

答案 0 :(得分:3)

您必须为每个SSLEngine创建一个新的SslHandler。不是将SSLEngine传递给ServerInitializer,而是通过SslContext并在SslHandler中通过SslContext.newHandler()创建新的ServerInitializer.initChannel()。有关更多信息,请查看SecureChat示例:

https://github.com/netty/netty/blob/4.0/example/src/main/java/io/netty/example/securechat/SecureChatServerInitializer.java