Netty ssl mutual authentication

Certificates and code generation operation about passwords, modify into their own in accordance with your own needs

Use keytool to generate a certificate

This command is usually JDK \ jre \ lib \ security \ directory operations

keytool commonly used commands

parameter DEFINITIONS
-alias Alias ​​certificate
-keystore Name of the certificate library
-storepass Password certificate store
-keypass Password certificate
-list Display certificate information keystore
-v Display certificate keystore details
-export Display certificate information keystore
-file Specify export certificate file name and path
-delete To delete an entry key store
-import The signed digital certificate into the key store
-keypasswd Modify keystore password specified entry
-dname Specify the certificate owner information
-Keylg Algorithm specified key
-validity Specifies the number of days to create the certificate is valid
-keysize Specifying a key length

Specific operations to generate a certificate

  1. Create a server-side keys
keytool -genkey -alias nettyServer -keysize 1024 -validity 3650 -keyalg RSA -dname "CN=localhost" -keypass 证书密码 -storepass 服务端的证书仓库密码 -keystore serverCerts.jks
  1. Export server keys
keytool -export -alias nettyServer -keystore serverCerts.jks -storepass 服务端的证书仓库密码 -file serverCert.cer
  1. Creating client keys
keytool -genkey -alias nettyClient -keysize 1024 -validity 3650 -keyalg RSA -dname "CN=PF,OU=YJC,O=YJC,L=BJ,S=BJ,C=ZN" -keypass 证书密码 -storepass 客户端的证书仓库密码 -keystore clientCerts.jks
  1. Export client keys
keytool -export -alias nettyClient -keystore clientCerts.jks -file nettyclientCert.cer -storepass 客户端的证书仓库密码
  1. The client's certificate into the trusted certificate in warehouse server
keytool -import -trustcacerts -alias smcc -file nettyClientCert.cer -storepass 服务端的证书仓库密码 -keystore serverCerts.jks
  1. The service side of the import certificate to a trusted certificate in the client's warehouse
keytool -import -trustcacerts -alias smccClient -file serverCert.cer -storepass 客户端的证书仓库密码 -keystore clientCerts.jks

Server create ContextSSLFactory

package com.yjc.rpc.ssl;


import org.springframework.core.io.ClassPathResource;

import java.io.FileInputStream;
import java.io.IOException;
import java.security.KeyStore;
import java.security.NoSuchAlgorithmException;

import javax.net.ssl.*;


public class ContextSSLFactory {

    private static final SSLContext SSL_CONTEXT_S ;

    static{
        SSLContext sslContextServer = null ;
        try {
            sslContextServer = SSLContext.getInstance("SSLv3") ;

        } catch (NoSuchAlgorithmException e1) {
            e1.printStackTrace();
        }
        try{
            if(getKeyManagersServer() != null && getTrustManagersServer() != null ){
                sslContextServer.init(getKeyManagersServer(), getTrustManagersServer(), null);
            }


        }catch(Exception e){
            e.printStackTrace() ;
        }
        sslContextServer.createSSLEngine().getSupportedCipherSuites() ;
        SSL_CONTEXT_S = sslContextServer ;
    }
    public ContextSSLFactory(){

    }
    public static SSLContext getSslContext(){
        return SSL_CONTEXT_S ;
    }
    /**
     * 获取服务端信任的证书
     * @param:             @return
     * @return:         TrustManager[]
     * @throws
     */
    private static TrustManager[] getTrustManagersServer(){
        FileInputStream is = null ;
        TrustManager[] trustManagersw=null;
        TrustManagerFactory trustManagerFactory=null;
        KeyStore ks=null;
        try {
            trustManagerFactory = TrustManagerFactory.getInstance("SunX509") ;
            is =is =new FileInputStream( (new ClassPathResource("certs/serverCerts.jks")).getFile() );
            String keyStorePass = "服务端的证书仓库密码" ;
            ks=KeyStore.getInstance("JKS");
            ks.load(is,keyStorePass.toCharArray());
            trustManagerFactory.init(ks);
            trustManagersw=trustManagerFactory.getTrustManagers();
        } catch (Exception e) {
            e.printStackTrace();
        }
        finally{
            if(is != null ){
                try {
                    is.close() ;
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return trustManagersw;
    }


    /**
     * 获取keymanager列表
     * @param:             @return
     * @return:         KeyManager[]
     * @throws
     */
    private static KeyManager[] getKeyManagersServer(){
        FileInputStream is = null ;
        KeyStore ks = null ;
        KeyManagerFactory keyFac = null ;

        KeyManager[] kms = null ;
        try {
            // 获得KeyManagerFactory对象. 初始化位默认算法
            keyFac = KeyManagerFactory.getInstance("SunX509") ;
//            String keyStorePath = PropertyUtil.getProperty("httpsKeyStorePath");
            is =new FileInputStream( (new ClassPathResource("certs/serverCerts.jks")).getFile() );
            ks = KeyStore.getInstance("JKS") ;
            String keyStorePass = "服务端的证书仓库密码";
            ks.load(is , keyStorePass.toCharArray()) ;
            keyFac.init(ks, keyStorePass.toCharArray()) ;
            kms = keyFac.getKeyManagers() ;
        } catch (Exception e) {
            e.printStackTrace();
        }
        finally{
            if(is != null ){
                try {
                    is.close() ;
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return kms ;
    }
}

Add netty comes sslHandler in the pipeline

It should be noted that SslHandler needs to be added to the front of the pipeline, or even added, unlawful client can connect as normal

   try {
            //设置事件处理
            serverBootstrap.childHandler(new ChannelInitializer<SocketChannel>() {
                @Override
                protected void initChannel(SocketChannel ch) {
                    ChannelPipeline pipeline = ch.pipeline();
                    // 添加心跳支持
                    pipeline.addLast(new IdleStateHandler(5, 0, 0, TimeUnit.SECONDS));
                    // 基于定长的方式解决粘包/拆包问题
//                    pipeline.addLast(new LengthFieldBasedFrameDecoder(nettyConfig.getMaxFrameLength()
//                            , 0, 2, 0, 2));
//                    pipeline.addLast(new LengthFieldPrepender(2));
                    // 序列化
//                    pipeline.addLast(new MessagePackDecoder());
//                    pipeline.addLast(new MessagePackEncoder());
                    pipeline.addLast(MarshallingCodeCFactory.buildMarshallingDecoder());
                    pipeline.addLast(MarshallingCodeCFactory.buildMarshallingEncoder());
                    pipeline.addLast(channelHandlerAdapter);
                    SSLEngine engine = ContextSSLFactory.getSslContext().createSSLEngine();
                    engine.setUseClientMode(false); //设置为服务端模式
                    engine.setNeedClientAuth(true); //需要验证客户端
                    pipeline.addFirst("ssl", new SslHandler(engine));   //这个handler需要加到最前面
                }
            });
            LOGGER.info("netty服务器在[{}]端口启动监听", port);
            ChannelFuture f = serverBootstrap.bind(port).sync();
            f.channel().closeFuture().sync();
        } catch (InterruptedException e) {
            LOGGER.info("[出现异常] 释放资源");
            boss.shutdownGracefully();
            work.shutdownGracefully();
        }

The client code is basically similar, there is not posted.

Guess you like

Origin www.cnblogs.com/falcon-fei/p/11453727.html