SSL连接的JAVA实现

SSL连接分为双向认证和单向认证。其中双向认证表示服务器和客户端都需要分别校验对方的身份。单向认证则只需要客户端校验服务器的身份。

SSL的双向认证的流程如下图:

从以上流程可见,要完成双向认证,服务器端和客户端都需要验证对方的证书,然后再进行加密的协商。这里基于JAVA来实现一个服务器端和客户端的程序,可以实现双向认证。

首先需要准备服务器和客户端的相关证书:

1. 创建自签名的根密钥

openssl genrsa -out rootkey.pem 2048

2. 生成根证书

openssl req -x509 -new -key rootkey.pem -out root.crt -subj="/C=CN/ST=GD/L=GZ/O=RootCA/OU=RootCA/CN=RootCA"

3. 生成客户端密钥

openssl genrsa -out clientkey.pem 2048

4. 生成客户端证书请求文件,使用根证书进行签发

openssl req -new -key clientkey.pem -out client.csr -subj="/C=CN/ST=GD/L=GZ/O=BMW/OU=Vehicle/CN=Vehicle1"

5. 用根证书来签发客户端请求文件,生成客户端证书client.crt

openssl x509 -req -in client.csr -CA root.crt -CAkey rootkey.pem -CAcreateserial -days 3650 -out client.crt

6. 打包客户端资料为pkcs12格式(client.pkcs12)

openssl pkcs12 -export -in client.crt -inkey clientkey.pem -out client.pkcs12

7. 生成服务器端的密匙

openssl genrsa -out serverkey.pem 2048

8. 生成服务器端证书的请求文件。请求根证书来签发

openssl req -new -key serverkey.pem -out server.csr -subj="/C=CN/ST=GD/L=GZ/O=BMW/OU=IT/CN=Broker"

9. 用根证书来签发服务器端请求文件,生成服务器端证书server.crt

openssl x509 -req -in server.csr -CA root.crt -CAkey rootkey.pem -CAcreateserial -days 3650 -out server.crt

10. 打包服务器端资料为pkcs12格式(server.pkcs12 )

openssl pkcs12 -export -in server.crt -inkey serverkey.pem -out server.pkcs12

11. 生成信任客户端的keystore,把根证书以及需要信任的客户端的证书添加到这个keystore

keytool -importcert -alias ca -file root.crt -keystore clienttrust.jks

keytool -importcert -alias clientcert -file client.crt -keystore clienttrust.jks

12. 生成信任服务器端的keystore,把根证书以及需要信任的服务端的证书添加到这个keystore

keytool -importcert -alias ca -file root.crt -keystore servertrust.jks

keytool -importcert -alias servercert -file server.crt -keystore servertrust.jks

服务器程序

以下是服务器的程序

public class SSLServer 
{
    private SSLServerSocket sslServerSocket;
    public static void main( String[] args ) throws Exception
    {
        SSLServer server = new SSLserver();
        server.init();
        System.out.println( "Server initialted!" );
        server.process();
    }

    public void init() throws Exception {
        int port = 9999;
        String keystorePath = "/home/roy/projects/cert/server.pkcs12";
        String keystorePass = "123456";
        SSLContext context = SSLContext.getInstance("TLSv1.2");

        //加载服务器的证书和Private key
        KeyStore serverKeyStore = KeyStore.getInstance("pkcs12");
        FileInputStream keystoreFis = new FileInputStream(keystorePath);
        serverKeyStore.load(keystoreFis, keystorePass.toCharArray());
        KeyManagerFactory kmf = KeyManagerFactory.getInstance("sunx509");
        kmf.init(serverKeyStore, keystorePass.toCharArray());

        //加载要信任的客户端证书的keystore
        String trustClientKeystorePath = "/home/roy/projects/cert/clienttrust.jks";
        KeyStore trustKeyStore = KeyStore.getInstance("jks");
        FileInputStream trustKeystoreFis = new FileInputStream(trustClientKeystorePath);
        trustKeyStore.load(trustKeystoreFis, keystorePass.toCharArray());
        TrustManagerFactory tmf = TrustManagerFactory.getInstance("sunx509");
        tmf.init(trustKeyStore);

        context.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
        sslServerSocket = (SSLServerSocket)context.getServerSocketFactory().createServerSocket(port);
        sslServerSocket.setNeedClientAuth(true);
    }

    public void process() throws Exception {
        String bye = "Bye!";
        byte[] buffer = new byte[50];
        while(true) {
            Socket socket = sslServerSocket.accept();
            InputStream in = socket.getInputStream();
            in.read(buffer);
            System.out.println("Received: " + new String(buffer));
            OutputStream out = socket.getOutputStream();
            out.write(bye.getBytes());
            out.flush();
        }
    }
}

客户端程序

如以下代码:

public class SSLClient
{
    private SSLSocket sslSocket;
    public static void main( String[] args ) throws Exception
    {
        SSLClient client = new SSLClient();
        client.init();
        System.out.println( "Client initiated." );
        client.process();
    }

    public void init() throws Exception {
        String host = "127.0.0.1";
        int port = 9999;
        String keystorePath = "/home/roy/projects/cert/client.pkcs12";
        String keystorePass = "123456";

        SSLContext context = SSLContext.getInstance("TLSv1.2");

        //加载客户端的证书和private key
        KeyStore clientKeyStore = KeyStore.getInstance("pkcs12");
        FileInputStream keystoreFis = new FileInputStream(keystorePath);
        clientKeyStore.load(keystoreFis, keystorePass.toCharArray());

        KeyManagerFactory kmf = KeyManagerFactory.getInstance("sunx509");
        kmf.init(clientKeyStore, keystorePass.toCharArray());

        //加载信任的服务器证书的keystore
        String trustServerKeystorePath = "/home/roy/projects/cert/servertrust.jks";
        KeyStore trustKeyStore = KeyStore.getInstance("jks");
        FileInputStream trustKeystoreFis = new FileInputStream(trustServerKeystorePath);
        trustKeyStore.load(trustKeystoreFis, keystorePass.toCharArray());
        TrustManagerFactory tmf = TrustManagerFactory.getInstance("sunx509");
        tmf.init(trustKeyStore);

        context.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
        sslSocket = (SSLSocket)context.getSocketFactory().createSocket(host, port);
    }

    public void process() throws Exception {
        String hello = "Hello World";
        OutputStream out = sslSocket.getOutputStream();
        out.write(hello.getBytes(), 0, hello.getBytes().length);
        out.flush();
        Thread.sleep(1000);
        InputStream in = sslSocket.getInputStream();
        byte [] buffer = new byte[50];
        in.read(buffer);
        System.out.println(new String(buffer));
    }
}

之后分别运行服务器和客户端程序,可以见到SSL的双向认证通过,建立连接并成功收发信息。

如果要实现单向认证,那么客户端的代码不需要改动,服务器端的代码改动如下:

public class SSLServer 
{
    private SSLServerSocket sslServerSocket;
    public static void main( String[] args ) throws Exception
    {
        SSLServer server = new SSLserver();
        server.init();
        System.out.println( "Server initialted!" );
        server.process();
    }

    public void init() throws Exception {
        int port = 9999;
        String keystorePath = "/home/roy/projects/cert/server.pkcs12";
        String keystorePass = "123456";
        SSLContext context = SSLContext.getInstance("TLSv1.2");

        //加载服务器的证书和Private key
        KeyStore serverKeyStore = KeyStore.getInstance("pkcs12");
        FileInputStream keystoreFis = new FileInputStream(keystorePath);
        serverKeyStore.load(keystoreFis, keystorePass.toCharArray());
        KeyManagerFactory kmf = KeyManagerFactory.getInstance("sunx509");
        kmf.init(serverKeyStore, keystorePass.toCharArray());

        context.init(kmf.getKeyManagers(), null, null);
        sslServerSocket = (SSLServerSocket)context.getServerSocketFactory().createServerSocket(port);
        sslServerSocket.setNeedClientAuth(false);
    }

    public void process() throws Exception {
        String bye = "Bye!";
        byte[] buffer = new byte[50];
        while(true) {
            Socket socket = sslServerSocket.accept();
            InputStream in = socket.getInputStream();
            in.read(buffer);
            System.out.println("Received: " + new String(buffer));
            OutputStream out = socket.getOutputStream();
            out.write(bye.getBytes());
            out.flush();
        }
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

gzroy

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值