• 转载 Netty tls验证


    https://blog.csdn.net/luo15242208310/article/details/108215019

    目录
    Java ssl
    单向TLS
    Server端
    Client端
    双向TLS
    server端
    client端
    KeyStore读取P12
    TODO 自定义验证规则
    Java ssl
    netty中使用SslHandler进行tls验证拦截,通过Java Ssl相关接口+jks密钥库,生成SslHandler流程如下图:

    ks.load(jksFile, storePassw)
    kmf.init(ks, keyPassw)
    tks.load(jksFile, storePassw)
    tmf.init(tks)
    sslContext.init(kmf.km, tkf.tkm)
    sslContext.init(kmf.km, tkf.tkm)
    sslContext.createSslEngine
    new SslHander(sslEngine)
    jksFile
    keyStore
    keyManagerFactory
    trustKeyStore
    trustManagerFactory
    sslContext
    sslEngine
    sslHander
    以上Jdk原生支持(支持jks密钥库)的初始化方法,比较繁琐。可以借助Apache httpcore(支持jks密钥库)、netty sslContextBuilder(支持openssl crt+key.pk8)简化构建流程。

    单向TLS
    以下示例代码均使用如下证书相关文件:

    ca根证书:
    ca.crt+ca.key -> ca.p12 -> ca.jks
    由openssl生成自签ca.crt+ca.key,然后导出ca.p12,最后由ca.p12转换成ca.jks
    服务端证书:
    emqx-dev.crt+emqx-dev.key -> emqx-dev.p12 -> emqx-dev.jks
    emqx-dev.key -> emqx-dev.pk8
    由ca根证书签署服务端证书emqx-dev.crt,然后导出emqx-dev.p12,最后由emqx-dev.p12转换成emqx-dev.jks
    客户端证书:
    emqx-dev-client.crt+emqx-dev-client.key -> emqx-dev-client.p12 -> emqx-dev-client.jks
    emqx-dev-client.key -> emqx-dev-client.pk8
    由ca根证书签署客户端证书emqx-dev-client.crt,然后导出emqx-dev-client.p12,最后由emqx-dev-client.p12转换成emqx-dev-client.jks

    注:
    关于证书的转换可参考:证书格式及其转换
    或者可使用xca等工具进行转换

    Server端
    import io.netty.bootstrap.ServerBootstrap;
    import io.netty.buffer.ByteBuf;
    import io.netty.buffer.Unpooled;
    import io.netty.channel.*;
    import io.netty.channel.nio.NioEventLoopGroup;
    import io.netty.channel.socket.SocketChannel;
    import io.netty.channel.socket.nio.NioServerSocketChannel;
    import io.netty.handler.ssl.ClientAuth;
    import io.netty.handler.ssl.SslContext;
    import io.netty.handler.ssl.SslContextBuilder;
    import org.apache.http.ssl.SSLContextBuilder;

    import javax.net.ssl.KeyManagerFactory;
    import javax.net.ssl.SSLContext;
    import javax.net.ssl.SSLEngine;
    import java.io.File;
    import java.io.FileInputStream;
    import java.security.KeyStore;

    /**
    * Netty服务器 - tls单向验证
    *
    * @author luohq
    * @date 2020/8/25
    */
    public class NettyServerWithTls {

    private int port;

    public NettyServerWithTls(int port) {
    this.port = port;
    }

    public void run() throws Exception {
    /** 证书 */
    String basePath = "D:/idea_workspace/dev-utils/src/main/resources/";
    File certFile = new File(basePath + "jks/emqx-dev.crt");
    File keyFile = new File(basePath + "jks/emqx-dev.pk8");
    File rootFile = new File(basePath + "jks/ca.crt");
    File jksFile = new File(basePath + "jks/emqx-dev.jks");
    String jksKeyPassw = "mykeypass";
    String jksStorePassw = "mystorepass";


    /** ============ TLS - 单向 ===============*/
    SSLContext sslContext = null;

    /** 方式1: Java SSL(使用jks) - keyMangerFactory */
    //keyStore(仅需设置keyManager,用于管理服务端crt+key)
    //defaultType: jks 或者系统属性: keystore.type
    KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
    ks.load(new FileInputStream(jksFile), jksStorePassw.toCharArray());
    //defaultAlgorithm: SunX509 或者系统属性: ssl.KeyManagerFactory.algorithm
    KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
    kmf.init(ks, jksKeyPassw.toCharArray());
    //生成SSLContext
    sslContext = SSLContext.getInstance("TLS");
    sslContext.init(kmf.getKeyManagers(), null, null);

    /** 方式2: httpcore SSLContentBuilder(使用jks) - keyMaterial */
    sslContext = SSLContextBuilder.create()
    //keyStore
    .loadKeyMaterial(jksFile, jksStorePassw.toCharArray(), jksKeyPassw.toCharArray())
    .build();

    //方式1,2: 生成sslEngine
    SSLEngine sslEngine = sslContext.createSSLEngine();
    //是否客户端模式 - 服务端模式
    sslEngine.setUseClientMode(false);
    //是否需要验证客户端(双向验证) - 单向验证
    sslEngine.setNeedClientAuth(false);
    //pipeline.addFirst("ssl", new SslHandler(sslEngine));


    /** 方式3: netty sslContextBuilder server端 - 单向tls(使用crt+pk8) - keyManager */
    SslContext nettySslContext = SslContextBuilder.forServer(certFile, keyFile)
    .clientAuth(ClientAuth.NONE)
    .build();
    //pipeline.addFirst("ssl", nettySslContext.newHandler(socketChannel.alloc()));


    EventLoopGroup bossGroup = new NioEventLoopGroup(); //用于处理服务器端接收客户端连接
    EventLoopGroup workerGroup = new NioEventLoopGroup(); //进行网络通信(读写)
    try {
    ServerBootstrap bootstrap = new ServerBootstrap(); //辅助工具类,用于服务器通道的一系列配置
    bootstrap.group(bossGroup, workerGroup) //绑定两个线程组
    .channel(NioServerSocketChannel.class) //指定NIO的模式
    .childHandler(new ChannelInitializer<SocketChannel>() { //配置具体的数据处理方式
    @Override
    protected void initChannel(SocketChannel socketChannel) throws Exception {
    ChannelPipeline pipeline = socketChannel.pipeline();
    /** 方式1,2: ssl handler */
    //pipeline.addFirst("ssl", new SslHandler(sslEngine));
    /** 方式3: netty sslContext */
    pipeline.addFirst("ssl", nettySslContext.newHandler(socketChannel.alloc()));
    //业务handler
    pipeline.addLast(new ServerHandler());
    }
    })
    .option(ChannelOption.SO_BACKLOG, 128) //设置TCP缓冲区
    .childOption(ChannelOption.SO_SNDBUF, 32 * 1024) //设置发送数据缓冲大小
    .childOption(ChannelOption.SO_RCVBUF, 32 * 1024) //设置接受数据缓冲大小
    .childOption(ChannelOption.SO_KEEPALIVE, true); //保持连接
    ChannelFuture future = bootstrap.bind(port).sync();
    future.channel().closeFuture().sync();
    } catch (Exception e) {
    e.printStackTrace();
    } finally {
    workerGroup.shutdownGracefully();
    bossGroup.shutdownGracefully();
    }
    }


    public class ServerHandler extends ChannelInboundHandlerAdapter {

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
    //do something msg
    ByteBuf buf = (ByteBuf) msg;
    byte[] data = new byte[buf.readableBytes()];
    buf.readBytes(data);
    String request = new String(data, "utf-8");
    System.out.println("Server Recv from Client: " + request);
    //写给客户端
    String response = "888";
    System.out.println("Server send to Client: " + response);
    ctx.writeAndFlush(Unpooled.copiedBuffer(response.getBytes()));
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
    cause.printStackTrace();
    ctx.close();
    }

    }


    public static void main(String[] args) throws Exception {
    new NettyServerWithTls(8379).run();
    }

    }

    Client端
    import io.netty.bootstrap.Bootstrap;
    import io.netty.buffer.ByteBuf;
    import io.netty.buffer.Unpooled;
    import io.netty.channel.*;
    import io.netty.channel.nio.NioEventLoopGroup;
    import io.netty.channel.socket.SocketChannel;
    import io.netty.channel.socket.nio.NioSocketChannel;
    import io.netty.handler.ssl.SslContext;
    import io.netty.handler.ssl.SslContextBuilder;
    import io.netty.util.ReferenceCountUtil;
    import org.apache.http.ssl.SSLContextBuilder;

    import javax.net.ssl.SSLContext;
    import javax.net.ssl.SSLEngine;
    import javax.net.ssl.TrustManagerFactory;
    import java.io.File;
    import java.io.FileInputStream;
    import java.security.KeyStore;

    /**
    * Netty客户端 - tls单向验证
    *
    * @author luohq
    * @date 2020/8/25
    */
    public class NettyClientWithTls {

    public static void main(String[] args) throws Exception {
    String basePath = "D:/idea_workspace/dev-utils/src/main/resources/";
    File rootFile = new File(basePath + "jks/ca.crt");
    File jksFile = new File(basePath + "jks/emqx-dev.jks");
    String jksStorePassw = "mystorepass";

    /** ============ TLS - 单向 ===============*/
    SSLContext sslContext = null;
    /** 方式1: Java SSL(使用jks) - trustManagerFactory */
    //trustKeyStore
    KeyStore tks = KeyStore.getInstance(KeyStore.getDefaultType());
    tks.load(new FileInputStream(jksFile), jksStorePassw.toCharArray());
    TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
    tmf.init(tks);
    //生成SSLContext
    sslContext = SSLContext.getInstance("TLS");
    sslContext.init(null, tmf.getTrustManagers(), null);


    /** 方式2: httpcore SSLContentBuilder(使用jks) - trustMaterial */
    sslContext = SSLContextBuilder.create()
    //trustKeyStore
    .loadTrustMaterial(jksFile, jksStorePassw.toCharArray())
    .build();

    //方式1,2: 生成sslEngine
    SSLEngine sslEngine = sslContext.createSSLEngine();
    //是否客户端模式 - 客户端模式
    sslEngine.setUseClientMode(true);
    //是否需要验证客户端(双向验证) - 单向验证
    sslEngine.setNeedClientAuth(false);
    //pipeline.addFirst("ssl", new SslHandler(sslEngine));


    /** 方式3: netty sslContextBuilder - 客户端 trustCa - 单向 (使用ca) - trustManager */
    SslContext nettySslContext = SslContextBuilder.forClient()
    //trustKeyStore(此处指定ca.crt或者server.crt均可)
    .trustManager(rootFile)
    .build();
    //pipeline.addFirst("ssl", nettySslContext.newHandler(socketChannel.alloc()));


    EventLoopGroup workerGroup = new NioEventLoopGroup();
    Bootstrap bootstrap = new Bootstrap();
    bootstrap.group(workerGroup)
    .channel(NioSocketChannel.class)
    .handler(new ChannelInitializer<SocketChannel>() {
    @Override
    protected void initChannel(SocketChannel socketChannel) throws Exception {
    ChannelPipeline pipeline = socketChannel.pipeline();
    /** 方式1,2: ssl handler(trust ca) */
    //pipeline.addFirst("ssl", new SslHandler(sslEngine));
    /** 方式3: netty sslContext */
    pipeline.addFirst("ssl", nettySslContext.newHandler(socketChannel.alloc()));
    pipeline.addLast(new ClientHandler());
    }
    });
    ChannelFuture future = bootstrap.connect("127.0.0.1", 8379).sync();
    String sendMsg = "777";
    System.out.println("Client send to Server:" + sendMsg);
    future.channel().writeAndFlush(Unpooled.copiedBuffer(sendMsg.getBytes()));
    future.channel().closeFuture().sync();
    workerGroup.shutdownGracefully();
    }


    public static class ClientHandler extends ChannelInboundHandlerAdapter {

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
    try {
    ByteBuf buf = (ByteBuf) msg;
    byte[] data = new byte[buf.readableBytes()];
    buf.readBytes(data);
    System.out.println("Client recv from Server:" + new String(data).trim());
    } finally {
    ReferenceCountUtil.release(msg);
    }
    }


    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
    cause.printStackTrace();
    ctx.close();
    }

    }
    }


    双向TLS
    server端
    import io.netty.bootstrap.ServerBootstrap;
    import io.netty.buffer.ByteBuf;
    import io.netty.buffer.Unpooled;
    import io.netty.channel.*;
    import io.netty.channel.nio.NioEventLoopGroup;
    import io.netty.channel.socket.SocketChannel;
    import io.netty.channel.socket.nio.NioServerSocketChannel;
    import io.netty.handler.ssl.ClientAuth;
    import io.netty.handler.ssl.SslContext;
    import io.netty.handler.ssl.SslContextBuilder;
    import org.apache.http.ssl.SSLContextBuilder;

    import javax.net.ssl.KeyManagerFactory;
    import javax.net.ssl.SSLContext;
    import javax.net.ssl.SSLEngine;
    import javax.net.ssl.TrustManagerFactory;
    import java.io.File;
    import java.io.FileInputStream;
    import java.security.KeyStore;

    /**
    * Netty服务器 - 双向tls验证
    *
    * @author luohq
    * @date 2020/8/25
    */
    public class NettyServerWithMtls {

    private int port;

    public NettyServerWithMtls(int port) {
    this.port = port;
    }

    public void run() throws Exception {
    /** 证书 */
    String basePath = "D:/idea_workspace/dev-utils/src/main/resources/";
    File certFile = new File(basePath + "jks/emqx-dev.crt");
    File keyFile = new File(basePath + "jks/emqx-dev.pk8");
    File rootFile = new File(basePath + "jks/ca.crt");
    File jksServerFile = new File(basePath + "jks/emqx-dev.jks");
    File jksCaFile = new File(basePath + "jks/ca.jks");
    String jksKeyPassw = "mykeypass";
    String jksStorePassw = "mystorepass";


    /** ============ TLS - 双向 ===============*/
    SSLContext sslContext = null;
    /** 方式1:Java SSL(使用jks) - server端keyManagerFactory+trustManagerFactory */
    /** keyStore */
    //defaultType: jks 或者系统属性: keystore.type"
    KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
    ks.load(new FileInputStream(jksServerFile), jksStorePassw.toCharArray());
    //defaultAlgorithm: SunX509 或者系统属性: ssl.KeyManagerFactory.algorithm
    KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
    kmf.init(ks, jksKeyPassw.toCharArray());
    /** trustKeyStore */
    KeyStore tks = KeyStore.getInstance(KeyStore.getDefaultType());
    tks.load(new FileInputStream(jksCaFile), jksStorePassw.toCharArray());
    TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
    tmf.init(tks);
    //生成SSLContext
    sslContext = SSLContext.getInstance("TLS");
    sslContext.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);


    /** 方式2: httpcore SSLContentBuilder(使用jks) - server端keyMaterial+trustMaterial */
    sslContext = SSLContextBuilder.create()
    //keyStore
    .loadKeyMaterial(jksServerFile, jksStorePassw.toCharArray(), jksKeyPassw.toCharArray())
    //trustKeyStore
    .loadTrustMaterial(jksCaFile, jksStorePassw.toCharArray())
    .build();

    //方式1,2: 生成sslEngine
    SSLEngine sslEngine = sslContext.createSSLEngine();
    //是否客户端模式 - 服务端模式
    sslEngine.setUseClientMode(false);
    //是否需要验证客户端(双向验证) - 双向验证
    sslEngine.setNeedClientAuth(true);
    //pipeline.addFirst("ssl", new SslHandler(sslEngine));

    /** 方式3: netty sslContextBuilder server端 - 双向tls(使用server端crt+pk8+ca) */
    SslContext nettySslContext = SslContextBuilder.forServer(certFile, keyFile)
    .trustManager(rootFile)
    .clientAuth(ClientAuth.REQUIRE)
    .build();


    EventLoopGroup bossGroup = new NioEventLoopGroup(); //用于处理服务器端接收客户端连接
    EventLoopGroup workerGroup = new NioEventLoopGroup(); //进行网络通信(读写)
    try {
    ServerBootstrap bootstrap = new ServerBootstrap(); //辅助工具类,用于服务器通道的一系列配置
    bootstrap.group(bossGroup, workerGroup) //绑定两个线程组
    .channel(NioServerSocketChannel.class) //指定NIO的模式
    .childHandler(new ChannelInitializer<SocketChannel>() { //配置具体的数据处理方式
    @Override
    protected void initChannel(SocketChannel socketChannel) throws Exception {
    ChannelPipeline pipeline = socketChannel.pipeline();
    /** 方式1,2: ssl handler */
    //pipeline.addFirst("ssl", new SslHandler(sslEngine));
    /** 方式3: netty sslContext */
    pipeline.addFirst("ssl", nettySslContext.newHandler(socketChannel.alloc()));
    //业务handler
    pipeline.addLast(new ServerHandler());
    }
    })
    .option(ChannelOption.SO_BACKLOG, 128) //设置TCP缓冲区
    .childOption(ChannelOption.SO_SNDBUF, 32 * 1024) //设置发送数据缓冲大小
    .childOption(ChannelOption.SO_RCVBUF, 32 * 1024) //设置接受数据缓冲大小
    .childOption(ChannelOption.SO_KEEPALIVE, true); //保持连接
    ChannelFuture future = bootstrap.bind(port).sync();
    future.channel().closeFuture().sync();
    } catch (Exception e) {
    e.printStackTrace();
    } finally {
    workerGroup.shutdownGracefully();
    bossGroup.shutdownGracefully();
    }
    }


    public class ServerHandler extends ChannelInboundHandlerAdapter {

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
    //do something msg
    ByteBuf buf = (ByteBuf) msg;
    byte[] data = new byte[buf.readableBytes()];
    buf.readBytes(data);
    String request = new String(data, "utf-8");
    System.out.println("Server Recv from Client: " + request);
    //写给客户端
    String response = "888";
    System.out.println("Server send to Client: " + response);
    ctx.writeAndFlush(Unpooled.copiedBuffer(response.getBytes()));
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
    cause.printStackTrace();
    ctx.close();
    }

    }


    public static void main(String[] args) throws Exception {
    new NettyServerWithMtls(8379).run();
    }

    }


    client端
    import io.netty.bootstrap.Bootstrap;
    import io.netty.buffer.ByteBuf;
    import io.netty.buffer.Unpooled;
    import io.netty.channel.*;
    import io.netty.channel.nio.NioEventLoopGroup;
    import io.netty.channel.socket.SocketChannel;
    import io.netty.channel.socket.nio.NioSocketChannel;
    import io.netty.handler.ssl.ClientAuth;
    import io.netty.handler.ssl.SslContext;
    import io.netty.handler.ssl.SslContextBuilder;
    import io.netty.util.ReferenceCountUtil;
    import org.apache.http.ssl.SSLContextBuilder;

    import javax.net.ssl.KeyManagerFactory;
    import javax.net.ssl.SSLContext;
    import javax.net.ssl.SSLEngine;
    import javax.net.ssl.TrustManagerFactory;
    import java.io.File;
    import java.io.FileInputStream;
    import java.security.KeyStore;

    /**
    * Netty客户端 - 双向tls验证
    *
    * @author luohq
    * @date 2020/8/25
    */
    public class NettyClientWithMtls {

    public static void main(String[] args) throws Exception {
    String basePath = "D:/idea_workspace/dev-utils/src/main/resources/";
    File certFile = new File(basePath + "jks/emqx-dev.crt");
    File keyFile = new File(basePath + "jks/emqx-dev.pk8");
    File rootFile = new File(basePath + "jks/ca.crt");
    File jksServerFile = new File(basePath + "jks/emqx-dev.jks");
    File jksCaFile = new File(basePath + "jks/ca.jks");
    File jksClientFile = new File(basePath + "jks/emqx-dev-client.jks");
    String jksKeyPassw = "mykeypass";
    String jksStorePassw = "mystorepass";

    /** ============ TLS - 双向 ===============*/
    SSLContext sslContext = null;
    /** 方式1: Java SSL(使用jks) - 客户端keyManagerFactory+服务端trustManagerFactory */
    //keyStore
    //defaultType: jks 或者系统属性: keystore.type"
    KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
    ks.load(new FileInputStream(jksClientFile), jksStorePassw.toCharArray());
    //defaultAlgorithm: SunX509 或者系统属性: ssl.KeyManagerFactory.algorithm
    KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
    kmf.init(ks, jksKeyPassw.toCharArray());
    //trustKeyStore
    KeyStore tks = KeyStore.getInstance(KeyStore.getDefaultType());
    //此处暴露server.jks 或 ca.jks均可通过验证
    tks.load(new FileInputStream(jksCaFile), jksStorePassw.toCharArray());
    //tks.load(new FileInputStream(jksServerFile), jksStorePassw.toCharArray());
    TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
    tmf.init(tks);
    //生成SSLContext
    sslContext = SSLContext.getInstance("TLS");
    sslContext.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);


    /** 方式2: httpcore SSLContentBuilder(使用jks) - 客户端keyMaterial+服务端trustMaterial */
    sslContext = SSLContextBuilder.create()
    //keyStore
    .loadKeyMaterial(jksClientFile, jksStorePassw.toCharArray(), jksKeyPassw.toCharArray())
    //trustKeyStore
    .loadTrustMaterial(jksCaFile, jksStorePassw.toCharArray())
    .build();

    //方式1,2: 生成sslEngine
    SSLEngine sslEngine = sslContext.createSSLEngine();
    //是否客户端模式 - 客户端模式
    sslEngine.setUseClientMode(true);
    //是否需要验证客户端(双向验证) - 双向验证
    sslEngine.setNeedClientAuth(true);
    //pipeline.addFirst("ssl", new SslHandler(sslEngine));


    /** 方式3: netty sslContextBuilder(使用客户端cert+key.pk8,ca) - 客户端keyManager+ca端trustManager */
    SslContext nettySslContext = SslContextBuilder.forClient()
    //客户端crt+key.pk8
    .keyManager(certFile, keyFile)
    //ca根证书
    .trustManager(rootFile)
    //双向验证
    .clientAuth(ClientAuth.REQUIRE)
    .build();
    //pipeline.addFirst("ssl", nettySslContext.newHandler(socketChannel.alloc()));


    EventLoopGroup workerGroup = new NioEventLoopGroup();
    Bootstrap bootstrap = new Bootstrap();
    bootstrap.group(workerGroup)
    .channel(NioSocketChannel.class)
    .handler(new ChannelInitializer<SocketChannel>() {
    @Override
    protected void initChannel(SocketChannel socketChannel) throws Exception {
    ChannelPipeline pipeline = socketChannel.pipeline();
    /** 方式1,2: ssl handler(trust ca) */
    //pipeline.addFirst("ssl", new SslHandler(sslEngine));
    /** 方式3: netty sslContext */
    pipeline.addFirst("ssl", nettySslContext.newHandler(socketChannel.alloc()));
    pipeline.addLast(new ClientHandler());
    }
    });
    ChannelFuture future = bootstrap.connect("127.0.0.1", 8379).sync();
    String sendMsg = "777";
    System.out.println("Client send to Server:" + sendMsg);
    future.channel().writeAndFlush(Unpooled.copiedBuffer(sendMsg.getBytes()));
    future.channel().closeFuture().sync();
    workerGroup.shutdownGracefully();
    }


    public static class ClientHandler extends ChannelInboundHandlerAdapter {

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
    try {
    ByteBuf buf = (ByteBuf) msg;
    byte[] data = new byte[buf.readableBytes()];
    buf.readBytes(data);
    System.out.println("Client recv from Server:" + new String(data).trim());
    } finally {
    ReferenceCountUtil.release(msg);
    }
    }


    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
    cause.printStackTrace();
    ctx.close();
    }

    }
    }

    KeyStore读取P12
    keyStore除了读取JKS外,还可以读取P12密钥库,以上代码中使用KeyStore读取JKS的地方都可以换成读取P12(如使用openssl生成的证书或其他X.509证书都以直接转到p12而无需再转到jks)

    /** 证书 */
    String basePath = "D:/idea_workspace/dev-utils/src/main/resources/";
    File p12File = new File(basePath + "jks/emqx-dev.p12");
    String p12Passw = "myp12pass";
    ...
    /** 方式1: Java SSL(使用p12) - keyMangerFactory */
    //keyStore(仅需设置keyManager,用于管理服务端crt+key)
    //defaultType: jks 或者系统属性: keystore.type
    KeyStore ks = KeyStore.getInstance("PKCS12");
    ks.load(new FileInputStream(p12File), p12Passw.toCharArray());
    //defaultAlgorithm: SunX509 或者系统属性: ssl.KeyManagerFactory.algorithm
    KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
    kmf.init(ks, p12Passw.toCharArray());
    //生成SSLContext
    sslContext = SSLContext.getInstance("TLS");
    sslContext.init(kmf.getKeyManagers(), null, null);
    ...

    TODO 自定义验证规则
    例如对证书中的特定subject进行验证(如设备ID等)

  • 相关阅读:
    npm的qs包的使用:stringify()将json对象序列化成表单数据
    git放弃本地某个文件或所有文件的修改
    git关联本地分支和远程分支, 在本地删除远程已经不存在的分支
    vs code代码提示的问题
    js BOM(二)offset系列,scroll系列,client系列,封装变速动画函数
    解决antd design的Modal组件弹出卡顿的问题
    js BOM(一)window、location、history、navigator、定时器setInterval,setTimeout,轮播图
    BizCharts渲染多条曲线时color的使用
    js DOM(三)节点、元素创建3种方式、为元素绑定多个事件addEventListener、attachEvent
    HDU 1081 To The Max
  • 原文地址:https://www.cnblogs.com/exmyth/p/14811555.html
Copyright © 2020-2023  润新知