Keytool工具生成SSL证书以及在Java中实现SSL

1.Keytool工具生成SSL证书

    keytool即JDK中自带的证书生成工具,常见的还有openssl工具。

     1.生成一个自签名的CA证书,为了给Client和Server的证书签名。

      命令:keytool -genkeypair (-keyalg RSA) -alias TEST_ROOT -keystore test_root.jks

      解释:生成一对密钥,存储在test_root.jks中,条目别名为TEST_ROOT。输入该命令后会提示输入个人信息。当命令完成后,会在test_root.jks中生成一个自签名的证书。当然,私钥也保存在该文件中。这里密钥库的密码和密钥密码都设置成123456

如果不加keyalg 的,默认是DSA算法生成

    

2.为server生成一对密钥(也就是一个自签名的证书)

 命令:keytool -genkeypair -alias TEST_SERVER -keystore test_server.jks

解释:生成一对密钥,存储在test_server.jks中,条目别名TEST_SERVER。

3.生成一个签名请求文件(即请求CA给server自签名的证书签名)

扫描二维码关注公众号,回复: 11896578 查看本文章

命令:keytool -certreq -file test_server.csr -alias TEST_SERVER -keystore test_server.jks

解释:为存储在test_server.jks中的别名TEST_SERVER生成一个证书请求文件test_server.csr。

4.ca为server的证书签名

命令:keytool -gencert -infile test_server.csr -outfile test_server.cer -alias TEST_ROOT -keystore TEST_ROOT.jks

解释:利用TEST_ROOT.jks中条目别名为TEST_ROOT的私钥为test_server.csr证书请求对应的证书签名,并将签名后的证书保存在test_server.cer中。

5.导出ca证书

命令:keytool -exportcert -alias TEST_ROOT -file test_root.cer -keystore test_root.jks

解释:将test_root.jks中条目别名为TEST_ROOT的证书导出到test_root.cer中。

6.将ca证书导入到test_server.jks中。

命令:keytool -importcert -alias TEST_ROOT -file test_root.cer -keystore TEST_SERVER.jks

解释:将test_root.cer证书文件导入TEST_SERVER.jks中,条目别名为TEST_ROOT。这里需要注意,在TEST_SERVER.jks中之前应不存在条目别名为TEST_ROOT,这样才会以信任证书的方式导入。

7.更新server证书

命令:keytool -importcert -alias TEST_SERVER -file test_server.cer -keystore TEST_SERVER.jks

解释:将test_server.cer导入到TEST_SERVER.jks中。因为在生成server密钥对的时候,在test_server.jks中已经存在自签的证书,条目别名为TEST_SERVER。而该命令保存的别名还是TEST_SERVER。意思上就是更新证书。将之前自签名的证书替换为ca签名过的证书。

8.查看test_server.jks中server的证书和ca证书。

命令:keytool -list -v -keystore test_server.jks

从条目test_server中可以看出,该证书被ca签名后,ca的证书也保存在该条目中,形成证书链。

对于Client的证书生成参考2-7步。在该过程中生成的文件如下:

2.在Java中实现SSL通信

  Java中主要通过JSSE(Java Secure Socket Extension)来完成安全套接字的编写。其中主要涉及了一些类,例如Keystore、KeyManagerFactory、TrustManagerFactory、SSLContext等。它们的关系如下图(图的来源于文章结尾的链接中

 

编程的步骤如下

1.利用keystore类完成客户端和服务器的证书库和信任库的加载

2.利用加载的证书库和信任库,完成KeyManagerFactory和TrustManagerFactory的初始化。

3.生成SSLContext对象,并用keyManagerFactory和TrustManagerFactory生成的keyManager和TrustManager完成初始化。

4.利用SSLContext对象,生成对应的SSLSocket和SSLServerSocket。

需要的文件

1.test_root.jks(存储了ca证书,因为client和server的证书都是被ca签名的,所以ca证书被信任,则client和server的证书都会被信任)。

2.test_client.jks(存储了client的证书)。

3.test_server.jks(存储了server的证书)。

客户端代码

public class Client {
    public static void main(String[] args) throws Exception {
        String clientKeyStoreFile = "d:\\keystore\\test_client.jks";
        String clientKeyStorePwd = "123456";
        String clientKeyPwd = "123456";
        String clientTrustKeyStoreFile = "d:\\keystore\\test_root.jks";
        String clientTrustKeyStorePwd = "123456";
        //生成client的keystore对象
        KeyStore clientKeyStore = KeyStore.getInstance("JKS");
        clientKeyStore.load(new FileInputStream(clientKeyStoreFile), clientKeyStorePwd.toCharArray());
        //生成信任证书的keystore对象
        KeyStore clientTrustKeyStore = KeyStore.getInstance("JKS");
        clientTrustKeyStore.load(new FileInputStream(clientTrustKeyStoreFile), clientTrustKeyStorePwd.toCharArray());
 
        KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
        kmf.init(clientKeyStore, clientKeyPwd.toCharArray());
 
        TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
        tmf.init(clientTrustKeyStore);
 
        SSLContext sslContext = SSLContext.getInstance("TLSv1");
        sslContext.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
        
        SSLSocketFactory socketFactory = sslContext.getSocketFactory();
        Socket socket = socketFactory.createSocket("localhost", Server.SERVER_PORT);
        
        PrintWriter out = new PrintWriter(socket.getOutputStream(), true);
        BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream())); 
        send("hello", out);
        send("exit", out);
        receive(in);
        socket.close();
    }
    
    public static void send(String s, PrintWriter out) throws IOException {
        System.out.println("Sending: " + s);     
        out.println(s);
    }
 
    public static void receive(BufferedReader in) throws IOException {
        String s;
        while ((s = in.readLine()) != null) {
            System.out.println("Reveived: " + s);
        }
    }
}

服务器代码

public class Server implements Runnable,HandshakeCompletedListener {
    public static final int SERVER_PORT = 11123; 
    private final Socket s;
    private String peerCerName;
    public Server(Socket s) {
      		this.s = s;
    }
     public static void main(String[] args) throws Exception {
        String serverKeyStoreFile = "d:\\keystore\\test_server.jks";
        String serverKeyStorePwd = "123456";
        String ServerKeyPwd = "123456";
        String serverTrustKeyStoreFile = "d:\\keystore\\test_root.jks";
        String serverTrustKeyStorePwd = "123456";
        /*
         * 加载server.keystore
         * 
         */
        KeyStore serverKeyStore = KeyStore.getInstance("JKS");
        serverKeyStore.load(new FileInputStream(serverKeyStoreFile), serverKeyStorePwd.toCharArray());
        /*
         * 加载servertrust.keystore
         * 
         */
        KeyStore serverTrustKeyStore = KeyStore.getInstance("JKS");
        serverTrustKeyStore.load(new FileInputStream(serverTrustKeyStoreFile), serverTrustKeyStorePwd.toCharArray());
 
        KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
        kmf.init(serverKeyStore, ServerKeyPwd.toCharArray());
 
        TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
        tmf.init(serverTrustKeyStore);
 
        SSLContext sslContext = SSLContext.getInstance("TLSv1");
        sslContext.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
 
        SSLServerSocketFactory sslServerSocketFactory = sslContext.getServerSocketFactory();
        SSLServerSocket sslServerSocket = (SSLServerSocket) sslServerSocketFactory.createServerSocket(SERVER_PORT);
        //设置双向验证
        sslServerSocket.setNeedClientAuth(true);
 
        while (true) {
            SSLSocket s = (SSLSocket)sslServerSocket.accept();
            Server cs = new Server(s);
            s.addHandshakeCompletedListener(cs);
            new Thread(cs).start();
        }
    }
 
    @Override
    public void run() {
        try {
            BufferedReader reader = new BufferedReader(new InputStreamReader(s.getInputStream()));
            PrintWriter writer = new PrintWriter(s.getOutputStream(), true);
 
            writer.println("Welcome~, enter exit to leave.");
            String message;
            while ((message = reader.readLine()) != null && !message.trim().equalsIgnoreCase("exit")) {
                writer.println("Echo: " + message);
            }
            writer.println("Bye~, " + peerCerName);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                s.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
 
    @Override
    public void handshakeCompleted(HandshakeCompletedEvent event) {
        try {
            X509Certificate cert = (X509Certificate) event.getPeerCertificates()[0];
            peerCerName = cert.getSubjectX500Principal().getName();
        } catch (SSLPeerUnverifiedException ex) {
            ex.printStackTrace();
        }
    }

}

运行结果

说明SSL握手成功建立。

参考的文章:https://www.ibm.com/developerworks/cn/java/j-lo-socketkeytool/

猜你喜欢

转载自blog.csdn.net/sinat_33822516/article/details/81057646