对于VPN应用来说,为了提升安全性,对消息加密是常规操作。
众所周之,Netty是高性能的Java NIO网络通信框架,因而用Netty来写VPN通信是再正常不过了。网上关于为Netty生成、以及使用SSL/TLS证书的文章有很多,但由于各种原因,生成的证书要么是Netty中无法读取和使用,要么是代码不全或不具体导致根本配不通SSL/TLS加密。(通常TLS有两种 普通TLS 和国密TLS,本章主要讲述普通TLS)
一、通过openSSL 生成证书
OpenSSL是一个开放源代码的软件库,应用程序可以使用这个包来进行安全通信,它包括代码、脚本、配置和过程的集合。其主要库是以 C 语言所写成,实现了基本的加密功能,实现了 SSL 与 TLS 协议。OpenSSL整个软件包大概可以分成三个主要功能部分:SSL协议库、应用程序、密码算法库。
如果自己电脑已经安装了openSSL并配置相应的环境变量,可以直接使用命令生成证书。
命令如下:
创建私钥证书 openssl genrsa -des3 -out netty/netty-key.pem 1024
创建证书请求 openssl req -new -out netty/netty-req.csr -key netty/netty-key.pem
生成公钥证书 openssl x509 -req -inca/ca-req.csr -out netty/netty-cert.crt -signkey netty/netty-key.pem -days 3650
二、netty 绑定TLS证书
1、创建一个sslContext 来绑定证书
if (sslContext != null) {
return;
}
if (BuildConfig.GMSSL_ENABLE) {
//这是国密的TLS证书 本章暂时忽略
try {
sslContext = (SslContext) GmUtils.getInstance().createNettySslContext(clientCry, clientKey, caCrt, signGm, signGmKey);
} catch (Exception e) {
e.printStackTrace();
}
return;
}
InputStream clientCryInput = new ByteArrayInputStream(clientCry.getBytes());
InputStream clientKeyInput = new ByteArrayInputStream(clientKey.getBytes());
InputStream caCrtInput = new ByteArrayInputStream(caCrt.getBytes());
try {
this.sslContext = SslContextBuilder
.forClient()
.keyManager(clientCryInput, clientKeyInput)
.trustManager(caCrtInput)
.build();
} catch (SSLException e) {
e.printStackTrace();
Logger.p("fail to create ssl", e);
}
2、在netty中绑定 sslContext,创建一个SslHandler 来处理sslContext 如下:
public class SslHandler extends ChannelInitializer<SocketChannel> {
private SslContext sslContext;
private ConcurrentLinkedQueue<ByteBuffer> readQueue;
private ConcurrentLinkedQueue<Object> writeQueue;
public SdpNettyHandler(SslContext sslContext, ConcurrentLinkedQueue<ByteBuffer> readQueue,ConcurrentLinkedQueue<Object> writeQueue) {
this.sslContext = sslContext;
this.writeQueue = writeQueue;
this.readQueue = readQueue;
}
@Override
protected void initChannel(SocketChannel ch) throws Exception {
if (this.sslContext != null) {
//绑定sslContext
ch.pipeline().addLast(this.sslContext.newHandler(ch.alloc()));
}
ch.pipeline().addLast(new TcpFrameEncoder());
ch.pipeline().addLast(new HeartHandler(readQueue,writeQueue));
ch.pipeline().addLast(new EchoClientHandlerV2(this.readQueue));
ch.pipeline().addLast(new EchoClientHandler(this.readQueue));
ch.pipeline().addLast(new DatagramDnsResponseDecoder());
}
}
3、在创建netty 连接绑定SslHandler
bootstrap = new Bootstrap();
bootstrap.group(eventLoopGroup).channel(NioSocketChannel.class)
.resolver(MyAddressResolverGroup.getInstance(hostMap))
.option(ChannelOption.TCP_NODELAY, true)
.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 3000)
.option(ChannelOption.ALLOCATOR, ByteBufAllocator.DEFAULT)
.option(ChannelOption.RCVBUF_ALLOCATOR, new AdaptiveRecvByteBufAllocator(5000, 5000, 80000))
.option(ChannelOption.SO_KEEPALIVE, true)
.handler(new SslHandler(sslContext, readQueue, writeQueue));
channelFuture = bootstrap.connect(host, port).sync();
到此netty 绑定证书完毕