netty集成ssl双向验证
文章分为两部分,
- 生成服务器和客户端两个证书
- 将证应用到netty中
生成证书用到jak自带的工具,一会再讲,先看如果假设我们已经有两个证书(服务器和客户端)如何写程序
服务器上要添加sslhandler,参数是sslEngine,而engine由sslContext创建
p.addLast(new SslHandler(context.newEngine(socketChannel.alloc())));
- 服务器,创建sslContext
public static SslContext getSslContextService() {
List<String> ciphers = Arrays.asList("ECDHE-RSA-AES128-SHA", "ECDHE-RSA-AES256-SHA", "AES128-SHA", "AES256-SHA", "DES-CBC3-SHA");
try {
//创建KeyStore
KeyStore keyStore = KeyStore.getInstance("JKS");
//加载证书,第一个参数是一个指向服务器证书的流,第二个参数是证书密码转成char数组
keyStore.load(ResourceManager.gerResourceForFile("sChat.jks"), "密码".toCharArray());
//创建KeyManagerFactory(密钥管理器,不带这个过不去客户端的信任管理器)
KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance("SunX509");
keyManagerFactory.init(keyStore, "密码".toCharArray());
//信任管理器(信任列表的客户端才会被接受)
TrustManagerFactory tf = TrustManagerFactory.getInstance("SunX509");
tf.init(keyStore);
//SslContextBuilder创建sslcontext
return SslContextBuilder
.forServer(keyManagerFactory)
.trustManager(tf)
.ciphers(ciphers)
.clientAuth(ClientAuth.REQUIRE) //必须校验客户端
//要用openssl,必须在maven中添加 netty-tcnative-boringssl-static 才行
.sslProvider(SslProvider.OPENSSL)
.build();
} catch (Exception e) {
e.printStackTrace();
}
throw new IllegalArgumentException("无法创建SslContext");
}
- 客户端相同道理,也要创建 sslContext
public static SslContext getSslContextClient() {
List<String> ciphers = Arrays.asList("ECDHE-RSA-AES128-SHA", "ECDHE-RSA-AES256-SHA", "AES128-SHA", "AES256-SHA", "DES-CBC3-SHA");
try {
//同理
KeyStore keyStore = KeyStore.getInstance("JKS");
//客户端证书的流 和 客户端证书密码
keyStore.load(ResourceManager.gerResourceForFile("cChat.jks"), "密码".toCharArray());
//
TrustManagerFactory tf = TrustManagerFactory.getInstance("SunX509");
//初始化
tf.init(keyStore);
KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance("SunX509");
keyManagerFactory.init(keyStore, "密码".toCharArray());
return SslContextBuilder
.forClient()
.trustManager(tf)
.keyManager(keyManagerFactory)
.ciphers(ciphers)
.sslProvider(SslProvider.OPENSSL) //同样也要加入相应jar包
.build();
} catch (Exception e) {
e.printStackTrace();
}
throw new IllegalArgumentException("无法创建SslContext");
}
上面两步是根据证书创建sslContext的方法,接下来将如何生成证书
第一步: 生成Netty服务端私钥和证书(高版本的java可能会提示升级转换之类的,复制他的提示,直接运行会产生因版本的证书)
keytool -genkey -alias securechat -keysize 2048 -validity 365 -keyalg RSA -dname "CN=qiuzi" -keypass 123456 -storepass 123456 -keystore sChat.jks
第二步:生成Netty服务端自签名证书
keytool -export -alias securechat -keystore sChat.jks -storepass 123456 -file sChat.cer
第三步:生成客户端的密钥对和证书仓库,用于将服务端的证书保存到客户端的授信证书仓库中
keytool -genkey -alias smcc -keysize 2048 -validity 365 -keyalg RSA -dname "CN=qiuzi" -keypass 123456 -storepass 123456 -keystore cChat.jks
第四步:将Netty服务端证书导入到客户端的证书仓库中
keytool -import -trustcacerts -alias securechat -file sChat.cer -storepass 123456 -keystore cChat.jks
如果你只做单向认证,则到此就可以结束了,如果是双响认证,则还需继续往下走
第五步:生成客户端自签名证书
keytool -export -alias smcc -keystore cChat.jks -storepass 123456 -file cChat.cer
最后一步:将客户端的自签名证书导入到服务端的信任证书仓库中:
keytool -import -trustcacerts -alias smcc -file cChat.cer -storepass 123456 -keystore sChat.jks
以上生成的两个后缀为jks的文件,两个后缀为cer的文件,我们将cChat.jks作为客户端生成sslcontext的文件,sChat.jks作为服务器生成sslContext的文件,即可。