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自签名的证书签名)

命令: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/

你可能感兴趣的:(Keytool工具生成SSL证书以及在Java中实现SSL)