SSL的Netty 4解码器错误

时间:2015-12-11 01:28:38

标签: java android ssl netty

我使用的是Netty 4.0.30 我在模拟器和运行Android 4.4.4的设备上测试了我的代码,但我没有看到这个问题。在这些情况下一切正常。

在运行Android 5.02的HTC One上,但每次在我的SSL连接期间都会发生这种情况。我是SSL的总菜鸟,我的代码几乎没有从netty(https://github.com/netty/netty/tree/4.0/example/src/main/java/io/netty/example/securechat)提供的SSL聊天示例中修改过。

服务器端看到" SSL通道激活"和#34; SSL操作完成称为"但不会打印任何其他错误或其他错误。客户端看到" SSL通道处于活动状态,发送是:blah"然后错误。基本上双方似乎都没有成功阅读。以下是来自客户端的堆栈跟踪:

W/System.err: io.netty.handler.codec.DecoderException: javax.net.ssl.SSLException: javax.net.ssl.SSLProtocolException: Read error: ssl=0xb8c20ae0: Failure in SSL library, usually a protocol error
W/System.err: error:1408F119:SSL routines:SSL3_GET_RECORD:decryption failed or bad record mac (external/openssl/ssl/s3_pkt.c:485 0xb150b0dd:0x00000000)
W/System.err:     at io.netty.handler.codec.ByteToMessageDecoder.callDecode(ByteToMessageDecoder.java:358)
W/System.err:     at io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:230)
W/System.err:     at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:308)
W/System.err:     at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:294)
W/System.err:     at io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:846)
W/System.err:     at io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:131)
W/System.err:     at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:511)
W/System.err:     at io.netty.channel.nio.NioEventLoop.processSelectedKeysPlain(NioEventLoop.java:430)
W/System.err:     at io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:384)
W/System.err:     at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:354)
W/System.err:     at io.netty.util.concurrent.SingleThreadEventExecutor$2.run(SingleThreadEventExecutor.java:110)
W/System.err:     at io.netty.util.concurrent.DefaultThreadFactory$DefaultRunnableDecorator.run(DefaultThreadFactory.java:137)
W/System.err:     at java.lang.Thread.run(Thread.java:818)
W/System.err: Caused by: javax.net.ssl.SSLException: javax.net.ssl.SSLProtocolException: Read error: ssl=0xb8c20ae0: Failure in SSL library, usually a protocol error
W/System.err: error:1408F119:SSL routines:SSL3_GET_RECORD:decryption failed or bad record mac (external/openssl/ssl/s3_pkt.c:485 0xb150b0dd:0x00000000)
W/System.err:     at com.android.org.conscrypt.OpenSSLEngineImpl.unwrap(OpenSSLEngineImpl.java:491)
W/System.err:     at javax.net.ssl.SSLEngine.unwrap(SSLEngine.java:1006)
W/System.err:     at io.netty.handler.ssl.SslHandler.unwrap(SslHandler.java:1129)
W/System.err:     at io.netty.handler.ssl.SslHandler.unwrap(SslHandler.java:1019)
W/System.err:     at io.netty.handler.ssl.SslHandler.decode(SslHandler.java:959)
W/System.err:     at io.netty.handler.codec.ByteToMessageDecoder.callDecode(ByteToMessageDecoder.java:327)
W/System.err:   ... 12 more
W/System.err: Caused by: javax.net.ssl.SSLProtocolException: Read error: ssl=0xb8c20ae0: Failure in SSL library, usually a protocol error
W/System.err: error:1408F119:SSL routines:SSL3_GET_RECORD:decryption failed or bad record mac (external/openssl/ssl/s3_pkt.c:485 0xb150b0dd:0x00000000)
W/System.err:     at com.android.org.conscrypt.NativeCrypto.SSL_read_BIO(Native Method)
W/System.err:     at com.android.org.conscrypt.OpenSSLEngineImpl.unwrap(OpenSSLEngineImpl.java:472)
W/System.err:   ... 17 more

以下是我的代码中的代码段,但实际上它们与客户端的示例几乎没有区别:

        // Configure SSL.
    EventLoopGroup group = new NioEventLoopGroup();
    try {
        final SslContext sslCtx = SslContextBuilder.forClient()
                .trustManager(InsecureTrustManagerFactory.INSTANCE).build();

        Bootstrap b = new Bootstrap();
        b.group(group)
                .channel(NioSocketChannel.class)
                .handler(new SSLClientInitializer(sslCtx,server,port));

        // Start the connection attempt.
        Channel ch = b.connect(server, port).sync().channel();

        // Wait until the connection is closed.
        ch.closeFuture().sync();
        System.out.println("SSL closed");

初​​始化器:

   @Override
public void initChannel(SocketChannel ch) throws Exception {
    ChannelPipeline pipeline = ch.pipeline();

    // Add SSL handler first to encrypt and decrypt everything.
    // In this example, we use a bogus certificate in the server side
    // and accept any invalid certificates in the client side.
    // You will need something more complicated to identify both
    // and server in the real world.
    pipeline.addLast(sslCtx.newHandler(ch.alloc(), server, port));

    // On top of the SSL handler, add the text line codec.
    pipeline.addLast(new DelimiterBasedFrameDecoder(8192, Delimiters.lineDelimiter()));
    pipeline.addLast(new StringDecoder());
    pipeline.addLast(new StringEncoder());

    // and then business logic.
    pipeline.addLast(new SSLClientHandler());
}

处理程序:

@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
    super.channelActive(ctx);
    String send = "blah"
    System.out.println("SSL channel active, send is:"+send);
    ctx.channel().writeAndFlush(send);
}

@Override
public void channelRead0(ChannelHandlerContext ctx, String msg) throws Exception {
    System.out.println("SSL read0:" + msg);
    ctx.close();//close this channel.

}

服务器:

EventLoopGroup bossGroup = new NioEventLoopGroup(1);
    EventLoopGroup workerGroup = new NioEventLoopGroup();
    try {
        SelfSignedCertificate ssc = new SelfSignedCertificate();//@todo need a real cert
        SslContext sslCtx = SslContextBuilder.forServer(ssc.certificate(), ssc.privateKey())
                .build();

        ServerBootstrap b = new ServerBootstrap();
        b.group(bossGroup, workerGroup)
                .channel(NioServerSocketChannel.class)
                //.handler(new LoggingHandler(LogLevel.INFO))
                .childHandler(new SSLServerInitializer(sslCtx));

        b.bind(port).sync().channel().closeFuture().sync();

初​​始化器:

@Override
public void initChannel(SocketChannel ch) throws Exception {
    ChannelPipeline pipeline = ch.pipeline();

    // Add SSL handler first to encrypt and decrypt everything.
    // In this example, we use a bogus certificate in the server side
    // and accept any invalid certificates in the client side.
    // You will need something more complicated to identify both
    // and server in the real world.
    pipeline.addLast(sslCtx.newHandler(ch.alloc()));

    // On top of the SSL handler, add the text line codec.
    pipeline.addLast(new DelimiterBasedFrameDecoder(8192, Delimiters.lineDelimiter()));
    pipeline.addLast(new StringDecoder());
    pipeline.addLast(new StringEncoder());

    // and then business logic.
    pipeline.addLast(new SSLServerHandler());
}

处理程序:

@Override
public void channelActive(final ChannelHandlerContext ctx) {
    // Once session is secured, send a greeting and register the channel to the global channel
    // list so the channel received the messages from others.
    System.out.println("SSL channel active");
    ctx.pipeline().get(SslHandler.class).handshakeFuture().addListener(
            new GenericFutureListener<Future<Channel>>() {
                @Override
                public void operationComplete(Future<Channel> future) throws Exception {
                    System.out.println("SSL Operate Complete called");
                    ctx.writeAndFlush("Your session is protected by " +
                                    ctx.pipeline().get(SslHandler.class).engine().getSession().getCipherSuite() +
                                    " cipher suite.\n");

                    channels.add(ctx.channel());
                }
            });
}

@Override
public void channelRead0(ChannelHandlerContext ctx, String msg) throws Exception {
    System.out.println("SSL read0:" + msg);
    ctx.writeAndFlush("granted\n");

    ctx.close();

}

感谢任何帮助,我看到了这一点并担心它是相关的/不是固定的:https://github.com/netty/netty/issues/4116 谢谢你的阅读!

更新 此行为在模拟器上也是一致的,连接适用于KitKat但不适用于Android&gt; 5.0。我注意到我的(连接工作)4.4.4设备仅支持TLSv1和SSLv3,其中(非工作连接)设备支持TLSv1.2,我相信使用此版本的协议

1 个答案:

答案 0 :(得分:0)

虽然不理想,但目前的解决方法是使用旧版本的Netty 4.0.25,然后填写SslContextBuilder的空白,因为它在此版本中不存在。客户端已在4.0.30中更改为:

final SslContext sslCtx = SslContextBuilder.forClient()
                .trustManager(InsecureTrustManagerFactory.INSTANCE).build();

以4.0.25开头:

final SslContext sslCtx;
        TrustManagerFactory trustManagerFactory = InsecureTrustManagerFactory.INSTANCE;
        SslProvider provider = SslContext.defaultClientProvider();
        File trustCertChainFile = null;
        File keyCertChainFile = null;
        File keyFile = null;
        String keyPassword = null;
        KeyManagerFactory keyManagerFactory = null;
        Iterable<String> ciphers = null;
        ApplicationProtocolConfig apn = null;
        switch (provider) {
            case JDK:
                sslCtx = new JdkSslClientContext(
                        trustCertChainFile, trustManagerFactory, keyCertChainFile, keyFile, keyPassword,
                        keyManagerFactory, ciphers, IdentityCipherSuiteFilter.INSTANCE, apn, 0, 0);
                break;
            case OPENSSL:
            default:
                sslCtx = new OpenSslClientContext(
                        trustCertChainFile, trustManagerFactory,
                        ciphers, apn, 0, 0);
                break;
        }

编辑#2 无视编辑#1